unsigned int calculate_crc(unsigned char *ptr,unsigned char datacount) { unsigned int crc=0; while(datacount--) crc=xmodem_crc_check(crc,*ptr++); return crc; }
long xmodem_receive( char* dest, u32 limit ) { unsigned char xmbuf[XMODEM_BUFFER_SIZE+6]; unsigned char seqnum=1; // xmodem sequence number starts at 1 unsigned short pktsize=128; // default packet size is 128 bytes unsigned char response='C'; // solicit a connection with CRC char retry=XMODEM_RETRY_LIMIT; unsigned char crcflag=0; unsigned long totalbytes=0; int i,c; while(retry > 0) { // solicit a connection/packet xmodem_out_func(response); // wait for start of packet if( (c = xmodem_in_func(XMODEM_TIMEOUT_DELAY)) >= 0) { switch(c) { case SOH: pktsize = 128; break; case EOT: xmodem_flush(); xmodem_out_func(ACK); // completed transmission normally return totalbytes; case CAN: if((c = xmodem_in_func(XMODEM_TIMEOUT_DELAY)) == CAN) { xmodem_flush(); xmodem_out_func(ACK); // transaction cancelled by remote node return XMODEM_ERROR_REMOTECANCEL; } default: break; } } else { // timed out, try again // no need to flush because receive buffer is already empty retry--; //response = NAK; continue; } // check if CRC mode was accepted if(response == 'C') crcflag = 1; // got SOH/STX, add it to processing buffer xmbuf[0] = c; // try to get rest of packet for(i=0; i<(pktsize+crcflag+4-1); i++) { if((c = xmodem_in_func(XMODEM_TIMEOUT_DELAY)) >= 0) { xmbuf[1+i] = c; } else { // timed out, try again retry--; xmodem_flush(); response = NAK; break; } } // packet was too small, retry if(i<(pktsize+crcflag+4-1)) continue; // got whole packet // check validity of packet if( (xmbuf[1] == (unsigned char)(~xmbuf[2])) && // sequence number was transmitted w/o error xmodem_crc_check(crcflag, &xmbuf[3], pktsize) ) // packet is not corrupt { // is this the packet we were waiting for? if(xmbuf[1] == seqnum) { // write/deliver data if( totalbytes + pktsize > limit ) { // Cancel transmission xmodem_flush(); xmodem_out_func(CAN); xmodem_out_func(CAN); xmodem_out_func(CAN); return XMODEM_ERROR_OUTOFMEM; } memcpy( dest + totalbytes, xmbuf + 3, pktsize ); totalbytes += pktsize; // next sequence number seqnum++; // reset retries retry = XMODEM_RETRY_LIMIT; // reply with ACK response = ACK; continue; } else if(xmbuf[1] == (unsigned char)(seqnum-1)) { // this is a retransmission of the last packet // ACK and move on response = ACK; continue; } else { // we are completely out of sync // cancel transmission xmodem_flush(); xmodem_out_func(CAN); xmodem_out_func(CAN); xmodem_out_func(CAN); return XMODEM_ERROR_OUTOFSYNC; } } else { // packet was corrupt // NAK it and try again retry--; xmodem_flush(); response = NAK; continue; } } // exceeded retry count xmodem_flush(); xmodem_out_func(CAN); xmodem_out_func(CAN); xmodem_out_func(CAN); return XMODEM_ERROR_RETRYEXCEED; }