diff --git a/Application/Tasks/CMakeLists.txt b/Application/Tasks/CMakeLists.txt index 12c644d..3c55720 100644 --- a/Application/Tasks/CMakeLists.txt +++ b/Application/Tasks/CMakeLists.txt @@ -9,10 +9,12 @@ target_sources(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/UsbDataHandler.c ${CMAKE_CURRENT_LIST_DIR}/CanDataTask.c ${CMAKE_CURRENT_LIST_DIR}/FirmwareHandler.c + ${CMAKE_CURRENT_LIST_DIR}/FirmwareUpdate.c INTERFACE ${CMAKE_CURRENT_LIST_DIR}/UsbDataHandler.h ${CMAKE_CURRENT_LIST_DIR}/CanDataTask.h - + ${CMAKE_CURRENT_LIST_DIR}/FirmwareUpdate.h + ) target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/Application/Tasks/FirmwareHandler.c b/Application/Tasks/FirmwareHandler.c index b4e97f3..8bba0d7 100644 --- a/Application/Tasks/FirmwareHandler.c +++ b/Application/Tasks/FirmwareHandler.c @@ -6,6 +6,7 @@ #include #include "UsbDataHandler.h" #include "crc.h" +#include "FirmwareUpdate.h" // static memory only for decoding messages static FirmwareStart msg_FirmwareStart; @@ -123,14 +124,10 @@ void DataClbk_FirmwareDone(void *msg, uint32_t length) { fresult_open = 0xFF; FileOpen=false; + FirmwareUpdateArgs args; + args.device = msg_FirmwareDone.device_id; + memcpy(args.name, msg_FirmwareStart.name, sizeof(args.name)); - // Spawn Task to Send this File over CAN - // this task should - // 1. send can message to send device with matching device id into bootloader mode - // - open the fw file on the SD card. - // 2. wait for the device to get ready. - // - send data 4x data - // - wait for ack - // 3 onec we are at the EOF - // - send done + FirmwareUpdateTask_start(args); + } \ No newline at end of file diff --git a/Application/Tasks/FirmwareUpdate.c b/Application/Tasks/FirmwareUpdate.c new file mode 100644 index 0000000..becef4b --- /dev/null +++ b/Application/Tasks/FirmwareUpdate.c @@ -0,0 +1,169 @@ +#include "CanDataHandler.h" +#include "cmsis_os2.h" +#include "FreeRTOS.h" +#include "CLSAddress.h" +#include "fatfs.h" +#include "FirmwareUpdate.h" + +// Memory for the task +StaticTask_t CLS_FW_Task_cb; +uint32_t CLS_FW_Task_stk[512]; +// Attributes for the task +osThreadId_t CLS_FW_Task_id; +const osThreadAttr_t CLS_FW_Task_attr = { + .name = "CLS_FW_Task", + .attr_bits = 0U, + .cb_mem = &CLS_FW_Task_cb, + .cb_size = sizeof(CLS_FW_Task_cb), + .stack_mem = CLS_FW_Task_stk, + .stack_size = sizeof(CLS_FW_Task_stk), + .priority = osPriorityNormal, + .reserved = 0U +}; + +osMutexId_t CLS_FW_Task_FileLock = NULL; +static FirmwareUpdateArgs configuration = {0}; +static FIL fw_file; +static FwFrame frame = {0}; + + + +// wait_for_start_callback to get notified when the slave is ready +void wait_for_start_callback(uint16_t canid, uint8_t * data, uint8_t size) { + osThreadFlagsSet(CLS_FW_Task_id, TASK_FLAG_WAIT); +} + +void wait_for_start() { + + // setup wait_for_start_callback to get notified when the slave is ready + uint16_t ready_canid = GENERATE_CLS_ADDRESS(CLS_CODE_FIMWARE, configuration.device, CLS_CH_FW_MISO); + // wait_for_start_callback // MessageCode::Firmware(FirmwareChannel::SlaveOutMasterIn); + CanData_regEventMsg(ready_canid, wait_for_start_callback); + + // setup the command to send the slave into booloader mode + uint16_t target_canid = GENERATE_CLS_ADDRESS(CLS_CODE_FIMWARE, configuration.device, CLS_CH_FW_BOOTCALL); + uint8_t bootloader_call[8] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab}; + + + // wait for the slave to be ready to update: + uint32_t counter = 0; + do { + // send bootloader command + CLS_BSP_TxHeaderType header = CREATE_BSP_CAN_HEADER(target_canid,CLS_BSP_DLC_BYTES_8); + CLS_BSP_CAN_AddMessageToSend(&header,bootloader_call); + counter++; + + // after some time abort if we dont get a connection + if(counter > BOOTLOADER_CALL_MAX_TRIES) { + // TODO: Logging + CanData_removeEvent(ready_canid); + f_close(&fw_file); + osThreadExit(); + } + + // wait for the slave + } while(osThreadFlagsWait(TASK_FLAG_WAIT,osFlagsWaitAny,BOOTLOADER_CALL_RETRY_TIME) == (uint32_t)osErrorTimeout); + + //remove the wait_for_start_callback again + CanData_removeEvent(ready_canid); + + // reset the fw_file + f_lseek(&fw_file,0); + frame.counter = 0; +} + + + +void running_callback_error(uint16_t canid, uint8_t * data, uint8_t size) { + osMutexAcquire(CLS_FW_Task_FileLock, osWaitForever); + f_lseek(&fw_file,0); + frame.counter = 0; + osMutexRelease(CLS_FW_Task_FileLock); + osThreadFlagsSet(CLS_FW_Task_id, TASK_FLAG_RUNNING); +} + +void running_callback_ack(uint16_t canid, uint8_t * data, uint8_t size) { + osThreadFlagsSet(CLS_FW_Task_id, TASK_FLAG_RUNNING); +} + + +void running() { + uint16_t error_canid = GENERATE_CLS_ADDRESS(CLS_CODE_FIMWARE, configuration.device, CLS_CH_FW_MISO); + uint16_t ack_canid = GENERATE_CLS_ADDRESS(CLS_CODE_FIMWARE, configuration.device, CLS_CH_FW_SLAVE_FEEDBACK); + uint16_t target_canid = GENERATE_CLS_ADDRESS(CLS_CODE_FIMWARE, configuration.device, CLS_CH_FW_MOSI); + CLS_BSP_TxHeaderType header = CREATE_BSP_CAN_HEADER(target_canid,CLS_BSP_DLC_BYTES_8); + + CanData_regEventMsg(error_canid,running_callback_error); + CanData_regEventMsg(ack_canid, running_callback_ack); + + unsigned int read_bytes = 0; + + while (true) + { + + // read fw file and and send data + osMutexAcquire(CLS_FW_Task_FileLock, osWaitForever); + f_read(&fw_file, &frame.data, sizeof(frame.data), &read_bytes); + CLS_BSP_CAN_AddMessageToSend(&header, (uint8_t*)&frame); + frame.counter++; + osMutexRelease(CLS_FW_Task_FileLock); + + // transport window response + if(frame.counter % UPDATE_ACK_WINDOW == 0) { + osThreadFlagsWait(TASK_FLAG_RUNNING, osFlagsWaitAny, osWaitForever); + } + + // end of file + if(read_bytes != sizeof(frame.data)) { + break; + } + + } + + + uint64_t done = UPDATE_DONE_MSG; + CLS_BSP_CAN_AddMessageToSend(&header,(uint8_t*)&done); + + CanData_removeEvent(error_canid); + CanData_removeEvent(ack_canid); +} + + + + +void CLSFirmwareUpdateTask_func(void *argument); + +void FirmwareUpdateTask_start(FirmwareUpdateArgs args) { + // Task functionality here + if(CLS_FW_Task_FileLock == NULL) { + CLS_FW_Task_FileLock = osMutexNew(NULL); + } + + if(CLS_FW_Task_FileLock == NULL) { + // error cant create mutex + return; + } + + // check CLS_FW_Task_id is null or stopped + // only one Task can runn at once + if(CLS_FW_Task_id == NULL || osThreadGetState(CLS_FW_Task_id) == osThreadTerminated) { + configuration = args; + CLS_FW_Task_id = osThreadNew(CLSFirmwareUpdateTask_func, NULL, &CLS_FW_Task_attr); + } +} + + +void CLSFirmwareUpdateTask_func(void *argument) { + char * filename = configuration.name; + if( f_open(&fw_file, filename, FA_READ) != FR_OK) { + // TODO: Logging + osThreadExit(); + } + + wait_for_start(); + + running(); + + f_close(&fw_file); + osThreadExit(); +} \ No newline at end of file diff --git a/Application/Tasks/FirmwareUpdate.h b/Application/Tasks/FirmwareUpdate.h new file mode 100644 index 0000000..51e819f --- /dev/null +++ b/Application/Tasks/FirmwareUpdate.h @@ -0,0 +1,27 @@ +#pragma once + +#include "stdint.h" + +#define BOOTLOADER_CALL_RETRY_TIME 1000 +#define BOOTLOADER_CALL_MAX_TRIES 10 + +#define TASK_FLAG_WAIT 1 +#define TASK_FLAG_RUNNING 2 + +#define UPDATE_ACK_WINDOW 4 +#define UPDATE_DONE_MSG 0xFFFFD04EFFFFD04E + + +typedef struct { + char name[32]; + uint8_t device; +} FirmwareUpdateArgs; + + +typedef struct { + uint32_t counter; + uint8_t data[4]; +} FwFrame; + + +void FirmwareUpdateTask_start(FirmwareUpdateArgs args); \ No newline at end of file