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