/* app.c * * Copyright (C) 2024 wolfSSL Inc. * * This file is part of wolfBoot. * * wolfBoot is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfBoot is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ /** * @file app.c * @brief test update application for microchip targets, over SERCOM5 * verification. */ #include "config/default/definitions.h" #include #include #include #include #include "hal.h" #define HAVE_LIBWOLFBOOT 1 #define USART_BUFFER_SZ (16) static const char UPDATE_ERR = '!'; static const char UPDATE_START = '*'; static const char UPDATE_ACK = '#'; void APP_Initialize(void) { int i; uint32_t ver; uint8_t *v_array = (uint8_t *) & ver; unsigned char cmd; SERCOM5_USART_Enable(); #ifdef HAVE_LIBWOLFBOOT wolfBoot_success(); ver = wolfBoot_current_firmware_version(); #else #define WOLFBOOT_SECTOR_SIZE (0x2000) #define WOLFBOOT_PARTITION_SIZE (0x20000) #define WOLFBOOT_PARTITION_UPDATE_ADDRESS (0x088000) ver = 1U; #endif /* Send command to start the update */ cmd = UPDATE_START; SERCOM5_USART_Write(&cmd, 1); /* Send current version */ for (i = 3; i >= 0; i--) { SERCOM5_USART_Write(&v_array[i], 1); } /* Ready to receive the update now */ } static void ack(uint32_t _off) { uint8_t *off = (uint8_t *)(&_off); unsigned char cmd = UPDATE_ACK; SERCOM5_USART_Write(&cmd, 1); SERCOM5_USART_Write(off, 4); } static int check(uint8_t *pkt, int size) { int i; uint16_t c = 0; uint16_t c_rx = *((uint16_t *)(pkt + 2)); uint16_t *p = (uint16_t *)(pkt + 4); for (i = 0; i < ((size - 4) >> 1); i++) c += p[i]; if (c == c_rx) return 0; return -1; } static uint8_t rxbuf[USART_BUFFER_SZ]; #define PAGESIZE 256 static uint8_t page[PAGESIZE]; void APP_Tasks(void) { uint32_t r_total = 0; uint32_t tot_len = 0, tlen = 0; uint32_t next_seq = 0, recv_seq = 0; hal_flash_unlock(); while (1) { int r; r_total = 0; do { /* Serial update packages start with "0xA5 0x5A" * * Loop until synchronized */ while (r_total < 2) { r = SERCOM5_USART_Read(&rxbuf[r_total], 1); if (r == 1) r_total++; if ((r_total == 2) && ((rxbuf[0] != 0xA5) || rxbuf[1] != 0x5A)) { r_total = 0; continue; } } r = SERCOM5_USART_Read(&rxbuf[r_total], 1); if (r > 0) r_total += r; /* Break if tot_len is received from the host */ if ((tot_len == 0) && r_total == 2 + sizeof (uint32_t)) break; /* Break if data received is bigger than the total len */ if ((r_total > 8) && (tot_len <= ((r_total - 8) + next_seq))) break; } while (r_total < USART_BUFFER_SZ); /* Set total length based on the first packet received */ if (tot_len == 0) { tlen = rxbuf[2] + (rxbuf[3] << 8) + (rxbuf[4] << 16) + (rxbuf[5] << 24); if (tlen > WOLFBOOT_PARTITION_SIZE - 8) { /* Invalid total length: abort transfer + restart */ unsigned char cmd = UPDATE_ERR; SERCOM5_USART_Write(&cmd, 1); SERCOM5_USART_Write(&cmd, 1); SERCOM5_USART_Write(&cmd, 1); cmd = UPDATE_START; SERCOM5_USART_Write(&cmd, 1); recv_seq = 0; tot_len = 0; continue; } tot_len = tlen; /* (acknowledging '0' starts the actual transfer) */ ack(0); continue; } if (check(rxbuf, r_total) < 0) { ack(next_seq); continue; } recv_seq = rxbuf[4] + (rxbuf[5] << 8) + (rxbuf[6] << 16) + (rxbuf[7] << 24); if (recv_seq == next_seq) { int psize = r_total - 8; int page_idx = recv_seq % PAGESIZE; memcpy(&page[recv_seq % PAGESIZE], rxbuf + 8, psize); page_idx += psize; if ((page_idx == PAGESIZE) || (next_seq + psize >= tot_len)) { uint32_t dst = (WOLFBOOT_PARTITION_UPDATE_ADDRESS + recv_seq + psize) - page_idx; if ((dst % WOLFBOOT_SECTOR_SIZE) == 0) { hal_flash_erase(dst, WOLFBOOT_SECTOR_SIZE); } hal_flash_write(dst, page, PAGESIZE); memset(page, 0xFF, PAGESIZE); } next_seq += psize; } ack(next_seq); if (next_seq >= tot_len) { /* Update complete */ wolfBoot_update_trigger(); hal_flash_lock(); break; } } /* Wait for reboot */ while (1) ; }