📄 xymodem.c
字号:
/****************************************************************************//* Copyright 2000 Compaq Computer Corporation. *//* . *//* Copying or modifying this code for any purpose is permitted, *//* provided that this copyright notice is preserved in its entirety *//* in all copies or modifications. COMPAQ COMPUTER CORPORATION *//* MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, AS TO THE USEFULNESS *//* OR CORRECTNESS OF THIS CODE OR ITS FITNESS FOR ANY PARTICULAR *//* PURPOSE. *//****************************************************************************//* * xymodem.c - an implementation of the xmodem protocol from the spec. * * George France <france@crl.dec.com> * based on the code of Edwin Foo <efoo@crl.dec.com> * * WARNING: - This code has mixed coding styles. */#include "bootconfig.h"#include "bootldr.h"#ifdef CONFIG_BITSY#include "sa1100.h"#endif/* XMODEM parameters */#define RETRIES 10 /* maximum number of retries */#define GET_BYTE_TIMEOUT 200000 /* efoo's magic number because I do not know the real number i.e. - how many times = 1 sec. *//* Line control codes */#define SOH 0x01 /* start of header */#define ACK 0x06 /* Acknowledge */#define NAK 0x15 /* Negative acknowledge */#define CAN 0x18 /* Cancel */#define EOT 0x04 /* end of text *//* Return Codes - I know non-negitive error codes */enum { xyOK = 0, /* OK - no error */ xyMalfunctioned, /* Malfunctioned - recoverable error */ xyFailed, /* Failed - unrecoverable error */ xyBadPacket, xyEOT, /* End of Text */ xyEndOfSession, xyTimeout, xyTransmission, xySerial, /* problem with the serial port */ xyBuffer, /* buffer overflow */ xyNumErrorCodes};static int errorCounts[xyNumErrorCodes];#define XYERROR(code) (((xy.err == code) || errorCounts[code]++), xy.err = code)#define XY_COUNT_PACKET() (errorCounts[xyOK]++)struct xyModem { int crc, /* Does the sender support CRC? */ longPacket, /* Does the sender support 1K Packets? */ batch, /* Does the sender support batch? */ g; /* Does the sender support 'G' */ int timeout; /* Timeout in number of seconds */ int retries; /* Number of times to retry a packet */ int userAbort; /* Does the user want to Abort? */ int packetNumber; /* Current Packet Number */ char *filename; long fileLength; long transferred; /* Number of bytes transferred */ int check_value; /* one byte checksum or two byte crc */ int err; /* error code */} xy;/************************************************************************ * * Global Vars. * ************************************************************************//************************************************************************ * * Debugging Routines * ***********************************************************************/#define xyDisplayMsg() xyDsplyMsg() /* change to (err) for no debugging mesages */void xyDsplyMsg(void) { switch (xy.err) { case xyOK: break; case xyMalfunctioned: putstr("Malfunctioned\r\n"); break; case xyFailed: putstr("Failed\r\n"); break; case xyBadPacket: putstr("BadPacket\r\n"); break; case xyEOT: putstr("End of Text\r\n"); break; case xyEndOfSession: putstr("End of Session\r\n"); break; case xyTimeout: putstr("Timed Out\r\n"); break; case xyTransmission: putstr("Transmission Breakdown\r\n"); break; case xyBuffer: putstr("Buffer Overflow"); break; default: putstr("Unknown Error\r\n "); break; } return;}/************************************************************************ * * Utility Routines * * init_crc_16 pre-computes a table of constants, using the bitwise * algorithm with the x^16+x^12+x^5+1 polynomial = 0x11021 * binary. The leading term is implied. ************************************************************************/unsigned int crc_table[256];void InitCRC16(void){ unsigned i, j, crc; for (i=0; i<256; i++) { crc = (i << 8); for (j=0; j<8; j++) crc = (crc << 1) ^ ((crc & 0x8000) ? 0x1021 : 0); crc_table[i] = crc & 0xffff; }}/************************************************************************* * * Interface to Serial Port * *************************************************************************/byte getBytesWithTimeout(){ byte c = 0, rxstat; dword i; xy.err = 0; /* reset errno */ if (xy.userAbort ) { XYERROR(xyFailed); return(c); } i = xy.timeout;#ifdef CONFIG_SKIFF while (((CSR_READ_BYTE(UARTFLG_REG) & UART_RX_FIFO_EMPTY)) && i) i--;#else { while ((!((*(volatile long *)SA1100_UART3_UTSR1) & SA1100_UTSR1_RNE)) && i) i--; }#endif if (i) {#ifdef CONFIG_SKIFF /* must read UARTDR before RXSTAT */ c = CSR_READ_BYTE(UARTDR_REG); rxstat = CSR_READ_BYTE(RXSTAT_REG);#else c = *(volatile long *)SA1100_UART3_UTDR; rxstat = (*(volatile long *)SA1100_UART3_UTSR1) & SA1100_UTSR1_ERROR_MASK;#endif if (rxstat) { /* i do not know the values of rxstat - just following Edwin */ XYERROR(xySerial); } } else { XYERROR(xyTimeout); } return(c);}/***************************************************************************** * Subroutines * xyReceivePacket -- gets a packet * xyReceivePacketReliable -- retries bad packets * xyReceiveFile -- gets the file * xyReceiveFallback -- Fallback to the next lower protocol * xySendHandshake -- Sends a handshake to the sender * xyReadBytesWithCheck -- Reads a Packet and verifies Check Sum * xyReadBytesWithCRC -- Reads a Packet and verifies CRC 16 * xyGobble -- Eats bytes from the serial port * ***************************************************************************/void xyGobble(void) { int i; int junkLength = 64; byte c; do { for (i=0; i < junkLength; i++ ) c = getBytesWithTimeout(); if (xy.err == xySerial) /* ignore framing errors */ xy.err = xyOK; } while ( xy.err == xyOK ); if ( xy.err == xyTimeout) xy.err = xyOK; return;}void xyReadBytesWithCheck( byte *pBuffer, int buf_length ) { int i; byte c; xy.check_value = 0; for (i=0; i < buf_length; i++) { c = getBytesWithTimeout(); if (xy.err != xyOK ) return; *(byte *)(pBuffer+i) = c; xy.check_value += c; } c = getBytesWithTimeout(); if (xy.err != xyOK ) return; if ( (xy.check_value & 0xFF) != c ) XYERROR(xyBadPacket); return;}void xyReadBytesWithCRC( byte *pBuffer, int buf_length ) { int i, received_crc; byte c; xy.check_value = 0; for (i=0; i < buf_length; i++) { c = getBytesWithTimeout(); if (xy.err != xyOK ) return; *(byte *)(pBuffer+i) = c; xy.check_value = crc_table[((xy.check_value >> 8 ) ^ c) & 0xFF] ^ (xy.check_value << 8); } xy.check_value &= 0xFFFF; c = getBytesWithTimeout(); if (xy.err != xyOK ) return; received_crc = ( c & 0xFF ) << 8; c = getBytesWithTimeout(); if (xy.err != xyOK ) return; received_crc |= ( c & 0xFF ); if ( xy.check_value != received_crc ) XYERROR(xyBadPacket); return;}void xyReceiveFallback(void) { if (xy.g) { xy.g = 0; return; } if (xy.crc) { xy.crc = xy.batch = xy.longPacket = 0; return; } /* xy.g = xy.crc = xy.batch = xy.longPacket = -1; */ return;}void xySendHandshake(void){ if (xy.g) { putc('G'); return; } if (xy.crc) { putc('C'); return; } putc(NAK); return;}void xyReceivePacket(byte *pBuffer, int *packetNumber, int *pLength) { byte startOfPacket = 0; byte packet = 0; byte packetCheck = 0; int packetLength=0; packetCheck = getBytesWithTimeout(); if ( xy.err != xyOK ) return; if (packetCheck == EOT ) { XYERROR(xyEOT); return; } do { startOfPacket = packet; packet = packetCheck; if ((packetCheck == CAN) && (packet == CAN)) { XYERROR(xyFailed); return; } packetCheck = getBytesWithTimeout(); if ( xy.err != xyOK ) return; } while ( ( ( startOfPacket != SOH ) && (startOfPacket != 0x02) ) || ( ( (packet ^ packetCheck) & 0xFF) != 0xFF) ); /* a vaild start of packet */ if (startOfPacket == SOH) packetLength = 128; else packetLength = 1024; *packetNumber = packet; *pLength = packetLength; if (xy.crc) { xyReadBytesWithCRC( pBuffer, packetLength); } else { xyReadBytesWithCheck( pBuffer, packetLength); } return;}void xyReceivePacketReliable(byte *pBuffer, int *packetNumber, int *pLength) { int retries = xy.retries; int eotCount = 0; do { xyReceivePacket( pBuffer, packetNumber, pLength ); if (xy.err == xyEOT) { if ( xy.g) { xy.err = xyEOT; return; } eotCount += 3; if ( eotCount >= 6) { xy.err = xyEOT; return; } } else if ((xy.err == xyTimeout) && (eotCount > 0 )) { eotCount++; if (eotCount >= 6) { xy.err = xyEOT; return; } } else { /* Data packet or timeout seen */ eotCount = 0; if ((xy.err == xyBadPacket) && ( xy.err != xyTimeout)) return; else if (xy.g) { XYERROR(xyMalfunctioned); return; } } putc(NAK); } while (retries-- > 0 ); XYERROR(xyMalfunctioned); return;}void xyReceiveFile(dword dldaddr, dword img_size) { int retries = xy.retries / 2 + 1; int totalRetries = ( xy.retries * 3 ) / 2 + 1; int packetNumber, packetLength; byte *pBuffer; /* Try different handshakes until we get the first packet */ xy.err = xyOK; pBuffer = (byte *)dldaddr; do { if (--retries == 0 ) { xyReceiveFallback(); retries = xy.retries / 3; } if (totalRetries-- == 0) { XYERROR(xyFailed); return; } xySendHandshake(); xyReceivePacketReliable( pBuffer, &packetNumber, &packetLength); if ((xy.err == xyEOT) || (xy.err == xyBadPacket)) { xyGobble(); } } while ( (xy.err == xyTimeout) || (xy.err == xyBadPacket) || (xy.err == xyMalfunctioned) || (xy.err == xyEOT) ); if ( ( packetNumber != 0 ) && ( packetNumber != 1 ) ) { XYERROR(xyFailed); return; } /* the first packet tells if the sender is in batch mode */ if ( packetNumber == 0 ) { xy.batch = -1; putc(ACK); XY_COUNT_PACKET(); xySendHandshake(); /* get next packet */ xyReceivePacketReliable( pBuffer, &packetNumber, &packetLength ); } else { xy.batch = 0; xy.g = 0; /* g is always batch */ } xy.packetNumber = 1; xy.transferred = 0; /* we have the first packet and the correct protocol */ /* Now we get the remaining packets */ while (xy.err == xyOK) { if (packetNumber == ( xy.packetNumber & 0xFF )) { xy.packetNumber++; xy.transferred += packetLength; if (!xy.g) { putc(ACK); /* ACK correct packet */ XY_COUNT_PACKET(); } } else if (packetNumber == (xy.packetNumber - 1) & 0xFF) { putc(ACK); /* ACK repeat of previous packet */ } pBuffer += packetLength; if (pBuffer >= (byte *)(dldaddr + img_size - 1024)) { XYERROR(xyBuffer); return; } xyReceivePacketReliable( pBuffer, &packetNumber, &packetLength ); } /* ACK the EOT. */ if (xy.err == xyEOT) { putc(ACK); XY_COUNT_PACKET(); } return; }/***************************************************************************** * * Main Program - main entry is xmodem_dld * abort entry is xyModemAbort * ****************************************************************************/int xyModemAbort(void) { xy.userAbort = -1;};int init_xmodem_dld(void) { InitCRC16(); /* init the CRC 16 table */ /* non of these are certain yet, each of these setting implies a lower protocol */#ifdef CONFIG_XYMODEM_CRC xy.crc = -1;#else xy.crc = 0;#endif#ifdef CONFIG_XYMODEM_CRC xy.longPacket = -1;#else xy.longPacket = 0;#endif xy.batch = 0;#ifdef CONFIG_XYMODEM_G xy.g = -1;#else xy.g = 0;#endif xy.timeout = GET_BYTE_TIMEOUT; xy.retries = RETRIES; xy.userAbort = 0; xy.packetNumber = 0; xy.fileLength = 0; xy.transferred = 0; xy.err = xyOK; memset(errorCounts, 0, sizeof(errorCounts)); return ( xyOK );}void cleanup_xmodem_dld(void) {}dword xymodem_receive(dword dldaddr, dword img_size){ if (init_xmodem_dld() == xyOK) { /* do the init stuff */ putstr("ready for xmodem download..\r\n"); xyReceiveFile(dldaddr, img_size); if (xy.err == xyOK) { putstr("Download Successful\r\n"); } else { putstr("\r\n"); putstr("Download Failed!\r\n"); xyDisplayMsg(); putLabeledWord("Packets=", errorCounts[xyOK]); putLabeledWord("Malfunctions=", errorCounts[xyMalfunctioned]); putLabeledWord("Failed=", errorCounts[xyFailed]); putLabeledWord("BadPackets=", errorCounts[xyBadPacket]); putLabeledWord("EndOfText=", errorCounts[xyEOT]); putLabeledWord("EndOfSession=", errorCounts[xyEndOfSession]); putLabeledWord("Timeout=", errorCounts[xyTimeout]); putLabeledWord("Transmissions=", errorCounts[xyTransmission]); putLabeledWord("SerialErrors=", errorCounts[xySerial]); putLabeledWord("BufferOverflows=", errorCounts[xyBuffer]); xy.transferred = 0; /* return failure */ } cleanup_xmodem_dld(); /* do the cleanup stuff */ } return xy.transferred;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -