blob: e93176769fe07852233881e24c725c9307edd5b4 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2010, Atmel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaiimer below.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the disclaimer below in the documentation and/or
* other materials provided with the distribution.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of XMODEM transfer protocols
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <board.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/** The definitions are followed by the X/Ymodem protocol */
#define XMDM_SOH 0x01 /**< Start of heading */
#define XMDM_EOT 0x04 /**< End of text */
#define XMDM_ACK 0x06 /**< Acknowledge */
#define XMDM_NAK 0x15 /**< negative acknowledge */
#define XMDM_CAN 0x18 /**< Cancel */
#define XMDM_ESC 0x1b /**< Escape */
#define CRC16POLY 0x1021 /**< CRC 16 polynom */
#define PKTLEN_128 128 /**< Packet length */
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
/** Xmodem transfer error indicator */
int8_t cRrror;
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/**
* \brief Transmit the character through xmodem protocol.
*
* \param ucChar Character to be transmitted.
*/
static void XMODEM_PutChar(uint8_t ucChar)
{
UART_PutChar(ucChar);
}
/**
* \brief Get the character through xmodem protocol.
*
* \return The character received
*/
static uint8_t XMODEM_GetChar(void)
{
return (uint8_t)UART_GetChar();
}
/**
* \brief Get calculated crc value for xmodem transfer
*
* \param ucChar The CRC original character.
* \param uwCrc Calculated CRC value.
* \return Calculated CRC value.
*/
static uint16_t XMODEM_GetCrc(int8_t ucChar, uint16_t uwCrc)
{
uint16_t uwCmpt;
uwCrc = uwCrc ^ (int32_t) ucChar << 8;
for (uwCmpt= 0; uwCmpt < 8; uwCmpt++)
{
if (uwCrc & 0x8000)
uwCrc = uwCrc << 1 ^ CRC16POLY;
else
uwCrc = uwCrc << 1;
}
return (uwCrc & 0xFFFF);
}
/**
* \brief Get bytes through xmodem protocol.
*
* \param pData Pointer to the data buffer.
* \param dwLength Length of data expected.
* \return Bytes received
*/
static uint16_t XMODEM_Getbytes(int8_t *pData, uint32_t dwLength)
{
uint16_t uwCrc = 0;
uint32_t dwCpt;
int8_t cChar;
for (dwCpt = 0; dwCpt < dwLength; ++dwCpt)
{
cChar = XMODEM_GetChar();
if (cRrror)
return 1;
uwCrc = XMODEM_GetCrc(cChar,uwCrc);
*pData++ = cChar;
}
return uwCrc;
}
/**
* \brief Get a packet through xmodem protocol
*
* \param pData Pointer to the data buffer.
* \param ucSno Sequnce number.
* \return 0 for sucess and other value for xmodem error
*/
static int32_t XMODEM_GetPacket(int8_t *pData, uint8_t ucSno)
{
uint8_t cpSeq[2];
uint16_t uwCrc, uwXcrc;
XMODEM_Getbytes((int8_t *)cpSeq, 2);
uwXcrc = XMODEM_Getbytes(pData,PKTLEN_128);
if(cRrror)
return (-1);
/* An "endian independent way to combine the CRC bytes. */
uwCrc = (unsigned short)XMODEM_GetChar() << 8;
uwCrc += (unsigned short)XMODEM_GetChar();
if(cRrror == 1)
return (-1);
if ((uwCrc != uwXcrc) || (cpSeq[0] != ucSno) || (cpSeq[1] != (uint8_t) ((~(uint32_t)ucSno)&0xff)))
{
XMODEM_PutChar(XMDM_CAN);
return(-1);
}
return(0);
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Receive the files through xmodem protocol
*
* \param pBuffer Pointer to received buffers
* \return 0 for sucess and other value for xmodem error
*/
extern uint32_t XMODEM_ReceiveFile(int8_t *pBuffer)
{
int32_t wTimeout;
int8_t cChar;
int32_t wDone;
uint8_t ucSno = 0x01;
uint32_t dwWavSize = 0;
/* Wait and put 'C' till start xmodem transfer */
while(1)
{
XMODEM_PutChar('C');
wTimeout = (BOARD_MCK/10);
while(!(UART_IsRxReady())&&wTimeout)
wTimeout--;
if (UART_IsRxReady())
break;
}
/* Begin to receive the data */
cRrror = 0;
wDone = 0;
while(wDone == 0)
{
cChar = (int8_t)XMODEM_GetChar();
if(cRrror)
return 0;
switch(cChar)
{
/* Start of transfer */
case XMDM_SOH:
wDone = XMODEM_GetPacket(pBuffer+dwWavSize, ucSno);
if(cRrror)
return 0;
if (wDone == 0)
{
ucSno++;
dwWavSize += PKTLEN_128;
}
XMODEM_PutChar(XMDM_ACK);
break;
/* End of transfer */
case XMDM_EOT:
XMODEM_PutChar(XMDM_ACK);
wDone = dwWavSize;
break;
case XMDM_CAN:
case XMDM_ESC:
default:
wDone = -1;
break;
}
}
return dwWavSize;
}