blob: 8ee7a52906e50b52af4505b96348e773a04deb65 [file] [log] [blame]
/*
* xmodem-at91.c
*
* A simple program using xmodem/1kxmode upload file to at91rm9200 based board.
* Created by (C) Copyright 2004
* Linhang.Zhang, Jilin University of PR.China, linxing@jlu.edu.cn.
*
* Modified 01-Feb-2005 (C)Copyright 2005
* Marco Cavallini, www.KoanSoftware.com - ITALY, m.cavallini@koansoftware.com
* - edited indentations and changed break usage in switch statement.
* - added "\r" to printf
*
* Modified 13-Apr-2006 Marco Cavallini
* - typo error (thank you Goran !)
*
* Modified 7-jun-2012
* - Adapted to work with the ArmadaXP-A0 Silicone
* - replaced CRC with checksum
* - discarded meanless characters in RX (printings done by BootROM).
*
* - build with
* gcc sx-at91.c -o sx-at91
*
* - Howto use this program with minicom/xminicom and AT91
* start minicom or xminicom
* edit Options / File transfer protocol,
* add a name (for example J) like the following example
*
* | Name Program Name U/D FullScr IO-Red. Multi |
* | A zmodem /usr/bin/sz -vv -b Y U N Y Y |
* | B ymodem /usr/bin/sb -vv Y U N Y Y |
* | C xmodem /usr/bin/sx -vv Y U N Y N |
* | D zmodem /usr/bin/rz -vv -b -E N D N Y Y |
* | E ymodem /usr/bin/rb -vv N D N Y Y |
* | F xmodem /usr/bin/rx -vv Y D N Y N |
* | G kermit /usr/bin/kermit -i -l %l -s Y U Y N N |
* | H kermit /usr/bin/kermit -i -l %l -r N D Y N N |
* | I ascii /usr/bin/ascii-xfr -dsv Y U N Y N |
* | J at91 /home/koan/xmodem/sx-at91 Y U Y N N |
* | K - |
* | L - |
*
* save and use it selecting at91 protocol when you start an Xmodem upload to AT91
*
*************************************************************************************
*
* 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 2 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <time.h>
/*
Xmodem Frame form: <SOH><blk #><255-blk #><--128 data bytes--><CRC hi><CRC lo>
*/
#define XMODEM_SOH 0x01
#define XMODEM_STX 0x02
#define XMODEM_EOT 0x04
#define XMODEM_ACK 0x06
#define XMODEM_NAK 0x15
#define XMODEM_CRC_CHR 'C'
#define XMODEM_CHECKSUM_SIZE 1
#define XMODEM_CRC_SIZE 2 /* Crc_High Byte + Crc_Low Byte */
#define XMODEM_FRAME_ID_SIZE 2 /* Frame_Id + 255-Frame_Id */
#define XMODEM_DATA_SIZE_SOH 128 /* for Xmodem protocol */
#define XMODEM_DATA_SIZE_STX 1024 /* for 1K xmodem protocol */
#define USE_1K_XMODEM 0 /* 1 for use 1k_xmodem 0 for xmodem */
#if (USE_1K_XMODEM)
#define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_STX
#define XMODEM_HEAD XMODEM_STX
#else
#define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_SOH
#define XMODEM_HEAD XMODEM_SOH
#endif
/*********/
#define SERIAL_DEVICE "/dev/ttyUSB0"
#define MYBAUDRATE B115200
/***************SUB PROGRAM*******/
unsigned short GetCrc16 ( char *ptr, unsigned short count )
{
unsigned short crc, i;
crc = 0;
while(count--)
{
crc = crc ^ (int) *ptr++ << 8;
for(i = 0; i < 8; i++)
{
if(crc & 0x8000)
crc = crc << 1 ^ 0x1021;
else
crc = crc << 1;
}
}
return (crc & 0xFFFF);
}
/*******************************/
int Initial_SerialPort(char * serial_port)
{
int fd;
struct termios options;
fd = open( serial_port, O_RDWR | O_NOCTTY | O_NDELAY );
if ( fd == -1 )
{
/*open error!*/
perror("Can't open serial port!");
return -1;
}
/*Get the current options for the port...*/
tcgetattr(fd, &options);
/*Set the baud rates to BAUDRATE...*/
cfsetispeed(&options,MYBAUDRATE);
cfsetospeed(&options,MYBAUDRATE);
tcsetattr(fd, TCSANOW, &options);
if (0 != tcgetattr(fd, &options))
{
perror("SetupSerial 1");
return -1;
}
/*
* 8bit Data,no partity,1 stop bit...
*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcflush(fd,TCIFLUSH);
/***Choosing Raw Input*/
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
/*
* Set the new options for the port...
*/
if (0 != tcsetattr(fd, TCSANOW, &options))
{
perror("SetupSerial error");
return -1 ;
}
return fd ;
}
//******************************
void ClearReceiveBuffer(int fd)
{
unsigned char tmp;
while ((read(fd,&tmp,1))>0);
return;
}
//********************************
int main(int argc,char *argv[])
{
int fd;
char *data_file_name;
char packet_data[ XMODEM_DATA_SIZE ];
// char frame_data[ XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1 ];
char frame_data[ XMODEM_DATA_SIZE + XMODEM_CHECKSUM_SIZE + XMODEM_FRAME_ID_SIZE + 1 ];
unsigned char tmp;
FILE *datafile;
int complete,retry_num,pack_counter,read_number,write_number,i;
unsigned short crc_value;
unsigned char ack_id;
unsigned int checksum = 0;
if (argc == 1) {
printf("Usage %s <uart device> <file to transfer>\n", argv[0]);
printf(" Example %s /dev/ttyS0 myfile.bin\n", argv[0]);
return 0;
}
printf("Opening Uart %s... ", argv[1]);
if ( (fd = Initial_SerialPort(argv[1])) == -1) {
perror ("Failed!\n");
return -1 ;
}
printf("Done\n");
data_file_name = argv[2];
if((datafile=fopen(data_file_name,"rb"))==NULL)
{
perror ("Can't open file!");
return -1 ;
}
//*******************************
pack_counter = 0;
complete = 0;
retry_num = 0;
ClearReceiveBuffer(fd);
while((read(fd,&ack_id,1))<=0);
printf("%c\r\n",ack_id);
ack_id=XMODEM_ACK;
while(!complete)
{
switch(ack_id)
{
case XMODEM_ACK:
retry_num = 0;
checksum = 0;
pack_counter++;
read_number = fread( packet_data, sizeof(char), XMODEM_DATA_SIZE, datafile);
if(read_number>0)
{
if(read_number<XMODEM_DATA_SIZE_SOH)
{
printf("Start filling the last frame!\r\n");
for(;read_number<XMODEM_DATA_SIZE;read_number++)
packet_data[read_number] = 0x00;
}
frame_data[0] = XMODEM_HEAD;
frame_data[1] = (char)pack_counter;
frame_data[2] = (char)(255-frame_data[1]);
for(i=0;i<XMODEM_DATA_SIZE;i++) {
frame_data[i+3]=packet_data[i];
checksum+=packet_data[i];
}
checksum = checksum%256;
// crc_value = GetCrc16(packet_data,XMODEM_DATA_SIZE);
// frame_data[XMODEM_DATA_SIZE_SOH+3]=(unsigned char)(crc_value >> 8);
frame_data[XMODEM_DATA_SIZE_SOH+3]=(unsigned char)(checksum);
// frame_data[XMODEM_DATA_SIZE_SOH+4]=(unsigned char)(crc_value);
// write_number = write( fd, frame_data, XMODEM_DATA_SIZE_SOH + 5);
write_number = write( fd, frame_data, XMODEM_DATA_SIZE_SOH + 4);
printf("wait for ACK,%d,%d,...",pack_counter,write_number);
while(1) {
while((read(fd,&ack_id,1))<=0);
if(ack_id == XMODEM_ACK) {
printf("Ok! \r");
break;
}
else if(ack_id == XMODEM_NAK) {
printf("Error! NAK\r");
break;
}
else
printf("Skip! \r");
}
}
else
{
ack_id = XMODEM_EOT;
complete = 1;
printf("Waiting for complete ACK ...");
while(ack_id != XMODEM_ACK)
{
ack_id = XMODEM_EOT;
write_number=write(fd,&ack_id,1);
while((read(fd,&ack_id,1))<=0);
}
printf("OK\r");
printf("Sending file complete\r\n");
}
break;
case XMODEM_NAK:
if( retry_num++ > 10)
{
printf("Retry too many times,Quit!\r\n");
complete = 1;
}
else
{
// write_number = write(fd,frame_data,XMODEM_DATA_SIZE + 5);
write_number = write(fd,frame_data,XMODEM_DATA_SIZE + 4);
printf("Retry for ACK,%d,%d...",pack_counter,write_number);
while(1) {
while((read(fd,&ack_id,1))<=0);
if(ack_id == XMODEM_ACK) {
printf("Ok! \r");
break;
}
else if(ack_id == XMODEM_NAK) {
printf("Error! NAK\r");
break;
}
else
printf("Skip! \r");
}
}
break;
default:
printf("Fatal Error!\r\n");
complete = 1;
break;
}
}
fclose(datafile);
close(fd);
return 0;
}