diff --git a/tests/native/.gitignore b/tests/native/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/tests/native/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/tests/native/.vscode/launch.json b/tests/native/.vscode/launch.json new file mode 100644 index 0000000..26fe127 --- /dev/null +++ b/tests/native/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ { + "name": "Debug CLS_Master_Test", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/CLS_Master_Unity", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + //"preLaunchTask": "build" // If you have a build task setup + }] +} \ No newline at end of file diff --git a/tests/native/CMakeLists.txt b/tests/native/CMakeLists.txt new file mode 100644 index 0000000..c10f31b --- /dev/null +++ b/tests/native/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.10) + +# set the project name +project(CLS_Master_Unity) + +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + +add_executable(${CMAKE_PROJECT_NAME}) +target_sources(${CMAKE_PROJECT_NAME} PUBLIC + tests.c + mock_os/mock_os.c + ../lib/Unity/src/unity.c +) + +target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC + ./ + ../lib/Unity/src +) + +include_directories(mock_os) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/nanopb/extra) +find_package(Nanopb REQUIRED) +include_directories(${NANOPB_INCLUDE_DIRS}) +nanopb_generate_cpp(PROTO_SRCS PROTO_HDRS RELPATH proto ../../proto/firmware.proto) +add_library(PROTOS ${PROTO_SRCS} ${PROTO_HDRS}) +target_include_directories(PROTOS PUBLIC ${NANOPB_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}) +include_directories(${PROJECT_BINARY_DIR}) + + + +add_subdirectory(../../Application/Tasks Tasks) + +target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tasks) \ No newline at end of file diff --git a/tests/native/mock_os/cmsis_os2.h b/tests/native/mock_os/cmsis_os2.h new file mode 100644 index 0000000..0434696 --- /dev/null +++ b/tests/native/mock_os/cmsis_os2.h @@ -0,0 +1,107 @@ +#include "stdint.h" + +#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value. + +/// Status code values returned by CMSIS-RTOS functions. +typedef enum { + osOK = 0, ///< Operation completed successfully. + osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits. + osErrorTimeout = -2, ///< Operation not completed within the timeout period. + osErrorResource = -3, ///< Resource not available. + osErrorParameter = -4, ///< Parameter error. + osErrorNoMemory = -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation. + osErrorISR = -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines. + osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. +} osStatus_t; + + +/// Priority values. +typedef enum { + osPriorityNone = 0, ///< No priority (not initialized). + osPriorityIdle = 1, ///< Reserved for Idle thread. + osPriorityLow = 8, ///< Priority: low + osPriorityLow1 = 8+1, ///< Priority: low + 1 + osPriorityLow2 = 8+2, ///< Priority: low + 2 + osPriorityLow3 = 8+3, ///< Priority: low + 3 + osPriorityLow4 = 8+4, ///< Priority: low + 4 + osPriorityLow5 = 8+5, ///< Priority: low + 5 + osPriorityLow6 = 8+6, ///< Priority: low + 6 + osPriorityLow7 = 8+7, ///< Priority: low + 7 + osPriorityBelowNormal = 16, ///< Priority: below normal + osPriorityBelowNormal1 = 16+1, ///< Priority: below normal + 1 + osPriorityBelowNormal2 = 16+2, ///< Priority: below normal + 2 + osPriorityBelowNormal3 = 16+3, ///< Priority: below normal + 3 + osPriorityBelowNormal4 = 16+4, ///< Priority: below normal + 4 + osPriorityBelowNormal5 = 16+5, ///< Priority: below normal + 5 + osPriorityBelowNormal6 = 16+6, ///< Priority: below normal + 6 + osPriorityBelowNormal7 = 16+7, ///< Priority: below normal + 7 + osPriorityNormal = 24, ///< Priority: normal + osPriorityNormal1 = 24+1, ///< Priority: normal + 1 + osPriorityNormal2 = 24+2, ///< Priority: normal + 2 + osPriorityNormal3 = 24+3, ///< Priority: normal + 3 + osPriorityNormal4 = 24+4, ///< Priority: normal + 4 + osPriorityNormal5 = 24+5, ///< Priority: normal + 5 + osPriorityNormal6 = 24+6, ///< Priority: normal + 6 + osPriorityNormal7 = 24+7, ///< Priority: normal + 7 + osPriorityAboveNormal = 32, ///< Priority: above normal + osPriorityAboveNormal1 = 32+1, ///< Priority: above normal + 1 + osPriorityAboveNormal2 = 32+2, ///< Priority: above normal + 2 + osPriorityAboveNormal3 = 32+3, ///< Priority: above normal + 3 + osPriorityAboveNormal4 = 32+4, ///< Priority: above normal + 4 + osPriorityAboveNormal5 = 32+5, ///< Priority: above normal + 5 + osPriorityAboveNormal6 = 32+6, ///< Priority: above normal + 6 + osPriorityAboveNormal7 = 32+7, ///< Priority: above normal + 7 + osPriorityHigh = 40, ///< Priority: high + osPriorityHigh1 = 40+1, ///< Priority: high + 1 + osPriorityHigh2 = 40+2, ///< Priority: high + 2 + osPriorityHigh3 = 40+3, ///< Priority: high + 3 + osPriorityHigh4 = 40+4, ///< Priority: high + 4 + osPriorityHigh5 = 40+5, ///< Priority: high + 5 + osPriorityHigh6 = 40+6, ///< Priority: high + 6 + osPriorityHigh7 = 40+7, ///< Priority: high + 7 + osPriorityRealtime = 48, ///< Priority: realtime + osPriorityRealtime1 = 48+1, ///< Priority: realtime + 1 + osPriorityRealtime2 = 48+2, ///< Priority: realtime + 2 + osPriorityRealtime3 = 48+3, ///< Priority: realtime + 3 + osPriorityRealtime4 = 48+4, ///< Priority: realtime + 4 + osPriorityRealtime5 = 48+5, ///< Priority: realtime + 5 + osPriorityRealtime6 = 48+6, ///< Priority: realtime + 6 + osPriorityRealtime7 = 48+7, ///< Priority: realtime + 7 + osPriorityISR = 56, ///< Reserved for ISR deferred thread. + osPriorityError = -1, ///< System cannot determine priority or illegal priority. + osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. +} osPriority_t; + +typedef struct { + const char *name; ///< name of the thread + uint32_t attr_bits; ///< attribute bits + void *cb_mem; ///< memory for control block + uint32_t cb_size; ///< size of provided memory for control block + void *stack_mem; ///< memory for stack + uint32_t stack_size; ///< size of stack + osPriority_t priority; ///< initial thread priority (default: osPriorityNormal) + uint32_t reserved; ///< reserved (must be 0) +} osThreadAttr_t; + + + +/// Attributes structure for message queue. +typedef struct { + const char *name; ///< name of the message queue + uint32_t attr_bits; ///< attribute bits + void *cb_mem; ///< memory for control block + uint32_t cb_size; ///< size of provided memory for control block + void *mq_mem; ///< memory for data storage + uint32_t mq_size; ///< size of provided memory for data storage +} osMessageQueueAttr_t; + + +typedef void (*osThreadFunc_t) (void *argument); +typedef void* osMessageQueueId_t; +typedef void* osThreadId_t; +void Error_Handler(); + +osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr); +osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout); +osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout); +osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) ; \ No newline at end of file diff --git a/tests/native/mock_os/mock_os.c b/tests/native/mock_os/mock_os.c new file mode 100644 index 0000000..6edf041 --- /dev/null +++ b/tests/native/mock_os/mock_os.c @@ -0,0 +1,63 @@ + +#include "cmsis_os2.h" +#include + +void Error_Handler() { + +} + +void MX_USB_DEVICE_Init() { + +} + +#define NUM_BUFFERS 10 +static uint32_t mockQueue[NUM_BUFFERS]; +static int mockQueueFront = 0; +static int mockQueueBack = 0; +static bool mockQueueEmpty = true; + +osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) +{ + return (osThreadId_t)1; +} + +osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) { + if (!mockQueueEmpty) + { + // Remove the message from the queue + *(uint32_t *)msg_ptr = mockQueue[mockQueueFront]; + mockQueueFront = (mockQueueFront + 1) % NUM_BUFFERS; + if (mockQueueFront == mockQueueBack) + { + mockQueueEmpty = true; + } + return osOK; + } + else + { + // The queue is empty + return osErrorResource; + } +} + +osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) { + if (mockQueueEmpty || mockQueueBack != mockQueueFront) + { + // Add the message to the queue + mockQueue[mockQueueBack] = *(uint32_t *)msg_ptr; + mockQueueBack = (mockQueueBack + 1) % NUM_BUFFERS; + mockQueueEmpty = false; + return osOK; + } + else + { + // The queue is full + return osErrorResource; + } +} + + +osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) { + return &mockQueue; +} + diff --git a/tests/native/mock_os/usb_device.h b/tests/native/mock_os/usb_device.h new file mode 100644 index 0000000..1376908 --- /dev/null +++ b/tests/native/mock_os/usb_device.h @@ -0,0 +1 @@ +void MX_USB_DEVICE_Init(); \ No newline at end of file diff --git a/tests/native/tests.c b/tests/native/tests.c new file mode 100644 index 0000000..af29ebf --- /dev/null +++ b/tests/native/tests.c @@ -0,0 +1,166 @@ +#include "unity.h" + +#include "UsbDataHandler.h" +#include "pb_encode.h" +#include "firmware.pb.h" + +void setUp() { + +} + + + +#define START_PACKAES 10 +#define START_SIZE 123456 +#define START_CRC 0xffff +#define START_DEVICE 0x04 +#define START_NAME "slave0x04.bin" + +#define PACK_COUTNER 3 +#define PACK_CRC 0xabcd +#define PACK_DEVICE 0x04 +#define PACK_DATA_SIZE 50 + +#define ACK_COUTNER 43 +#define ACK_CRC 0xabcdef +#define ACK_DEVICE 0x9 + +#define DONE_CRC 0xffffffff +#define DONE_DEVICE 0xf +#define DONE_SIZE 1024 * 65 + +uint16_t StartCounter = 0; +uint16_t PackageCounter = 0; +uint16_t AckCounter = 0; +uint16_t DoneCounter = 0; + + +void transmit_package(uint16_t id, const pb_msgdesc_t *fields , const void* msg){ + UsbDataPacket buffer = {0}; + buffer.head.type = id; + pb_ostream_t ostream = pb_ostream_from_buffer(buffer.data, sizeof(buffer.data)); + pb_encode(&ostream, fields, msg); + buffer.head.length= ostream.bytes_written; + + buffer.head.check = UsbDataPacket_head_sum(&buffer); + + UsbDataHandler_RxCallback((uint8_t*)(&buffer), buffer.head.length+sizeof(UsbDataPacketHead)); +} + +void test_UsbDataHandler(void) { + // Set up the module + UsbDataHandler_Start(); + + // Call the runner with no messages this should do nothing + UsbDataHandler_Runner(); + + FirmwareStart start ={ + .name=START_NAME, + .packages=START_PACKAES, + .size=START_SIZE, + .crc_fw=START_CRC, + .device_id=START_DEVICE, + }; + transmit_package(0xf01, FirmwareStart_fields, &start); + + // Call the runner with start message in the queue + UsbDataHandler_Runner(); + TEST_ASSERT_EQUAL(StartCounter,1); + + + //Put 2 packages in the buffer an parse them + transmit_package(0xf01, FirmwareStart_fields, &start); + transmit_package(0xf01, FirmwareStart_fields, &start); + UsbDataHandler_Runner(); + UsbDataHandler_Runner(); + TEST_ASSERT_EQUAL(StartCounter,3); + + + + FirmwarePackage pack = { + .counter =PACK_COUTNER , + .crc_pac = PACK_CRC, + .device_id= PACK_DEVICE, + .data={.size = PACK_DATA_SIZE, + .bytes={0} + }, + }; + transmit_package(0xf02, FirmwarePackage_fields, &pack); + UsbDataHandler_Runner(); + TEST_ASSERT_EQUAL(PackageCounter,1); + + FirmwarePackageAck ack = { + .ack =true, + .counter = ACK_COUTNER, + .crc_pac = ACK_CRC, + .device_id = ACK_DEVICE, + }; + transmit_package(0xf04, FirmwarePackageAck_fields, &ack); + UsbDataHandler_Runner(); + TEST_ASSERT_EQUAL(PackageCounter,1); + + + FirmwareDone done = { + .crc_fw = DONE_CRC, + .device_id = DONE_DEVICE, + .size = DONE_SIZE, + }; + + transmit_package(0xf03, FirmwareDone_fields, &done); + UsbDataHandler_Runner(); + TEST_ASSERT_EQUAL(DoneCounter,1); + +} + +void tearDown() { + +} + + +int main(void) { + UNITY_BEGIN(); + RUN_TEST(test_UsbDataHandler); + return UNITY_END(); +} + + +void DataClbk_FirmwareStart(void * msg, uint32_t length) { + FirmwareStart start; + memcpy(&start,msg,sizeof(start)); + TEST_ASSERT_EQUAL(START_SIZE, start.size); + TEST_ASSERT_EQUAL(START_PACKAES, start.packages); + TEST_ASSERT_EQUAL(START_CRC, start.crc_fw); + TEST_ASSERT_EQUAL(START_DEVICE, start.device_id); + TEST_ASSERT_EQUAL_STRING(START_NAME,start.name); + StartCounter++; +} +void DataClbk_FirmwarePackage(void * msg, uint32_t length) { + FirmwarePackage pack; + memcpy(&pack,msg,sizeof(pack)); + TEST_ASSERT_EQUAL(FirmwarePackage_size, length); + TEST_ASSERT_EQUAL(PACK_COUTNER, pack.counter); + TEST_ASSERT_EQUAL(PACK_CRC, pack.crc_pac); + TEST_ASSERT_EQUAL(PACK_DEVICE, pack.device_id); + TEST_ASSERT_EQUAL(PACK_DATA_SIZE, pack.data.size); + PackageCounter++; +} +void DataClbk_FirmwarePackageAck(void * msg, uint32_t length) { + FirmwarePackageAck ack; + memcpy(&ack,msg,sizeof(ack)); + TEST_ASSERT_EQUAL(FirmwarePackageAck_size, length); + TEST_ASSERT(ack.ack); + TEST_ASSERT_EQUAL(ACK_COUTNER, ack.counter); + TEST_ASSERT_EQUAL(ACK_CRC, ack.crc_pac); + TEST_ASSERT_EQUAL(ACK_DEVICE, ack.device_id); + + AckCounter++; +} +void DataClbk_FirmwareDone(void * msg, uint32_t length) { + FirmwareDone done; + memcpy(&done,msg,sizeof(done)); + TEST_ASSERT_EQUAL(FirmwareDone_size, length); + TEST_ASSERT_EQUAL(DONE_CRC,done.crc_fw); + TEST_ASSERT_EQUAL(DONE_DEVICE,done.device_id); + TEST_ASSERT_EQUAL(DONE_SIZE,done.size); + DoneCounter++; +} \ No newline at end of file