diff --git a/Src/Drivers/sbus.c b/Src/Drivers/sbus.c index 4fc08b2..43f3909 100644 --- a/Src/Drivers/sbus.c +++ b/Src/Drivers/sbus.c @@ -70,6 +70,8 @@ static bool sbus_decode(uint8_t data) { void sbus_init(void) { decode_byte_count = 0; + latest_data.failsafe = true; + latest_data.frame_lost = true; ring_buffer_data = ring_buffer_init(); uart_init(UART_ID, UART_BAUD, EVEN, 2, uart_callback); } diff --git a/Src/Drivers/sbus.h b/Src/Drivers/sbus.h index c4a67ea..80de227 100644 --- a/Src/Drivers/sbus.h +++ b/Src/Drivers/sbus.h @@ -27,18 +27,83 @@ typedef struct { } sbus_data_t; /** - * Initializes the SBUS module by initializing all internal data and the UART connection. + * @brief Initialize the SBUS module. + * + * The initialization consists of the following tasks: + * * Initialize the internal ring buffer + * * Initialize the uart to the following parameters: + * * ID: 2 + * * Baud Rate: 100 000 + * * Parity: Even + * * Stop Bits: 2 + * * Callback: pointer to the internal uart callback function + * * Initialize all internal state for decoding + * + * The internal uart callback function performs the following tasks: + * * Add the received byte to the internal ring-buffer + * + * @see https://github.com/bolderflight/sbus/blob/main/README.md */ void sbus_init(void); /** - * Decodes all data received since the last call and returns whether the data contains a full new packet. + * @brief Decodes all data received since the last call and returns whether the data contains a full new packet. + * + * This function iterates over all in the ring buffer and feeds the bytes, in the order they were received, + * into the following state machine (initialized in the INIT state, with the state kept between calls to the + * function): + * + * \dot + * digraph { + * rankdir = "LR"; + * + * INIT -> INIT [ + * label = "data!=0x0F/\nindex=0"; + * ] + * INIT -> IN_DATA [ + * label = "data=0x0F/"; + * ] + * + * IN_DATA -> IN_DATA [ + * label = "index<22/\nbuffer[index]=data\nindex += 1"; + * ] + * + * IN_DATA -> AT_END [ + * label = "index>=22/\nfailsave = data_3,\nframe-lost= data_2"; + * ] + * + * AT_END -> INIT [ + * label = "data=0x00/\nDecode result"; + * ] + * + * AT_END -> INIT [ + * label = "data=0x00/\nTrigger warning"; + * ] + * + * } + * \enddot + * + * **Decode result** consists of the following tasks: + * * For every bit in the (receive-) buffer calculate the overall index as the index in the byte plus the 8 times the + * index of the byte + * * Calculate the channel index as the result of the integer division of the (receive-) buffer index with 11 and + * * Set the channel bit index as the remainder of the integer division + * * Set the bit of the respective channel to the bit value + * + * After all data has been consumed the function shall return true if the **Decode result** was triggered, otherwise + * it shall return false. + * + * @see https://github.com/bolderflight/sbus/blob/main/README.md * @return true if a new packet was received, otherwise false. */ bool sbus_data_available(void); /** - * Get the last packet that was received. + * @brief Get the last packet that was received. + * + * Returns the last fully received package, if no package was received both the failsafe and the frame-lost flag + * shall be true. + * * @return a copy of the last packet. */ sbus_data_t sbus_get_latest_data(void); diff --git a/Tests/LowLevel/Drivers/sbus.cpp b/Tests/LowLevel/Drivers/sbus.cpp index 2339c6d..a77b2b1 100644 --- a/Tests/LowLevel/Drivers/sbus.cpp +++ b/Tests/LowLevel/Drivers/sbus.cpp @@ -11,16 +11,14 @@ TEST(TEST_NAME, init) { auto ringBufferHandle = mock::ring_buffer.getHandle(); ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); sbus_init(); - /* - * https://github.com/bolderflight/sbus/blob/main/README.md: - * The SBUS protocol uses an inverted serial logic with a baud rate of 100000, 8 data bits, even parity, and 2 stop - * bits - */ + EXPECT_TRUE(uartHandle.functionGotCalled(2, 100000U, EVEN, 2, std::ignore)); EXPECT_TRUE(ringBufferHandle.functionGotCalled()); + EXPECT_TRUE(sbus_get_latest_data().frame_lost); + EXPECT_TRUE(sbus_get_latest_data().failsafe); } -TEST(TEST_NAME, rx_fill_buffer) { +TEST(TEST_NAME, init__callback) { auto uartHandle = mock::uart.getHandle(); auto ringBufferHandle = mock::ring_buffer.getHandle(); ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); @@ -44,7 +42,228 @@ TEST(TEST_NAME, rx_fill_buffer) { EXPECT_TRUE(ringBufferHandle.functionGotCalled(std::ignore, 54)); } -TEST(TEST_NAME, decode) { +TEST(TEST_NAME, data_available__no_data) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + ringBufferHandle.overrideFunc([](ring_buffer_data_t *ringBufferData, uint8_t * /*out*/) { + EXPECT_NE(ringBufferData, nullptr); + return false; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + EXPECT_FALSE(sbus_data_available()); + EXPECT_TRUE(sbus_get_latest_data().failsafe); + EXPECT_TRUE(sbus_get_latest_data().frame_lost); +} + +TEST(TEST_NAME, data_available__till_init) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + std::size_t count = 0; + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { + EXPECT_NE(ringBufferData, nullptr); + if (count == 0) { + *out = 0x0F; // Start byte + } + count += 1; + return count <= 1; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + EXPECT_FALSE(sbus_data_available()); + EXPECT_TRUE(sbus_get_latest_data().failsafe); + EXPECT_TRUE(sbus_get_latest_data().frame_lost); +} + +TEST(TEST_NAME, data_available__till_data_0) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + std::size_t count = 0; + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { + EXPECT_NE(ringBufferData, nullptr); + if (count == 0) { + *out = 0x0F; // Start byte + } else { // First data byte + *out = 0x00; + } + count += 1; + return count <= 2; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + EXPECT_FALSE(sbus_data_available()); + EXPECT_TRUE(sbus_get_latest_data().failsafe); + EXPECT_TRUE(sbus_get_latest_data().frame_lost); +} + +TEST(TEST_NAME, data_available__till_data_22) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + std::size_t count = 0; + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { + EXPECT_NE(ringBufferData, nullptr); + if (count == 0) { + *out = 0x0F; // Start byte + } else if (count == 22) { // Last data byte + *out = 0x00; + } else { // Data bytes + *out = 0x00; + } + count += 1; + return count <= 23; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + EXPECT_FALSE(sbus_data_available()); + EXPECT_TRUE(sbus_get_latest_data().failsafe); + EXPECT_TRUE(sbus_get_latest_data().frame_lost); +} + +TEST(TEST_NAME, data_available__till_flags) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + std::size_t count = 0; + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { + EXPECT_NE(ringBufferData, nullptr); + if (count == 0) { + *out = 0x0F; // Start byte + } else if (count == 23) { + *out = 0x08; // Flags + } else { // Data bytes + *out = 0x00; + } + count += 1; + return count <= 24; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + EXPECT_FALSE(sbus_data_available()); + EXPECT_TRUE(sbus_get_latest_data().failsafe); + EXPECT_TRUE(sbus_get_latest_data().frame_lost); +} + +TEST(TEST_NAME, data_available__no_end) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + std::size_t count = 0; + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { + EXPECT_NE(ringBufferData, nullptr); + if (count == 0) { + *out = 0x0F; // Start byte + } else if (count == 23) { + *out = 0x08; // Flags + } else if (count == 24) { // End byte + *out = 0xFF; // Invalid end byte + } else { // Data bytes + *out = 0x00; + } + count += 1; + return count <= 25; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + // TODO check warning + + EXPECT_FALSE(sbus_data_available()); + EXPECT_TRUE(sbus_get_latest_data().failsafe); + EXPECT_TRUE(sbus_get_latest_data().frame_lost); +} + +TEST(TEST_NAME, data_available__multiple_init) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + std::size_t count = 0; + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { + EXPECT_NE(ringBufferData, nullptr); + if (count == 0 + 5) { + *out = 0x0F; // Start byte + } else if (count == 23 + 5) { + *out = 0x00; // Flags + } else if (count == 24 + 5) { // End byte + *out = 0x00; + } else { // Data bytes + *out = 0x00; + } + count += 1; + return count <= 25 + 5; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + EXPECT_TRUE(sbus_data_available()); + EXPECT_FALSE(sbus_get_latest_data().failsafe); + EXPECT_FALSE(sbus_get_latest_data().frame_lost); + + for (const uint16_t channel : sbus_get_latest_data().channel) { + EXPECT_EQ(channel, 0); + } +} + +TEST(TEST_NAME, data_available__multiple_data) { + auto uartHandle = mock::uart.getHandle(); + auto ringBufferHandle = mock::ring_buffer.getHandle(); + ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); + + std::size_t count = 0; + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { + EXPECT_NE(ringBufferData, nullptr); + if (count % 25 == 0) { + *out = 0x0F; // Start byte + } else if (count % 25 == 23) { + *out = 0x00; // Flags + } else if (count % 25 == 24) { // End byte + *out = 0x00; + } else { // Data bytes + if (count < 25) { + *out = 0x00; + } else { + *out = 0xFF; + } + } + count += 1; + return count <= 50; + }); + + sbus_init(); + EXPECT_TRUE(uartHandle.functionGotCalled()); + + EXPECT_TRUE(sbus_data_available()); + EXPECT_FALSE(sbus_get_latest_data().failsafe); + EXPECT_FALSE(sbus_get_latest_data().frame_lost); + + for (const uint16_t channel : sbus_get_latest_data().channel) { + EXPECT_EQ(channel, 2047); + } +} + +TEST(TEST_NAME, data_available__decode_result) { auto uartHandle = mock::uart.getHandle(); auto ringBufferHandle = mock::ring_buffer.getHandle(); ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); @@ -62,31 +281,31 @@ TEST(TEST_NAME, decode) { * - Bit 3: failsafe activated (0x08) * - Byte[24]: SBUS footer */ - std::vector data = {/* 0 */ 0x0F, - /* 1 */ (uint8_t) (1 << 0), - /* 2 */ (uint8_t) (2 << 3 | 1 >> 8), - /* 3 */ (uint8_t) (3 << 6 | 2 >> 5), - /* 4 */ (uint8_t) (3 >> 2), - /* 5 */ (uint8_t) (4 << 1 | 3 >> 10), - /* 6 */ (uint8_t) (5 << 4 | 4 >> 7), - /* 7 */ (uint8_t) (6 << 7 | 5 >> 4), - /* 8 */ (uint8_t) (6 >> 1), - /* 9 */ (uint8_t) (7 << 2 | 6 >> 9), - /* 10 */ (uint8_t) (8 << 5 | 7 >> 6), - /* 11 */ (uint8_t) (8 >> 3), - /* 12 */ (uint8_t) (9 << 0), - /* 13 */ (uint8_t) (10 << 3 | 9 >> 8), - /* 14 */ (uint8_t) (11 << 6 | 10 >> 5), - /* 15 */ (uint8_t) (11 >> 2), - /* 16 */ (uint8_t) (12 << 1 | 11 >> 10), - /* 17 */ (uint8_t) (13 << 4 | 12 >> 7), - /* 18 */ (uint8_t) (14 << 7 | 13 >> 4), - /* 19 */ (uint8_t) (14 >> 1), - /* 20 */ (uint8_t) (15 << 2 | 14 >> 9), - /* 21 */ (uint8_t) (16 << 5 | 15 >> 6), - /* 22 */ (uint8_t) (16 >> 3), - /* 23 */ 0b00, - /* 24 */ 0x00}; + const std::vector data = {/* 0 */ 0x0F, + /* 1 */ (uint8_t) (1 << 0), + /* 2 */ (uint8_t) (2 << 3 | 1 >> 8), + /* 3 */ (uint8_t) (3 << 6 | 2 >> 5), + /* 4 */ (uint8_t) (3 >> 2), + /* 5 */ (uint8_t) (4 << 1 | 3 >> 10), + /* 6 */ (uint8_t) (5 << 4 | 4 >> 7), + /* 7 */ (uint8_t) (6 << 7 | 5 >> 4), + /* 8 */ (uint8_t) (6 >> 1), + /* 9 */ (uint8_t) (7 << 2 | 6 >> 9), + /* 10 */ (uint8_t) (8 << 5 | 7 >> 6), + /* 11 */ (uint8_t) (8 >> 3), + /* 12 */ (uint8_t) (9 << 0), + /* 13 */ (uint8_t) (10 << 3 | 9 >> 8), + /* 14 */ (uint8_t) (11 << 6 | 10 >> 5), + /* 15 */ (uint8_t) (11 >> 2), + /* 16 */ (uint8_t) (12 << 1 | 11 >> 10), + /* 17 */ (uint8_t) (13 << 4 | 12 >> 7), + /* 18 */ (uint8_t) (14 << 7 | 13 >> 4), + /* 19 */ (uint8_t) (14 >> 1), + /* 20 */ (uint8_t) (15 << 2 | 14 >> 9), + /* 21 */ (uint8_t) (16 << 5 | 15 >> 6), + /* 22 */ (uint8_t) (16 >> 3), + /* 23 */ 0b00, + /* 24 */ 0x00}; std::size_t count = 0; ringBufferHandle.overrideFunc([&count, data](ring_buffer_data_t *ringBufferData, uint8_t *out) { EXPECT_NE(ringBufferData, nullptr); @@ -107,22 +326,25 @@ TEST(TEST_NAME, decode) { } } -TEST(TEST_NAME, decode_failsave) { +TEST(TEST_NAME, data_available__decode_result_failsave) { auto uartHandle = mock::uart.getHandle(); auto ringBufferHandle = mock::ring_buffer.getHandle(); ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); - std::vector data(25); - data[0] = 0x0F; - data[23] = 0x08; - data[24] = 0; - std::size_t count = 0; - ringBufferHandle.overrideFunc([&count, data](ring_buffer_data_t *ringBufferData, uint8_t *out) { + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { EXPECT_NE(ringBufferData, nullptr); - *out = data[count]; + if (count == 0) { + *out = 0x0F; // Start byte + } else if (count == 23) { + *out = 0x08; // Flags + } else if (count == 24) { // End byte + *out = 0x00; + } else { // Data bytes + *out = 0x00; + } count += 1; - return count <= data.size(); + return count <= 25; }); sbus_init(); @@ -137,23 +359,27 @@ TEST(TEST_NAME, decode_failsave) { } } -TEST(TEST_NAME, decode_framelost) { +TEST(TEST_NAME, data_available__decode_result_framelost) { auto uartHandle = mock::uart.getHandle(); auto ringBufferHandle = mock::ring_buffer.getHandle(); ringBufferHandle.overrideFunc([]() { return ring_buffer_data_t{}; }); - std::vector data(25); - data[0] = 0x0F; - data[23] = 0x04; - data[24] = 0; - std::size_t count = 0; - ringBufferHandle.overrideFunc([&count, data](ring_buffer_data_t *ringBufferData, uint8_t *out) { + ringBufferHandle.overrideFunc([&count](ring_buffer_data_t *ringBufferData, uint8_t *out) { EXPECT_NE(ringBufferData, nullptr); - *out = data[count]; + if (count == 0) { + *out = 0x0F; // Start byte + } else if (count == 23) { + *out = 0x04; // Flags + } else if (count == 24) { // End byte + *out = 0x00; + } else { // Data bytes + *out = 0x00; + } count += 1; - return count <= data.size(); + return count <= 25; }); + uart_callback_t uartCallback = nullptr; uartHandle.overrideFunc([&uartCallback](uint8_t /*id*/, uint32_t /*baud*/, uart_parity_t /*parity*/, uint8_t /*stop_bits*/,