1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-10 18:24:11 +01:00
LibrePilot/flight/Bootloaders/OpenPilot/ymodem.c

325 lines
8.6 KiB
C
Raw Normal View History

/**
******************************************************************************
*
* @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 */
/* 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;
}