Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/blackbox/blackbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,8 @@ static void writeInterframe(void)
*/
blackboxWriteSignedVB((int32_t) (blackboxHistory[0]->time - 2 * blackboxHistory[1]->time + blackboxHistory[2]->time));

int32_t deltas[8];
// Up to 9 optional fields below: vbat, amperage, mag x3, baro, pitot, surface, rssi
int32_t deltas[9];
arraySubInt32(deltas, blackboxCurrent->axisPID_Setpoint, blackboxLast->axisPID_Setpoint, XYZ_AXIS_COUNT);
blackboxWriteSignedVBArray(deltas, XYZ_AXIS_COUNT);

Expand Down
23 changes: 16 additions & 7 deletions src/main/blackbox/blackbox_encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,7 @@ void blackboxWriteTag8_4S16(int32_t *values)
}
}

/**
* 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)
static void blackboxWriteTag8_8SVBGroup(int32_t *values, int valueCount)
{
uint8_t header;

Expand Down Expand Up @@ -365,6 +359,21 @@ void blackboxWriteTag8_8SVB(int32_t *values, int valueCount)
}
}

/**
* 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).
*/
void blackboxWriteTag8_8SVB(int32_t *values, int valueCount)
{
// Decoders read a run of these fields as groups of 8, and a lone last field as a plain signed VB
while (valueCount > 8) {
blackboxWriteTag8_8SVBGroup(values, 8);
values += 8;
valueCount -= 8;
}
blackboxWriteTag8_8SVBGroup(values, valueCount);
}

/** Write unsigned integer **/
void blackboxWriteU32(int32_t value)
{
Expand Down
3 changes: 3 additions & 0 deletions src/test/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ set_property(SOURCE accgyro_lsm6dxx_unittest.cc PROPERTY depends
set_property(SOURCE accgyro_lsm6dxx_unittest.cc PROPERTY definitions USE_IMU_LSM6DXX)

set_property(SOURCE adsb_unittest.cc PROPERTY depends "io/adsb.c" "common/maths.c")

set_property(SOURCE blackbox_encoding_unittest.cc PROPERTY depends "blackbox/blackbox_encoding.c" "common/encoding.c")
set_property(SOURCE blackbox_encoding_unittest.cc PROPERTY definitions USE_BLACKBOX)
set_property(SOURCE adsb_unittest.cc PROPERTY definitions USE_ADSB MAX_ADSB_VEHICLES=5 ADSB_LIMIT_CM=6400000)
set_property(SOURCE adsb_unittest.cc PROPERTY extra_includes "../../lib/main/MAVLink")

Expand Down
97 changes: 97 additions & 0 deletions src/test/unit/blackbox_encoding_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* This file is part of INAV.
*
* INAV 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.
*
* INAV 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 INAV. If not, see <http://www.gnu.org/licenses/>.
*/

#include <cstdarg>
#include <cstdint>
#include <vector>

extern "C" {
#include "blackbox/blackbox_encoding.h"
}

#include "gtest/gtest.h"

static std::vector<uint8_t> written;

extern "C" {
int32_t blackboxHeaderBudget;

void blackboxWrite(uint8_t value)
{
written.push_back(value);
}

int blackboxPrint(const char *s)
{
int n = 0;
for (; *s; s++, n++) {
blackboxWrite(*s);
}
return n;
}

int tfp_format(void *putp, void (*putf)(void *, char), const char *fmt, va_list va)
{
(void)putp;
(void)putf;
(void)fmt;
(void)va;
return 0;
}
}

static std::vector<uint8_t> writeTag8_8SVB(std::vector<int32_t> values)
{
written.clear();
blackboxWriteTag8_8SVB(values.data(), (int)values.size());
return written;
}

// Small values zigzag-encode to one byte: 0 -> 0, -1 -> 1, 1 -> 2, 2 -> 4, ...

TEST(BlackboxEncodingTest, Tag8_8SVBNothing)
{
EXPECT_EQ(writeTag8_8SVB({}), std::vector<uint8_t>({}));
}

TEST(BlackboxEncodingTest, Tag8_8SVBOneFieldHasNoHeader)
{
EXPECT_EQ(writeTag8_8SVB({0}), std::vector<uint8_t>({0x00}));
EXPECT_EQ(writeTag8_8SVB({5}), std::vector<uint8_t>({0x0A}));
}

TEST(BlackboxEncodingTest, Tag8_8SVBHeaderMarksNonZeroFields)
{
EXPECT_EQ(writeTag8_8SVB({1, 0, -1}), std::vector<uint8_t>({0x05, 0x02, 0x01}));
EXPECT_EQ(writeTag8_8SVB({1, 2, 3, 4, 5, 6, 7, 8}),
std::vector<uint8_t>({0xFF, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10}));
}

// Decoders read a run longer than 8 as groups of 8, and a lone last field as a plain signed VB
TEST(BlackboxEncodingTest, Tag8_8SVBNinthFieldIsAPlainVB)
{
EXPECT_EQ(writeTag8_8SVB({1, 2, 3, 4, 5, 6, 7, 8, 0}),
std::vector<uint8_t>({0xFF, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x00}));
EXPECT_EQ(writeTag8_8SVB({0, 0, 0, 0, 0, 0, 0, 0, 3}),
std::vector<uint8_t>({0x00, 0x06}));
}

TEST(BlackboxEncodingTest, Tag8_8SVBSeventeenFields)
{
EXPECT_EQ(writeTag8_8SVB({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 2}),
std::vector<uint8_t>({0x01, 0x02, 0x80, 0x01, 0x04}));
}
Loading