diff options
Diffstat (limited to 'apps/system/zmodem/zm_proto.c')
-rw-r--r-- | apps/system/zmodem/zm_proto.c | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/apps/system/zmodem/zm_proto.c b/apps/system/zmodem/zm_proto.c new file mode 100644 index 000000000..4ef1c143d --- /dev/null +++ b/apps/system/zmodem/zm_proto.c @@ -0,0 +1,499 @@ +/**************************************************************************** + * system/zmodem/zm_proto.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * References: + * "The ZMODEM Inter Application File Transfer Protocol", Chuck Forsberg, + * Omen Technology Inc., October 14, 1988 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <crc16.h> +#include <crc32.h> + +#include "zm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Paragraph 8.4. Session Abort Sequence + * + * "If the receiver is receiving data in streaming mode, the Attn sequence + * is executed to interrupt data transmission before the Cancel sequence is + * sent. The Cancel sequence consists of eight CAN characters and ten + * backspace characters. ZMODEM only requires five Cancel characters, the + * other three are "insurance". + * + * "The trailing backspace characters attempt to erase the effects of the + * CAN characters if they are received by a command interpreter. + */ + +#define CANISTR_SIZE (8+10) + +const uint8_t g_canistr[CANISTR_SIZE] = +{ + /* Eight CAN characters */ + + ASCII_CAN, ASCII_CAN, ASCII_CAN, ASCII_CAN, ASCII_CAN, ASCII_CAN, + ASCII_CAN, ASCII_CAN, + + /* Ten backspace characters */ + + ASCII_BS, ASCII_BS, ASCII_BS, ASCII_BS, ASCII_BS, ASCII_BS, + ASCII_BS, ASCII_BS, ASCII_BS, ASCII_BS +}; + +/**************************************************************************** + * Public Function Protypes + ****************************************************************************/ + +/**************************************************************************** + * Name: zm_putzdle + * + * Description: + * Transfer a value to a buffer performing ZDLE escaping if necessary. + * + * Input Parameters: + * pzm - Zmodem session state + * buffer - Buffer in which to add the possibly escaped character + * ch - The raw, unescaped character to be added + * + ****************************************************************************/ + +FAR uint8_t *zm_putzdle(FAR struct zm_state_s *pzm, FAR uint8_t *buffer, + uint8_t ch) +{ + uint8_t ch7 = ch & 0x7f; + + /* Check if this character requires ZDLE escaping. + * + * The Zmodem protocol requires that CAN(ZDLE), DLE, XON, XOFF and a CR + * following '@' be escaped. + */ + + if (ch == ZDLE || + ch7 == ASCII_DLE || + ch7 == ASCII_DC1 || + ch7 == ASCII_DC3 || + ch7 == ASCII_GS || + (ch7 == '\r' && (pzm->flags & ZM_FLAG_ATSIGN) != 0) || + (ch7 < ' ' && (pzm->flags & ZM_FLAG_ESCCTRL) != 0) || + ch7 == ASCII_DEL || + ch == 0xff + ) + { + /* Yes... save the data link escape the character */ + + *buffer++ = ZDLE; + + /* And modify the character itself as appropriate */ + + if (ch == ASCII_DEL) + { + ch = ZRUB0; + } + else if (ch == 0xff) + { + ch = ZRUB1; + } + else + { + ch ^= 0x40; + } + } + + /* Save the possibly escaped character */ + + *buffer++ = ch; + + /* Check if the character is the AT sign */ + + if (ch7 == '@') + { + pzm->flags |= ZM_FLAG_ATSIGN; + } + else + { + pzm->flags &= ~ZM_FLAG_ATSIGN; + } + + return buffer; +} + +/**************************************************************************** + * Name: zm_senddata + * + * Description: + * Send data to the remote peer performing CRC operations as required + * (ZBIN or ZBIN32 format assumed, ZCRCW terminator is always used) + * + * Input Parameters: + * pzm - Zmodem session state + * buffer - Buffer of data to be sent (must not be pzm->rcvbuf) + * buflen - The number of bytes in buffer to be sent + * + ****************************************************************************/ + +int zm_senddata(FAR struct zm_state_s *pzm, FAR const uint8_t *buffer, + size_t buflen) +{ + uint8_t *ptr = pzm->rcvbuf; + ssize_t nwritten; + uint32_t crc; + uint8_t zbin; + uint8_t term; + + /* Make select ZBIN or ZBIN32 format and the ZCRCW terminator */ + + if ((pzm->flags & ZM_FLAG_CRC32) != 0) + { + zbin = ZBIN32; + } + else + { + zbin = ZBIN; + } + + term = ZCRCW; + zmdbg("zbin=%c, buflen=%d, term=%c\n", zbin, buflen, term); + + /* Transfer the data to the I/O buffer, accumulating the CRC */ + + crc = (zbin == ZBIN) ? 0 : 0xffffffff; + while (buflen-- > 0) + { + if (zbin == ZBIN) + { + crc = (uint32_t)crc16part(buffer, 1, (uint16_t)crc); + } + else /* zbin = ZBIN32 */ + { + crc = crc32part(buffer, 1, crc); + } + + ptr = zm_putzdle(pzm, ptr, *buffer++); + } + + /* Trasnfer the data link escape character (without updating the CRC) */ + + *ptr++ = ZDLE; + + /* Transfer the terminating character, updating the CRC */ + + if (zbin == ZBIN) + { + crc = (uint32_t)crc16part((FAR const uint8_t *)&term, 1, (uint16_t)crc); + } + else + { + crc = crc32part((FAR const uint8_t *)&term, 1, crc); + } + + *ptr++ = term; + + /* Calcualate and transfer the final CRC value */ + + if (zbin == ZBIN) + { + crc = (uint32_t)crc16part(g_zeroes, 2, (uint16_t)crc); + ptr = zm_putzdle(pzm, ptr, (crc >> 8) & 0xff); + ptr = zm_putzdle(pzm, ptr, crc & 0xff); + } + else + { + crc = ~crc; + for (buflen = 4; --buflen >= 0; crc >>= 8) + { + ptr = zm_putzdle(pzm, ptr, crc & 0xff); + } + } + + /* Send the header */ + + nwritten = zm_remwrite(pzm->remfd, pzm->rcvbuf, ptr - pzm->rcvbuf); + return nwritten < 0 ? (int)nwritten : OK; +} + +/**************************************************************************** + * Name: zm_sendhexhdr + * + * Description: + * Send a ZHEX header to the remote peer performing CRC operations as + * necessary. + * + * Hex header: + * ZPAD ZPAD ZDLE ZHEX type f3/p0 f2/p1 f1/p2 f0/p3 crc-1 crc-2 CR LF [XON] + * Payload length: 16 (14 hex digits, cr, lf, ignoring optional XON) + * + * Input Parameters: + * pzm - Zmodem session state + * type - Header type {ZRINIT, ZRQINIT, ZDATA, ZACK, ZNAK, ZCRC, ZRPOS, + * ZCOMPL, ZEOF, ZFIN} + * buffer - 4-byte buffer of data to be sent + * + * Assumptions: + * The allocated I/O buffer is available to buffer file data. + * + ****************************************************************************/ + +int zm_sendhexhdr(FAR struct zm_state_s *pzm, int type, + FAR const uint8_t *buffer) +{ + FAR uint8_t *ptr; + ssize_t nwritten; + uint16_t crc; + int i; + + zmdbg("Sending type %d: %02x %02x %02x %02x\n", + type, buffer[0], buffer[1], buffer[2], buffer[3]); + + /* ZPAD ZPAD ZDLE ZHEX */ + + ptr = pzm->scratch; + *ptr++ = ZPAD; + *ptr++ = ZPAD; + *ptr++ = ZDLE; + *ptr++ = ZHEX; + + /* type */ + + crc = crc16part((FAR const uint8_t *)&type, 1, 0); + ptr = zm_puthex8(ptr, type); + + /* f3/p0 f2/p1 f1/p2 f0/p3 */ + + crc = crc16part(buffer, 4, crc); + for (i = 0; i < 4; i++) + { + ptr = zm_puthex8(ptr, *buffer++); + } + + /* crc-1 crc-2 */ + + crc = crc16part(g_zeroes, 2, crc); + ptr = zm_puthex8(ptr, (crc >> 8) & 0xff); + ptr = zm_puthex8(ptr, crc & 0xff); + + /* CR LF */ + + *ptr++ = '\r'; + *ptr++ = '\n'; + + /* [XON] */ + + if (type != ZACK && type != ZFIN) + { + *ptr++ = ASCII_XON; + } + + /* Send the header */ + + nwritten = zm_remwrite(pzm->remfd, pzm->scratch, ptr - pzm->scratch); + return nwritten < 0 ? (int)nwritten : OK; +} + +/**************************************************************************** + * Name: zm_sendbin16hdr + * + * Description: + * Send a ZBIN header to the remote peer performing CRC operations as + * necessary. Normally called indirectly through zm_sendbinhdr(). + * + * 16-bit binary header: + * ZPAD ZDLE ZBIN type f3/p0 f2/p1 f1/p2 f0/p3 crc-1 crc-2 + * Payload length: 7 (type, 4 bytes data, 2 byte CRC) + * + * Input Parameters: + * pzm - Zmodem session state + * type - Header type {ZSINIT, ZFILE, ZDATA, ZDATA} + * buffer - 4-byte buffer of data to be sent + * + * Assumptions: + * The allocated I/O buffer is available to buffer file data. + * + ****************************************************************************/ + +int zm_sendbin16hdr(FAR struct zm_state_s *pzm, int type, + FAR const uint8_t *buffer) +{ + FAR uint8_t *ptr; + ssize_t nwritten; + uint16_t crc; + int buflen; + int i; + + zmdbg("Sending type %d: %02x %02x %02x %02x\n", + type, buffer[0], buffer[1], buffer[2], buffer[3]); + + /* XPAD ZDLE ZBIN */ + + ptr = pzm->scratch; + *ptr++ = ZPAD; + *ptr++ = ZDLE; + *ptr++ = ZBIN; + + /* type */ + + crc = crc16part((FAR const uint8_t *)&type, 1, 0); + ptr = zm_putzdle(pzm, ptr, type); + + /* f3/p0 f2/p1 f1/p2 f0/p3 */ + + crc = crc16part(buffer, 4, crc); + for (i = 0; i < 4; i++) + { + ptr = zm_putzdle(pzm, ptr, *buffer++); + } + + /* crc-1 crc-2 */ + + crc = crc16part(g_zeroes, 2, crc); + ptr = zm_putzdle(pzm, ptr, (crc >> 8) & 0xff); + ptr = zm_putzdle(pzm, ptr, crc & 0xff); + + /* Send the header */ + + buflen = ptr - pzm->scratch; + nwritten = zm_remwrite(pzm->remfd, pzm->scratch, buflen); + return nwritten < 0 ? (int)nwritten : OK; +} + +/**************************************************************************** + * Name: zm_sendbin32hdr + * + * Description: + * Send a ZBIN32 header to the remote peer performing CRC operations as + * necessary. Normally called indirectly through zm_sendbinhdr(). + * + * 32-bit inary header: + * ZPAD ZDLE ZBIN32 type f3/p0 f2/p1 f1/p2 f0/p3 crc-1 crc-2 crc-3 crc-4 + * Payload length: 9 (type, 4 bytes data, 4 byte CRC) + * + * Input Parameters: + * pzm - Zmodem session state + * type - Header type {ZSINIT, ZFILE, ZDATA, ZDATA} + * buffer - 4-byte buffer of data to be sent + * + * Assumptions: + * The allocated I/O buffer is available to buffer file data. + * + ****************************************************************************/ + +int zm_sendbin32hdr(FAR struct zm_state_s *pzm, int type, + FAR const uint8_t *buffer) +{ + FAR uint8_t *ptr; + ssize_t nwritten; + uint32_t crc; + int buflen; + int i; + + zmdbg("Sending type %d: %02x %02x %02x %02x\n", + type, buffer[0], buffer[1], buffer[2], buffer[3]); + + /* XPAD ZDLE ZBIN32 */ + + ptr = pzm->scratch; + *ptr++ = ZPAD; + *ptr++ = ZDLE; + *ptr++ = ZBIN32; + + /* type */ + + ptr = zm_putzdle(pzm, ptr, type); + crc = crc32part((FAR const uint8_t *)&type, 1, 0xffffffffL); + + /* f3/p0 f2/p1 f1/p2 f0/p3 */ + + crc = crc32part(buffer, 4, crc); + for (i = 0; i < 4; i++) + { + ptr = zm_putzdle(pzm, ptr, *buffer++); + } + + /* crc-1 crc-2 crc-3 crc-4 */ + + crc = ~crc; + for (i = 0; i < 4; i++, crc >>= 8) + { + ptr = zm_putzdle(pzm, ptr, crc & 0xff); + } + + /* Send the header */ + + buflen = ptr - pzm->scratch; + nwritten = zm_remwrite(pzm->remfd, pzm->scratch, buflen); + return nwritten < 0 ? (int)nwritten : OK; +} + +/**************************************************************************** + * Name: zm_sendbinhdr + * + * Description: + * Send a binary header to the remote peer. This is a simple wrapper + * function for zm_sendbin16hdr() and zm_sendbin32hdr(). It decides on + * the correct CRC format and re-directs the call appropriately. + * + * Input Parameters: + * pzm - Zmodem session state + * type - Header type {ZSINIT, ZFILE, ZDATA, ZDATA} + * buffer - 4-byte buffer of data to be sent + * + * Assumptions: + * The allocated I/O buffer is available to buffer file data. + * + ****************************************************************************/ + +int zm_sendbinhdr(FAR struct zm_state_s *pzm, int type, + FAR const uint8_t *buffer) +{ + if ((pzm->flags & ZM_FLAG_CRC32) == 0) + { + return zm_sendbin16hdr(pzm, type, buffer); + } + else + { + return zm_sendbin16hdr(pzm, type, buffer); + } +} |