2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
31 #include "blackbox_encoding.h"
32 #include "blackbox_io.h"
34 #include "common/encoding.h"
35 #include "common/printf.h"
38 static void _putc(void *p
, char c
)
44 static int blackboxPrintfv(const char *fmt
, va_list va
)
46 return tfp_format(NULL
, _putc
, fmt
, va
);
50 //printf() to the blackbox serial port with no blocking shenanigans (so it's caller's responsibility to not write too fast!)
51 int blackboxPrintf(const char *fmt
, ...)
57 const int written
= blackboxPrintfv(fmt
, va
);
65 * printf a Blackbox header line with a leading "H " and trailing "\n" added automatically. blackboxHeaderBudget is
66 * decreased to account for the number of bytes written.
68 void blackboxPrintfHeaderLine(const char *name
, const char *fmt
, ...)
74 blackboxWriteString(name
);
79 const int written
= blackboxPrintfv(fmt
, va
);
85 blackboxHeaderBudget
-= written
+ 3;
89 * Write an unsigned integer to the blackbox serial port using variable byte encoding.
91 void blackboxWriteUnsignedVB(uint32_t value
)
93 //While this isn't the final byte (we can only write 7 bits at a time)
95 blackboxWrite((uint8_t) (value
| 0x80)); // Set the high bit to mean "more bytes follow"
102 * Write a signed integer to the blackbox serial port using ZigZig and variable byte encoding.
104 void blackboxWriteSignedVB(int32_t value
)
106 //ZigZag encode to make the value always positive
107 blackboxWriteUnsignedVB(zigzagEncode(value
));
110 void blackboxWriteSignedVBArray(int32_t *array
, int count
)
112 for (int i
= 0; i
< count
; i
++) {
113 blackboxWriteSignedVB(array
[i
]);
117 void blackboxWriteSigned16VBArray(int16_t *array
, int count
)
119 for (int i
= 0; i
< count
; i
++) {
120 blackboxWriteSignedVB(array
[i
]);
124 void blackboxWriteS16(int16_t value
)
126 blackboxWrite(value
& 0xFF);
127 blackboxWrite((value
>> 8) & 0xFF);
131 * Write a 2 bit tag followed by 3 signed fields of 2, 4, 6 or 32 bits
133 void blackboxWriteTag2_3S32(int32_t *values
)
135 static const int NUM_FIELDS
= 3;
137 //Need to be enums rather than const ints if we want to switch on them (due to being C)
152 int selector
= BITS_2
, selector2
;
155 * Find out how many bits the largest value requires to encode, and use it to choose one of the packing schemes
158 * Selector possibilities
160 * 2 bits per field ss11 2233,
161 * 4 bits per field ss00 1111 2222 3333
162 * 6 bits per field ss11 1111 0022 2222 0033 3333
163 * 32 bits per field sstt tttt followed by fields of various byte counts
165 for (int x
= 0; x
< NUM_FIELDS
; x
++) {
166 //Require more than 6 bits?
167 if (values
[x
] >= 32 || values
[x
] < -32) {
172 //Require more than 4 bits?
173 if (values
[x
] >= 8 || values
[x
] < -8) {
174 if (selector
< BITS_6
) {
177 } else if (values
[x
] >= 2 || values
[x
] < -2) { //Require more than 2 bits?
178 if (selector
< BITS_4
) {
186 blackboxWrite((selector
<< 6) | ((values
[0] & 0x03) << 4) | ((values
[1] & 0x03) << 2) | (values
[2] & 0x03));
189 blackboxWrite((selector
<< 6) | (values
[0] & 0x0F));
190 blackboxWrite((values
[1] << 4) | (values
[2] & 0x0F));
193 blackboxWrite((selector
<< 6) | (values
[0] & 0x3F));
194 blackboxWrite((uint8_t)values
[1]);
195 blackboxWrite((uint8_t)values
[2]);
199 * Do another round to compute a selector for each field, assuming that they are at least 8 bits each
201 * Selector2 field possibilities
209 //Encode in reverse order so the first field is in the low bits:
210 for (int x
= NUM_FIELDS
- 1; x
>= 0; x
--) {
213 if (values
[x
] < 128 && values
[x
] >= -128) {
214 selector2
|= BYTES_1
;
215 } else if (values
[x
] < 32768 && values
[x
] >= -32768) {
216 selector2
|= BYTES_2
;
217 } else if (values
[x
] < 8388608 && values
[x
] >= -8388608) {
218 selector2
|= BYTES_3
;
220 selector2
|= BYTES_4
;
224 //Write the selectors
225 blackboxWrite((selector
<< 6) | selector2
);
227 //And now the values according to the selectors we picked for them
228 for (int x
= 0; x
< NUM_FIELDS
; x
++, selector2
>>= 2) {
229 switch (selector2
& 0x03) {
231 blackboxWrite(values
[x
]);
234 blackboxWrite(values
[x
]);
235 blackboxWrite(values
[x
] >> 8);
238 blackboxWrite(values
[x
]);
239 blackboxWrite(values
[x
] >> 8);
240 blackboxWrite(values
[x
] >> 16);
243 blackboxWrite(values
[x
]);
244 blackboxWrite(values
[x
] >> 8);
245 blackboxWrite(values
[x
] >> 16);
246 blackboxWrite(values
[x
] >> 24);
255 * Write a 2 bit tag followed by 3 signed fields of 2, 554, 877 or 32 bits
257 int blackboxWriteTag2_3SVariable(int32_t *values
)
259 static const int FIELD_COUNT
= 3;
276 * Find out how many bits the largest value requires to encode, and use it to choose one of the packing schemes
279 * Selector possibilities
281 * 2 bits per field ss11 2233,
282 * 554 bits per field ss11 1112 2222 3333
283 * 877 bits per field ss11 1111 1122 2222 2333 3333
284 * 32 bits per field sstt tttt followed by fields of various byte counts
286 int selector
= BITS_2
;
288 // Require more than 877 bits?
289 if (values
[0] >= 256 || values
[0] < -256
290 || values
[1] >= 128 || values
[1] < -128
291 || values
[2] >= 128 || values
[2] < -128) {
293 // Require more than 554 bits?
294 } else if (values
[0] >= 16 || values
[0] < -16
295 || values
[1] >= 16 || values
[1] < -16
296 || values
[2] >= 8 || values
[2] < -8) {
298 // Require more than 2 bits?
299 } else if (values
[0] >= 2 || values
[0] < -2
300 || values
[1] >= 2 || values
[1] < -2
301 || values
[2] >= 2 || values
[2] < -2) {
307 blackboxWrite((selector
<< 6) | ((values
[0] & 0x03) << 4) | ((values
[1] & 0x03) << 2) | (values
[2] & 0x03));
310 // 554 bits per field ss11 1112 2222 3333
311 blackboxWrite((selector
<< 6) | ((values
[0] & 0x1F) << 1) | ((values
[1] & 0x1F) >> 4));
312 blackboxWrite(((values
[1] & 0x0F) << 4) | (values
[2] & 0x0F));
315 // 877 bits per field ss11 1111 1122 2222 2333 3333
316 blackboxWrite((selector
<< 6) | ((values
[0] & 0xFF) >> 2));
317 blackboxWrite(((values
[0] & 0x03) << 6) | ((values
[1] & 0x7F) >> 1));
318 blackboxWrite(((values
[1] & 0x01) << 7) | (values
[2] & 0x7F));
322 * Do another round to compute a selector for each field, assuming that they are at least 8 bits each
324 * Selector2 field possibilities
331 //Encode in reverse order so the first field is in the low bits:
332 for (int x
= FIELD_COUNT
- 1; x
>= 0; x
--) {
335 if (values
[x
] < 128 && values
[x
] >= -128) {
336 selector2
|= BYTES_1
;
337 } else if (values
[x
] < 32768 && values
[x
] >= -32768) {
338 selector2
|= BYTES_2
;
339 } else if (values
[x
] < 8388608 && values
[x
] >= -8388608) {
340 selector2
|= BYTES_3
;
342 selector2
|= BYTES_4
;
346 //Write the selectors
347 blackboxWrite((selector
<< 6) | selector2
);
349 //And now the values according to the selectors we picked for them
350 for (int x
= 0; x
< FIELD_COUNT
; x
++, selector2
>>= 2) {
351 switch (selector2
& 0x03) {
353 blackboxWrite(values
[x
]);
356 blackboxWrite(values
[x
]);
357 blackboxWrite(values
[x
] >> 8);
360 blackboxWrite(values
[x
]);
361 blackboxWrite(values
[x
] >> 8);
362 blackboxWrite(values
[x
] >> 16);
365 blackboxWrite(values
[x
]);
366 blackboxWrite(values
[x
] >> 8);
367 blackboxWrite(values
[x
] >> 16);
368 blackboxWrite(values
[x
] >> 24);
378 * Write an 8-bit selector followed by four signed fields of size 0, 4, 8 or 16 bits.
380 void blackboxWriteTag8_4S16(int32_t *values
)
383 //Need to be enums rather than const ints if we want to switch on them (due to being C)
391 uint8_t selector
= 0;
392 //Encode in reverse order so the first field is in the low bits:
393 for (int x
= 3; x
>= 0; x
--) {
396 if (values
[x
] == 0) {
397 selector
|= FIELD_ZERO
;
398 } else if (values
[x
] < 8 && values
[x
] >= -8) {
399 selector
|= FIELD_4BIT
;
400 } else if (values
[x
] < 128 && values
[x
] >= -128) {
401 selector
|= FIELD_8BIT
;
403 selector
|= FIELD_16BIT
;
407 blackboxWrite(selector
);
411 for (int x
= 0; x
< 4; x
++, selector
>>= 2) {
412 switch (selector
& 0x03) {
417 if (nibbleIndex
== 0) {
418 //We fill high-bits first
419 buffer
= values
[x
] << 4;
422 blackboxWrite(buffer
| (values
[x
] & 0x0F));
427 if (nibbleIndex
== 0) {
428 blackboxWrite(values
[x
]);
430 //Write the high bits of the value first (mask to avoid sign extension)
431 blackboxWrite(buffer
| ((values
[x
] >> 4) & 0x0F));
432 //Now put the leftover low bits into the top of the next buffer entry
433 buffer
= values
[x
] << 4;
437 if (nibbleIndex
== 0) {
438 //Write high byte first
439 blackboxWrite(values
[x
] >> 8);
440 blackboxWrite(values
[x
]);
442 //First write the highest 4 bits
443 blackboxWrite(buffer
| ((values
[x
] >> 12) & 0x0F));
445 blackboxWrite(values
[x
] >> 4);
446 //Only the smallest 4 bits are still left to write
447 buffer
= values
[x
] << 4;
452 //Anything left over to write?
453 if (nibbleIndex
== 1) {
454 blackboxWrite(buffer
);
459 * Write `valueCount` fields from `values` to the Blackbox using signed variable byte encoding. A 1-byte header is
460 * written first which specifies which fields are non-zero (so this encoding is compact when most fields are zero).
462 * valueCount must be 8 or less.
464 void blackboxWriteTag8_8SVB(int32_t *values
, int valueCount
)
468 if (valueCount
> 0) {
469 //If we're only writing one field then we can skip the header
470 if (valueCount
== 1) {
471 blackboxWriteSignedVB(values
[0]);
473 //First write a one-byte header that marks which fields are non-zero
476 // First field should be in low bits of header
477 for (int i
= valueCount
- 1; i
>= 0; i
--) {
480 if (values
[i
] != 0) {
485 blackboxWrite(header
);
487 for (int i
= 0; i
< valueCount
; i
++) {
488 if (values
[i
] != 0) {
489 blackboxWriteSignedVB(values
[i
]);
496 /** Write unsigned integer **/
497 void blackboxWriteU32(int32_t value
)
499 blackboxWrite(value
& 0xFF);
500 blackboxWrite((value
>> 8) & 0xFF);
501 blackboxWrite((value
>> 16) & 0xFF);
502 blackboxWrite((value
>> 24) & 0xFF);
505 /** Write float value in the integer form **/
506 void blackboxWriteFloat(float value
)
508 blackboxWriteU32(castFloatBytesToInt(value
));