|
@@ -1,382 +1,393 @@
|
|
|
-#include "at32f403a_407.h"
|
|
|
-#include "iap.h"
|
|
|
-#include "common_config.h"
|
|
|
-#include "FreeRTOS.h"
|
|
|
-#include "task.h"
|
|
|
-#include "semphr.h"
|
|
|
-#include "fr_timers.h"
|
|
|
-#include "event_groups.h"
|
|
|
-#include "mb.h"
|
|
|
-#include "mbport.h"
|
|
|
-#include "mbrtu.h"
|
|
|
-#include <stdio.h>
|
|
|
-#include <string.h>
|
|
|
-
|
|
|
-
|
|
|
-EventGroupHandle_t event;
|
|
|
-SemaphoreHandle_t buf_sem;
|
|
|
-SemaphoreHandle_t flash_sem;
|
|
|
-TimerHandle_t led_timer_handle;
|
|
|
-
|
|
|
-uint32_t fw_size; // Размер FW (передается в первом пакете)
|
|
|
-static uint16_t i_big_package;
|
|
|
-static uint16_t i_short_package;
|
|
|
-uint8_t fw_buf_1[FW_BUF_SIZE];
|
|
|
-uint8_t fw_buf_2[FW_BUF_SIZE];
|
|
|
-bool flash_err_flag = false;
|
|
|
-
|
|
|
-void led_timer(TimerHandle_t timer);
|
|
|
-void iap_task(void *params);
|
|
|
-
|
|
|
-
|
|
|
-//
|
|
|
-void iap_init(void)
|
|
|
-{
|
|
|
- flash_sem = xSemaphoreCreateBinary();
|
|
|
-
|
|
|
- led_timer_handle = xTimerCreate("led_timer", 500, pdTRUE, (void *)0, led_timer);
|
|
|
- xTimerStart(led_timer_handle, 0);
|
|
|
-
|
|
|
- xTaskCreate(iap_task, "iap_task", 4*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-void iap_task(void *params)
|
|
|
-{
|
|
|
- (void)(params);
|
|
|
- unsigned int ev;
|
|
|
-
|
|
|
- event = xEventGroupCreate();
|
|
|
- buf_sem = xSemaphoreCreateBinary();
|
|
|
- xSemaphoreGive(buf_sem);
|
|
|
-
|
|
|
- if (ev = xEventGroupWaitBits(event, IAP_START | IAP_RETURN, pdTRUE, pdFALSE, 60000) != IAP_START)
|
|
|
- {
|
|
|
- printf("IAP: switch to FW!\r\n");
|
|
|
- bpr_data_write(BPR_DATA1, 0);
|
|
|
- NVIC_SystemReset();
|
|
|
- }
|
|
|
-
|
|
|
- if (ev == IAP_RETURN)
|
|
|
- {
|
|
|
- printf("IAP: return to FW\r\n");
|
|
|
- bpr_data_write(BPR_DATA1, 0);
|
|
|
- vTaskDelay(200);
|
|
|
- NVIC_SystemReset();
|
|
|
- }
|
|
|
-
|
|
|
- for (;;)
|
|
|
- {
|
|
|
- ev = xEventGroupWaitBits(event,
|
|
|
- IAP_BLOCK | IAP_FINISH | IAP_RETURN |
|
|
|
- IAP_FLASH_ERROR | IAP_RESET,
|
|
|
- pdTRUE, pdFALSE, portMAX_DELAY);
|
|
|
-
|
|
|
- switch (ev)
|
|
|
- {
|
|
|
- case IAP_BLOCK :
|
|
|
-
|
|
|
- write_buf();
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- // Запись завершена. Нужно провести проверку CRC.
|
|
|
- case IAP_FINISH :
|
|
|
-
|
|
|
- flash_lock();
|
|
|
- DBG printf("IAP: finish\r\n");
|
|
|
- bpr_data_write(BPR_DATA1, 0);
|
|
|
- vTaskDelay(100);
|
|
|
- NVIC_SystemReset();
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- // Возврат в основное ПО
|
|
|
- case IAP_RETURN :
|
|
|
-
|
|
|
- DBG printf("IAP: return to FW\r\n");
|
|
|
- bpr_data_write(BPR_DATA1, 0);
|
|
|
- vTaskDelay(100);
|
|
|
- NVIC_SystemReset();
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- // Ошибка работы с flash
|
|
|
- case IAP_FLASH_ERROR :
|
|
|
-
|
|
|
- DBG printf("IAP: flash error");
|
|
|
- vTaskDelay(100);
|
|
|
- NVIC_SystemReset();
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- // Общая ошибка (что-то пошло не так)
|
|
|
- case IAP_RESET :
|
|
|
-
|
|
|
- DBG printf("IAP: common error");
|
|
|
- vTaskDelay(100);
|
|
|
- NVIC_SystemReset();
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- default : break;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// Обработчик приема первого пакета с ключом и размером
|
|
|
-mb_err_code_t iap_start(uint8_t *data, uint8_t len)
|
|
|
-{
|
|
|
- // Проверка контрольного слова
|
|
|
- if (data[0] != 0xEF || data[1] != 0xBE || data[2] != 0xAD || data[3] != 0xDE)
|
|
|
- return MB_BOOT_ERR_WRONG_CONTENT;
|
|
|
-
|
|
|
- swap((uint8_t*)&data[4], (uint8_t*)&fw_size, 4);
|
|
|
-
|
|
|
- DBG printf("FW size: %u\r\n", fw_size);
|
|
|
-
|
|
|
- erase_flash();
|
|
|
-
|
|
|
-/*
|
|
|
- // Проверка размера загружаемого файла
|
|
|
- if (fw_size != FW_SIZE)
|
|
|
- {
|
|
|
- DBG printf("ERR: wrong FW size! Size should be: %u\r\n", (uint32_t)FW_SIZE);
|
|
|
- xEventGroupSetBits(event, IAP_RETURN);
|
|
|
- return MB_BOOT_ERR_WRONG_FW_SIZE;
|
|
|
- }
|
|
|
-*/
|
|
|
- i_big_package = 0;
|
|
|
- i_short_package = 0;
|
|
|
-
|
|
|
- xEventGroupSetBits(event, IAP_START);
|
|
|
-
|
|
|
- return MB_BOOT_ERR_NO;
|
|
|
-}
|
|
|
-
|
|
|
-// Обработчик приема блока прошивки
|
|
|
-mb_err_code_t iap_block(uint8_t *data, uint8_t len)
|
|
|
-{
|
|
|
- uint16_t pack_num;
|
|
|
- static uint16_t pack_index = 0;
|
|
|
-
|
|
|
- // Проверка номера пакета
|
|
|
- swap(data, (uint8_t*)&pack_num, 2);
|
|
|
- if (pack_num != pack_index) {
|
|
|
- xEventGroupSetBits(event, IAP_RESET);
|
|
|
- return MB_BOOT_WRONG_PACK_INDEX;
|
|
|
- }
|
|
|
- pack_index++;
|
|
|
-
|
|
|
- memcpy(&fw_buf_1[BLOCK_SIZE*i_short_package++], &data[2], BLOCK_SIZE);
|
|
|
-
|
|
|
- // Когда буфер заполняется нужно писать во флеш
|
|
|
- if (i_short_package == (FLASH_PAGE_SIZE / BLOCK_SIZE))
|
|
|
- {
|
|
|
- i_short_package = 0;
|
|
|
- i_big_package++;
|
|
|
-
|
|
|
- if (i_big_package != 1)
|
|
|
- {
|
|
|
- memcpy(fw_buf_2, fw_buf_1, FLASH_PAGE_SIZE);
|
|
|
- xEventGroupSetBits(event, IAP_BLOCK);
|
|
|
- return MB_BOOT_ERR_NO;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Собрали данные для первой станицы. Нужно проверить ключ прошивки.
|
|
|
- if ((i_big_package == 1) && (i_short_package == 0))
|
|
|
- {
|
|
|
- memcpy(fw_buf_2, fw_buf_1, FLASH_PAGE_SIZE);
|
|
|
- xEventGroupSetBits(event, IAP_BLOCK);
|
|
|
- return MB_BOOT_ERR_NO;
|
|
|
-#if 0
|
|
|
- if (memcmp(&fw_buf_1[KEY_FW_SHIFT], HW_REW, strlen(HW_REW)))
|
|
|
- {
|
|
|
- DBG printf("ERR: wrong fw key! Should be: %s\r\n", HW_REW);
|
|
|
- xEventGroupSetBits(event, IAP_RETURN);
|
|
|
- return MB_BOOT_ERR_WRONG_KEY;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- memcpy(fw_buf_2, fw_buf_1, FLASH_PAGE_SIZE);
|
|
|
- xEventGroupSetBits(event, IAP_BLOCK);
|
|
|
- return MB_BOOT_ERR_NO;
|
|
|
- }
|
|
|
-#endif
|
|
|
- }
|
|
|
-
|
|
|
- xSemaphoreGive(flash_sem);
|
|
|
- return MB_BOOT_ERR_NO;
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-bool write_buf(void)
|
|
|
-{
|
|
|
- uint32_t *ptr = (uint32_t*)fw_buf_2;
|
|
|
- uint32_t addr = FW_BEGIN_ADDRESS + FLASH_PAGE_SIZE*(i_big_package - 1);
|
|
|
-
|
|
|
- // Когда принят и проверен первый блок данных (2кБт) нужно очистить память
|
|
|
- if (i_big_package == 1)
|
|
|
- {
|
|
|
-/*
|
|
|
- if (!erase_flash())
|
|
|
- {
|
|
|
- flash_err_flag = true; // ошибка flash
|
|
|
- xSemaphoreGive(flash_sem);
|
|
|
- return false;
|
|
|
- }
|
|
|
-*/
|
|
|
- }
|
|
|
-
|
|
|
- flash_unlock();
|
|
|
-
|
|
|
- for (uint32_t i = 0; i < 512; i++)
|
|
|
- {
|
|
|
- if (flash_word_program(addr, *ptr) != FLASH_OPERATE_DONE)
|
|
|
- {
|
|
|
- flash_lock();
|
|
|
- flash_err_flag = true; // ошибка flash
|
|
|
- }
|
|
|
- ptr++;
|
|
|
- addr += 4;
|
|
|
- }
|
|
|
-
|
|
|
-#if 0
|
|
|
- for (uint32_t i = 0; i < 256; i++)
|
|
|
- {
|
|
|
- if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, (uint64_t)*ptr) != HAL_OK)
|
|
|
- {
|
|
|
- HAL_FLASH_Lock();
|
|
|
- flash_err_flag = true; // ошибка flash
|
|
|
- }
|
|
|
- ptr++;
|
|
|
- addr += 8;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- xSemaphoreGive(flash_sem);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-// Нужно определить количество секторов для записи FW
|
|
|
-bool erase_flash(void)
|
|
|
-{
|
|
|
- uint32_t sector = FW_BEGIN_ADDRESS;
|
|
|
- int sector_number = fw_size/FLASH_PAGE_SIZE + 1;
|
|
|
-
|
|
|
- //DBG printf("Need to erase %u sectros\r\n", sector_number);
|
|
|
-
|
|
|
- flash_unlock();
|
|
|
-
|
|
|
- for (int i = 0; i < sector_number; i++)
|
|
|
- {
|
|
|
- if (flash_sector_erase(sector) != FLASH_OPERATE_DONE) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- //DBG printf("Sector %X erased\r\n", sector);
|
|
|
- sector += FLASH_PAGE_SIZE;
|
|
|
- }
|
|
|
-
|
|
|
- flash_lock();
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-mb_err_code_t check_crc(void)
|
|
|
-{
|
|
|
- uint32_t calc_crc;
|
|
|
- uint32_t read_crc;
|
|
|
-#if 0
|
|
|
- cortex_crc_init();
|
|
|
- read_crc = (*(uint32_t*)FW_CRC_ADDRESS);
|
|
|
- calc_crc = cortex_crc((uint8_t*)FW_BEGIN_ADDRESS, (FW_SIZE - 4));
|
|
|
-
|
|
|
- if (read_crc != calc_crc)
|
|
|
- return MB_BOOT_ERR_WRONG_FW_CRC;
|
|
|
-#endif
|
|
|
- return MB_BOOT_ERR_NO;
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-void iap_finish(void)
|
|
|
-{
|
|
|
- xEventGroupSetBits(event, IAP_BLOCK | IAP_FINISH);
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-void led_timer(TimerHandle_t timer)
|
|
|
-{
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-// 65 (0x41) Read Input Registers
|
|
|
-eMBErrorCode
|
|
|
-eMBUpdateCB( UCHAR * pucFrame, USHORT * usLen)
|
|
|
-{
|
|
|
- int res;
|
|
|
-
|
|
|
- switch (pucFrame[1])
|
|
|
- {
|
|
|
- case 1:
|
|
|
-
|
|
|
- pucFrame[1] = iap_start(&pucFrame[2], *usLen);
|
|
|
- *usLen = 2;
|
|
|
- return MB_ENOERR;
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 2:
|
|
|
-#if 1
|
|
|
- res = iap_block(&pucFrame[2], *usLen);
|
|
|
-
|
|
|
- xSemaphoreTake(flash_sem, 500);
|
|
|
-
|
|
|
- if (flash_err_flag) {
|
|
|
- pucFrame[1] = MB_BOOT_FLASH_ERR;
|
|
|
- xEventGroupSetBits(event, IAP_FLASH_ERROR);
|
|
|
- }
|
|
|
- else if (res == MB_BOOT_ERR_NO)
|
|
|
- pucFrame[1] = WRITE_BLOCK_COM;
|
|
|
- else if (res == MB_BOOT_ERR_WRONG_KEY)
|
|
|
- pucFrame[1] = MB_BOOT_ERR_WRONG_KEY;
|
|
|
- else if (res == MB_BOOT_WRONG_PACK_INDEX)
|
|
|
- pucFrame[1] = MB_BOOT_WRONG_PACK_INDEX;
|
|
|
-
|
|
|
- *usLen = 2;
|
|
|
-#endif
|
|
|
- return MB_ENOERR;
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 3:
|
|
|
-#if 1
|
|
|
- res = check_crc();
|
|
|
-
|
|
|
- if (res == MB_BOOT_ERR_WRONG_FW_CRC)
|
|
|
- pucFrame[1] = WRITE_BLOCK_COM;
|
|
|
- else
|
|
|
- iap_finish();
|
|
|
-
|
|
|
- *usLen = 2;
|
|
|
-#endif
|
|
|
- return MB_ENOERR;
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- return MB_EPORTERR;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-//
|
|
|
-void swap(uint8_t *in_buf, uint8_t *out_buf, uint8_t size)
|
|
|
-{
|
|
|
- for (uint8_t i = 0; i < size; i++)
|
|
|
- out_buf[size - i - 1] = in_buf[i];
|
|
|
-}
|
|
|
-
|
|
|
+#include "at32f403a_407.h"
|
|
|
+#include "iap.h"
|
|
|
+#include "common_config.h"
|
|
|
+#include "FreeRTOS.h"
|
|
|
+#include "task.h"
|
|
|
+#include "semphr.h"
|
|
|
+#include "fr_timers.h"
|
|
|
+#include "event_groups.h"
|
|
|
+#include "mb.h"
|
|
|
+#include "mbport.h"
|
|
|
+#include "mbrtu.h"
|
|
|
+#include "model_cfg.h"
|
|
|
+#include <stdio.h>
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
+
|
|
|
+EventGroupHandle_t event;
|
|
|
+SemaphoreHandle_t buf_sem;
|
|
|
+SemaphoreHandle_t flash_sem;
|
|
|
+TimerHandle_t led_timer_handle;
|
|
|
+TimerHandle_t iap_timeout_handle;
|
|
|
+
|
|
|
+uint32_t fw_size; // Размер FW (передается в первом пакете)
|
|
|
+static uint16_t i_big_package;
|
|
|
+static uint16_t i_short_package;
|
|
|
+uint8_t fw_buf_1[FW_BUF_SIZE];
|
|
|
+uint8_t fw_buf_2[FW_BUF_SIZE];
|
|
|
+bool flash_err_flag = false;
|
|
|
+
|
|
|
+void led_timer(TimerHandle_t timer);
|
|
|
+void iap_timeout(TimerHandle_t timer);
|
|
|
+void iap_task(void *params);
|
|
|
+
|
|
|
+
|
|
|
+//
|
|
|
+void iap_init(void)
|
|
|
+{
|
|
|
+ flash_sem = xSemaphoreCreateBinary();
|
|
|
+
|
|
|
+ led_timer_handle = xTimerCreate("led_timer", 500, pdTRUE, (void *)0, led_timer);
|
|
|
+ xTimerStart(led_timer_handle, 0);
|
|
|
+
|
|
|
+ iap_timeout_handle = xTimerCreate("iap_timer", 100000, pdTRUE, (void *)0, iap_timeout);
|
|
|
+
|
|
|
+ xTaskCreate(iap_task, "iap_task", 4*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+void iap_task(void *params)
|
|
|
+{
|
|
|
+ (void)(params);
|
|
|
+ unsigned int ev;
|
|
|
+
|
|
|
+ event = xEventGroupCreate();
|
|
|
+ buf_sem = xSemaphoreCreateBinary();
|
|
|
+ xSemaphoreGive(buf_sem);
|
|
|
+
|
|
|
+ if (ev = xEventGroupWaitBits(event, IAP_START | IAP_RETURN, pdTRUE, pdFALSE, 60000) != IAP_START)
|
|
|
+ {
|
|
|
+ printf("IAP: switch to FW!\r\n");
|
|
|
+ bpr_data_write(BPR_DATA1, 0);
|
|
|
+ NVIC_SystemReset();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ev == IAP_RETURN)
|
|
|
+ {
|
|
|
+ printf("IAP: return to FW\r\n");
|
|
|
+ bpr_data_write(BPR_DATA1, 0);
|
|
|
+ vTaskDelay(200);
|
|
|
+ NVIC_SystemReset();
|
|
|
+ }
|
|
|
+
|
|
|
+ for (;;)
|
|
|
+ {
|
|
|
+ ev = xEventGroupWaitBits(event,
|
|
|
+ IAP_BLOCK | IAP_FINISH | IAP_RETURN |
|
|
|
+ IAP_FLASH_ERROR | IAP_RESET,
|
|
|
+ pdTRUE, pdFALSE, portMAX_DELAY);
|
|
|
+
|
|
|
+ switch (ev)
|
|
|
+ {
|
|
|
+ case IAP_BLOCK :
|
|
|
+
|
|
|
+ write_buf();
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ // Запись завершена. Нужно провести проверку CRC.
|
|
|
+ case IAP_FINISH :
|
|
|
+
|
|
|
+ flash_lock();
|
|
|
+ DBG printf("IAP: finish\r\n");
|
|
|
+ bpr_data_write(BPR_DATA1, 0);
|
|
|
+ vTaskDelay(100);
|
|
|
+ NVIC_SystemReset();
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ // Возврат в основное ПО
|
|
|
+ case IAP_RETURN :
|
|
|
+
|
|
|
+ DBG printf("IAP: return to FW\r\n");
|
|
|
+ bpr_data_write(BPR_DATA1, 0);
|
|
|
+ vTaskDelay(100);
|
|
|
+ NVIC_SystemReset();
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ // Ошибка работы с flash
|
|
|
+ case IAP_FLASH_ERROR :
|
|
|
+
|
|
|
+ DBG printf("IAP: flash error");
|
|
|
+ vTaskDelay(100);
|
|
|
+ NVIC_SystemReset();
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ // Общая ошибка (что-то пошло не так)
|
|
|
+ case IAP_RESET :
|
|
|
+
|
|
|
+ DBG printf("IAP: common error");
|
|
|
+ vTaskDelay(100);
|
|
|
+ NVIC_SystemReset();
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ default : break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Обработчик приема первого пакета с ключом и размером
|
|
|
+mb_err_code_t iap_start(uint8_t *data, uint8_t len)
|
|
|
+{
|
|
|
+ char model[MODEL_LEN] = {0};
|
|
|
+ char new_model[MODEL_LEN] = {0};
|
|
|
+
|
|
|
+ // Проверка контрольного слова
|
|
|
+ if (data[0] != 0xEF || data[1] != 0xBE || data[2] != 0xAD || data[3] != 0xDE)
|
|
|
+ return MB_BOOT_ERR_WRONG_CONTENT;
|
|
|
+
|
|
|
+ // Проверка модели выполняется если флеш не пустая.
|
|
|
+ // Если флеш пуста, то можно залить прошивку от любой модели
|
|
|
+ memcpy(model, (void const*)MODEL_ADDR, MODEL_LEN);
|
|
|
+
|
|
|
+ if ((model[0] != 0xFF) && (model[1] != 0xFF) && (model[2] != 0xFF) && (model[3] != 0xFF))
|
|
|
+ {
|
|
|
+ memcpy(new_model, &data[8], MODEL_LEN);
|
|
|
+ printf("Current model: %s\r\n", model);
|
|
|
+ printf("New model: %s\r\n", new_model);
|
|
|
+ printf("Model size: %u\r\n", strlen(new_model));
|
|
|
+ if (memcmp(new_model, model, strlen(new_model)) != 0)
|
|
|
+ {
|
|
|
+ DBG printf("Model error!\r\n");
|
|
|
+ return MB_BOOT_ERR_WRONG_CONTENT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ swap((uint8_t*)&data[4], (uint8_t*)&fw_size, 4);
|
|
|
+
|
|
|
+ DBG printf("FW size: %u\r\n", fw_size);
|
|
|
+
|
|
|
+ erase_flash();
|
|
|
+
|
|
|
+ i_big_package = 0;
|
|
|
+ i_short_package = 0;
|
|
|
+
|
|
|
+ // Запуск таймера для отсчета timeout
|
|
|
+ xTimerStart(iap_timeout_handle, 0);
|
|
|
+
|
|
|
+ xEventGroupSetBits(event, IAP_START);
|
|
|
+
|
|
|
+ return MB_BOOT_ERR_NO;
|
|
|
+}
|
|
|
+
|
|
|
+// Обработчик приема блока прошивки
|
|
|
+mb_err_code_t iap_block(uint8_t *data, uint8_t len)
|
|
|
+{
|
|
|
+ uint16_t pack_num;
|
|
|
+ static uint16_t pack_index = 0;
|
|
|
+
|
|
|
+ // Проверка номера пакета
|
|
|
+ swap(data, (uint8_t*)&pack_num, 2);
|
|
|
+ if (pack_num != pack_index) {
|
|
|
+ xEventGroupSetBits(event, IAP_RESET);
|
|
|
+ return MB_BOOT_WRONG_PACK_INDEX;
|
|
|
+ }
|
|
|
+ pack_index++;
|
|
|
+
|
|
|
+ memcpy(&fw_buf_1[BLOCK_SIZE*i_short_package++], &data[2], len - 4);
|
|
|
+
|
|
|
+ // Когда буфер заполняется нужно писать во флеш.
|
|
|
+ // Файл может быть не кратен размеру блока!
|
|
|
+ if ((i_short_package == (FLASH_PAGE_SIZE / BLOCK_SIZE)) || (len != (BLOCK_SIZE + 4)))
|
|
|
+ {
|
|
|
+ i_short_package = 0;
|
|
|
+ i_big_package++;
|
|
|
+
|
|
|
+ if (i_big_package != 1)
|
|
|
+ {
|
|
|
+ memcpy(fw_buf_2, fw_buf_1, FLASH_PAGE_SIZE);
|
|
|
+ xEventGroupSetBits(event, IAP_BLOCK);
|
|
|
+ return MB_BOOT_ERR_NO;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Собрали данные для первой станицы. Нужно проверить ключ прошивки.
|
|
|
+ if ((i_big_package == 1) && (i_short_package == 0))
|
|
|
+ {
|
|
|
+ memcpy(fw_buf_2, fw_buf_1, FLASH_PAGE_SIZE);
|
|
|
+ xEventGroupSetBits(event, IAP_BLOCK);
|
|
|
+ return MB_BOOT_ERR_NO;
|
|
|
+ }
|
|
|
+
|
|
|
+ xSemaphoreGive(flash_sem);
|
|
|
+ return MB_BOOT_ERR_NO;
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+bool write_buf(void)
|
|
|
+{
|
|
|
+ uint32_t *ptr = (uint32_t*)fw_buf_2;
|
|
|
+ uint32_t addr = FW_BEGIN_ADDRESS + FLASH_PAGE_SIZE*(i_big_package - 1);
|
|
|
+
|
|
|
+ // Когда принят и проверен первый блок данных (2кБт) нужно очистить память
|
|
|
+ if (i_big_package == 1)
|
|
|
+ {
|
|
|
+/*
|
|
|
+ if (!erase_flash())
|
|
|
+ {
|
|
|
+ flash_err_flag = true; // ошибка flash
|
|
|
+ xSemaphoreGive(flash_sem);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+*/
|
|
|
+ }
|
|
|
+
|
|
|
+ flash_unlock();
|
|
|
+
|
|
|
+ for (uint32_t i = 0; i < 512; i++)
|
|
|
+ {
|
|
|
+ if (flash_word_program(addr, *ptr) != FLASH_OPERATE_DONE)
|
|
|
+ {
|
|
|
+ flash_lock();
|
|
|
+ flash_err_flag = true; // ошибка flash
|
|
|
+ }
|
|
|
+ ptr++;
|
|
|
+ addr += 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ xSemaphoreGive(flash_sem);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+// Нужно определить количество секторов для записи FW
|
|
|
+bool erase_flash(void)
|
|
|
+{
|
|
|
+ uint32_t sector = FW_BEGIN_ADDRESS;
|
|
|
+ int sector_number = fw_size/FLASH_PAGE_SIZE + 1;
|
|
|
+
|
|
|
+ //DBG printf("Need to erase %u sectros\r\n", sector_number);
|
|
|
+
|
|
|
+ flash_unlock();
|
|
|
+
|
|
|
+ for (int i = 0; i < sector_number; i++)
|
|
|
+ {
|
|
|
+ if (flash_sector_erase(sector) != FLASH_OPERATE_DONE) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //DBG printf("Sector %X erased\r\n", sector);
|
|
|
+ sector += FLASH_PAGE_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
+ flash_lock();
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+mb_err_code_t check_crc(void)
|
|
|
+{
|
|
|
+ uint32_t calc_crc;
|
|
|
+ uint32_t read_crc;
|
|
|
+
|
|
|
+
|
|
|
+ read_crc = *(uint32_t*)(FW_BEGIN_ADDRESS + fw_size - 4);
|
|
|
+ DBG printf("Read CRC: %X\r\n", read_crc);
|
|
|
+
|
|
|
+ crm_periph_clock_enable(CRM_CRC_PERIPH_CLOCK, TRUE);
|
|
|
+ crc_data_reset();
|
|
|
+
|
|
|
+ for (uint32_t* ptr = (uint32_t*)FW_BEGIN_ADDRESS; ptr != (uint32_t*)(FW_BEGIN_ADDRESS + fw_size - 4); ptr++)
|
|
|
+ crc_one_word_calculate(*ptr); // добавляем всю прошивку в CRC
|
|
|
+
|
|
|
+ calc_crc = crc_data_get();
|
|
|
+
|
|
|
+ DBG printf("Calc CRC: %X\r\n", calc_crc);
|
|
|
+
|
|
|
+ if (read_crc != calc_crc)
|
|
|
+ return MB_BOOT_ERR_WRONG_FW_CRC;
|
|
|
+
|
|
|
+ return MB_BOOT_ERR_NO;
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+void iap_finish(void)
|
|
|
+{
|
|
|
+ xEventGroupSetBits(event, IAP_BLOCK | IAP_FINISH);
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+void led_timer(TimerHandle_t timer)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+// 65 (0x41) Read Input Registers
|
|
|
+eMBErrorCode
|
|
|
+eMBUpdateCB( UCHAR * pucFrame, USHORT * usLen)
|
|
|
+{
|
|
|
+ int res;
|
|
|
+
|
|
|
+ switch (pucFrame[1])
|
|
|
+ {
|
|
|
+ case 1:
|
|
|
+
|
|
|
+ pucFrame[1] = iap_start(&pucFrame[2], *usLen);
|
|
|
+ *usLen = 2;
|
|
|
+ return MB_ENOERR;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+
|
|
|
+ res = iap_block(&pucFrame[2], *usLen);
|
|
|
+
|
|
|
+ xSemaphoreTake(flash_sem, 500);
|
|
|
+
|
|
|
+ if (flash_err_flag) {
|
|
|
+ pucFrame[1] = MB_BOOT_FLASH_ERR;
|
|
|
+ xEventGroupSetBits(event, IAP_FLASH_ERROR);
|
|
|
+ }
|
|
|
+ else if (res == MB_BOOT_ERR_NO)
|
|
|
+ pucFrame[1] = WRITE_BLOCK_COM;
|
|
|
+ else if (res == MB_BOOT_ERR_WRONG_KEY)
|
|
|
+ pucFrame[1] = MB_BOOT_ERR_WRONG_KEY;
|
|
|
+ else if (res == MB_BOOT_WRONG_PACK_INDEX)
|
|
|
+ pucFrame[1] = MB_BOOT_WRONG_PACK_INDEX;
|
|
|
+
|
|
|
+ *usLen = 2;
|
|
|
+
|
|
|
+ return MB_ENOERR;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+
|
|
|
+ res = check_crc();
|
|
|
+
|
|
|
+ if (res == MB_BOOT_ERR_WRONG_FW_CRC)
|
|
|
+ pucFrame[1] = WRITE_BLOCK_COM;
|
|
|
+ else
|
|
|
+ iap_finish();
|
|
|
+
|
|
|
+ *usLen = 2;
|
|
|
+
|
|
|
+ return MB_ENOERR;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return MB_EPORTERR;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//
|
|
|
+void swap(uint8_t *in_buf, uint8_t *out_buf, uint8_t size)
|
|
|
+{
|
|
|
+ for (uint8_t i = 0; i < size; i++)
|
|
|
+ out_buf[size - i - 1] = in_buf[i];
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+void iap_timeout(TimerHandle_t timer)
|
|
|
+{
|
|
|
+ DBG printf("IAP timeout callback\r\nReset...");
|
|
|
+ vTaskDelay(1000);
|
|
|
+ flash_lock();
|
|
|
+ NVIC_SystemReset();
|
|
|
+}
|