Fix header name.
[bertos.git] / mware / xmodem.c
index 5861ac9acc9a07890116d1d462c3c9e1b13ec04b..2b9651dfc5973dff8c10742317719ce500f89d28 100755 (executable)
@@ -1,38 +1,65 @@
+#error This module has not been revised for the API changes in several DevLib modules
 /*!
  * \file
  * <!--
  * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
  * Copyright 1999, 2001 Bernardo Innocenti <bernie@develer.com>
- * This file is part of DevLib - See devlib/README for information.
+ * This file is part of DevLib - See README.devlib for information.
  * -->
  * \brief X-Modem serial transmission protocol (implementation)
  *
  * Suppots the CRC-16 and 1K-blocks variants of the standard.
  * \see ymodem.txt for the protocol description.
  *
- * \version $Id$
- * \author Bernardo Innocenti <bernie@develer.com>
- */
-
-/*
- * $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().
+ * \todo Decouple this code from the LCD, buzzer and timer drivers
+ *       introducing user hooks or macros like CHECK_ABORT.
  *
- * Revision 1.3  2004/08/12 23:34:36  bernie
- * Replace if/else with continue to reduce indentation level.
+ * \todo Break xmodem_send() and xmodem_recv() in smaller functions.
  *
- * Revision 1.2  2004/08/12 23:24:07  bernie
- * Rename UPDCRC() to UPDCRC16().
+ * \todo Add CONFIG_* vars to exclude either the receiver or the sender,
+ *       to reduce the footprint for applications that don't need both.
  *
- * Revision 1.1  2004/08/11 19:54:22  bernie
- * Import XModem protocol into DevLib.
+ * \todo Maybe convert drv/ser.c to the KFile interface for symmetry and
+ *       flexibility.
  *
+ * \version $Id$
+ * \author Bernardo Innocenti <bernie@develer.com>
  */
 
+/*#*
+ *#* $Log$
+ *#* Revision 1.9  2005/11/04 16:20:02  bernie
+ *#* Fix reference to README.devlib in header.
+ *#*
+ *#* Revision 1.8  2004/08/25 14:12:09  rasky
+ *#* Aggiornato il comment block dei log RCS
+ *#*
+ *#* Revision 1.7  2004/08/15 06:30:06  bernie
+ *#* Make the buffer a local variable, as documented.
+ *#*
+ *#* Revision 1.6  2004/08/15 05:31:46  bernie
+ *#* Add an #error to spread some FUD about the quality of this module;
+ *#* Add a few TODOs from Rasky's review;
+ *#* Update to the new drv/ser.c API;
+ *#* Move FlushSerial() to drv/ser.c and generalize.
+ *#*
+ *#* 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 <drv/ser.h>
 #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.
+ * Decode serial driver errors and print them on the display.
  */
-static void SerialError(int retries)
+static void print_serial_error(struct Serial *port, int retries)
 {
        serstatus_t err, status;
 
        /* Get serial error code and reset it */
-       status = ser_getstatus();
-       ser_setstatus(0);
+       status = ser_getstatus(port);
+       ser_setstatus(port, 0);
 
        /* Mostra tutti gli errori in sequenza */
        for (err = 0; status != 0; status >>= 1, err++)
@@ -110,21 +132,16 @@ static void SerialError(int retries)
 
 
 /*!
- * Reset previous serial errors and flush the receive buffer
- * (set a short timeout to speed up purge)
+ * \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 (>1KB).
  */
-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;
@@ -137,16 +154,16 @@ bool xmodem_recv(KFile *fd)
        lcd_printf(0, 2, LCD_FILL, "Starting Transfer...");
        lcd_clear();
        purge = true;
-       ser_settimeouts(SER_DEFRXTIMEOUT, SER_DEFTXTIMEOUT);
-       ser_setstatus(0);
+       ser_settimeouts(port, SER_DEFRXTIMEOUT, SER_DEFTXTIMEOUT);
+       ser_setstatus(port, 0);
 
        /* Send initial NAK to start transmission */
        for(;;)
        {
                if (CHECK_ABORT)
                {
-                       ser_putchar(XM_CAN);
-                       ser_putchar(XM_CAN);
+                       ser_putchar(XM_CAN, port);
+                       ser_putchar(XM_CAN, port);
                        lcd_printf(0, 2, LCD_FILL, "Transfer aborted");
                        return false;
                }
@@ -162,13 +179,13 @@ bool xmodem_recv(KFile *fd)
                        if (ser_getstatus())
                                SerialError(retries);
 
-                       FlushSerial();
+                       ser_resync(port, 200);
                        retries++;
 
                        if (retries >= XM_MAXRETRIES)
                        {
-                               ser_putchar(XM_CAN);
-                               ser_putchar(XM_CAN);
+                               ser_putchar(XM_CAN, port);
+                               ser_putchar(XM_CAN, port);
                                lcd_printf(0, 2, LCD_FILL, "Transfer aborted");
                                return false;
                        }
@@ -179,21 +196,21 @@ bool xmodem_recv(KFile *fd)
                                if (retries < XM_MAXCRCRETRIES)
                                {
                                        lcd_printf(0, 2, LCD_FILL, "Request Tx (CRC)");
-                                       ser_putchar(XM_C);
+                                       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);
+                                       ser_putchar(XM_NAK, port);
                                }
                        }
                        else
-                               ser_putchar(XM_NAK);
+                               ser_putchar(XM_NAK, port);
                }
 
-               switch (ser_getchar())
+               switch (ser_getchar(port))
                {
                case XM_STX:  /* Start of header (1024-byte block) */
                        blocksize = 1024;
@@ -204,10 +221,10 @@ bool xmodem_recv(KFile *fd)
 
                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);
                                purge = true;
@@ -234,7 +251,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 +271,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 +282,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;
@@ -299,7 +316,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,7 +330,7 @@ bool xmodem_recv(KFile *fd)
                        break;
 
                case XM_EOT:    /* End of transmission */
-                       ser_putchar(XM_ACK);
+                       ser_putchar(XM_ACK, port);
                        lcd_printf(0, 2, LCD_FILL, "Transfer completed");
                        return true;
 
@@ -330,8 +347,18 @@ bool xmodem_recv(KFile *fd)
 }
 
 
-bool xmodem_send(KFile *fd)
+/*!
+ * \brief Transmit a file 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 (1KB).
+ */
+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;
@@ -339,9 +366,9 @@ bool xmodem_send(KFile *fd)
        uint8_t sum;
 
 
-       ser_settimeouts(SER_DEFRXTIMEOUT, SER_DEFTXTIMEOUT);
-       ser_setstatus(0);
-       FlushSerial();
+       ser_settimeouts(port, SER_DEFRXTIMEOUT, SER_DEFTXTIMEOUT);
+       ser_setstatus(port, 0);
+       ser_purge(port);
        lcd_printf(0, 2, LCD_FILL, "Wait remote host");
 
        for(;;)
@@ -352,7 +379,7 @@ bool xmodem_send(KFile *fd)
                        if (CHECK_ABORT)
                                return false;
 
-                       switch (c = ser_getchar())
+                       switch (c = ser_getchar(port))
                        {
                        case XM_NAK:
                        case XM_C:
@@ -407,7 +434,7 @@ bool xmodem_send(KFile *fd)
 
                if (!size)
                {
-                       ser_putchar(XM_EOT);
+                       ser_putchar(XM_EOT, port);
                        continue;
                }
 
@@ -415,16 +442,16 @@ 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);
+               ser_putchar(XM_STX, port);
+               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 +461,10 @@ 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);
        }
 }