Sistema l'errore da me commesso in fase di conversione...
[bertos.git] / mware / xmodem.c
old mode 100755 (executable)
new mode 100644 (file)
index 5861ac9..5f4c12f
-/*!
+/**
  * \file
  * <!--
- * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2004, 2005, 2006, 2007 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.
+ * 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 <bernie@develer.com>
+ * \author Francesco Sacchi <batt@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().
- *
- * 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.
- *
- */
+/*#*
+ *#* $Log$
+ *#* Revision 1.12  2007/10/05 09:14:15  batt
+ *#* Fix some debug strings; suppress warning if XM_BUFSIZE < 1024.
+ *#*
+ *#* Revision 1.11  2007/06/07 09:10:44  batt
+ *#* Fix some todos.
+ *#*
+ *#* Revision 1.10  2006/07/19 12:56:28  bernie
+ *#* Convert to new Doxygen style.
+ *#*
+ *#* 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 <appconfig.h>
+#include <string.h> /* for memset() */
 #include <drv/ser.h>
-#include <drv/lcd.h>
-#include <drv/buzzer.h>
-#include <mware/crc.h>
-#include <mware/kfile.h>
+#include <algos/crc.h>
+#include <cfg/debug.h>
 
-#include <string.h> /* 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 +118,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 +141,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 +160,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 +202,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 +219,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 +239,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 +250,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 +260,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 +268,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 +284,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 +298,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 +307,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 +382,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 +409,7 @@ bool xmodem_send(KFile *fd)
 
                if (!size)
                {
-                       ser_putchar(XM_EOT);
+                       ser_putchar(XM_EOT, port);
                        continue;
                }
 
@@ -415,16 +417,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 +440,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