// xmodem interface file #include #include #include #define CLK 16000000L #define SOH 0x01 #define EOT 0x04 #define ACK 0x06 #define NAK 0x15 #define CAN 0x18 #define _C_ 0x43 void initcomm(int baud) { unsigned short ubrr; ubrr=CLK/16/baud-1; // initialize baud rate UBRRH=ubrr>>8; UBRRL=ubrr&0xff; UCSRB=0b00011000; // RX&TX enabled, no interrupts, 8 data bits } #define byte unsigned char typedef struct { byte start; byte blockno; byte _blockno; byte data[128]; byte crc1; // hibyte byte crc2; // lobyte } xmodem_pkt; xmodem_pkt pkt; #define SENDNAK putchar(NAK) #define SENDACK putchar(ACK) #define SENDC putchar('C') // this function calculates a crc for 128 byte packet unsigned short int getcrc(byte *buffer) { int i,j; unsigned short int crc=0; for(i=0;i<128;i++) { crc=crc^(((unsigned short int)buffer[i])<<8); for(j=0;j<8;j++) { if(crc & 0x8000) crc=(crc<<1)^0x1021; else crc=crc<<1; } } return crc; } int xmodem_receive(int (*callback)(byte *)) { // receive an xmodem file int i,j; int errcount=0; byte curblock=1; byte check; int eof=0; unsigned short int crc,crcpkt; SENDC; while(!UCSRA.7) { for(i=0;i<1000;i++) { delay_ms(1); if(UCSRA.7) break; } SENDC; } // DDRB=0xff; // PORTB=0xff; while(1) { // PORTB=~1; pkt.start=getchar(); // PORTB=~2; switch(pkt.start) { case SOH: // header eof=0; pkt.blockno=getchar(); // PORTB=~4; if(pkt.blockno!=curblock) { break; } // make sure we're getting the current block // PORTB=~8; pkt._blockno=getchar(); // PORTB=~16; crc=0; // read the packet and calculate CRC on the fly for(i=0;i<128;i++) { pkt.data[i]=getchar(); crc=crc^(((unsigned short int)pkt.data[i])<<8); for(j=0;j<8;j++) { if(crc & 0x8000) crc=(crc<<1)^0x1021; else crc=crc<<1; } } // PORTB=~32; // grab the CRC and check pkt.crc1=getchar(); pkt.crc2=getchar(); crcpkt=(((unsigned short int)pkt.crc1)<<8)|pkt.crc2; // check for validity of block number if(pkt.blockno!=(~pkt._blockno)) { SENDNAK; break; } // check for CRC if(crcpkt!=crc) { SENDNAK; break; } // PORTB=~64; // call our project if((*callback)(pkt.data)) { // bad packet SENDNAK; } else { // good packet SENDACK; curblock++; } // PORTB=~0; break; case EOT: // end of transmission // PORTB=~3; if(eof==0) { SENDNAK; eof=1; } else { SENDACK; return 0; } break; default: // erroneous eof=0; // PORTB=~7; } } return 0; } int xmodem_send(int (*callback)(byte *)) { byte resp; byte pktno=1; byte i,j; int keep=1; unsigned short int crc; while((resp=getchar())!='C') { if(resp==CAN || resp==EOT) return -1; } // fill the 128 byte buffer for the first packet keep=(*callback)(pkt.data); while(keep) { //PORTB=~pktno; // generate the packet pkt.start=SOH; pkt.blockno=pktno; pkt._blockno=~pktno; pktno++; // crc=getcrc(pkt.data); // pkt.checksum=0; // for(i=0;i<128;i++) { // pkt.checksum+=pkt.data[i]; // } do { // write the packet putchar(pkt.start); putchar(pkt.blockno); putchar(pkt._blockno); crc=0; // write the actual data and calculate CRC on the fly for(i=0;i<128;i++) { crc=crc^(((unsigned short int)pkt.data[i])<<8); putchar(pkt.data[i]); for(j=0;j<8;j++) { if(crc & 0x8000) crc=(crc<<1)^0x1021; else crc=crc<<1; } } pkt.crc1=crc>>8; pkt.crc2=crc&0xff; // write the CRC // putchar(pkt.checksum); putchar(pkt.crc1); putchar(pkt.crc2); // grab the next packet keep=(*callback)(pkt.data); resp=getchar(); if(resp!=NAK && resp!=ACK) { //PORTB=~0b11110000; return -1; } } while(resp==NAK); } putchar(EOT); return 0; } #ifdef XMODEMDEBUG // for XMODEM testing only // callback function that is called with the 128 byte buffer // callback returns nonzero if there's an error int sample_callback(byte *buf) { return 0; } byte state=0; byte count=100; // callback for sender // this function fills a 128 byte buffer // return 0 when finished int sample_callback2(byte *buf) { int i; if(count==0) return 0; for(i=0;i<128;i++) { buf[i]=state; state=state*0xa6; state=state+1; } count--; return 1; } void main(void) { int i; initcomm(19200); DDRB=0b11111111; //PORTB=0; for(i=0;i<1000;i++); //PORTB=0b11111111; putsf("XMODEM TEST\r\n"); while(1) { putsf("MENU:\r\n"); putsf(" 1) Upload file\r\n"); putsf(" 2) Download file\r\n"); i=getchar(); switch(i) { case '1': putsf("Start sending on your end with XModem CRC\r"); xmodem_receive(sample_callback); putsf("TRANSFER DONE\r\n"); i=UDR; break; case '2': putsf("Start receiving on your end with XModem CRC\r"); state=0; count=100; xmodem_send(sample_callback2); putsf("TRANSFER COMPLETE\r\n"); i=UDR; break; default: putsf("Unknown command\r\n"); break; } } } #endif