X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=mware%2Fxmodem.c;h=030783d36369d17649c8523e5268fbb339df37d2;hb=45add65abd59bd79f528501c85f3e5891a9c2c29;hp=5861ac9acc9a07890116d1d462c3c9e1b13ec04b;hpb=b329fe228f081ec0d011874dfb3774e515648053;p=bertos.git diff --git a/mware/xmodem.c b/mware/xmodem.c old mode 100755 new mode 100644 index 5861ac9a..030783d3 --- a/mware/xmodem.c +++ b/mware/xmodem.c @@ -1,130 +1,97 @@ -/*! +/** * \file * * \brief X-Modem serial transmission protocol (implementation) * - * Suppots the CRC-16 and 1K-blocks variants of the standard. + * Supports the CRC-16 and 1K-blocks variants of the standard. * \see ymodem.txt for the protocol description. * + * \todo Break xmodem_send() and xmodem_recv() in smaller functions. + * + * \todo Maybe convert drv/ser.c to the KFile interface for symmetry and + * flexibility. + * * \version $Id$ * \author Bernardo Innocenti + * \author Francesco Sacchi */ -/* - * $Log$ - * Revision 1.5 2004/08/12 23:46:21 bernie - * Remove extra indentation level in switch statements. - * - * Revision 1.4 2004/08/12 23:35:50 bernie - * Replace a handmade loop with memset(). - * - * Revision 1.3 2004/08/12 23:34:36 bernie - * Replace if/else with continue to reduce indentation level. - * - * Revision 1.2 2004/08/12 23:24:07 bernie - * Rename UPDCRC() to UPDCRC16(). - * - * Revision 1.1 2004/08/11 19:54:22 bernie - * Import XModem protocol into DevLib. - * - */ #include "xmodem.h" +#include +#include /* for memset() */ #include -#include -#include -#include -#include +#include +#include + -#include /* for memset() */ -/*! +/** * \name Protocol control codes * \{ */ -#define XM_SOH 0x01 /*!< Start Of Header (128-byte block) */ -#define XM_STX 0x02 /*!< Start Of Header (1024-byte block) */ -#define XM_EOT 0x04 /*!< End Of Transmission */ -#define XM_ACK 0x06 /*!< Acknowledge block */ -#define XM_NAK 0x15 /*!< Negative Acknowledge */ -#define XM_C 0x43 /*!< Request CRC-16 transmission */ -#define XM_CAN 0x18 /*!< CANcel transmission */ +#define XM_SOH 0x01 /**< Start Of Header (128-byte block) */ +#define XM_STX 0x02 /**< Start Of Header (1024-byte block) */ +#define XM_EOT 0x04 /**< End Of Transmission */ +#define XM_ACK 0x06 /**< Acknowledge block */ +#define XM_NAK 0x15 /**< Negative Acknowledge */ +#define XM_C 0x43 /**< Request CRC-16 transmission */ +#define XM_CAN 0x18 /**< CANcel transmission */ /*\}*/ -#define XM_MAXRETRIES 15 /*!< Max retries before giving up */ -#define XM_MAXCRCRETRIES 7 /*!< Max retries before switching to BCC */ -#define XM_BUFSIZE 1024 /*!< Size of block buffer */ - +#define XM_MAXRETRIES 15 /**< Max retries before giving up */ +#define XM_MAXCRCRETRIES 7 /**< Max retries before switching to BCC */ -#if (ARCH & ARCH_BOOT) - #include "kbdhw.h" - #if (ARCH & ARCH_SLIM) - #define CHECK_ABORT KEYPRESSED_STOP - #elif (ARCH & ARCH_SARF) - #define CHECK_ABORT KEYPRESSED_ESC - #endif +#if CONFIG_XMODEM_1KCRC == 1 + #define XM_BUFSIZE 1024 /**< 1024 bytes of block buffer */ #else - #include "kbd.h" - #if (ARCH & ARCH_SLIM) - #define CHECK_ABORT (kbd_getchar() == K_STOP) - #elif (ARCH & ARCH_SARF) - #define CHECK_ABORT (kbd_getchar() == K_ESC) - #endif -#endif /* ARCH_BOOT */ - - -/*! Buffer to hold a block of data */ -static char block_buffer[XM_BUFSIZE]; - - -/*! - * Decode serial driver errors and print - * them on the display. - */ -static void SerialError(int retries) -{ - serstatus_t err, status; - - /* Get serial error code and reset it */ - status = ser_getstatus(); - ser_setstatus(0); - - /* Mostra tutti gli errori in sequenza */ - for (err = 0; status != 0; status >>= 1, err++) - { - /* Se il bit dell'errore e' settato */ - if (status & 1) - { - lcd_printf(0, 3, LCD_FILL, "%s %d", serial_errors[err], retries); - buz_beep(200); - timer_delay(500); - } - } -} + #define XM_BUFSIZE 128 /**< 128 bytes of block buffer */ +#endif -/*! - * Reset previous serial errors and flush the receive buffer - * (set a short timeout to speed up purge) +#if CONFIG_XMODEM_RECV +/** + * \brief Receive a file using the XModem protocol. + * + * \param port Serial port to use for transfer + * \param fd Destination file + * + * \note This function allocates a large amount of stack (\see XM_BUFSIZE). */ -static void FlushSerial(void) -{ - ser_setstatus(0); - ser_settimeouts(200, SER_DEFTXTIMEOUT); - while (ser_getchar() != EOF) {} - ser_settimeouts(SER_DEFRXTIMEOUT, SER_DEFTXTIMEOUT); - ser_setstatus(0); -} - - -bool xmodem_recv(KFile *fd) +bool xmodem_recv(struct Serial *port, KFile *fd) { + char block_buffer[XM_BUFSIZE]; /* Buffer to hold a block of data */ int c, i, blocksize; int blocknr = 0, last_block_done = 0, retries = 0; char *buf; @@ -134,20 +101,18 @@ bool xmodem_recv(KFile *fd) bool usecrc = true; - lcd_printf(0, 2, LCD_FILL, "Starting Transfer..."); - lcd_clear(); + XMODEM_PROGRESS("Starting Transfer...\n"); purge = true; - ser_settimeouts(SER_DEFRXTIMEOUT, SER_DEFTXTIMEOUT); - ser_setstatus(0); + ser_setstatus(port, 0); /* Send initial NAK to start transmission */ for(;;) { - if (CHECK_ABORT) + if (XMODEM_CHECK_ABORT) { - ser_putchar(XM_CAN); - ser_putchar(XM_CAN); - lcd_printf(0, 2, LCD_FILL, "Transfer aborted"); + ser_putchar(XM_CAN, port); + ser_putchar(XM_CAN, port); + XMODEM_PROGRESS("Transfer aborted\n"); return false; } @@ -159,17 +124,17 @@ bool xmodem_recv(KFile *fd) { purge = false; - if (ser_getstatus()) - SerialError(retries); + if (ser_getstatus(port)) + XMODEM_PROGRESS("Retries %d\n", retries); - FlushSerial(); + ser_resync(port, 200); retries++; if (retries >= XM_MAXRETRIES) { - ser_putchar(XM_CAN); - ser_putchar(XM_CAN); - lcd_printf(0, 2, LCD_FILL, "Transfer aborted"); + ser_putchar(XM_CAN, port); + ser_putchar(XM_CAN, port); + XMODEM_PROGRESS("Transfer aborted\n"); return false; } @@ -178,38 +143,41 @@ bool xmodem_recv(KFile *fd) { if (retries < XM_MAXCRCRETRIES) { - lcd_printf(0, 2, LCD_FILL, "Request Tx (CRC)"); - ser_putchar(XM_C); + XMODEM_PROGRESS("Request Tx (CRC)\n"); + ser_putchar(XM_C, port); } else { /* Give up with CRC and fall back to checksum */ usecrc = false; - lcd_printf(0, 2, LCD_FILL, "Request Tx (BCC)"); - ser_putchar(XM_NAK); + XMODEM_PROGRESS("Request Tx (BCC)\n"); + ser_putchar(XM_NAK, port); } } else - ser_putchar(XM_NAK); + ser_putchar(XM_NAK, port); } - switch (ser_getchar()) + switch (ser_getchar(port)) { + #if XM_BUFSIZE >= 1024 case XM_STX: /* Start of header (1024-byte block) */ blocksize = 1024; goto getblock; + #endif case XM_SOH: /* Start of header (128-byte block) */ blocksize = 128; - + /* Needed to avoid warning if XM_BUFSIZE < 1024 */ + goto getblock; getblock: /* Get block number */ - c = ser_getchar(); + c = ser_getchar(port); /* Check complemented block number */ - if ((~c & 0xff) != ser_getchar()) + if ((~c & 0xff) != ser_getchar(port)) { - lcd_printf(0, 3, LCD_FILL, "Bad blk (%d)", c); + XMODEM_PROGRESS("Bad blk (%d)\n", c); purge = true; break; } @@ -217,14 +185,14 @@ bool xmodem_recv(KFile *fd) /* Determine which block is being sent */ if (c == (blocknr & 0xff)) /* Last block repeated */ - lcd_printf(0, 2, LCD_FILL, "Repeat blk %d", blocknr); + XMODEM_PROGRESS("Repeat blk %d\n", blocknr); else if (c == ((blocknr + 1) & 0xff)) /* Next block */ - lcd_printf(0, 2, LCD_FILL, "Recv blk %d", ++blocknr); + XMODEM_PROGRESS("Recv blk %d\n", ++blocknr); else { /* Sync lost */ - lcd_printf(0, 3, LCD_FILL, "Sync lost (%d/%d)", c, blocknr); + XMODEM_PROGRESS("Sync lost (%d/%d)\n", c, blocknr); purge = true; break; } @@ -234,7 +202,7 @@ bool xmodem_recv(KFile *fd) crc = 0; for (i = 0; i < blocksize; i++) { - if ((c = ser_getchar()) == EOF) + if ((c = ser_getchar(port)) == EOF) { purge = true; break; @@ -254,7 +222,7 @@ bool xmodem_recv(KFile *fd) break; /* Get the checksum byte or the CRC-16 MSB */ - if ((c = ser_getchar()) == EOF) + if ((c = ser_getchar(port)) == EOF) { purge = true; break; @@ -265,7 +233,7 @@ bool xmodem_recv(KFile *fd) crc = UPDCRC16(c, crc); /* Get CRC-16 LSB */ - if ((c = ser_getchar()) == EOF) + if ((c = ser_getchar(port)) == EOF) { purge = true; break; @@ -275,7 +243,7 @@ bool xmodem_recv(KFile *fd) if (crc) { - lcd_printf(0, 3, LCD_FILL, "Bad CRC: %04x", crc); + XMODEM_PROGRESS("Bad CRC: %04x\n", crc); purge = true; break; } @@ -283,7 +251,7 @@ bool xmodem_recv(KFile *fd) /* Compare the checksum */ else if (c != checksum) { - lcd_printf(0, 3, LCD_FILL, "Bad sum: %04x/%04x", checksum, c); + XMODEM_PROGRESS("Bad sum: %04x/%04x\n", checksum, c); purge = true; break; } @@ -299,7 +267,7 @@ bool xmodem_recv(KFile *fd) if (fd->write(fd, block_buffer, blocksize)) { /* Acknowledge block and clear error counter */ - ser_putchar(XM_ACK); + ser_putchar(XM_ACK, port); retries = 0; last_block_done = blocknr; } @@ -313,8 +281,8 @@ bool xmodem_recv(KFile *fd) break; case XM_EOT: /* End of transmission */ - ser_putchar(XM_ACK); - lcd_printf(0, 2, LCD_FILL, "Transfer completed"); + ser_putchar(XM_ACK, port); + XMODEM_PROGRESS("Transfer completed\n"); return true; case EOF: /* Timeout or serial error */ @@ -322,55 +290,71 @@ bool xmodem_recv(KFile *fd) break; default: - lcd_printf(0, 3, LCD_FILL, "Skipping garbage"); + XMODEM_PROGRESS("Skipping garbage\n"); purge = true; break; } } /* End forever */ } +#endif -bool xmodem_send(KFile *fd) +#if CONFIG_XMODEM_SEND +/** + * \brief Transmit some data using the XModem protocol. + * + * \param port Serial port to use for transfer + * \param fd Source file + * + * \note This function allocates a large amount of stack for + * the XModem transfer buffer (\see XM_BUFSIZE). + */ +bool xmodem_send(struct Serial *port, KFile *fd) { + char block_buffer[XM_BUFSIZE]; /* Buffer to hold a block of data */ size_t size = -1; int blocknr = 1, retries = 0, c, i; bool proceed, usecrc = false; uint16_t crc; uint8_t sum; + /* + * Reading a block can be very slow, so we read the first block early + * to avoid receiving double XM_C char. + * This could happen if we check for XM_C and then read the block, giving + * the receiving device time to send another XM_C char misinterpretating + * the blocks sent. + */ + size = fd->read(fd, block_buffer, XM_BUFSIZE); - ser_settimeouts(SER_DEFRXTIMEOUT, SER_DEFTXTIMEOUT); - ser_setstatus(0); - FlushSerial(); - lcd_printf(0, 2, LCD_FILL, "Wait remote host"); + ser_setstatus(port, 0); + ser_purge(port); + XMODEM_PROGRESS("Wait remote host\n"); for(;;) { proceed = false; do { - if (CHECK_ABORT) + if (XMODEM_CHECK_ABORT) return false; - switch (c = ser_getchar()) + switch (c = ser_getchar(port)) { case XM_NAK: + XMODEM_PROGRESS("Resend blk %d\n", blocknr); + proceed = true; + break; + case XM_C: - if (blocknr == 1) + if (c == XM_C) { - if (c == XM_C) - { - lcd_printf(0, 2, LCD_FILL, "Tx start (CRC)"); - usecrc = true; - } - else - lcd_printf(0, 2, LCD_FILL, "Tx start (BCC)"); - - /* Call user function to read in one block */ - size = fd->read(fd, block_buffer, XM_BUFSIZE); + XMODEM_PROGRESS("Tx start (CRC)\n"); + usecrc = true; } else - lcd_printf(0, 2, LCD_FILL, "Resend blk %d", blocknr); + XMODEM_PROGRESS("Tx start (BCC)\n"); + proceed = true; break; @@ -381,25 +365,26 @@ bool xmodem_send(KFile *fd) /* Call user function to read in one block */ size = fd->read(fd, block_buffer, XM_BUFSIZE); + XMODEM_PROGRESS("Send blk %d\n", blocknr); blocknr++; retries = 0; proceed = true; - lcd_printf(0, 2, LCD_FILL, "Send blk %d", blocknr); break; case EOF: + ser_setstatus(port, 0); retries++; - SerialError(retries); + XMODEM_PROGRESS("Retries %d\n", retries); if (retries <= XM_MAXRETRIES) break; /* falling through! */ case XM_CAN: - lcd_printf(0, 2, LCD_FILL, "Transfer aborted"); + XMODEM_PROGRESS("Transfer aborted\n"); return false; default: - lcd_printf(0, 3, LCD_FILL, "Skipping garbage"); + XMODEM_PROGRESS("Skipping garbage\n"); break; } } @@ -407,7 +392,7 @@ bool xmodem_send(KFile *fd) if (!size) { - ser_putchar(XM_EOT); + ser_putchar(XM_EOT, port); continue; } @@ -415,16 +400,20 @@ bool xmodem_send(KFile *fd) memset(block_buffer + size, 0xFF, XM_BUFSIZE - size); /* Send block header (STX, blocknr, ~blocknr) */ - ser_putchar(XM_STX); - ser_putchar(blocknr & 0xFF); - ser_putchar(~blocknr & 0xFF); + #if XM_BUFSIZE == 128 + ser_putchar(XM_SOH, port); + #else + ser_putchar(XM_STX, port); + #endif + ser_putchar(blocknr & 0xFF, port); + ser_putchar(~blocknr & 0xFF, port); /* Send block and compute its CRC/checksum */ sum = 0; crc = 0; for (i = 0; i < XM_BUFSIZE; i++) { - ser_putchar(block_buffer[i]); + ser_putchar(block_buffer[i], port); crc = UPDCRC16(block_buffer[i], crc); sum += block_buffer[i]; } @@ -434,10 +423,11 @@ bool xmodem_send(KFile *fd) { crc = UPDCRC16(0, crc); crc = UPDCRC16(0, crc); - ser_putchar(crc >> 8); - ser_putchar(crc & 0xFF); + ser_putchar(crc >> 8, port); + ser_putchar(crc & 0xFF, port); } else - ser_putchar(sum); + ser_putchar(sum, port); } } +#endif