diff --git a/src/main/blackbox/blackbox_io.c b/src/main/blackbox/blackbox_io.c
index 245e67d65..c1fb2434b 100644
--- a/src/main/blackbox/blackbox_io.c
+++ b/src/main/blackbox/blackbox_io.c
@@ -40,8 +40,10 @@ static uint8_t blackboxMaxHeaderBytesPerIteration;
// How many bytes can we write *this* iteration without overflowing transmit buffers or overstressing the OpenLog?
int32_t blackboxHeaderBudget;
-static serialPort_t *blackboxPort = NULL;
+STATIC_UNIT_TESTED serialPort_t *blackboxPort = NULL;
+#ifndef UNIT_TEST
static portSharing_e blackboxPortSharing;
+#endif
#ifdef USE_SDCARD
@@ -66,6 +68,7 @@ static struct {
#endif
+#ifndef UNIT_TEST
void blackboxOpen()
{
serialPort_t *sharedBlackboxAndMspPort = findSharedSerialPort(FUNCTION_BLACKBOX, FUNCTION_MSP);
@@ -73,6 +76,7 @@ void blackboxOpen()
mspSerialReleasePortIfAllocated(sharedBlackboxAndMspPort);
}
}
+#endif
void blackboxWrite(uint8_t value)
{
@@ -541,6 +545,7 @@ bool blackboxDeviceFlushForce(void)
/**
* Attempt to open the logging device. Returns true if successful.
*/
+#ifndef UNIT_TEST
bool blackboxDeviceOpen(void)
{
switch (blackboxConfig()->device) {
@@ -611,6 +616,7 @@ bool blackboxDeviceOpen(void)
return false;
}
}
+#endif
/**
* Erase all blackbox logs
@@ -650,6 +656,7 @@ 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) {
@@ -670,6 +677,7 @@ void blackboxDeviceClose(void)
;
}
}
+#endif
#ifdef USE_SDCARD
diff --git a/src/test/Makefile b/src/test/Makefile
index 14f767019..5edd12e68 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -46,6 +46,12 @@ battery_unittest_SRC := \
$(USER_DIR)/common/maths.c
+blackbox_unittest_SRC := \
+ $(USER_DIR)/blackbox/blackbox_io.c \
+ $(USER_DIR)/common/encoding.c \
+ $(USER_DIR)/common/printf.c \
+ $(USER_DIR)/common/typeconversion.c
+
cms_unittest_SRC := \
$(USER_DIR)/cms/cms.c \
$(USER_DIR)/common/typeconversion.c \
diff --git a/src/test/unit/blackbox_unittest.cc b/src/test/unit/blackbox_unittest.cc
new file mode 100644
index 000000000..3edf4197a
--- /dev/null
+++ b/src/test/unit/blackbox_unittest.cc
@@ -0,0 +1,130 @@
+/*
+ *
+ * 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 .
+ */
+
+#include
+#include
+
+extern "C" {
+ #include "platform.h"
+
+ #include "blackbox/blackbox.h"
+ #include "blackbox/blackbox_io.h"
+ #include "common/utils.h"
+
+ #include "config/parameter_group.h"
+ #include "config/parameter_group_ids.h"
+
+ #include "drivers/serial.h"
+ extern serialPort_t *blackboxPort;
+
+ PG_REGISTER_WITH_RESET_TEMPLATE(blackboxConfig_t, blackboxConfig, PG_BLACKBOX_CONFIG, 0);
+
+ PG_RESET_TEMPLATE(blackboxConfig_t, blackboxConfig,
+ .device = DEFAULT_BLACKBOX_DEVICE,
+ .rate_num = 1,
+ .rate_denom = 1,
+ .on_motor_test = 0 // default off
+ );
+}
+
+#include "unittest_macros.h"
+#include "gtest/gtest.h"
+
+
+static int serialWritePos = 0;
+static int serialReadPos = 0;
+static int serialReadEnd = 0;
+#define SERIAL_BUFFER_SIZE 256
+static uint8_t serialReadBuffer[SERIAL_BUFFER_SIZE];
+static uint8_t serialWriteBuffer[SERIAL_BUFFER_SIZE];
+
+serialPort_t serialTestInstance;
+
+void serialWrite(serialPort_t *instance, uint8_t ch)
+{
+ EXPECT_EQ(instance, &serialTestInstance);
+ EXPECT_LT(serialWritePos, sizeof(serialWriteBuffer));
+ serialWriteBuffer[serialWritePos++] = ch;
+}
+
+void serialWriteBuf(serialPort_t *instance, const uint8_t *data, int count)
+{
+ while(count--)
+ serialWrite(instance, *data++);
+}
+
+void serialBeginWrite(serialPort_t *instance)
+{
+ EXPECT_EQ(instance, &serialTestInstance);
+}
+
+void serialEndWrite(serialPort_t *instance)
+{
+ EXPECT_EQ(instance, &serialTestInstance);
+}
+
+uint32_t serialRxBytesWaiting(const serialPort_t *instance)
+{
+ EXPECT_EQ(instance, &serialTestInstance);
+ EXPECT_GE(serialReadEnd, serialReadPos);
+ int ret = serialReadEnd - serialReadPos;
+ if (ret >= 0) return ret;
+ return 0;
+}
+
+uint8_t serialRead(serialPort_t *instance)
+{
+ EXPECT_EQ(instance, &serialTestInstance);
+ EXPECT_LT(serialReadPos, serialReadEnd);
+ const uint8_t ch = serialReadBuffer[serialReadPos++];
+ return ch;
+}
+
+uint32_t serialTxBytesFree(const serialPort_t *instance)
+{
+ UNUSED(instance);
+ return SERIAL_BUFFER_SIZE - serialWritePos;
+}
+
+bool isSerialTransmitBufferEmpty(const serialPort_t *instance)
+{
+ EXPECT_EQ(instance, &serialTestInstance);
+ return true;
+}
+
+void serialTestResetBuffers()
+{
+ memset(&serialReadBuffer, 0, sizeof(serialReadBuffer));
+ serialReadPos = 0;
+ serialReadEnd = 0;
+ memset(&serialWriteBuffer, 0, sizeof(serialWriteBuffer));
+ serialWritePos = 0;
+}
+
+TEST(BlackboxTest, Test1)
+{
+ blackboxPort = &serialTestInstance;
+ blackboxWriteUnsignedVB(0);
+ EXPECT_EQ(0, serialWriteBuffer[0]);
+ blackboxWriteUnsignedVB(128);
+ EXPECT_EQ(0x80, serialWriteBuffer[1]);
+ EXPECT_EQ(1, serialWriteBuffer[2]);
+}
+
+// STUBS
+extern "C" {
+void mspSerialAllocatePorts(void) {}
+}
diff --git a/src/test/unit/target.h b/src/test/unit/target.h
index 6f2bbbd62..e3b04dc19 100644
--- a/src/test/unit/target.h
+++ b/src/test/unit/target.h
@@ -20,6 +20,7 @@
#define CMS
#define CMS_MAX_DEVICE 4
#define USE_FAKE_GYRO
+#define BLACKBOX
#define MAG
#define BARO
#define GPS
@@ -61,6 +62,8 @@
#define TARGET_BOARD_IDENTIFIER "TEST"
+#define DEFAULT_BLACKBOX_DEVICE BLACKBOX_DEVICE_SERIAL
+
#define LED_STRIP_TIMER 1
#define SOFTSERIAL_1_TIMER 2
#define SOFTSERIAL_2_TIMER 3