📄 xmodem.c
字号:
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : xmodem.c
//* Object : xmodem receive utility with PDC
//*
//* 1.0 14/11/00 JPP : Creation
//* without PDC 256K AT->PC PC->RAM
//* 38400 1'26 s 1'52
//* 115200 0'56 s 1'
//*----------------------------------------------------------------------------
//* ------------------------------ include file -------------------------------
#include "xmodem.h"
#include "drivers/com/com.h" //* Communication driver
//* --------------------------- Constant definition ---------------------------
#define WAIT_1S 100000
#define WAIT_2S (WAIT_1S*2)
#define WAIT_3S (WAIT_1S*3)
//* ---------------------------- extern function ----------------------------
//* --------------------------- extern global data --------------------------
extern ComDesc *Xmodem_COM;
//* ----------------------------- Local variable -----------------------------
static int wait_time;
static volatile u_char buffer_status;
static volatile u_char recv_error;
static volatile u_char timed_out;
static u_char packet_number;
static volatile u_char eot_flag;
static u_char next_frame=TRUE;
static XmodemFrame *ptr_frame;
static XmodemFrame input_buff[2];
//* ------------------------------- Functions -------------------------------
//*----------------------------------------------------------------------------
//* Function Name : time_out
//* Object : Compute the CRC
//* Input Parameters : Global wait_time
//* Output Parameters : Global timed_out = TRUE
//*----------------------------------------------------------------------------
static void time_out(void)
{
wait_time--;
if (wait_time <=0)
{
wait_time=0;
timed_out= TRUE;
}
}
//*----------------------------------------------------------------------------
//* Function Name : init_usart
//* Object : init_usart_with PDC
//* Input Parameters : Global time_out
//* Output Parameters : Global timed_out = TRUE
//*----------------------------------------------------------------------------
static void init_usart(void)
{
//* Store the address of the buffer
Xmodem_COM->usart->usart_base->US_RPR = (u_int) input_buff ;
//* Store the number of bytes to receive
Xmodem_COM->usart->usart_base->US_RCR = sizeof(input_buff);
}
//*----------------------------------------------------------------------------
//* Function Name : get_usart
//* Object : Get char in usart
//* Input Parameters : none
//* Output Parameters : none
//*----------------------------------------------------------------------------
static void get_usart (void)
{
u_int status;
// check for recv_errors before reading data register
// Framing, over run or parity error
status = at91_usart_get_status(Xmodem_COM->usart);
if ( status & (US_OVRE | US_FRAME| US_PARE) )
{
recv_error = TRUE;
//* Reset Status Bits
at91_usart_trig_cmd( Xmodem_COM->usart,US_RSTSTA);
}
else
{
//* check end of transmission
if ( (input_buff[0].Header != SOH) | (input_buff[1].Header != SOH))
{
buffer_status = FULL;
eot_flag = TRUE;
}
//* check end of frame
//* if the recivied size at XMODEM_FRAME_SIZE the [0] is full
else if( ( Xmodem_COM->usart->usart_base->US_RCR == XMODEM_FRAME_SIZE) &
(next_frame==TRUE)
)
{
buffer_status = FULL;
ptr_frame= &input_buff[0];
next_frame=FALSE;
}
else if ( Xmodem_COM->usart->usart_base->US_RCR == 0 )
{
init_usart();
buffer_status = FULL;
ptr_frame= &input_buff[1];
next_frame=TRUE;
}
}
}
//*----------------------------------------------------------------------------
//* Function Name : calcrc
//* Object : Compute the CRC
//* Input Parameters : <ptr> char pointer
//* <count> nb of char
//* Output Parameters : crc value
//*----------------------------------------------------------------------------
static u_short calcrc(u_char *ptr, int count)
{
u_short crc, cmpt;
crc = 0;
//* For all char
while (--count >= 0)
{
crc = crc ^ (int) *ptr++ << 8;
//* For All bit
for (cmpt = 0; cmpt < 8; cmpt++)
{
if (crc & 0x8000)
crc = crc << 1 ^ CRC16POLY;
else
crc = crc << 1;
}//* end bit
}//* Frame end
return (crc & 0xFFFF);
}
//*----------------------------------------------------------------------------
//* Function Name : recv_wait_frame
//* Object : wait data or time out
//* Input Parameters : <time> Wait time
//* Output Parameters : none
//*----------------------------------------------------------------------------
static void recv_wait_frame(int time)
{
buffer_status = EMPTY;
timed_out = FALSE; // set in timer counter 0 overflow interrupt routine
recv_error = FALSE; // framing and over run detection
wait_time = time;
// wait for packet or error
while (!buffer_status && !recv_error && !timed_out)
{
get_usart();
time_out();
}
}
//*----------------------------------------------------------------------------
//* Function Name : purge
//* Object : wait 1 second for sender to EMPTY its transmit buffer
//* Input Parameters : none
//* Output Parameters : none
//*----------------------------------------------------------------------------
static void purge(void)
{
wait_time =WAIT_1S;
init_usart();
while (!timed_out) // read uart until done
{
time_out();
}
//* stop pdc reception
Xmodem_COM->usart->usart_base->US_RCR = 0;
//* clear error
at91_usart_trig_cmd( Xmodem_COM->usart,US_RSTSTA);
}
//*----------------------------------------------------------------------------
//* Function Name : respond
//* Object : Compute the CRC
//* Input Parameters : <responce type>: TRUE send ACK FALSE send NAK
//* Output Parameters : none
//*----------------------------------------------------------------------------
static void respond(u_char packet)
{
if (packet)
{
at91_send_byte(Xmodem_COM,ACK);
}
else
{ // tell sender error
at91_send_byte(Xmodem_COM,NAK);
}
}
//*----------------------------------------------------------------------------
//* Function Name : validate_packet
//* Object : check the data frame
//* SOH | nr | ns | < 128 data > | check|sum |
//* data size = XMODEM_FRAME_SIZE 133
//* Input Parameters : <check_buf> end address buffer address
//* Output Parameters : none
//*----------------------------------------------------------------------------
static u_char validate_packet(XmodemFrame *check_buf)
{
u_short crc;
u_char status = NOK;
if (buffer_status && !recv_error)
{ // no framing, over run, or time out errors
if (check_buf->Header == SOH)
{ // valid start
if (check_buf->packet == ((packet_number+1) & 0xff))
{ // sequential block number ?
if ((check_buf->packet + check_buf->packet_crc) == 0xff)
{ // block number and block number checksum are ok
// compute CRC and validate it
crc = calcrc((u_char*)check_buf->data,XMODEM_DATA_SIZE);
if ( (check_buf->crc_lsb == (unsigned char)(crc >> 8)) &&
(check_buf->crc_msb == (unsigned char)(crc))
)
{
packet_number++;
status = OK;
}// if end CRC
}// block Checksum
}// sequential block
}// valid start
// check for the end
else if (check_buf->Header == EOT)
{// no start
eot_flag = TRUE;
status = OK;
}
}// recieved with error
return (status);
}
//*----------------------------------------------------------------------------
//* Function Name : xmodem_receive
//* Object : Recived all frame
//* Input Parameters : address of write function (flash,or ram, ...
//* Output Parameters : Status
//* Functions called : validate_packet static function
//* respond static function
//*----------------------------------------------------------------------------
int xmodem_receive(int (*write_function)(u_char *ptr_data,int size))
{
u_char packet;
int status;
// init static data
packet_number = 0x00;
eot_flag = FALSE;
ptr_frame = input_buff;
buffer_status = EMPTY;
next_frame=TRUE;
//* init the header
input_buff[1].Header=input_buff[0].Header=SOH;
init_usart();
status = TRUE;
// send 'C' character until we get a packet from the sender
while (!buffer_status)
{
at91_send_byte(Xmodem_COM,CRCCHR);
recv_wait_frame(WAIT_1S/2);
}
//* validate 1st packet
packet = validate_packet(ptr_frame);
//* ack or nak
respond(packet);
if ( packet)
{ // if Ok write data
//* external function for write data
if (!(*write_function)((u_char *) ptr_frame->data,XMODEM_DATA_SIZE))
{
eot_flag = TRUE ;
status = FALSE;
}
}
// get remainder of file
while (!eot_flag)
{
// wait for error or buffer FULL
recv_wait_frame(WAIT_2S);
// validate the packet
packet = validate_packet(ptr_frame);
// ack or nak
respond(packet);
if (packet && (eot_flag == FALSE))
{ // if Ok write data
if (!(*write_function)((u_char *) ptr_frame->data,XMODEM_DATA_SIZE))
{
eot_flag = TRUE ;
status = FALSE;
}
}
} // end of 1st file transmission
at91_send_byte(Xmodem_COM,ACK);
purge();
return (status);
}
//*----------------------------------------------------------------------------
//* Function Name : recv_char_wait
//* Object : wait data
//* Input Parameters : <data> char to read
//* Output Parameters : if Recievied char retrun this char
//*----------------------------------------------------------------------------
static u_char recv_char_wait(u_char data)
{
int read;
buffer_status = EMPTY;
recv_error = FALSE; // framing and over run detection
timed_out = FALSE; // set in timer counter 0 overflow interrupt routine
wait_time = WAIT_3S;
// wait for packet or error
while (!buffer_status && !recv_error && !timed_out)
{
if ( at91_usart_get_status(Xmodem_COM->usart) & (US_OVRE | US_PARE) )
{
recv_error = TRUE;
//* Reset Status Bits
at91_usart_trig_cmd( Xmodem_COM->usart,US_RSTSTA);
}
else if (!at91_getch(Xmodem_COM,&read))
{
// determine if read char is ok buffer FULL
if ((u_char)read == data )
buffer_status = FULL;
}
// Time out
time_out();
}
return( (u_char) read);
}
//*----------------------------------------------------------------------------
//* Function Name : xmodem_transmit
//* Object : transmit data area
//* Input Parameters : <bufptr> start data address
//* <size> lenght
//* Output Parameters : none
//* Functions called : at91_send_byte define in com.c driver
//* at91_print_frame define in com.c driver
//* calcrc static function
//*----------------------------------------------------------------------------
int xmodem_transmit(u_char *bufptr,u_int len)
{
u_int count;
int status = TRUE;
u_short crc;
u_char sent_packet = 0x01;
//* wait the recievied
while ( recv_char_wait(CRCCHR) != CRCCHR );
for (count =0 ; count <len ;sent_packet++)
{
// send header
at91_send_byte(Xmodem_COM,SOH);
at91_send_byte(Xmodem_COM,sent_packet);
at91_send_byte(Xmodem_COM,0xFF - sent_packet);
// send data frame
at91_print_frame (Xmodem_COM, (char*) bufptr , XMODEM_DATA_SIZE);
count+= XMODEM_DATA_SIZE;
bufptr+=XMODEM_DATA_SIZE;
// send CRC
crc = calcrc((bufptr-XMODEM_DATA_SIZE),XMODEM_DATA_SIZE);
at91_send_byte(Xmodem_COM,(u_char)(crc >> 8));
at91_send_byte(Xmodem_COM,(u_char)(crc));
// wait ACK
switch ( recv_char_wait(ACK))
{
case NAK: //* retransmit the la st frame
bufptr -=XMODEM_DATA_SIZE;
count -=XMODEM_DATA_SIZE;
sent_packet--;
status =FALSE;
break;
case ACK://* Continue
break;
default: // Stop the transmission
at91_send_byte(Xmodem_COM,NAK);
count = len;
break;
}// switch End
}// for end
// send end of file
at91_send_byte(Xmodem_COM,EOT);
return (status);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -