5 #include "blackbox_io.h"
10 #include "common/maths.h"
11 #include "common/axis.h"
12 #include "common/color.h"
14 #include "drivers/gpio.h"
15 #include "drivers/sensor.h"
16 #include "drivers/system.h"
17 #include "drivers/serial.h"
18 #include "drivers/compass.h"
19 #include "drivers/timer.h"
20 #include "drivers/pwm_rx.h"
21 #include "drivers/accgyro.h"
22 #include "drivers/light_led.h"
23 #include "drivers/sound_beeper.h"
25 #include "sensors/sensors.h"
26 #include "sensors/boardalignment.h"
27 #include "sensors/acceleration.h"
28 #include "sensors/barometer.h"
29 #include "sensors/gyro.h"
30 #include "sensors/battery.h"
32 #include "io/beeper.h"
33 #include "io/display.h"
34 #include "io/escservo.h"
36 #include "io/rc_controls.h"
38 #include "io/gimbal.h"
40 #include "io/ledstrip.h"
41 #include "io/serial.h"
42 #include "io/serial_cli.h"
43 #include "io/serial_msp.h"
44 #include "io/statusindicator.h"
46 #include "telemetry/telemetry.h"
47 #include "common/printf.h"
49 #include "flight/mixer.h"
50 #include "flight/altitudehold.h"
51 #include "flight/failsafe.h"
52 #include "flight/imu.h"
53 #include "flight/navigation.h"
55 #include "config/runtime_config.h"
56 #include "config/config.h"
57 #include "config/config_profile.h"
58 #include "config/config_master.h"
60 #include "io/flashfs.h"
64 #define BLACKBOX_BAUDRATE 115200
65 #define BLACKBOX_INITIAL_PORT_MODE MODE_TX
67 // How many bytes should we transmit per loop iteration?
68 uint8_t blackboxWriteChunkSize
= 16;
70 static serialPort_t
*blackboxPort
;
71 static portMode_t previousPortMode
;
72 static uint32_t previousBaudRate
;
74 void blackboxWrite(uint8_t value
)
76 switch (masterConfig
.blackbox_device
) {
78 case BLACKBOX_DEVICE_FLASH
:
79 flashfsWriteByte(value
); // Write byte asynchronously
82 case BLACKBOX_DEVICE_SERIAL
:
84 serialWrite(blackboxPort
, value
);
89 static void _putc(void *p
, char c
)
95 //printf() to the blackbox serial port with no blocking shenanigans (so it's caller's responsibility to not write too fast!)
96 void blackboxPrintf(char *fmt
, ...)
100 tfp_format(NULL
, _putc
, fmt
, va
);
104 // Print the null-terminated string 's' to the serial port and return the number of bytes written
105 int blackboxPrint(const char *s
)
110 switch (masterConfig
.blackbox_device
) {
113 case BLACKBOX_DEVICE_FLASH
:
115 flashfsWrite((const uint8_t*) s
, length
, false); // Write asynchronously
119 case BLACKBOX_DEVICE_SERIAL
:
123 serialWrite(blackboxPort
, *pos
);
127 length
= pos
- (uint8_t*) s
;
135 * Write an unsigned integer to the blackbox serial port using variable byte encoding.
137 void blackboxWriteUnsignedVB(uint32_t value
)
139 //While this isn't the final byte (we can only write 7 bits at a time)
140 while (value
> 127) {
141 blackboxWrite((uint8_t) (value
| 0x80)); // Set the high bit to mean "more bytes follow"
144 blackboxWrite(value
);
148 * Write a signed integer to the blackbox serial port using ZigZig and variable byte encoding.
150 void blackboxWriteSignedVB(int32_t value
)
152 //ZigZag encode to make the value always positive
153 blackboxWriteUnsignedVB((uint32_t)((value
<< 1) ^ (value
>> 31)));
156 void blackboxWriteS16(int16_t value
)
158 blackboxWrite(value
& 0xFF);
159 blackboxWrite((value
>> 8) & 0xFF);
163 * Write a 2 bit tag followed by 3 signed fields of 2, 4, 6 or 32 bits
165 void blackboxWriteTag2_3S32(int32_t *values
) {
166 static const int NUM_FIELDS
= 3;
168 //Need to be enums rather than const ints if we want to switch on them (due to being C)
184 int selector
= BITS_2
, selector2
;
187 * Find out how many bits the largest value requires to encode, and use it to choose one of the packing schemes
190 * Selector possibilities
192 * 2 bits per field ss11 2233,
193 * 4 bits per field ss00 1111 2222 3333
194 * 6 bits per field ss11 1111 0022 2222 0033 3333
195 * 32 bits per field sstt tttt followed by fields of various byte counts
197 for (x
= 0; x
< NUM_FIELDS
; x
++) {
198 //Require more than 6 bits?
199 if (values
[x
] >= 32 || values
[x
] < -32) {
204 //Require more than 4 bits?
205 if (values
[x
] >= 8 || values
[x
] < -8) {
206 if (selector
< BITS_6
) {
209 } else if (values
[x
] >= 2 || values
[x
] < -2) { //Require more than 2 bits?
210 if (selector
< BITS_4
) {
218 blackboxWrite((selector
<< 6) | ((values
[0] & 0x03) << 4) | ((values
[1] & 0x03) << 2) | (values
[2] & 0x03));
221 blackboxWrite((selector
<< 6) | (values
[0] & 0x0F));
222 blackboxWrite((values
[1] << 4) | (values
[2] & 0x0F));
225 blackboxWrite((selector
<< 6) | (values
[0] & 0x3F));
226 blackboxWrite((uint8_t)values
[1]);
227 blackboxWrite((uint8_t)values
[2]);
231 * Do another round to compute a selector for each field, assuming that they are at least 8 bits each
233 * Selector2 field possibilities
241 //Encode in reverse order so the first field is in the low bits:
242 for (x
= NUM_FIELDS
- 1; x
>= 0; x
--) {
245 if (values
[x
] < 128 && values
[x
] >= -128) {
246 selector2
|= BYTES_1
;
247 } else if (values
[x
] < 32768 && values
[x
] >= -32768) {
248 selector2
|= BYTES_2
;
249 } else if (values
[x
] < 8388608 && values
[x
] >= -8388608) {
250 selector2
|= BYTES_3
;
252 selector2
|= BYTES_4
;
256 //Write the selectors
257 blackboxWrite((selector
<< 6) | selector2
);
259 //And now the values according to the selectors we picked for them
260 for (x
= 0; x
< NUM_FIELDS
; x
++, selector2
>>= 2) {
261 switch (selector2
& 0x03) {
263 blackboxWrite(values
[x
]);
266 blackboxWrite(values
[x
]);
267 blackboxWrite(values
[x
] >> 8);
270 blackboxWrite(values
[x
]);
271 blackboxWrite(values
[x
] >> 8);
272 blackboxWrite(values
[x
] >> 16);
275 blackboxWrite(values
[x
]);
276 blackboxWrite(values
[x
] >> 8);
277 blackboxWrite(values
[x
] >> 16);
278 blackboxWrite(values
[x
] >> 24);
287 * Write an 8-bit selector followed by four signed fields of size 0, 4, 8 or 16 bits.
289 void blackboxWriteTag8_4S16(int32_t *values
) {
291 //Need to be enums rather than const ints if we want to switch on them (due to being C)
299 uint8_t selector
, buffer
;
304 //Encode in reverse order so the first field is in the low bits:
305 for (x
= 3; x
>= 0; x
--) {
308 if (values
[x
] == 0) {
309 selector
|= FIELD_ZERO
;
310 } else if (values
[x
] < 8 && values
[x
] >= -8) {
311 selector
|= FIELD_4BIT
;
312 } else if (values
[x
] < 128 && values
[x
] >= -128) {
313 selector
|= FIELD_8BIT
;
315 selector
|= FIELD_16BIT
;
319 blackboxWrite(selector
);
323 for (x
= 0; x
< 4; x
++, selector
>>= 2) {
324 switch (selector
& 0x03) {
329 if (nibbleIndex
== 0) {
330 //We fill high-bits first
331 buffer
= values
[x
] << 4;
334 blackboxWrite(buffer
| (values
[x
] & 0x0F));
339 if (nibbleIndex
== 0) {
340 blackboxWrite(values
[x
]);
342 //Write the high bits of the value first (mask to avoid sign extension)
343 blackboxWrite(buffer
| ((values
[x
] >> 4) & 0x0F));
344 //Now put the leftover low bits into the top of the next buffer entry
345 buffer
= values
[x
] << 4;
349 if (nibbleIndex
== 0) {
350 //Write high byte first
351 blackboxWrite(values
[x
] >> 8);
352 blackboxWrite(values
[x
]);
354 //First write the highest 4 bits
355 blackboxWrite(buffer
| ((values
[x
] >> 12) & 0x0F));
357 blackboxWrite(values
[x
] >> 4);
358 //Only the smallest 4 bits are still left to write
359 buffer
= values
[x
] << 4;
364 //Anything left over to write?
365 if (nibbleIndex
== 1) {
366 blackboxWrite(buffer
);
371 * Write `valueCount` fields from `values` to the Blackbox using signed variable byte encoding. A 1-byte header is
372 * written first which specifies which fields are non-zero (so this encoding is compact when most fields are zero).
374 * valueCount must be 8 or less.
376 void blackboxWriteTag8_8SVB(int32_t *values
, int valueCount
)
381 if (valueCount
> 0) {
382 //If we're only writing one field then we can skip the header
383 if (valueCount
== 1) {
384 blackboxWriteSignedVB(values
[0]);
386 //First write a one-byte header that marks which fields are non-zero
389 // First field should be in low bits of header
390 for (i
= valueCount
- 1; i
>= 0; i
--) {
393 if (values
[i
] != 0) {
398 blackboxWrite(header
);
400 for (i
= 0; i
< valueCount
; i
++) {
401 if (values
[i
] != 0) {
402 blackboxWriteSignedVB(values
[i
]);
410 * If there is data waiting to be written to the blackbox device, attempt to write (a portion of) that now.
412 * Returns true if all data has been flushed to the device.
414 bool blackboxDeviceFlush(void)
416 switch (masterConfig
.blackbox_device
) {
417 case BLACKBOX_DEVICE_SERIAL
:
418 //Nothing to speed up flushing on serial, as serial is continuously being drained out of its buffer
419 return isSerialTransmitBufferEmpty(blackboxPort
);
422 case BLACKBOX_DEVICE_FLASH
:
423 return flashfsFlushAsync();
432 * Attempt to open the logging device. Returns true if successful.
434 bool blackboxDeviceOpen(void)
437 * We want to write at about 7200 bytes per second to give the OpenLog a good chance to save to disk. If
438 * about looptime microseconds elapse between our writes, this is the budget of how many bytes we should
439 * transmit with each write.
441 * 9 / 1250 = 7200 / 1000000
443 blackboxWriteChunkSize
= MAX((masterConfig
.looptime
* 9) / 1250, 4);
445 switch (masterConfig
.blackbox_device
) {
446 case BLACKBOX_DEVICE_SERIAL
:
447 blackboxPort
= findOpenSerialPort(FUNCTION_BLACKBOX
);
449 previousPortMode
= blackboxPort
->mode
;
450 previousBaudRate
= blackboxPort
->baudRate
;
452 serialSetBaudRate(blackboxPort
, BLACKBOX_BAUDRATE
);
453 serialSetMode(blackboxPort
, BLACKBOX_INITIAL_PORT_MODE
);
454 beginSerialPortFunction(blackboxPort
, FUNCTION_BLACKBOX
);
456 blackboxPort
= openSerialPort(FUNCTION_BLACKBOX
, NULL
, BLACKBOX_BAUDRATE
, BLACKBOX_INITIAL_PORT_MODE
, SERIAL_NOT_INVERTED
);
459 previousPortMode
= blackboxPort
->mode
;
460 previousBaudRate
= blackboxPort
->baudRate
;
464 return blackboxPort
!= NULL
;
467 case BLACKBOX_DEVICE_FLASH
:
468 if (flashfsGetSize() == 0 || isBlackboxDeviceFull()) {
481 * Close the Blackbox logging device immediately without attempting to flush any remaining data.
483 void blackboxDeviceClose(void)
485 switch (masterConfig
.blackbox_device
) {
486 case BLACKBOX_DEVICE_SERIAL
:
487 serialSetMode(blackboxPort
, previousPortMode
);
488 serialSetBaudRate(blackboxPort
, previousBaudRate
);
490 endSerialPortFunction(blackboxPort
, FUNCTION_BLACKBOX
);
493 * Normally this would be handled by mw.c, but since we take an unknown amount
494 * of time to shut down asynchronously, we're the only ones that know when to call it.
496 if (isSerialPortFunctionShared(FUNCTION_BLACKBOX
, FUNCTION_MSP
)) {
497 mspAllocateSerialPorts(&masterConfig
.serialConfig
);
503 bool isBlackboxDeviceFull(void)
505 switch (masterConfig
.blackbox_device
) {
506 case BLACKBOX_DEVICE_SERIAL
:
510 case BLACKBOX_DEVICE_FLASH
:
511 return flashfsIsEOF();