4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2004, 2005, 2006, 2007 Develer S.r.l. (http://www.develer.com/)
30 * Copyright 1999, 2001 Bernardo Innocenti <bernie@develer.com>
33 * \brief X-Modem serial transmission protocol (implementation)
35 * Supports the CRC-16 and 1K-blocks variants of the standard.
36 * \see ymodem.txt for the protocol description.
38 * \todo Break xmodem_send() and xmodem_recv() in smaller functions.
40 * \todo Maybe convert drv/ser.c to the KFile interface for symmetry and
44 * \author Bernardo Innocenti <bernie@develer.com>
45 * \author Francesco Sacchi <batt@develer.com>
50 *#* Revision 1.12 2007/10/05 09:14:15 batt
51 *#* Fix some debug strings; suppress warning if XM_BUFSIZE < 1024.
53 *#* Revision 1.11 2007/06/07 09:10:44 batt
56 *#* Revision 1.10 2006/07/19 12:56:28 bernie
57 *#* Convert to new Doxygen style.
59 *#* Revision 1.9 2005/11/04 16:20:02 bernie
60 *#* Fix reference to README.devlib in header.
62 *#* Revision 1.8 2004/08/25 14:12:09 rasky
63 *#* Aggiornato il comment block dei log RCS
65 *#* Revision 1.7 2004/08/15 06:30:06 bernie
66 *#* Make the buffer a local variable, as documented.
68 *#* Revision 1.6 2004/08/15 05:31:46 bernie
69 *#* Add an #error to spread some FUD about the quality of this module;
70 *#* Add a few TODOs from Rasky's review;
71 *#* Update to the new drv/ser.c API;
72 *#* Move FlushSerial() to drv/ser.c and generalize.
74 *#* Revision 1.5 2004/08/12 23:46:21 bernie
75 *#* Remove extra indentation level in switch statements.
77 *#* Revision 1.4 2004/08/12 23:35:50 bernie
78 *#* Replace a handmade loop with memset().
80 *#* Revision 1.3 2004/08/12 23:34:36 bernie
81 *#* Replace if/else with continue to reduce indentation level.
83 *#* Revision 1.2 2004/08/12 23:24:07 bernie
84 *#* Rename UPDCRC() to UPDCRC16().
86 *#* Revision 1.1 2004/08/11 19:54:22 bernie
87 *#* Import XModem protocol into DevLib.
93 #include <appconfig.h>
94 #include <string.h> /* for memset() */
96 #include <algos/crc.h>
97 #include <cfg/debug.h>
103 * \name Protocol control codes
106 #define XM_SOH 0x01 /**< Start Of Header (128-byte block) */
107 #define XM_STX 0x02 /**< Start Of Header (1024-byte block) */
108 #define XM_EOT 0x04 /**< End Of Transmission */
109 #define XM_ACK 0x06 /**< Acknowledge block */
110 #define XM_NAK 0x15 /**< Negative Acknowledge */
111 #define XM_C 0x43 /**< Request CRC-16 transmission */
112 #define XM_CAN 0x18 /**< CANcel transmission */
115 #define XM_MAXRETRIES 15 /**< Max retries before giving up */
116 #define XM_MAXCRCRETRIES 7 /**< Max retries before switching to BCC */
118 #if CONFIG_XMODEM_1KCRC == 1
119 #define XM_BUFSIZE 1024 /**< 1024 bytes of block buffer */
121 #define XM_BUFSIZE 128 /**< 128 bytes of block buffer */
125 #if CONFIG_XMODEM_RECV
127 * \brief Receive a file using the XModem protocol.
129 * \param port Serial port to use for transfer
130 * \param fd Destination file
132 * \note This function allocates a large amount of stack (\see XM_BUFSIZE).
134 bool xmodem_recv(struct Serial *port, KFile *fd)
136 char block_buffer[XM_BUFSIZE]; /* Buffer to hold a block of data */
138 int blocknr = 0, last_block_done = 0, retries = 0;
146 XMODEM_PROGRESS("Starting Transfer...\n");
148 ser_setstatus(port, 0);
150 /* Send initial NAK to start transmission */
153 if (XMODEM_CHECK_ABORT)
155 ser_putchar(XM_CAN, port);
156 ser_putchar(XM_CAN, port);
157 XMODEM_PROGRESS("Transfer aborted\n");
162 * Discard incoming input until a timeout occurs, then send
163 * a NAK to the transmitter.
169 if (ser_getstatus(port))
170 XMODEM_PROGRESS("Retries %d\n", retries);
172 ser_resync(port, 200);
175 if (retries >= XM_MAXRETRIES)
177 ser_putchar(XM_CAN, port);
178 ser_putchar(XM_CAN, port);
179 XMODEM_PROGRESS("Transfer aborted\n");
183 /* Transmission start? */
186 if (retries < XM_MAXCRCRETRIES)
188 XMODEM_PROGRESS("Request Tx (CRC)\n");
189 ser_putchar(XM_C, port);
193 /* Give up with CRC and fall back to checksum */
195 XMODEM_PROGRESS("Request Tx (BCC)\n");
196 ser_putchar(XM_NAK, port);
200 ser_putchar(XM_NAK, port);
203 switch (ser_getchar(port))
205 #if XM_BUFSIZE >= 1024
206 case XM_STX: /* Start of header (1024-byte block) */
211 case XM_SOH: /* Start of header (128-byte block) */
213 /* Needed to avoid warning if XM_BUFSIZE < 1024 */
216 /* Get block number */
217 c = ser_getchar(port);
219 /* Check complemented block number */
220 if ((~c & 0xff) != ser_getchar(port))
222 XMODEM_PROGRESS("Bad blk (%d)\n", c);
227 /* Determine which block is being sent */
228 if (c == (blocknr & 0xff))
229 /* Last block repeated */
230 XMODEM_PROGRESS("Repeat blk %d\n", blocknr);
231 else if (c == ((blocknr + 1) & 0xff))
233 XMODEM_PROGRESS("Recv blk %d\n", ++blocknr);
237 XMODEM_PROGRESS("Sync lost (%d/%d)\n", c, blocknr);
242 buf = block_buffer; /* Reset pointer to start of buffer */
245 for (i = 0; i < blocksize; i++)
247 if ((c = ser_getchar(port)) == EOF)
253 /* Store in buffer */
256 /* Calculate block checksum or CRC */
258 crc = UPDCRC16(c, crc);
266 /* Get the checksum byte or the CRC-16 MSB */
267 if ((c = ser_getchar(port)) == EOF)
275 crc = UPDCRC16(c, crc);
278 if ((c = ser_getchar(port)) == EOF)
284 crc = UPDCRC16(c, crc);
288 XMODEM_PROGRESS("Bad CRC: %04x\n", crc);
293 /* Compare the checksum */
294 else if (c != checksum)
296 XMODEM_PROGRESS("Bad sum: %04x/%04x\n", checksum, c);
302 * Avoid flushing the same block twice.
303 * This could happen when the sender does not receive our
304 * acknowledge and resends the same block.
306 if (last_block_done < blocknr)
308 /* Call user function to flush the buffer */
309 if (fd->write(fd, block_buffer, blocksize))
311 /* Acknowledge block and clear error counter */
312 ser_putchar(XM_ACK, port);
314 last_block_done = blocknr;
318 /* User callback failed: abort transfer immediately */
319 retries = XM_MAXRETRIES;
325 case XM_EOT: /* End of transmission */
326 ser_putchar(XM_ACK, port);
327 XMODEM_PROGRESS("Transfer completed\n");
330 case EOF: /* Timeout or serial error */
335 XMODEM_PROGRESS("Skipping garbage\n");
344 #if CONFIG_XMODEM_SEND
346 * \brief Transmit some data using the XModem protocol.
348 * \param port Serial port to use for transfer
349 * \param fd Source file
351 * \note This function allocates a large amount of stack for
352 * the XModem transfer buffer (\see XM_BUFSIZE).
354 bool xmodem_send(struct Serial *port, KFile *fd)
356 char block_buffer[XM_BUFSIZE]; /* Buffer to hold a block of data */
358 int blocknr = 1, retries = 0, c, i;
359 bool proceed, usecrc = false;
364 * Reading a block can be very slow, so we read the first block early
365 * to avoid receiving double XM_C char.
366 * This could happen if we check for XM_C and then read the block, giving
367 * the receiving device time to send another XM_C char misinterpretating
370 size = fd->read(fd, block_buffer, XM_BUFSIZE);
372 ser_setstatus(port, 0);
374 XMODEM_PROGRESS("Wait remote host\n");
381 if (XMODEM_CHECK_ABORT)
384 switch (c = ser_getchar(port))
387 XMODEM_PROGRESS("Resend blk %d\n", blocknr);
394 XMODEM_PROGRESS("Tx start (CRC)\n");
398 XMODEM_PROGRESS("Tx start (BCC)\n");
404 /* End of transfer? */
408 /* Call user function to read in one block */
409 size = fd->read(fd, block_buffer, XM_BUFSIZE);
410 XMODEM_PROGRESS("Send blk %d\n", blocknr);
417 ser_setstatus(port, 0);
419 XMODEM_PROGRESS("Retries %d\n", retries);
420 if (retries <= XM_MAXRETRIES)
422 /* falling through! */
425 XMODEM_PROGRESS("Transfer aborted\n");
429 XMODEM_PROGRESS("Skipping garbage\n");
437 ser_putchar(XM_EOT, port);
441 /* Pad block with 0xFF if it's partially full */
442 memset(block_buffer + size, 0xFF, XM_BUFSIZE - size);
444 /* Send block header (STX, blocknr, ~blocknr) */
445 #if XM_BUFSIZE == 128
446 ser_putchar(XM_SOH, port);
448 ser_putchar(XM_STX, port);
450 ser_putchar(blocknr & 0xFF, port);
451 ser_putchar(~blocknr & 0xFF, port);
453 /* Send block and compute its CRC/checksum */
456 for (i = 0; i < XM_BUFSIZE; i++)
458 ser_putchar(block_buffer[i], port);
459 crc = UPDCRC16(block_buffer[i], crc);
460 sum += block_buffer[i];
463 /* Send CRC/Checksum */
466 crc = UPDCRC16(0, crc);
467 crc = UPDCRC16(0, crc);
468 ser_putchar(crc >> 8, port);
469 ser_putchar(crc & 0xFF, port);
472 ser_putchar(sum, port);