Split blackbox encoding into separate module
This commit is contained in:
parent
e4d8fa7592
commit
b1f290d218
1
Makefile
1
Makefile
|
@ -757,6 +757,7 @@ FC_SRC = \
|
|||
sensors/gyroanalyse.c \
|
||||
sensors/initialisation.c \
|
||||
blackbox/blackbox.c \
|
||||
blackbox/blackbox_encoding.c \
|
||||
blackbox/blackbox_io.c \
|
||||
cms/cms.c \
|
||||
cms/cms_menu_blackbox.c \
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#ifdef BLACKBOX
|
||||
|
||||
#include "blackbox.h"
|
||||
#include "blackbox_encoding.h"
|
||||
#include "blackbox_io.h"
|
||||
|
||||
#include "build/debug.h"
|
||||
|
|
|
@ -46,6 +46,6 @@ void blackboxLogEvent(FlightLogEvent event, flightLogEventData_t *data);
|
|||
|
||||
void blackboxInit(void);
|
||||
void blackboxUpdate(timeUs_t currentTimeUs);
|
||||
void blackboxValidateConfig();
|
||||
void blackboxValidateConfig(void);
|
||||
void blackboxFinish(void);
|
||||
bool blackboxMayEditConfig(void);
|
||||
|
|
|
@ -0,0 +1,367 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef BLACKBOX
|
||||
|
||||
#include "blackbox_encoding.h"
|
||||
#include "blackbox_io.h"
|
||||
|
||||
#include "common/encoding.h"
|
||||
#include "common/printf.h"
|
||||
|
||||
|
||||
static void _putc(void *p, char c)
|
||||
{
|
||||
(void)p;
|
||||
blackboxWrite(c);
|
||||
}
|
||||
|
||||
static int blackboxPrintfv(const char *fmt, va_list va)
|
||||
{
|
||||
return tfp_format(NULL, _putc, fmt, va);
|
||||
}
|
||||
|
||||
|
||||
//printf() to the blackbox serial port with no blocking shenanigans (so it's caller's responsibility to not write too fast!)
|
||||
int blackboxPrintf(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
|
||||
const int written = blackboxPrintfv(fmt, va);
|
||||
|
||||
va_end(va);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
/*
|
||||
* printf a Blackbox header line with a leading "H " and trailing "\n" added automatically. blackboxHeaderBudget is
|
||||
* decreased to account for the number of bytes written.
|
||||
*/
|
||||
void blackboxPrintfHeaderLine(const char *name, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
blackboxWrite('H');
|
||||
blackboxWrite(' ');
|
||||
blackboxPrint(name);
|
||||
blackboxWrite(':');
|
||||
|
||||
va_start(va, fmt);
|
||||
|
||||
const int written = blackboxPrintfv(fmt, va);
|
||||
|
||||
va_end(va);
|
||||
|
||||
blackboxWrite('\n');
|
||||
|
||||
blackboxHeaderBudget -= written + 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned integer to the blackbox serial port using variable byte encoding.
|
||||
*/
|
||||
void blackboxWriteUnsignedVB(uint32_t value)
|
||||
{
|
||||
//While this isn't the final byte (we can only write 7 bits at a time)
|
||||
while (value > 127) {
|
||||
blackboxWrite((uint8_t) (value | 0x80)); // Set the high bit to mean "more bytes follow"
|
||||
value >>= 7;
|
||||
}
|
||||
blackboxWrite(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a signed integer to the blackbox serial port using ZigZig and variable byte encoding.
|
||||
*/
|
||||
void blackboxWriteSignedVB(int32_t value)
|
||||
{
|
||||
//ZigZag encode to make the value always positive
|
||||
blackboxWriteUnsignedVB(zigzagEncode(value));
|
||||
}
|
||||
|
||||
void blackboxWriteSignedVBArray(int32_t *array, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
blackboxWriteSignedVB(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void blackboxWriteSigned16VBArray(int16_t *array, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
blackboxWriteSignedVB(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void blackboxWriteS16(int16_t value)
|
||||
{
|
||||
blackboxWrite(value & 0xFF);
|
||||
blackboxWrite((value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 2 bit tag followed by 3 signed fields of 2, 4, 6 or 32 bits
|
||||
*/
|
||||
void blackboxWriteTag2_3S32(int32_t *values)
|
||||
{
|
||||
static const int NUM_FIELDS = 3;
|
||||
|
||||
//Need to be enums rather than const ints if we want to switch on them (due to being C)
|
||||
enum {
|
||||
BITS_2 = 0,
|
||||
BITS_4 = 1,
|
||||
BITS_6 = 2,
|
||||
BITS_32 = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
BYTES_1 = 0,
|
||||
BYTES_2 = 1,
|
||||
BYTES_3 = 2,
|
||||
BYTES_4 = 3
|
||||
};
|
||||
|
||||
int selector = BITS_2, selector2;
|
||||
|
||||
/*
|
||||
* Find out how many bits the largest value requires to encode, and use it to choose one of the packing schemes
|
||||
* below:
|
||||
*
|
||||
* Selector possibilities
|
||||
*
|
||||
* 2 bits per field ss11 2233,
|
||||
* 4 bits per field ss00 1111 2222 3333
|
||||
* 6 bits per field ss11 1111 0022 2222 0033 3333
|
||||
* 32 bits per field sstt tttt followed by fields of various byte counts
|
||||
*/
|
||||
for (int x = 0; x < NUM_FIELDS; x++) {
|
||||
//Require more than 6 bits?
|
||||
if (values[x] >= 32 || values[x] < -32) {
|
||||
selector = BITS_32;
|
||||
break;
|
||||
}
|
||||
|
||||
//Require more than 4 bits?
|
||||
if (values[x] >= 8 || values[x] < -8) {
|
||||
if (selector < BITS_6) {
|
||||
selector = BITS_6;
|
||||
}
|
||||
} else if (values[x] >= 2 || values[x] < -2) { //Require more than 2 bits?
|
||||
if (selector < BITS_4) {
|
||||
selector = BITS_4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (selector) {
|
||||
case BITS_2:
|
||||
blackboxWrite((selector << 6) | ((values[0] & 0x03) << 4) | ((values[1] & 0x03) << 2) | (values[2] & 0x03));
|
||||
break;
|
||||
case BITS_4:
|
||||
blackboxWrite((selector << 6) | (values[0] & 0x0F));
|
||||
blackboxWrite((values[1] << 4) | (values[2] & 0x0F));
|
||||
break;
|
||||
case BITS_6:
|
||||
blackboxWrite((selector << 6) | (values[0] & 0x3F));
|
||||
blackboxWrite((uint8_t)values[1]);
|
||||
blackboxWrite((uint8_t)values[2]);
|
||||
break;
|
||||
case BITS_32:
|
||||
/*
|
||||
* Do another round to compute a selector for each field, assuming that they are at least 8 bits each
|
||||
*
|
||||
* Selector2 field possibilities
|
||||
* 0 - 8 bits
|
||||
* 1 - 16 bits
|
||||
* 2 - 24 bits
|
||||
* 3 - 32 bits
|
||||
*/
|
||||
selector2 = 0;
|
||||
|
||||
//Encode in reverse order so the first field is in the low bits:
|
||||
for (int x = NUM_FIELDS - 1; x >= 0; x--) {
|
||||
selector2 <<= 2;
|
||||
|
||||
if (values[x] < 128 && values[x] >= -128) {
|
||||
selector2 |= BYTES_1;
|
||||
} else if (values[x] < 32768 && values[x] >= -32768) {
|
||||
selector2 |= BYTES_2;
|
||||
} else if (values[x] < 8388608 && values[x] >= -8388608) {
|
||||
selector2 |= BYTES_3;
|
||||
} else {
|
||||
selector2 |= BYTES_4;
|
||||
}
|
||||
}
|
||||
|
||||
//Write the selectors
|
||||
blackboxWrite((selector << 6) | selector2);
|
||||
|
||||
//And now the values according to the selectors we picked for them
|
||||
for (int x = 0; x < NUM_FIELDS; x++, selector2 >>= 2) {
|
||||
switch (selector2 & 0x03) {
|
||||
case BYTES_1:
|
||||
blackboxWrite(values[x]);
|
||||
break;
|
||||
case BYTES_2:
|
||||
blackboxWrite(values[x]);
|
||||
blackboxWrite(values[x] >> 8);
|
||||
break;
|
||||
case BYTES_3:
|
||||
blackboxWrite(values[x]);
|
||||
blackboxWrite(values[x] >> 8);
|
||||
blackboxWrite(values[x] >> 16);
|
||||
break;
|
||||
case BYTES_4:
|
||||
blackboxWrite(values[x]);
|
||||
blackboxWrite(values[x] >> 8);
|
||||
blackboxWrite(values[x] >> 16);
|
||||
blackboxWrite(values[x] >> 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an 8-bit selector followed by four signed fields of size 0, 4, 8 or 16 bits.
|
||||
*/
|
||||
void blackboxWriteTag8_4S16(int32_t *values)
|
||||
{
|
||||
|
||||
//Need to be enums rather than const ints if we want to switch on them (due to being C)
|
||||
enum {
|
||||
FIELD_ZERO = 0,
|
||||
FIELD_4BIT = 1,
|
||||
FIELD_8BIT = 2,
|
||||
FIELD_16BIT = 3
|
||||
};
|
||||
|
||||
uint8_t selector = 0;
|
||||
//Encode in reverse order so the first field is in the low bits:
|
||||
for (int x = 3; x >= 0; x--) {
|
||||
selector <<= 2;
|
||||
|
||||
if (values[x] == 0) {
|
||||
selector |= FIELD_ZERO;
|
||||
} else if (values[x] < 8 && values[x] >= -8) {
|
||||
selector |= FIELD_4BIT;
|
||||
} else if (values[x] < 128 && values[x] >= -128) {
|
||||
selector |= FIELD_8BIT;
|
||||
} else {
|
||||
selector |= FIELD_16BIT;
|
||||
}
|
||||
}
|
||||
|
||||
blackboxWrite(selector);
|
||||
|
||||
int nibbleIndex = 0;
|
||||
uint8_t buffer = 0;
|
||||
for (int x = 0; x < 4; x++, selector >>= 2) {
|
||||
switch (selector & 0x03) {
|
||||
case FIELD_ZERO:
|
||||
//No-op
|
||||
break;
|
||||
case FIELD_4BIT:
|
||||
if (nibbleIndex == 0) {
|
||||
//We fill high-bits first
|
||||
buffer = values[x] << 4;
|
||||
nibbleIndex = 1;
|
||||
} else {
|
||||
blackboxWrite(buffer | (values[x] & 0x0F));
|
||||
nibbleIndex = 0;
|
||||
}
|
||||
break;
|
||||
case FIELD_8BIT:
|
||||
if (nibbleIndex == 0) {
|
||||
blackboxWrite(values[x]);
|
||||
} else {
|
||||
//Write the high bits of the value first (mask to avoid sign extension)
|
||||
blackboxWrite(buffer | ((values[x] >> 4) & 0x0F));
|
||||
//Now put the leftover low bits into the top of the next buffer entry
|
||||
buffer = values[x] << 4;
|
||||
}
|
||||
break;
|
||||
case FIELD_16BIT:
|
||||
if (nibbleIndex == 0) {
|
||||
//Write high byte first
|
||||
blackboxWrite(values[x] >> 8);
|
||||
blackboxWrite(values[x]);
|
||||
} else {
|
||||
//First write the highest 4 bits
|
||||
blackboxWrite(buffer | ((values[x] >> 12) & 0x0F));
|
||||
// Then the middle 8
|
||||
blackboxWrite(values[x] >> 4);
|
||||
//Only the smallest 4 bits are still left to write
|
||||
buffer = values[x] << 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Anything left over to write?
|
||||
if (nibbleIndex == 1) {
|
||||
blackboxWrite(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `valueCount` fields from `values` to the Blackbox using signed variable byte encoding. A 1-byte header is
|
||||
* written first which specifies which fields are non-zero (so this encoding is compact when most fields are zero).
|
||||
*
|
||||
* valueCount must be 8 or less.
|
||||
*/
|
||||
void blackboxWriteTag8_8SVB(int32_t *values, int valueCount)
|
||||
{
|
||||
uint8_t header;
|
||||
|
||||
if (valueCount > 0) {
|
||||
//If we're only writing one field then we can skip the header
|
||||
if (valueCount == 1) {
|
||||
blackboxWriteSignedVB(values[0]);
|
||||
} else {
|
||||
//First write a one-byte header that marks which fields are non-zero
|
||||
header = 0;
|
||||
|
||||
// First field should be in low bits of header
|
||||
for (int i = valueCount - 1; i >= 0; i--) {
|
||||
header <<= 1;
|
||||
|
||||
if (values[i] != 0) {
|
||||
header |= 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
blackboxWrite(header);
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
if (values[i] != 0) {
|
||||
blackboxWriteSignedVB(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Write unsigned integer **/
|
||||
void blackboxWriteU32(int32_t value)
|
||||
{
|
||||
blackboxWrite(value & 0xFF);
|
||||
blackboxWrite((value >> 8) & 0xFF);
|
||||
blackboxWrite((value >> 16) & 0xFF);
|
||||
blackboxWrite((value >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/** Write float value in the integer form **/
|
||||
void blackboxWriteFloat(float value)
|
||||
{
|
||||
blackboxWriteU32(castFloatBytesToInt(value));
|
||||
}
|
||||
#endif // BLACKBOX
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of Cleanflight.
|
||||
*
|
||||
* Cleanflight is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cleanflight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
int blackboxPrintf(const char *fmt, ...);
|
||||
void blackboxPrintfHeaderLine(const char *name, const char *fmt, ...);
|
||||
int blackboxPrint(const char *s);
|
||||
|
||||
void blackboxWriteUnsignedVB(uint32_t value);
|
||||
void blackboxWriteSignedVB(int32_t value);
|
||||
void blackboxWriteSignedVBArray(int32_t *array, int count);
|
||||
void blackboxWriteSigned16VBArray(int16_t *array, int count);
|
||||
void blackboxWriteS16(int16_t value);
|
||||
void blackboxWriteTag2_3S32(int32_t *values);
|
||||
void blackboxWriteTag8_4S16(int32_t *values);
|
||||
void blackboxWriteTag8_8SVB(int32_t *values, int valueCount);
|
||||
void blackboxWriteU32(int32_t value);
|
||||
void blackboxWriteFloat(float value);
|
|
@ -11,12 +11,7 @@
|
|||
#include "blackbox.h"
|
||||
#include "blackbox_io.h"
|
||||
|
||||
#include "common/encoding.h"
|
||||
#include "common/maths.h"
|
||||
#include "common/printf.h"
|
||||
|
||||
#include "config/parameter_group.h"
|
||||
#include "config/parameter_group_ids.h"
|
||||
|
||||
#include "flight/pid.h"
|
||||
|
||||
|
@ -34,10 +29,8 @@ static uint8_t blackboxMaxHeaderBytesPerIteration;
|
|||
// How many bytes can we write *this* iteration without overflowing transmit buffers or overstressing the OpenLog?
|
||||
int32_t blackboxHeaderBudget;
|
||||
|
||||
STATIC_UNIT_TESTED serialPort_t *blackboxPort = NULL;
|
||||
#ifndef UNIT_TEST
|
||||
static serialPort_t *blackboxPort = NULL;
|
||||
static portSharing_e blackboxPortSharing;
|
||||
#endif // UNIT_TEST
|
||||
|
||||
#ifdef USE_SDCARD
|
||||
|
||||
|
@ -60,9 +53,8 @@ static struct {
|
|||
#define LOGFILE_PREFIX "LOG"
|
||||
#define LOGFILE_SUFFIX "BFL"
|
||||
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
|
||||
#ifndef UNIT_TEST
|
||||
void blackboxOpen()
|
||||
{
|
||||
serialPort_t *sharedBlackboxAndMspPort = findSharedSerialPort(FUNCTION_BLACKBOX, FUNCTION_MSP);
|
||||
|
@ -70,7 +62,6 @@ void blackboxOpen()
|
|||
mspSerialReleasePortIfAllocated(sharedBlackboxAndMspPort);
|
||||
}
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
|
||||
void blackboxWrite(uint8_t value)
|
||||
{
|
||||
|
@ -92,56 +83,6 @@ void blackboxWrite(uint8_t value)
|
|||
}
|
||||
}
|
||||
|
||||
static void _putc(void *p, char c)
|
||||
{
|
||||
(void)p;
|
||||
blackboxWrite(c);
|
||||
}
|
||||
|
||||
static int blackboxPrintfv(const char *fmt, va_list va)
|
||||
{
|
||||
return tfp_format(NULL, _putc, fmt, va);
|
||||
}
|
||||
|
||||
|
||||
//printf() to the blackbox serial port with no blocking shenanigans (so it's caller's responsibility to not write too fast!)
|
||||
int blackboxPrintf(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
|
||||
int written = blackboxPrintfv(fmt, va);
|
||||
|
||||
va_end(va);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
/*
|
||||
* printf a Blackbox header line with a leading "H " and trailing "\n" added automatically. blackboxHeaderBudget is
|
||||
* decreased to account for the number of bytes written.
|
||||
*/
|
||||
void blackboxPrintfHeaderLine(const char *name, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
blackboxWrite('H');
|
||||
blackboxWrite(' ');
|
||||
blackboxPrint(name);
|
||||
blackboxWrite(':');
|
||||
|
||||
va_start(va, fmt);
|
||||
|
||||
int written = blackboxPrintfv(fmt, va);
|
||||
|
||||
va_end(va);
|
||||
|
||||
blackboxWrite('\n');
|
||||
|
||||
blackboxHeaderBudget -= written + 3;
|
||||
}
|
||||
|
||||
// Print the null-terminated string 's' to the blackbox device and return the number of bytes written
|
||||
int blackboxPrint(const char *s)
|
||||
{
|
||||
|
@ -155,14 +96,14 @@ int blackboxPrint(const char *s)
|
|||
length = strlen(s);
|
||||
flashfsWrite((const uint8_t*) s, length, false); // Write asynchronously
|
||||
break;
|
||||
#endif
|
||||
#endif // USE_FLASHFS
|
||||
|
||||
#ifdef USE_SDCARD
|
||||
case BLACKBOX_DEVICE_SDCARD:
|
||||
length = strlen(s);
|
||||
afatfs_fwrite(blackboxSDCard.logFile, (const uint8_t*) s, length); // Ignore failures due to buffers filling up
|
||||
break;
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
|
||||
case BLACKBOX_DEVICE_SERIAL:
|
||||
default:
|
||||
|
@ -179,306 +120,6 @@ int blackboxPrint(const char *s)
|
|||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned integer to the blackbox serial port using variable byte encoding.
|
||||
*/
|
||||
void blackboxWriteUnsignedVB(uint32_t value)
|
||||
{
|
||||
//While this isn't the final byte (we can only write 7 bits at a time)
|
||||
while (value > 127) {
|
||||
blackboxWrite((uint8_t) (value | 0x80)); // Set the high bit to mean "more bytes follow"
|
||||
value >>= 7;
|
||||
}
|
||||
blackboxWrite(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a signed integer to the blackbox serial port using ZigZig and variable byte encoding.
|
||||
*/
|
||||
void blackboxWriteSignedVB(int32_t value)
|
||||
{
|
||||
//ZigZag encode to make the value always positive
|
||||
blackboxWriteUnsignedVB(zigzagEncode(value));
|
||||
}
|
||||
|
||||
void blackboxWriteSignedVBArray(int32_t *array, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
blackboxWriteSignedVB(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void blackboxWriteSigned16VBArray(int16_t *array, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
blackboxWriteSignedVB(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void blackboxWriteS16(int16_t value)
|
||||
{
|
||||
blackboxWrite(value & 0xFF);
|
||||
blackboxWrite((value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 2 bit tag followed by 3 signed fields of 2, 4, 6 or 32 bits
|
||||
*/
|
||||
void blackboxWriteTag2_3S32(int32_t *values)
|
||||
{
|
||||
static const int NUM_FIELDS = 3;
|
||||
|
||||
//Need to be enums rather than const ints if we want to switch on them (due to being C)
|
||||
enum {
|
||||
BITS_2 = 0,
|
||||
BITS_4 = 1,
|
||||
BITS_6 = 2,
|
||||
BITS_32 = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
BYTES_1 = 0,
|
||||
BYTES_2 = 1,
|
||||
BYTES_3 = 2,
|
||||
BYTES_4 = 3
|
||||
};
|
||||
|
||||
int selector = BITS_2, selector2;
|
||||
|
||||
/*
|
||||
* Find out how many bits the largest value requires to encode, and use it to choose one of the packing schemes
|
||||
* below:
|
||||
*
|
||||
* Selector possibilities
|
||||
*
|
||||
* 2 bits per field ss11 2233,
|
||||
* 4 bits per field ss00 1111 2222 3333
|
||||
* 6 bits per field ss11 1111 0022 2222 0033 3333
|
||||
* 32 bits per field sstt tttt followed by fields of various byte counts
|
||||
*/
|
||||
for (int x = 0; x < NUM_FIELDS; x++) {
|
||||
//Require more than 6 bits?
|
||||
if (values[x] >= 32 || values[x] < -32) {
|
||||
selector = BITS_32;
|
||||
break;
|
||||
}
|
||||
|
||||
//Require more than 4 bits?
|
||||
if (values[x] >= 8 || values[x] < -8) {
|
||||
if (selector < BITS_6) {
|
||||
selector = BITS_6;
|
||||
}
|
||||
} else if (values[x] >= 2 || values[x] < -2) { //Require more than 2 bits?
|
||||
if (selector < BITS_4) {
|
||||
selector = BITS_4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (selector) {
|
||||
case BITS_2:
|
||||
blackboxWrite((selector << 6) | ((values[0] & 0x03) << 4) | ((values[1] & 0x03) << 2) | (values[2] & 0x03));
|
||||
break;
|
||||
case BITS_4:
|
||||
blackboxWrite((selector << 6) | (values[0] & 0x0F));
|
||||
blackboxWrite((values[1] << 4) | (values[2] & 0x0F));
|
||||
break;
|
||||
case BITS_6:
|
||||
blackboxWrite((selector << 6) | (values[0] & 0x3F));
|
||||
blackboxWrite((uint8_t)values[1]);
|
||||
blackboxWrite((uint8_t)values[2]);
|
||||
break;
|
||||
case BITS_32:
|
||||
/*
|
||||
* Do another round to compute a selector for each field, assuming that they are at least 8 bits each
|
||||
*
|
||||
* Selector2 field possibilities
|
||||
* 0 - 8 bits
|
||||
* 1 - 16 bits
|
||||
* 2 - 24 bits
|
||||
* 3 - 32 bits
|
||||
*/
|
||||
selector2 = 0;
|
||||
|
||||
//Encode in reverse order so the first field is in the low bits:
|
||||
for (int x = NUM_FIELDS - 1; x >= 0; x--) {
|
||||
selector2 <<= 2;
|
||||
|
||||
if (values[x] < 128 && values[x] >= -128) {
|
||||
selector2 |= BYTES_1;
|
||||
} else if (values[x] < 32768 && values[x] >= -32768) {
|
||||
selector2 |= BYTES_2;
|
||||
} else if (values[x] < 8388608 && values[x] >= -8388608) {
|
||||
selector2 |= BYTES_3;
|
||||
} else {
|
||||
selector2 |= BYTES_4;
|
||||
}
|
||||
}
|
||||
|
||||
//Write the selectors
|
||||
blackboxWrite((selector << 6) | selector2);
|
||||
|
||||
//And now the values according to the selectors we picked for them
|
||||
for (int x = 0; x < NUM_FIELDS; x++, selector2 >>= 2) {
|
||||
switch (selector2 & 0x03) {
|
||||
case BYTES_1:
|
||||
blackboxWrite(values[x]);
|
||||
break;
|
||||
case BYTES_2:
|
||||
blackboxWrite(values[x]);
|
||||
blackboxWrite(values[x] >> 8);
|
||||
break;
|
||||
case BYTES_3:
|
||||
blackboxWrite(values[x]);
|
||||
blackboxWrite(values[x] >> 8);
|
||||
blackboxWrite(values[x] >> 16);
|
||||
break;
|
||||
case BYTES_4:
|
||||
blackboxWrite(values[x]);
|
||||
blackboxWrite(values[x] >> 8);
|
||||
blackboxWrite(values[x] >> 16);
|
||||
blackboxWrite(values[x] >> 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an 8-bit selector followed by four signed fields of size 0, 4, 8 or 16 bits.
|
||||
*/
|
||||
void blackboxWriteTag8_4S16(int32_t *values)
|
||||
{
|
||||
|
||||
//Need to be enums rather than const ints if we want to switch on them (due to being C)
|
||||
enum {
|
||||
FIELD_ZERO = 0,
|
||||
FIELD_4BIT = 1,
|
||||
FIELD_8BIT = 2,
|
||||
FIELD_16BIT = 3
|
||||
};
|
||||
|
||||
uint8_t selector = 0;
|
||||
//Encode in reverse order so the first field is in the low bits:
|
||||
for (int x = 3; x >= 0; x--) {
|
||||
selector <<= 2;
|
||||
|
||||
if (values[x] == 0) {
|
||||
selector |= FIELD_ZERO;
|
||||
} else if (values[x] < 8 && values[x] >= -8) {
|
||||
selector |= FIELD_4BIT;
|
||||
} else if (values[x] < 128 && values[x] >= -128) {
|
||||
selector |= FIELD_8BIT;
|
||||
} else {
|
||||
selector |= FIELD_16BIT;
|
||||
}
|
||||
}
|
||||
|
||||
blackboxWrite(selector);
|
||||
|
||||
int nibbleIndex = 0;
|
||||
uint8_t buffer = 0;
|
||||
for (int x = 0; x < 4; x++, selector >>= 2) {
|
||||
switch (selector & 0x03) {
|
||||
case FIELD_ZERO:
|
||||
//No-op
|
||||
break;
|
||||
case FIELD_4BIT:
|
||||
if (nibbleIndex == 0) {
|
||||
//We fill high-bits first
|
||||
buffer = values[x] << 4;
|
||||
nibbleIndex = 1;
|
||||
} else {
|
||||
blackboxWrite(buffer | (values[x] & 0x0F));
|
||||
nibbleIndex = 0;
|
||||
}
|
||||
break;
|
||||
case FIELD_8BIT:
|
||||
if (nibbleIndex == 0) {
|
||||
blackboxWrite(values[x]);
|
||||
} else {
|
||||
//Write the high bits of the value first (mask to avoid sign extension)
|
||||
blackboxWrite(buffer | ((values[x] >> 4) & 0x0F));
|
||||
//Now put the leftover low bits into the top of the next buffer entry
|
||||
buffer = values[x] << 4;
|
||||
}
|
||||
break;
|
||||
case FIELD_16BIT:
|
||||
if (nibbleIndex == 0) {
|
||||
//Write high byte first
|
||||
blackboxWrite(values[x] >> 8);
|
||||
blackboxWrite(values[x]);
|
||||
} else {
|
||||
//First write the highest 4 bits
|
||||
blackboxWrite(buffer | ((values[x] >> 12) & 0x0F));
|
||||
// Then the middle 8
|
||||
blackboxWrite(values[x] >> 4);
|
||||
//Only the smallest 4 bits are still left to write
|
||||
buffer = values[x] << 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Anything left over to write?
|
||||
if (nibbleIndex == 1) {
|
||||
blackboxWrite(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `valueCount` fields from `values` to the Blackbox using signed variable byte encoding. A 1-byte header is
|
||||
* written first which specifies which fields are non-zero (so this encoding is compact when most fields are zero).
|
||||
*
|
||||
* valueCount must be 8 or less.
|
||||
*/
|
||||
void blackboxWriteTag8_8SVB(int32_t *values, int valueCount)
|
||||
{
|
||||
uint8_t header;
|
||||
|
||||
if (valueCount > 0) {
|
||||
//If we're only writing one field then we can skip the header
|
||||
if (valueCount == 1) {
|
||||
blackboxWriteSignedVB(values[0]);
|
||||
} else {
|
||||
//First write a one-byte header that marks which fields are non-zero
|
||||
header = 0;
|
||||
|
||||
// First field should be in low bits of header
|
||||
for (int i = valueCount - 1; i >= 0; i--) {
|
||||
header <<= 1;
|
||||
|
||||
if (values[i] != 0) {
|
||||
header |= 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
blackboxWrite(header);
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
if (values[i] != 0) {
|
||||
blackboxWriteSignedVB(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Write unsigned integer **/
|
||||
void blackboxWriteU32(int32_t value)
|
||||
{
|
||||
blackboxWrite(value & 0xFF);
|
||||
blackboxWrite((value >> 8) & 0xFF);
|
||||
blackboxWrite((value >> 16) & 0xFF);
|
||||
blackboxWrite((value >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/** Write float value in the integer form **/
|
||||
void blackboxWriteFloat(float value)
|
||||
{
|
||||
blackboxWriteU32(castFloatBytesToInt(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is data waiting to be written to the blackbox device, attempt to write (a portion of) that now.
|
||||
*
|
||||
|
@ -495,7 +136,7 @@ void blackboxDeviceFlush(void)
|
|||
case BLACKBOX_DEVICE_FLASH:
|
||||
flashfsFlushAsync();
|
||||
break;
|
||||
#endif
|
||||
#endif // USE_FLASHFS
|
||||
|
||||
default:
|
||||
;
|
||||
|
@ -517,7 +158,7 @@ bool blackboxDeviceFlushForce(void)
|
|||
#ifdef USE_FLASHFS
|
||||
case BLACKBOX_DEVICE_FLASH:
|
||||
return flashfsFlushAsync();
|
||||
#endif
|
||||
#endif // USE_FLASHFS
|
||||
|
||||
#ifdef USE_SDCARD
|
||||
case BLACKBOX_DEVICE_SDCARD:
|
||||
|
@ -525,7 +166,7 @@ bool blackboxDeviceFlushForce(void)
|
|||
* if it's done yet or not!
|
||||
*/
|
||||
return afatfs_flush();
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
@ -535,7 +176,6 @@ bool blackboxDeviceFlushForce(void)
|
|||
/**
|
||||
* Attempt to open the logging device. Returns true if successful.
|
||||
*/
|
||||
#ifndef UNIT_TEST
|
||||
bool blackboxDeviceOpen(void)
|
||||
{
|
||||
switch (blackboxConfig()->device) {
|
||||
|
@ -590,7 +230,7 @@ bool blackboxDeviceOpen(void)
|
|||
|
||||
return true;
|
||||
break;
|
||||
#endif
|
||||
#endif // USE_FLASHFS
|
||||
#ifdef USE_SDCARD
|
||||
case BLACKBOX_DEVICE_SDCARD:
|
||||
if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_FATAL || afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_UNKNOWN || afatfs_isFull()) {
|
||||
|
@ -601,12 +241,11 @@ bool blackboxDeviceOpen(void)
|
|||
|
||||
return true;
|
||||
break;
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
|
||||
/**
|
||||
* Erase all blackbox logs
|
||||
|
@ -621,7 +260,6 @@ void blackboxEraseAll(void)
|
|||
default:
|
||||
//not supported
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -638,7 +276,6 @@ bool isBlackboxErased(void)
|
|||
//not supported
|
||||
return true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -646,7 +283,6 @@ bool isBlackboxErased(void)
|
|||
/**
|
||||
* Close the Blackbox logging device immediately without attempting to flush any remaining data.
|
||||
*/
|
||||
#ifndef UNIT_TEST
|
||||
void blackboxDeviceClose(void)
|
||||
{
|
||||
switch (blackboxConfig()->device) {
|
||||
|
@ -667,7 +303,6 @@ void blackboxDeviceClose(void)
|
|||
;
|
||||
}
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
|
||||
#ifdef USE_SDCARD
|
||||
|
||||
|
@ -785,7 +420,7 @@ static bool blackboxSDCardBeginLog()
|
|||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
|
||||
/**
|
||||
* Begin a new log (for devices which support separations between the logs of multiple flights).
|
||||
|
@ -798,7 +433,7 @@ bool blackboxDeviceBeginLog(void)
|
|||
#ifdef USE_SDCARD
|
||||
case BLACKBOX_DEVICE_SDCARD:
|
||||
return blackboxSDCardBeginLog();
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -815,7 +450,7 @@ bool blackboxDeviceBeginLog(void)
|
|||
bool blackboxDeviceEndLog(bool retainLog)
|
||||
{
|
||||
#ifndef USE_SDCARD
|
||||
(void) retainLog;
|
||||
UNUSED(retainLog);
|
||||
#endif
|
||||
|
||||
switch (blackboxConfig()->device) {
|
||||
|
@ -832,7 +467,7 @@ bool blackboxDeviceEndLog(bool retainLog)
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -847,12 +482,12 @@ bool isBlackboxDeviceFull(void)
|
|||
#ifdef USE_FLASHFS
|
||||
case BLACKBOX_DEVICE_FLASH:
|
||||
return flashfsIsEOF();
|
||||
#endif
|
||||
#endif // USE_FLASHFS
|
||||
|
||||
#ifdef USE_SDCARD
|
||||
case BLACKBOX_DEVICE_SDCARD:
|
||||
return afatfs_isFull();
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
@ -884,7 +519,6 @@ void blackboxReplenishHeaderBudget()
|
|||
default:
|
||||
freeSpace = 0;
|
||||
}
|
||||
|
||||
blackboxHeaderBudget = MIN(MIN(freeSpace, blackboxHeaderBudget + blackboxMaxHeaderBytesPerIteration), BLACKBOX_MAX_ACCUMULATED_HEADER_BUDGET);
|
||||
}
|
||||
|
||||
|
@ -922,7 +556,6 @@ blackboxBufferReserveStatus_e blackboxDeviceReserveBufferSpace(int32_t bytes)
|
|||
if (blackboxPort->txBufferSize && bytes > (int32_t) blackboxPort->txBufferSize - 1) {
|
||||
return BLACKBOX_RESERVE_PERMANENT_FAILURE;
|
||||
}
|
||||
|
||||
return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
|
||||
|
||||
#ifdef USE_FLASHFS
|
||||
|
@ -939,19 +572,17 @@ blackboxBufferReserveStatus_e blackboxDeviceReserveBufferSpace(int32_t bytes)
|
|||
*/
|
||||
flashfsFlushAsync();
|
||||
}
|
||||
|
||||
return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
|
||||
#endif
|
||||
#endif // USE_FLASHFS
|
||||
|
||||
#ifdef USE_SDCARD
|
||||
case BLACKBOX_DEVICE_SDCARD:
|
||||
// Assume that all writes will fit in the SDCard's buffers
|
||||
return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
|
||||
#endif
|
||||
#endif // USE_SDCARD
|
||||
|
||||
default:
|
||||
return BLACKBOX_RESERVE_PERMANENT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // BLACKBOX
|
||||
|
|
|
@ -40,21 +40,6 @@ extern int32_t blackboxHeaderBudget;
|
|||
void blackboxOpen(void);
|
||||
void blackboxWrite(uint8_t value);
|
||||
|
||||
int blackboxPrintf(const char *fmt, ...);
|
||||
void blackboxPrintfHeaderLine(const char *name, const char *fmt, ...);
|
||||
int blackboxPrint(const char *s);
|
||||
|
||||
void blackboxWriteUnsignedVB(uint32_t value);
|
||||
void blackboxWriteSignedVB(int32_t value);
|
||||
void blackboxWriteSignedVBArray(int32_t *array, int count);
|
||||
void blackboxWriteSigned16VBArray(int16_t *array, int count);
|
||||
void blackboxWriteS16(int16_t value);
|
||||
void blackboxWriteTag2_3S32(int32_t *values);
|
||||
void blackboxWriteTag8_4S16(int32_t *values);
|
||||
void blackboxWriteTag8_8SVB(int32_t *values, int valueCount);
|
||||
void blackboxWriteU32(int32_t value);
|
||||
void blackboxWriteFloat(float value);
|
||||
|
||||
void blackboxDeviceFlush(void);
|
||||
bool blackboxDeviceFlushForce(void);
|
||||
bool blackboxDeviceOpen(void);
|
||||
|
|
|
@ -47,7 +47,7 @@ battery_unittest_SRC := \
|
|||
|
||||
|
||||
blackbox_unittest_SRC := \
|
||||
$(USER_DIR)/blackbox/blackbox_io.c \
|
||||
$(USER_DIR)/blackbox/blackbox_encoding.c \
|
||||
$(USER_DIR)/common/encoding.c \
|
||||
$(USER_DIR)/common/printf.c \
|
||||
$(USER_DIR)/common/typeconversion.c
|
||||
|
|
|
@ -21,14 +21,14 @@ extern "C" {
|
|||
#include "platform.h"
|
||||
|
||||
#include "blackbox/blackbox.h"
|
||||
#include "blackbox/blackbox_io.h"
|
||||
#include "blackbox/blackbox_encoding.h"
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "config/parameter_group.h"
|
||||
#include "config/parameter_group_ids.h"
|
||||
|
||||
#include "drivers/serial.h"
|
||||
extern serialPort_t *blackboxPort;
|
||||
#include "io/serial.h"
|
||||
|
||||
PG_REGISTER_WITH_RESET_TEMPLATE(blackboxConfig_t, blackboxConfig, PG_BLACKBOX_CONFIG, 0);
|
||||
|
||||
|
@ -44,6 +44,7 @@ extern "C" {
|
|||
#include "gtest/gtest.h"
|
||||
|
||||
|
||||
static serialPort_t *blackboxPort;
|
||||
static int serialWritePos = 0;
|
||||
static int serialReadPos = 0;
|
||||
static int serialReadEnd = 0;
|
||||
|
@ -126,5 +127,18 @@ TEST(BlackboxTest, Test1)
|
|||
|
||||
// STUBS
|
||||
extern "C" {
|
||||
int32_t blackboxHeaderBudget;
|
||||
void mspSerialAllocatePorts(void) {}
|
||||
void blackboxWrite(uint8_t value) {serialWrite(blackboxPort, value);}
|
||||
int blackboxPrint(const char *s)
|
||||
{
|
||||
const uint8_t *pos = (uint8_t*)s;
|
||||
while (*pos) {
|
||||
serialWrite(blackboxPort, *pos);
|
||||
pos++;
|
||||
}
|
||||
const int length = pos - (uint8_t*)s;
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue