1 /** @file
2     High-level utility functions for decoders.
3 
4     Copyright (C) 2018 Christian Zuckschwerdt
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 */
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include "data.h"
15 #include "util.h"
16 #include "decoder_util.h"
17 #include "fatal.h"
18 
19 // create decoder functions
20 
create_device(r_device * dev_template)21 r_device *create_device(r_device *dev_template)
22 {
23     r_device *r_dev = malloc(sizeof (*r_dev));
24     if (!r_dev) {
25         WARN_MALLOC("create_device()");
26         return NULL; // NOTE: returns NULL on alloc failure.
27     }
28     if (dev_template)
29         *r_dev = *dev_template; // copy
30 
31     return r_dev;
32 }
33 
34 // variadic print functions
35 
bitbuffer_printf(const bitbuffer_t * bitbuffer,_Printf_format_string_ char const * restrict format,...)36 void bitbuffer_printf(const bitbuffer_t *bitbuffer, _Printf_format_string_ char const *restrict format, ...)
37 {
38     va_list ap;
39     va_start(ap, format);
40     vfprintf(stderr, format, ap);
41     va_end(ap);
42     bitbuffer_print(bitbuffer);
43 }
44 
bitbuffer_debugf(const bitbuffer_t * bitbuffer,_Printf_format_string_ char const * restrict format,...)45 void bitbuffer_debugf(const bitbuffer_t *bitbuffer, _Printf_format_string_ char const *restrict format, ...)
46 {
47     va_list ap;
48     va_start(ap, format);
49     vfprintf(stderr, format, ap);
50     va_end(ap);
51     bitbuffer_debug(bitbuffer);
52 }
53 
bitrow_printf(uint8_t const * bitrow,unsigned bit_len,_Printf_format_string_ char const * restrict format,...)54 void bitrow_printf(uint8_t const *bitrow, unsigned bit_len, _Printf_format_string_ char const *restrict format, ...)
55 {
56     va_list ap;
57     va_start(ap, format);
58     vfprintf(stderr, format, ap);
59     va_end(ap);
60     bitrow_print(bitrow, bit_len);
61 }
62 
bitrow_debugf(uint8_t const * bitrow,unsigned bit_len,_Printf_format_string_ char const * restrict format,...)63 void bitrow_debugf(uint8_t const *bitrow, unsigned bit_len, _Printf_format_string_ char const *restrict format, ...)
64 {
65     va_list ap;
66     va_start(ap, format);
67     vfprintf(stderr, format, ap);
68     va_end(ap);
69     bitrow_debug(bitrow, bit_len);
70 }
71 
72 // variadic output functions
73 
decoder_output_messagef(r_device * decoder,_Printf_format_string_ char const * restrict format,...)74 void decoder_output_messagef(r_device *decoder, _Printf_format_string_ char const *restrict format, ...)
75 {
76     char msg[60]; // fixed length limit
77     va_list ap;
78     va_start(ap, format);
79     vsnprintf(msg, 60, format, ap);
80     va_end(ap);
81     decoder_output_message(decoder, msg);
82 }
83 
decoder_output_bitbufferf(r_device * decoder,bitbuffer_t const * bitbuffer,_Printf_format_string_ char const * restrict format,...)84 void decoder_output_bitbufferf(r_device *decoder, bitbuffer_t const *bitbuffer, _Printf_format_string_ char const *restrict format, ...)
85 {
86     char msg[60]; // fixed length limit
87     va_list ap;
88     va_start(ap, format);
89     vsnprintf(msg, 60, format, ap);
90     va_end(ap);
91     decoder_output_bitbuffer(decoder, bitbuffer, msg);
92 }
93 
decoder_output_bitbuffer_arrayf(r_device * decoder,bitbuffer_t const * bitbuffer,_Printf_format_string_ char const * restrict format,...)94 void decoder_output_bitbuffer_arrayf(r_device *decoder, bitbuffer_t const *bitbuffer, _Printf_format_string_ char const *restrict format, ...)
95 {
96     char msg[60]; // fixed length limit
97     va_list ap;
98     va_start(ap, format);
99     vsnprintf(msg, 60, format, ap);
100     va_end(ap);
101     decoder_output_bitbuffer_array(decoder, bitbuffer, msg);
102 }
103 
decoder_output_bitrowf(r_device * decoder,uint8_t const * bitrow,unsigned bit_len,_Printf_format_string_ char const * restrict format,...)104 void decoder_output_bitrowf(r_device *decoder, uint8_t const *bitrow, unsigned bit_len, _Printf_format_string_ char const *restrict format, ...)
105 {
106     char msg[60]; // fixed length limit
107     va_list ap;
108     va_start(ap, format);
109     vsnprintf(msg, 60, format, ap);
110     va_end(ap);
111     decoder_output_bitrow(decoder, bitrow, bit_len, msg);
112 }
113 
114 // output functions
115 
decoder_output_data(r_device * decoder,data_t * data)116 void decoder_output_data(r_device *decoder, data_t *data)
117 {
118     decoder->output_fn(decoder, data);
119 }
120 
decoder_output_message(r_device * decoder,char const * msg)121 void decoder_output_message(r_device *decoder, char const *msg)
122 {
123     data_t *data = data_make(
124             "msg", "", DATA_STRING, msg,
125             NULL);
126     decoder_output_data(decoder, data);
127 }
128 
bitrow_asprint_code(uint8_t const * bitrow,unsigned bit_len)129 static char *bitrow_asprint_code(uint8_t const *bitrow, unsigned bit_len)
130 {
131     char *row_code;
132     char row_bytes[BITBUF_ROWS * BITBUF_COLS * 2 + 1]; // TODO: this is a lot of stack
133 
134     row_bytes[0] = '\0';
135     // print byte-wide
136     for (unsigned col = 0; col < (unsigned)(bit_len + 7) / 8; ++col) {
137         sprintf(&row_bytes[2 * col], "%02x", bitrow[col]);
138     }
139     // remove last nibble if needed
140     row_bytes[2 * (bit_len + 3) / 8] = '\0';
141 
142     // a simple bitrow representation
143     row_code = malloc(8 + bit_len / 4 + 1); // "{nnnn}..\0"
144     if (!row_code) {
145         WARN_MALLOC("decoder_output_bitbuffer()");
146         return NULL; // NOTE: returns NULL on alloc failure.
147     }
148     sprintf(row_code, "{%u}%s", bit_len, row_bytes);
149 
150     return row_code;
151 }
152 
bitrow_asprint_bits(uint8_t const * bitrow,unsigned bit_len)153 static char *bitrow_asprint_bits(uint8_t const *bitrow, unsigned bit_len)
154 {
155     char *row_bits, *p;
156 
157     p = row_bits = malloc(bit_len + bit_len / 4 + 1); // "1..\0" (1 space per nibble)
158     if (!row_bits) {
159         WARN_MALLOC("bitrow_asprint_bits()");
160         return NULL; // NOTE: returns NULL on alloc failure.
161     }
162 
163     // print bit-wide with a space every nibble
164     for (unsigned i = 0; i < bit_len; ++i) {
165         if (i > 0 && i % 4 == 0) {
166             *p++ = ' ';
167         }
168         if (bitrow[i / 8] & (0x80 >> (i % 8))) {
169             *p++ = '1';
170         }
171         else {
172             *p++ = '0';
173         }
174     }
175     *p++ = '\0';
176 
177     return row_bits;
178 }
179 
decoder_output_bitbuffer(r_device * decoder,bitbuffer_t const * bitbuffer,char const * msg)180 void decoder_output_bitbuffer(r_device *decoder, bitbuffer_t const *bitbuffer, char const *msg)
181 {
182     data_t *data;
183     char *row_codes[BITBUF_ROWS];
184     char *row_bits[BITBUF_ROWS] = {0};
185     unsigned i;
186 
187     for (i = 0; i < bitbuffer->num_rows; i++) {
188         row_codes[i] = bitrow_asprint_code(bitbuffer->bb[i], bitbuffer->bits_per_row[i]);
189 
190         if (decoder->verbose_bits) {
191             row_bits[i] = bitrow_asprint_bits(bitbuffer->bb[i], bitbuffer->bits_per_row[i]);
192         }
193     }
194 
195     data = data_make(
196             "msg", "", DATA_STRING, msg,
197             "num_rows", "", DATA_INT, bitbuffer->num_rows,
198             "codes", "", DATA_ARRAY, data_array(bitbuffer->num_rows, DATA_STRING, row_codes),
199             NULL);
200 
201     if (decoder->verbose_bits) {
202         data_append(data,
203                 "bits", "", DATA_ARRAY, data_array(bitbuffer->num_rows, DATA_STRING, row_bits),
204                 NULL);
205     }
206 
207     decoder_output_data(decoder, data);
208 
209     for (i = 0; i < bitbuffer->num_rows; i++) {
210         free(row_codes[i]);
211         free(row_bits[i]);
212     }
213 }
214 
decoder_output_bitbuffer_array(r_device * decoder,bitbuffer_t const * bitbuffer,char const * msg)215 void decoder_output_bitbuffer_array(r_device *decoder, bitbuffer_t const *bitbuffer, char const *msg)
216 {
217     data_t *data;
218     data_t *row_data[BITBUF_ROWS];
219     char *row_codes[BITBUF_ROWS];
220     char row_bytes[BITBUF_ROWS * BITBUF_COLS * 2 + 1]; // TODO: this is a lot of stack
221     unsigned i;
222 
223     for (i = 0; i < bitbuffer->num_rows; i++) {
224         row_bytes[0] = '\0';
225         // print byte-wide
226         for (unsigned col = 0; col < (unsigned)(bitbuffer->bits_per_row[i] + 7) / 8; ++col) {
227             sprintf(&row_bytes[2 * col], "%02x", bitbuffer->bb[i][col]);
228         }
229         // remove last nibble if needed
230         row_bytes[2 * (bitbuffer->bits_per_row[i] + 3) / 8] = '\0';
231 
232         row_data[i] = data_make(
233                 "len", "", DATA_INT, bitbuffer->bits_per_row[i],
234                 "data", "", DATA_STRING, row_bytes,
235                 NULL);
236 
237         // a simpler representation for csv output
238         row_codes[i] = bitrow_asprint_code(bitbuffer->bb[i], bitbuffer->bits_per_row[i]);
239     }
240 
241     data = data_make(
242             "msg", "", DATA_STRING, msg,
243             "num_rows", "", DATA_INT, bitbuffer->num_rows,
244             "rows", "", DATA_ARRAY, data_array(bitbuffer->num_rows, DATA_DATA, row_data),
245             "codes", "", DATA_ARRAY, data_array(bitbuffer->num_rows, DATA_STRING, row_codes),
246             NULL);
247     decoder_output_data(decoder, data);
248 
249     for (i = 0; i < bitbuffer->num_rows; i++) {
250         free(row_codes[i]);
251     }
252 }
253 
decoder_output_bitrow(r_device * decoder,uint8_t const * bitrow,unsigned bit_len,char const * msg)254 void decoder_output_bitrow(r_device *decoder, uint8_t const *bitrow, unsigned bit_len, char const *msg)
255 {
256     data_t *data;
257     char *row_code;
258     char *row_bits = NULL;
259 
260     row_code = bitrow_asprint_code(bitrow, bit_len);
261 
262     data = data_make(
263             "msg", "", DATA_STRING, msg,
264             "codes", "", DATA_STRING, row_code,
265             NULL);
266 
267     if (decoder->verbose_bits) {
268         row_bits = bitrow_asprint_bits(bitrow, bit_len);
269         data_append(data,
270                 "bits", "", DATA_STRING, row_bits,
271                 NULL);
272     }
273 
274     decoder_output_data(decoder, data);
275 
276     free(row_code);
277     free(row_bits);
278 }
279