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