test suite + test helper + refactoring

This commit is contained in:
myles-parfeniuk 2024-11-14 13:29:46 -08:00
parent 991c447f05
commit 5b0af503ae
12 changed files with 178 additions and 96 deletions

View File

@ -1,3 +1,3 @@
idf_component_register(SRC_DIRS "source" "tests"
INCLUDE_DIRS "include" "tests"
REQUIRES driver esp_timer)
idf_component_register(SRC_DIRS "source"
INCLUDE_DIRS "include"
REQUIRES driver esp_timer cmock)

View File

@ -307,7 +307,6 @@ class BNO08x
static const constexpr int16_t GRAVITY_Q1 = 8; ///< Gravity Q point (See SH-2 Ref. Manual 6.5.11)
private:
/// @brief Holds data that is received over spi.
typedef struct bno08x_rx_packet_t
{
@ -326,15 +325,15 @@ class BNO08x
/// @brief Holds info about which functionality has been successfully initialized (used by deconstructor during cleanup).
typedef struct bno08x_init_status_t
{
bool gpio_outputs; ///< True if GPIO outputs have been initialized.
bool gpio_inputs; ///< True if GPIO inputs have been initialized.
bool isr_service; ///< True if global ISR service has been initialized.
bool isr_handler; ///< True if HINT ISR handler has been initialized.
uint8_t task_count; ///< How many successfully initialized tasks (max of TSK_CNT)
bool data_proc_task; ///< True if xTaskCreate has been called successfully for data_proc_task.
bool spi_task; ///< True if xTaskCreate has been called successfully for spi_task.
bool spi_bus; ///< True if spi_bus_initialize() has been called successfully.
bool spi_device; ///< True if spi_bus_add_device() has been called successfully.
bool gpio_outputs; ///< True if GPIO outputs have been initialized.
bool gpio_inputs; ///< True if GPIO inputs have been initialized.
bool isr_service; ///< True if global ISR service has been initialized.
bool isr_handler; ///< True if HINT ISR handler has been initialized.
uint8_t task_count; ///< How many successfully initialized tasks (max of TSK_CNT)
bool data_proc_task; ///< True if xTaskCreate has been called successfully for data_proc_task.
bool spi_task; ///< True if xTaskCreate has been called successfully for spi_task.
bool spi_bus; ///< True if spi_bus_initialize() has been called successfully.
bool spi_device; ///< True if spi_bus_add_device() has been called successfully.
bno08x_init_status_t()
: gpio_outputs(false)
@ -368,6 +367,7 @@ class BNO08x
bool wait_for_data();
bool receive_packet();
void send_packet(bno08x_tx_packet_t* packet);
void flush_rx_packets(uint8_t flush_count, TickType_t delay);
void enable_report(uint8_t report_ID, uint32_t time_between_reports, const EventBits_t report_evt_grp_bit, uint32_t special_config = 0);
void disable_report(uint8_t report_ID, const EventBits_t report_evt_grp_bit);
void queue_packet(uint8_t channel_number, uint8_t data_length, uint8_t* commands);
@ -421,7 +421,8 @@ class BNO08x
spi_device_interface_config_t imu_spi_config{}; ///<SPI slave device settings
spi_device_handle_t spi_hdl{}; ///<SPI device handle
spi_transaction_t spi_transaction{}; ///<SPI transaction handle
bno08x_init_status_t init_status; ///<Initialization status of various functionality, used by deconstructor during cleanup, set during initialization.
bno08x_init_status_t
init_status; ///<Initialization status of various functionality, used by deconstructor during cleanup, set during initialization.
// These are the raw sensor values (without Q applied) pulled from the user requested Input Report
uint32_t time_stamp; ///<Report timestamp (see datasheet 1.3.5.3)
@ -460,8 +461,17 @@ class BNO08x
static const constexpr uint16_t RX_DATA_LENGTH = 300U; ///<length buffer containing data received over spi
static const constexpr uint16_t MAX_METADATA_LENGTH = 9U; ///<max length of metadata used in frs read operations
static const constexpr uint64_t HOST_INT_TIMEOUT_MS =
300ULL; ///<Max wait between HINT being asserted by BNO08x before transaction is considered failed (in miliseconds)
static const constexpr TickType_t HOST_INT_TIMEOUT_MS =
300UL /
portTICK_PERIOD_MS; ///<Max wait between HINT being asserted by BNO08x before transaction is considered failed (in miliseconds)
static const constexpr TickType_t HARD_RESET_DELAY_MS =
200UL /
portTICK_PERIOD_MS; ///<How long RST pin is held low during hard reset (min 10ns according to datasheet, but should be longer for stable operation)
static const constexpr TickType_t CMD_EXECUTION_DELAY_MS = 10UL / portTICK_PERIOD_MS; ///<How long to delay after queueing command to allow it to execute (for ex. after sending command to enable report).
static const constexpr TickType_t FLUSH_PKT_DELAY_MS = 20UL / portTICK_PERIOD_MS; ///<How long to delay between wait_for_rx_done() calls when flush_rx_packets() is called.
static const constexpr uint32_t SCLK_MAX_SPEED = 3000000UL; ///<Max SPI SCLK speed BNO08x is capable of

View File

@ -0,0 +1,56 @@
#pragma once
#include "stdio.h"
#include "BNO08x.hpp"
class BNO08xTestHelper
{
private:
inline static BNO08x* test_imu = nullptr;
inline static bno08x_config_t imu_cfg;
static const constexpr char *TAG = "BNO08xTestHelper";
public:
static void print_test_start_banner(const char *TEST_TAG)
{
printf("------------------------BEGIN TEST: %s------------------------\n\r", TEST_TAG);
}
static void print_test_end_banner(const char *TEST_TAG)
{
printf("------------------------END TEST: %s------------------------\n\r", TEST_TAG);
}
static void print_test_msg(const char *TEST_TAG, const char *msg)
{
printf("%s: %s: %s\n\r", TAG, TEST_TAG, msg);
}
static void set_test_imu_cfg(bno08x_config_t cfg)
{
imu_cfg = cfg;
}
static void create_test_imu()
{
if(test_imu != nullptr)
destroy_test_imu();
test_imu = new BNO08x();
}
static void destroy_test_imu()
{
if (test_imu != nullptr)
{
delete test_imu;
test_imu = nullptr;
}
}
static BNO08x* get_test_imu()
{
return test_imu;
}
};

View File

@ -0,0 +1,19 @@
#pragma once
/*
YOU MUST ADD THE FOLLOWING LINE TO YOUR MAIN PROJECTS CMakeLists.txt IN ORDER FOR THIS TEST SUITE TO BE FUNCTIONAL:
set(TEST_COMPONENTS "esp32_BNO08x" CACHE STRING "Components to test.")
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "BNO08xTestHelper.hpp"
class BNO08xTestSuite
{
public:
static void run_all_tests();
static void run_init_deinit_tests();
};

View File

@ -438,7 +438,7 @@ bool BNO08x::wait_for_rx_done()
gpio_intr_enable(imu_config.io_int); // re-enable interrupts
// wait until an interrupt has been asserted and data received or timeout has occured
if (xEventGroupWaitBits(evt_grp_spi, EVT_GRP_SPI_RX_DONE_BIT, pdTRUE, pdTRUE, HOST_INT_TIMEOUT_MS / portTICK_PERIOD_MS))
if (xEventGroupWaitBits(evt_grp_spi, EVT_GRP_SPI_RX_DONE_BIT, pdTRUE, pdTRUE, HOST_INT_TIMEOUT_MS))
{
#ifdef CONFIG_ESP32_BNO08x_DEBUG_STATEMENTS
ESP_LOGI(TAG, "int asserted");
@ -471,11 +471,11 @@ bool BNO08x::wait_for_data()
gpio_intr_enable(imu_config.io_int); // re-enable interrupts
// check to see receive operation has finished
if (xEventGroupWaitBits(evt_grp_spi, EVT_GRP_SPI_RX_DONE_BIT, pdTRUE, pdTRUE, HOST_INT_TIMEOUT_MS / portTICK_PERIOD_MS))
if (xEventGroupWaitBits(evt_grp_spi, EVT_GRP_SPI_RX_DONE_BIT, pdTRUE, pdTRUE, HOST_INT_TIMEOUT_MS))
{
// wait until processing is done, this should never go to timeout; however, it will be set slightly after EVT_GRP_SPI_RX_DONE_BIT
if (xEventGroupWaitBits(evt_grp_spi, EVT_GRP_SPI_RX_VALID_PACKET_BIT | EVT_GRP_SPI_RX_INVALID_PACKET_BIT, pdFALSE, pdFALSE,
HOST_INT_TIMEOUT_MS / portTICK_PERIOD_MS))
if (xEventGroupWaitBits(
evt_grp_spi, EVT_GRP_SPI_RX_VALID_PACKET_BIT | EVT_GRP_SPI_RX_INVALID_PACKET_BIT, pdFALSE, pdFALSE, HOST_INT_TIMEOUT_MS))
{
// only return true if packet is valid
if (xEventGroupGetBits(evt_grp_spi) & EVT_GRP_SPI_RX_VALID_PACKET_BIT)
@ -514,7 +514,7 @@ bool BNO08x::wait_for_tx_done()
if (xEventGroupGetBits(evt_grp_report_en) == 0)
gpio_intr_enable(imu_config.io_int); // re-enable interrupts
if (xEventGroupWaitBits(evt_grp_spi, EVT_GRP_SPI_TX_DONE_BIT, pdTRUE, pdTRUE, HOST_INT_TIMEOUT_MS / portTICK_PERIOD_MS))
if (xEventGroupWaitBits(evt_grp_spi, EVT_GRP_SPI_TX_DONE_BIT, pdTRUE, pdTRUE, HOST_INT_TIMEOUT_MS))
{
#ifdef CONFIG_ESP32_BNO08x_DEBUG_STATEMENTS
ESP_LOGI(TAG, "Packet sent successfully.");
@ -547,7 +547,7 @@ bool BNO08x::hard_reset()
gpio_set_level(imu_config.io_wake, 1);
gpio_set_level(imu_config.io_rst, 0); // set reset pin low
vTaskDelay(50 / portTICK_PERIOD_MS); // 10ns min, set to 50ms to let things stabilize(Anton)
vTaskDelay(HARD_RESET_DELAY_MS); // 10ns min, set to larger delay to let things stabilize(Anton)
gpio_set_level(imu_config.io_rst, 1); // bring out of reset
// Receive advertisement message on boot (see SH2 Ref. Manual 5.2 & 5.3)
@ -592,11 +592,7 @@ bool BNO08x::soft_reset()
success = wait_for_tx_done();
// flush any packets received
for (int i = 0; i < 3; i++)
{
wait_for_rx_done();
vTaskDelay(20 / portTICK_PERIOD_MS);
}
flush_rx_packets(3, FLUSH_PKT_DELAY_MS);
return success;
}
@ -620,7 +616,7 @@ IMUResetReason BNO08x::get_reset_reason()
{
// receive product ID report
if (wait_for_data())
xQueueReceive(queue_reset_reason, &reset_reason, HOST_INT_TIMEOUT_MS / portTICK_PERIOD_MS);
xQueueReceive(queue_reset_reason, &reset_reason, HOST_INT_TIMEOUT_MS);
else
ESP_LOGE(TAG, "Failed to receive product ID report.");
}
@ -643,11 +639,7 @@ bool BNO08x::mode_on()
success = wait_for_tx_done();
// flush any packets received
for (int i = 0; i < 3; i++)
{
wait_for_rx_done();
vTaskDelay(10 / portTICK_PERIOD_MS);
}
flush_rx_packets(3, FLUSH_PKT_DELAY_MS);
return success;
}
@ -667,11 +659,7 @@ bool BNO08x::mode_sleep()
success = wait_for_tx_done();
// flush any packets received
for (int i = 0; i < 3; i++)
{
wait_for_rx_done();
vTaskDelay(10 / portTICK_PERIOD_MS);
}
flush_rx_packets(3, FLUSH_PKT_DELAY_MS);
return success;
}
@ -753,8 +741,7 @@ void BNO08x::enable_report(uint8_t report_ID, uint32_t time_between_reports, con
}
// flush the first few reports returned to ensure new data
for (int i = 0; i < 3; i++)
wait_for_rx_done();
flush_rx_packets(3, 0);
}
/**
@ -835,6 +822,15 @@ void BNO08x::send_packet(bno08x_tx_packet_t* packet)
xEventGroupSetBits(evt_grp_spi, EVT_GRP_SPI_TX_DONE_BIT);
}
void BNO08x::flush_rx_packets(uint8_t flush_count, TickType_t delay)
{
for (int i = 0; i < flush_count; i++)
{
wait_for_rx_done();
vTaskDelay(delay);
}
}
/**
* @brief Queues a packet containing a command.
*
@ -877,7 +873,7 @@ void BNO08x::calibrate_all()
{
queue_calibrate_command(CALIBRATE_ACCEL_GYRO_MAG);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -889,7 +885,7 @@ void BNO08x::calibrate_accelerometer()
{
queue_calibrate_command(CALIBRATE_ACCEL);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -901,7 +897,7 @@ void BNO08x::calibrate_gyro()
{
queue_calibrate_command(CALIBRATE_GYRO);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -913,7 +909,7 @@ void BNO08x::calibrate_magnetometer()
{
queue_calibrate_command(CALIBRATE_MAG);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -925,7 +921,7 @@ void BNO08x::calibrate_planar_accelerometer()
{
queue_calibrate_command(CALIBRATE_PLANAR_ACCEL);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -990,7 +986,7 @@ void BNO08x::request_calibration_status()
// Using this commands packet, send a command
queue_command(COMMAND_ME_CALIBRATE, commands);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -1015,7 +1011,7 @@ void BNO08x::end_calibration()
{
queue_calibrate_command(CALIBRATE_STOP); // Disables all calibrations
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -1030,7 +1026,7 @@ void BNO08x::save_calibration()
// Using this shtpData packet, send a command
queue_command(COMMAND_DCD, commands); // Save DCD command
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(50 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -1874,7 +1870,7 @@ void BNO08x::tare_now(uint8_t axis_sel, uint8_t rotation_vector_basis)
{
queue_tare_command(TARE_NOW, axis_sel, rotation_vector_basis);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(12 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -1886,7 +1882,7 @@ void BNO08x::save_tare()
{
queue_tare_command(TARE_PERSIST);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(12 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -1898,7 +1894,7 @@ void BNO08x::clear_tare()
{
queue_tare_command(TARE_SET_REORIENTATION);
wait_for_tx_done(); // wait for transmit operation to complete
vTaskDelay(12 / portTICK_PERIOD_MS); // allow some time for command to be executed
vTaskDelay(CMD_EXECUTION_DELAY_MS); // allow some time for command to be executed
}
/**
@ -2945,7 +2941,7 @@ bool BNO08x::FRS_read_data(uint16_t record_ID, uint8_t start_location, uint8_t w
return false;
}
if (xQueueReceive(queue_frs_read_data, &packet_body, HOST_INT_TIMEOUT_MS / portTICK_PERIOD_MS))
if (xQueueReceive(queue_frs_read_data, &packet_body, HOST_INT_TIMEOUT_MS))
{
if ((((uint16_t) packet_body[13] << 8) | (uint16_t) packet_body[12]) == record_ID)
break;
@ -3195,6 +3191,9 @@ esp_err_t BNO08x::kill_all_tasks()
static const constexpr uint8_t TASK_DELETE_TIMEOUT_MS = 10;
uint8_t kill_count = 0;
bno08x_rx_packet_t dummy_packet;
sem_kill_tasks = xSemaphoreCreateCounting(init_status.task_count, 0);
memset(&dummy_packet, 0, sizeof(dummy_packet));
xEventGroupClearBits(
evt_grp_task_flow, EVT_GRP_TSK_FLW_RUNNING_BIT); // clear task running bit in task flow event group to request deletion of tasks

View File

@ -0,0 +1,13 @@
#include "BNO08xTestSuite.hpp"
void BNO08xTestSuite::run_all_tests()
{
run_init_deinit_tests();
}
void BNO08xTestSuite::run_init_deinit_tests()
{
UNITY_BEGIN();
unity_run_test_by_name("Full Init & Deinit");
UNITY_END();
}

3
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES cmock esp32_BNO08x)

26
test/InitDeinitTests.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "unity.h"
#include "../include/BNO08xTestHelper.hpp"
TEST_CASE("Full Init & Deinit", "[InitDenit]")
{
const constexpr char *TEST_TAG ="Full Init & Deinit";
BNO08x* imu;
BNO08xTestHelper::print_test_start_banner(TEST_TAG);
BNO08xTestHelper::print_test_msg(TEST_TAG, "Initializing IMU attempt 1.");
BNO08xTestHelper::create_test_imu();
imu = BNO08xTestHelper::get_test_imu();
TEST_ASSERT_EQUAL(true, imu->initialize());
BNO08xTestHelper::print_test_msg(TEST_TAG, "Success, deinitializing IMU.");
BNO08xTestHelper::destroy_test_imu();
BNO08xTestHelper::print_test_msg(TEST_TAG, "Initializing IMU attempt 2.");
BNO08xTestHelper::create_test_imu();
imu = BNO08xTestHelper::get_test_imu();
TEST_ASSERT_EQUAL(true, imu->initialize());
BNO08xTestHelper::print_test_msg(TEST_TAG, "Success, deinitializing IMU.");
BNO08xTestHelper::destroy_test_imu();
BNO08xTestHelper::print_test_end_banner(TEST_TAG);
}

View File

@ -1,13 +0,0 @@
#include "BNO08xTestHelper.hpp"
BNO08x* BNO08xTestHelper::test_imu = nullptr;
void BNO08xTestHelper::set_test_imu(BNO08x *imu)
{
test_imu = imu;
}
BNO08x* BNO08xTestHelper::get_test_imu()
{
return test_imu;
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "stdio.h"
#include "BNO08x.hpp"
class BNO08xTestHelper
{
public:
static void set_test_imu(BNO08x *imu);
static BNO08x* get_test_imu();
private:
static BNO08x *test_imu;
};

View File

@ -1,9 +0,0 @@
#include "BNO08xTestSuite.hpp"
void BNO08xTestSuite::run_tests()
{
BNO08x imu;
BNO08xTestHelper::set_test_imu(&imu);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "BNO08xTestHelper.hpp"
class BNO08xTestSuite
{
public:
static void run_tests();
};