diff --git a/flight/Bootloaders/OpenPilot/Makefile b/flight/Bootloaders/OpenPilot/Makefile index 264ae9d38..24d0309b8 100644 --- a/flight/Bootloaders/OpenPilot/Makefile +++ b/flight/Bootloaders/OpenPilot/Makefile @@ -51,7 +51,7 @@ USE_THUMB_MODE = YES # - BOARD just passed as define (optional) MCU = cortex-m3 CHIP = STM32F103RET -MODEL = HD_BL +MODEL = HD BOARD = STM3210E_OP # Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) @@ -83,7 +83,9 @@ DOXYGENDIR = .../Doc/Doxygen # use file-extension c for "c-only"-files ## OPENPILOT Bootloader: -SRC = $(OPBLSYSTEM)/openpilot_bl.c +SRC = $(OPBLSYSTEM)/openpilot_bl.c +SRC += $(OPBLSYSTEM)/bootloader.c +SRC += $(OPBLSYSTEM)/ymodem.c ## PIOS Hardware (STM32F10x) SRC += $(PIOSSTM32F10X)/pios_sys.c @@ -91,8 +93,8 @@ SRC += $(PIOSSTM32F10X)/pios_led.c SRC += $(PIOSSTM32F10X)/pios_usart.c SRC += $(PIOSSTM32F10X)/pios_delay.c SRC += $(PIOSSTM32F10X)/pios_irq.c -#SRC += $(PIOSSTM32F10X)/pios_usb.c -#SRC += $(PIOSSTM32F10X)/pios_usb_hid.c +SRC += $(PIOSSTM32F10X)/pios_usb.c +SRC += $(PIOSSTM32F10X)/pios_usb_hid.c ## PIOS Hardware (Common) SRC += $(PIOSCOMMON)/pios_com.c @@ -105,16 +107,18 @@ SRC += $(CMSISDIR)/system_stm32f10x.c ## Used parts of the STM-Library SRC += $(STMSPDSRCDIR)/stm32f10x_gpio.c SRC += $(STMSPDSRCDIR)/stm32f10x_rcc.c +SRC += $(STMSPDSRCDIR)/stm32f10x_wwdg.c SRC += $(STMSPDSRCDIR)/stm32f10x_tim.c +SRC += $(STMSPDSRCDIR)/stm32f10x_flash.c SRC += $(STMSPDSRCDIR)/stm32f10x_usart.c SRC += $(STMSPDSRCDIR)/misc.c ## STM32 USB Library -#SRC += $(STMUSBSRCDIR)/usb_core.c -#SRC += $(STMUSBSRCDIR)/usb_init.c -#SRC += $(STMUSBSRCDIR)/usb_int.c -#SRC += $(STMUSBSRCDIR)/usb_mem.c -3SRC += $(STMUSBSRCDIR)/usb_regs.c +SRC += $(STMUSBSRCDIR)/usb_core.c +SRC += $(STMUSBSRCDIR)/usb_init.c +SRC += $(STMUSBSRCDIR)/usb_int.c +SRC += $(STMUSBSRCDIR)/usb_mem.c +SRC += $(STMUSBSRCDIR)/usb_regs.c # List C source files here which must be compiled in ARM-Mode (no -mthumb). # use file-extension c for "c-only"-files diff --git a/flight/Bootloaders/OpenPilot/bootloader.c b/flight/Bootloaders/OpenPilot/bootloader.c new file mode 100644 index 000000000..a74712ffa --- /dev/null +++ b/flight/Bootloaders/OpenPilot/bootloader.c @@ -0,0 +1,205 @@ +/** + ****************************************************************************** + * + * @file bootloader.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Bootloader functions header + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program 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. + * + * This program 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Includes */ +#include "openpilot_bl.h" + +/* Local Functions */ +static void Serial_PutString(uint8_t *s); +static void FLASH_DisableWriteProtectionPages(void); +static void SerialDownload(void); + +/* Global Variables */ +extern uint32_t FlashDestination; +extern uint8_t file_name[FILE_NAME_LENGTH]; + +/* Local variables */ +uint32_t BlockNbr = 0, UserMemoryMask = 0; +bool FlashProtection = FALSE; +uint8_t tab_1024[1024] = { 0 }; + +/** + * Main bootloader function + */ +void StartBootloader(void) +{ + uint8_t key = 0; + + /* Get the number of block (4 or 2 pages) from where the user program will be loaded */ + BlockNbr = (FlashDestination - 0x08000000) >> 12; + + /* Compute the mask to test if the Flash memory, where the user program will be loaded, is write protected */ + if(BlockNbr < 62) { + UserMemoryMask = ((uint32_t) ~((1 << BlockNbr) - 1)); + } else { + UserMemoryMask = ((uint32_t) 0x80000000); + } + + /* Test if any page of Flash memory where program user will be loaded is write protected */ + if((FLASH_GetWriteProtectionOptionByte() & UserMemoryMask) != UserMemoryMask) { + FlashProtection = TRUE; + SerialPutString(" Download Image To the STM32F10x Internal Flash ------- 1\r\n"); + SerialPutString(" Execute The New Program ------------------------------ 2\r\n"); + SerialPutString(" Disable the write protection ------------------------- 3\r\n"); + } else { + FlashProtection = FALSE; + SerialPutString(" Download Image To the STM32F10x Internal Flash ------- 1\r\n"); + SerialPutString(" Execute The New Program ------------------------------ 2\r\n"); + } + + /* Loop through 1mS check for specified time */ + for(int32_t i = 0; i < OPBL_MAGIC_TIMEOUT; i++) { + uint16_t start = PIOS_DELAY_TIMER->CNT; + + /* Check for magic character for 1mS */ + while((volatile uint16_t)(PIOS_DELAY_TIMER->CNT - start) <= 1000) { + /* Check to see if there is anything on the receiving buffer */ + if(PIOS_COM_ReceiveBufferUsed(OPBL_COM_PORT) > 0) { + key = PIOS_COM_ReceiveBuffer(OPBL_COM_PORT); + if(key == 0x31) { + /* Download user application in the Flash */ + SerialDownload(); + return; + } else if ((key == 0x33) && (FlashProtection == TRUE)) { + /* Disable the write protection of desired pages */ + FLASH_DisableWriteProtectionPages(); + } + } + } + } + + return; +} + +/** + * Calculate the number of pages + * \param[in] Size The image size + * \return The number of pages + */ +uint32_t FLASH_PagesMask(__IO uint32_t Size) +{ + uint32_t pagenumber = 0x0; + uint32_t size = Size; + + if((size % PAGE_SIZE) != 0) { + pagenumber = (size / PAGE_SIZE) + 1; + } else { + pagenumber = size / PAGE_SIZE; + } + return pagenumber; + +} + +/** + * Print a string on the HyperTerminal + * \param[in] s The string to be printed + */ +static void Serial_PutString(uint8_t *s) +{ + while(*s != '\0') { + PIOS_COM_SendChar(OPBL_COM_PORT, *s); + s++; + } +} + +/** + * Disable the write protection of desired pages + */ +static void FLASH_DisableWriteProtectionPages(void) +{ + uint32_t useroptionbyte = 0, WRPR = 0; + uint16_t var1 = OB_IWDG_SW, var2 = OB_STOP_NoRST, var3 = OB_STDBY_NoRST; + FLASH_Status status = FLASH_BUSY; + + WRPR = FLASH_GetWriteProtectionOptionByte(); + + /* Test if user memory is write protected */ + if((WRPR & UserMemoryMask) != UserMemoryMask) { + useroptionbyte = FLASH_GetUserOptionByte(); + + UserMemoryMask |= WRPR; + + status = FLASH_EraseOptionBytes(); + + if(UserMemoryMask != 0xFFFFFFFF) { + status = FLASH_EnableWriteProtection( + (uint32_t) ~UserMemoryMask); + } + + /* Test if user Option Bytes are programmed */ + if((useroptionbyte & 0x07) != 0x07) { /* Restore user Option Bytes */ + if((useroptionbyte & 0x01) == 0x0) { + var1 = OB_IWDG_HW; + } + if((useroptionbyte & 0x02) == 0x0) { + var2 = OB_STOP_RST; + } + if((useroptionbyte & 0x04) == 0x0) { + var3 = OB_STDBY_RST; + } + + FLASH_UserOptionByteConfig(var1, var2, var3); + } + + if(status == FLASH_COMPLETE) { + SerialPutString("Write Protection disabled...\r\n"); + + SerialPutString("...and a System Reset will be generated to re-load the new option bytes\r\n"); + + /* Enable WWDG clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); + + /* Generate a system Reset to re-load the new option bytes: enable WWDG and set + counter value to 0x4F, as T6 bit is cleared this will generate a WWDG reset */ + WWDG_Enable(0x4F); + } else { + SerialPutString("Error: Flash write unprotection failed...\r\n"); + } + } else { + SerialPutString("Flash memory not write protected\r\n"); + } +} + +/** + * Download and program the binary file + */ +static void SerialDownload(void) +{ + int32_t Size = 0; + + SerialPutString("Waiting for the file to be sent ... (press 'a' to abort)\n\r"); + Size = Ymodem_Receive(&tab_1024[0]); + if(Size > 0) { + SerialPutString("\n\n\r Programming Completed Successfully!\n\r--------------------------------\r\n Name: "); + } else if(Size == -1) { + SerialPutString("\n\n\rThe image size is higher than the allowed space memory!\n\r"); + } else if(Size == -2) { + SerialPutString("\n\n\rVerification failed!\n\r"); + } else if(Size == -3) { + SerialPutString("\r\n\nAborted by user.\n\r"); + } else { + SerialPutString("\n\rFailed to receive the file!\n\r"); + } +} diff --git a/flight/Bootloaders/OpenPilot/inc/bootloader.h b/flight/Bootloaders/OpenPilot/inc/bootloader.h new file mode 100644 index 000000000..4fa620ef9 --- /dev/null +++ b/flight/Bootloaders/OpenPilot/inc/bootloader.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * + * @file bootloader.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Bootloader functions header + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program 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. + * + * This program 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BOOTLOADER_H +#define BOOTLOADER_H + +/* Global Types */ +typedef void (*pFunction)(void); + +/* Global Defines */ +#define CMD_STRING_SIZE 128 +#define ApplicationAddress 0x8008000 +#define PAGE_SIZE (0x800) +#define FLASH_SIZE (0x80000) /* 512K */ + +/* Global macros */ +#define SerialPutString(x) Serial_PutString((uint8_t*)(x)) + +/* Public Functions */ +extern void StartBootloader(void); +extern uint32_t FLASH_PagesMask(volatile uint32_t Size); + +#endif /* BOOTLOADER_H */ diff --git a/flight/Bootloaders/OpenPilot/inc/openpilot_bl.h b/flight/Bootloaders/OpenPilot/inc/openpilot_bl.h index 694b3e80a..a8fef5a00 100644 --- a/flight/Bootloaders/OpenPilot/inc/openpilot_bl.h +++ b/flight/Bootloaders/OpenPilot/inc/openpilot_bl.h @@ -27,8 +27,12 @@ #ifndef OPENPILOT_BL_H #define OPENPILOT_BL_H +#define OPBL_MAGIC_TIMEOUT 2000 +#define OPBL_COM_PORT COM_DEBUG_USART /* PIOS Includes */ #include +#include "bootloader.h" +#include "ymodem.h" #endif /* OPENPILOT_BL_H */ diff --git a/flight/Bootloaders/OpenPilot/inc/pios_board.h b/flight/Bootloaders/OpenPilot/inc/pios_board.h index 983084e89..98e5530b1 100644 --- a/flight/Bootloaders/OpenPilot/inc/pios_board.h +++ b/flight/Bootloaders/OpenPilot/inc/pios_board.h @@ -27,6 +27,7 @@ #ifndef PIOS_BOARD_H #define PIOS_BOARD_H + //------------------------ // PIOS_LED //------------------------ @@ -54,7 +55,7 @@ #define PIOS_USART1_IRQHANDLER_FUNC void USART2_IRQHandler(void) #define PIOS_USART1_CLK_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE) #define PIOS_USART1_NVIC_PRIO PIOS_IRQ_PRIO_HIGHEST -#define PIOS_USART1_BAUDRATE 57600 +#define PIOS_USART1_BAUDRATE 115200 //------------------------- // PIOS_USART2 (GPS) @@ -90,8 +91,8 @@ // PIOS_USART //------------------------- #define PIOS_USART_NUM 1 -#define PIOS_USART_RX_BUFFER_SIZE 1024 -#define PIOS_USART_TX_BUFFER_SIZE 256 +#define PIOS_USART_RX_BUFFER_SIZE 128 +#define PIOS_USART_TX_BUFFER_SIZE 128 #define PIOS_COM_DEBUG_PORT USART_1 //------------------------- @@ -101,10 +102,11 @@ #define PIOS_DELAY_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE) //------------------------- -// Master Clock +// System Settings //------------------------- #define PIOS_MASTER_CLOCK 72000000 #define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) +#define PIOS_NVIC_VECTTAB_FLASH ((uint32_t)0x08000000) //------------------------- // Interrupt Priorities diff --git a/flight/Bootloaders/OpenPilot/inc/pios_config.h b/flight/Bootloaders/OpenPilot/inc/pios_config.h index 965bb274a..0e0e9ddd7 100644 --- a/flight/Bootloaders/OpenPilot/inc/pios_config.h +++ b/flight/Bootloaders/OpenPilot/inc/pios_config.h @@ -41,8 +41,8 @@ #define PIOS_INCLUDE_SYS #define PIOS_INCLUDE_USART //#define PIOS_INCLUDE_USB_COM -//#define PIOS_INCLUDE_USB_HID -//#define PIOS_INCLUDE_USB +#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_USB //#define PIOS_INCLUDE_BMP085 #define PIOS_INCLUDE_COM //#define PIOS_INCLUDE_SDCARD diff --git a/flight/Bootloaders/OpenPilot/inc/ymodem.h b/flight/Bootloaders/OpenPilot/inc/ymodem.h new file mode 100644 index 000000000..fd0053036 --- /dev/null +++ b/flight/Bootloaders/OpenPilot/inc/ymodem.h @@ -0,0 +1,73 @@ +/** + ****************************************************************************** + * + * @file ymodem.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief YModem functions header + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program 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. + * + * This program 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef YMODEM_H +#define YMODEM_H + +/* Global Defines */ +#define PACKET_SEQNO_INDEX (1) +#define PACKET_SEQNO_COMP_INDEX (2) + +#define PACKET_HEADER (3) +#define PACKET_TRAILER (2) +#define PACKET_OVERHEAD (PACKET_HEADER + PACKET_TRAILER) +#define PACKET_SIZE (128) +#define PACKET_1K_SIZE (1024) + +#define FILE_NAME_LENGTH (256) +#define FILE_SIZE_LENGTH (16) + +#define SOH (0x01) /* start of 128-byte data packet */ +#define STX (0x02) /* start of 1024-byte data packet */ +#define EOT (0x04) /* end of transmission */ +#define ACK (0x06) /* acknowledge */ +#define NAK (0x15) /* negative acknowledge */ +#define CA (0x18) /* two of these in succession aborts transfer */ +#define CRC16 (0x43) /* 'C' == 0x43, request 16-bit CRC */ + +#define ABORT1 (0x41) /* 'A' == 0x41, abort by user */ +#define ABORT2 (0x61) /* 'a' == 0x61, abort by user */ + +#define NAK_TIMEOUT (0x100000) +#define MAX_ERRORS (5) + +/* Global Macros */ +#define IS_AF(c) ((c >= 'A') && (c <= 'F')) +#define IS_af(c) ((c >= 'a') && (c <= 'f')) +#define IS_09(c) ((c >= '0') && (c <= '9')) +#define ISVALIDHEX(c) IS_AF(c) || IS_af(c) || IS_09(c) +#define ISVALIDDEC(c) IS_09(c) +#define CONVERTDEC(c) (c - '0') + +#define CONVERTHEX_alpha(c) (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10)) +#define CONVERTHEX(c) (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c)) + +/* Global Variables */ +extern uint8_t tab_1024[1024]; + +/* Public Functions */ +extern int32_t Ymodem_Receive(uint8_t *buf); + +#endif /* YMODEM_H */ diff --git a/flight/Bootloaders/OpenPilot/openpilot_bl.c b/flight/Bootloaders/OpenPilot/openpilot_bl.c index 1face1d6d..e6458e8a6 100644 --- a/flight/Bootloaders/OpenPilot/openpilot_bl.c +++ b/flight/Bootloaders/OpenPilot/openpilot_bl.c @@ -28,6 +28,8 @@ #include "openpilot_bl.h" /* Global Variables */ +static pFunction Jump_To_Application; +static uint32_t JumpAddress; /* Local Variables */ @@ -41,19 +43,47 @@ int main() /* Brings up System using CMSIS functions, enables the LEDs. */ PIOS_SYS_Init(); - /* Delay system */ - PIOS_DELAY_Init(); + /* Only go into bootloader when the USB cable is connected */ + if(PIOS_USB_CableConnected()) { + /* Delay system */ + PIOS_DELAY_Init(); - /* Initialise LED's */ - PIOS_LED_Init(); + /* Initialise the USB system */ + PIOS_USB_Init(0); - /* Loop for ever */ + /* Initialise COM Ports */ + PIOS_COM_Init(); + + /* Initialise LED's */ + PIOS_LED_Init(); + PIOS_LED_Off(LED1); + PIOS_LED_Off(LED2); + + /* Flash unlock */ + FLASH_Unlock(); + + /* Execute the IAP driver in order to re-program the Flash */ + StartBootloader(); + } + + /* Test if user code is programmed starting from address "ApplicationAddress" */ + if(((*(volatile uint32_t*) ApplicationAddress) & 0x2FFE0000) == 0x20000000) { + /* Jump to user application */ + JumpAddress = *(volatile uint32_t*) (ApplicationAddress + 4); + Jump_To_Application = (pFunction) JumpAddress; + + /* Initialise user application's Stack Pointer */ + __set_MSP(*(volatile uint32_t*) ApplicationAddress); + Jump_To_Application(); + } + + /* Loop for ever if no application code is not programmed */ PIOS_LED_Off(LED1); PIOS_LED_Off(LED2); for(;;) { PIOS_LED_Toggle(LED1); PIOS_LED_Toggle(LED2); - PIOS_DELAY_WaitmS(200); + PIOS_DELAY_WaitmS(50); } return 0; diff --git a/flight/Bootloaders/OpenPilot/ymodem.c b/flight/Bootloaders/OpenPilot/ymodem.c new file mode 100644 index 000000000..a5680ef76 --- /dev/null +++ b/flight/Bootloaders/OpenPilot/ymodem.c @@ -0,0 +1,325 @@ +/** + ****************************************************************************** + * + * @file ymodem.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief YModem functions + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program 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. + * + * This program 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Includes */ +#include "openpilot_bl.h" + +/* Local functions */ +static int32_t Receive_Byte(uint8_t *c, uint32_t timeout); +static uint32_t Send_Byte(uint8_t c); +static int32_t Receive_Packet(uint8_t *data, int32_t *length, uint32_t timeout); +static uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum); + +/* Global variables */ +uint32_t FlashDestination = ApplicationAddress; /* Flash user program offset */ +uint8_t tab_1024[1024]; + +/* Local variables */ +static uint8_t file_name[FILE_NAME_LENGTH]; +static uint16_t PageSize = PAGE_SIZE; +static uint32_t EraseCounter = 0x0; +static uint32_t NbrOfPage = 0; +static FLASH_Status FLASHStatus = FLASH_COMPLETE; +static uint32_t RamSource; + + +/** + * Receive a file using the ymodem protocol + * \param[in] buf Address of the first byte + * \return The size of the file + */ +int32_t Ymodem_Receive(uint8_t *buf) +{ + uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr; + int32_t i, j, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0; + + /* Initialise FlashDestination variable */ + FlashDestination = ApplicationAddress; + + for(session_done = 0, errors = 0, session_begin = 0;;) { + for(packets_received = 0, file_done = 0, buf_ptr = buf;;) { + switch(Receive_Packet(packet_data, &packet_length, + NAK_TIMEOUT)) { + case 0: + errors = 0; + switch(packet_length) { + /* Abort by sender */ + case -1: + Send_Byte(ACK); + return 0; + /* End of transmission */ + case 0: + Send_Byte(ACK); + file_done = 1; + break; + /* Normal packet */ + default: + if((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)) { + Send_Byte(NAK); + } else { + if(packets_received == 0) {/* Filename packet */ + if(packet_data[PACKET_HEADER] != 0) {/* Filename packet has valid data */ + for(i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);) { + file_name[i++] = *file_ptr++; + } + file_name[i++] = '\0'; + for(i = 0, file_ptr++; (*file_ptr != ' ') & (i < FILE_SIZE_LENGTH);) { + file_size[i++] = *file_ptr++; + } + file_size[i++] = '\0'; + Str2Int(file_size, &size); + /* Test the size of the image to be sent */ + /* Image size is greater than Flash size */ + if(size > (FLASH_SIZE - 1)) { + /* End session */ + Send_Byte(CA); + Send_Byte(CA); + return -1; + } + /* Erase the needed pages where the user application will be loaded */ + /* Define the number of page to be erased */ + NbrOfPage = FLASH_PagesMask(size); + /* Erase the FLASH pages */ + for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++) { + FLASHStatus = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter)); + } + Send_Byte(ACK); + Send_Byte(CRC16); + } + /* Filename packet is empty, end session */ + else { + Send_Byte(ACK); + file_done = 1; + session_done = 1; + break; + } + } + /* Data packet */ + else { + memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length); + RamSource = (uint32_t) buf; + for(j = 0; (j < packet_length) && (FlashDestination < ApplicationAddress + size); j += 4) { + /* Program the data received into STM32F10x Flash */ + FLASH_ProgramWord(FlashDestination, *(uint32_t*) RamSource); + if(*(uint32_t*) FlashDestination != *(uint32_t*) RamSource) { + /* End session */ + Send_Byte(CA); + Send_Byte(CA); + return -2; + } + FlashDestination += 4; + RamSource += 4; + } + Send_Byte(ACK); + } + packets_received++; + session_begin = 1; + } + } + break; + case 1: + Send_Byte(CA); + Send_Byte(CA); + return -3; + default: + if(session_begin > 0) { + errors++; + } + if(errors > MAX_ERRORS) { + Send_Byte(CA); + Send_Byte(CA); + return 0; + } + Send_Byte(CRC16); + break; + } + if(file_done != 0) { + break; + } + } + if(session_done != 0) { + break; + } + } + return (int32_t) size; +} + +/** + * Receive byte from sender + * \param[in] c Character + * \param[in] timeout Timeout + * \return 0 Byte received + * \return -1 Timeout + */ +static int32_t Receive_Byte(uint8_t *c, uint32_t timeout) +{ + while(timeout-- > 0) { + if(PIOS_COM_ReceiveBufferUsed(OPBL_COM_PORT) > 0) { + *c = PIOS_COM_ReceiveBuffer(OPBL_COM_PORT); + return 0; + } + } + return -1; +} + +/** + * Send a byte + * \param[in] c Character + * \return 0 Byte sent + */ +static uint32_t Send_Byte(uint8_t c) +{ + PIOS_COM_SendChar(OPBL_COM_PORT, c); + return 0; +} + +/** + * Receive a packet from sender + * \param[in] data + * \param[in] length + * \param[in] timeout + * 0 end of transmission + * -1 abort by sender + * >0 packet length + * \return 0 normally return + * \return -1 timeout or packet error + * \return 1 abort by user + */ +static int32_t Receive_Packet(uint8_t *data, int32_t *length, uint32_t timeout) +{ + uint16_t i, packet_size; + uint8_t c; + *length = 0; + if(Receive_Byte(&c, timeout) != 0) { + return -1; + } + switch(c) { + case SOH: + packet_size = PACKET_SIZE; + break; + case STX: + packet_size = PACKET_1K_SIZE; + break; + case EOT: + return 0; + case CA: + if((Receive_Byte(&c, timeout) == 0) && (c == CA)) { + *length = -1; + return 0; + } else { + return -1; + } + case ABORT1: + case ABORT2: + return 1; + default: + return -1; + } + *data = c; + for(i = 1; i < (packet_size + PACKET_OVERHEAD); i++) { + if(Receive_Byte(data + i, timeout) != 0) { + return -1; + } + } + if(data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) + & 0xff)) { + return -1; + } + *length = packet_size; + return 0; +} + +/** + * Convert a string to an integer + * \param[in] inputstr The string to be converted + * \param[in] intnum The intger value + * \return 1 Correct + * \return 0 Error + */ +static uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum) +{ + uint32_t i = 0, res = 0; + uint32_t val = 0; + + if(inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X')) { + if(inputstr[2] == '\0') { + return 0; + } + for(i = 2; i < 11; i++) { + if(inputstr[i] == '\0') { + *intnum = val; + /* return 1; */ + res = 1; + break; + } + if(ISVALIDHEX(inputstr[i])) { + val = (val << 4) + CONVERTHEX(inputstr[i]); + } else { + /* return 0, Invalid input */ + res = 0; + break; + } + } + /* over 8 digit hex --invalid */ + if(i >= 11) { + res = 0; + } + } else /* max 10-digit decimal input */ + { + for(i = 0; i < 11; i++) { + if(inputstr[i] == '\0') { + *intnum = val; + /* return 1 */ + res = 1; + break; + } else if((inputstr[i] == 'k' || inputstr[i] == 'K') + && (i > 0)) { + val = val << 10; + *intnum = val; + res = 1; + break; + } else if((inputstr[i] == 'm' || inputstr[i] == 'M') + && (i > 0)) { + val = val << 20; + *intnum = val; + res = 1; + break; + } else if(ISVALIDDEC(inputstr[i])) { + val = val * 10 + CONVERTDEC(inputstr[i]); + } else { + /* return 0, Invalid input */ + res = 0; + break; + } + } + /* Over 10 digit decimal --invalid */ + if(i >= 11) { + res = 0; + } + } + + return res; +} +