blob: 929ba77725ba91cea2458af1fb63157a9fda462f [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, 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 disclaimer below.
*
* 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
* Implement simple DBGU usage as stream receiver.
*/
/*-------------------------------
* Headers
*-------------------------------*/
//#include <board.h>
#include <stdio.h>
#include "dbg_util.h"
#include "timer.h"
#include "misc/console.h"
/*-------------------------------
* Defines
*-------------------------------*/
/** Data RX timeout in binary start up */
#define TIMEOUT_RX_START (1000*20)
/** Data RX timeout default value */
#define TIMEOUT_RX (200)
/* ASCII Character Codes */
#define SOH 0x01
#define STX 0x02
#define EOT 0x04
#define CTRL_D 0x04 /**< Transfer Done */
#define ACK 0x06
#define NAK 0x15
#define CAN 0x18 /**< Cancel transfer */
#define CTRL_X 0x24
/* 1K XMODEM Parameters */
#define SOH_LENGTH 128
#define STX_LENGTH 1024
#define SOH_TIMEOUT 1000
/*-------------------------------
* Local functions
*-------------------------------*/
/**
* \brief Compute the CRC
*/
static uint16_t
_GetCRC(uint8_t bByte, uint16_t wCrc)
{
int32_t cnt;
uint8_t newBit;
for (cnt = 7; cnt >= 0; cnt--) {
newBit = ((wCrc >> 15) & 0x1) ^ ((bByte >> cnt) & 0x1);
wCrc <<= 1;
if (newBit)
wCrc ^= (0x1021);
}
return wCrc;
}
/*-------------------------------
* Exported functions
*-------------------------------*/
/**
* \brief Receives byte with timeout.
* \param pByte pointer to locate received byte, can be NULL
* to discard data.
* \param timeOut timeout setting, in number of ticks.
*/
uint8_t
DbgReceiveByte(uint8_t * pByte, uint32_t timeOut)
{
uint32_t tick;
uint32_t delay;
tick = timer_get_tick();
while (1) {
if (console_is_rx_ready()) {
uint8_t tmp = console_get_char();
if (pByte)
*pByte = tmp;
return 1;
}
if (timeOut == 0) {
/* Never timeout */
} else {
delay = timer_get_interval(tick, timer_get_tick());
if (delay > timeOut) {
return 0;
}
}
}
}
/**
* \brief Receives raw binary file through DBGU.
* \param bStart 1 to start a new data stream.
* \param address receiving data address
* \param maxSize max receive data size in bytes
* \return number of received bytes
*/
uint32_t
DbgReceiveBinary(uint8_t bStart, uint32_t address, uint32_t maxSize)
{
volatile uint32_t tick0;
uint32_t delay;
uint8_t *pBuffer = (uint8_t *) address;
uint8_t xSign = 0;
uint32_t rxCnt = 0;
if (maxSize == 0)
return 0;
if (bStart) {
printf("\n\r-- Please start binary data in %d seconds:\n\r",
TIMEOUT_RX_START / 1000);
tick0 = timer_get_tick();
while (1) {
if (console_is_rx_ready()) {
pBuffer[rxCnt++] = console_get_char();
console_put_char(' ');
break;
} else {
delay = timer_get_interval(tick0, timer_get_tick());
if ((delay % 1000) == 0) {
if (xSign == 0) {
console_put_char('*');
xSign = 1;
}
} else if (xSign) {
xSign = 0;
}
if (delay > TIMEOUT_RX_START) {
printf("\n\rRX timeout!\n\r");
return rxCnt;
}
}
}
}
/* Get data */
while (1) {
tick0 = timer_get_tick();
while (1) {
if (console_is_rx_ready()) {
pBuffer[rxCnt++] = console_get_char();
if ((rxCnt % (10 * 1024)) == 0) {
console_put_char('.');
}
if (rxCnt >= maxSize) {
/* Wait until file transfer finished */
return rxCnt;
}
break;
}
delay = timer_get_interval(tick0, timer_get_tick());
if (delay > TIMEOUT_RX) {
return rxCnt;
}
}
}
}
/**
* \brief Receives raw binary file through DBGU.
*
* \note When "CCC..", uses Ctrl + D to exit.
*
* \param pktBuffer 1K size packet buffer
* \param address receiving data address
* \param maxSize max receive data size in bytes
* \return number of received bytes
*/
uint32_t
DbgReceive1KXModem(uint8_t * pktBuffer, uint32_t address, uint32_t maxSize)
{
uint8_t inChar;
uint32_t i, index = 0, pktLen = 0;
uint8_t pktNum = 0, prevPktNum = 0;
uint32_t error = 0;
uint16_t inCrc, myCrc;
uint8_t inCheckSum = 0xFF, checkSum = 0;
uint8_t *pBuffer = (uint8_t *) address;
uint32_t totalLen = 0;
console_put_char('C');
while (1) {
if (!DbgReceiveByte(&inChar, SOH_TIMEOUT)) {
console_put_char('C');
continue;
}
/* Done */
if (EOT == inChar) {
error = 0;
console_put_char(ACK);
break;
} else if (CAN == inChar) {
error = 2;
} else if (CTRL_X == inChar) {
error = 3;
} else if (SOH == inChar) {
pktLen = SOH_LENGTH;
} else if (STX == inChar) {
pktLen = STX_LENGTH;
} else
continue;
/* Get Packet Number */
if (!DbgReceiveByte(&pktNum, SOH_TIMEOUT))
error = 4;
/* Get 1's complement of packet number */
if (!DbgReceiveByte(&inChar, SOH_TIMEOUT))
error = 5;
/* Get 1 packet of information. */
checkSum = 0;
myCrc = 0;
index = 0;
for (i = 0; i < pktLen; i++) {
if (!DbgReceiveByte(&inChar, SOH_TIMEOUT))
error = 6;
checkSum += inChar;
myCrc = _GetCRC(inChar, myCrc);
if (pktNum != prevPktNum) {
pktBuffer[index++] = inChar;
}
}
/* Get CRC bytes */
if (!DbgReceiveByte(&inCheckSum, SOH_TIMEOUT))
error = 7;
inCrc = inCheckSum << 8;
if (!DbgReceiveByte(&inCheckSum, SOH_TIMEOUT))
error = 7;
inCrc += inCheckSum;
/* If CRC error, NAK */
if (error || (inCrc != myCrc)) {
console_put_char(NAK);
error = 0;
}
/* Save packet, ACK and next */
else {
prevPktNum = pktNum;
/* Buffer full? */
if (totalLen + pktLen > maxSize) {
/* Copy until buffer full? */
/* Stop transfer */
console_put_char(CAN);
return totalLen;
}
/* Copy the packet */
for (i = 0; i < pktLen; i++) {
pBuffer[totalLen + i] = pktBuffer[i];
}
totalLen += pktLen;
console_put_char(ACK);
}
}
return totalLen;
}