A few more zmodem files; still missing a few but those are still fragile and like to undergo some resign before they are usable
This commit is contained in:
parent
551af554c0
commit
929de26f6e
@ -38,40 +38,43 @@
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
ifeq ($(WINTOOL),y)
|
||||
INCDIROPT = -w
|
||||
INCDIROPT = -w
|
||||
endif
|
||||
|
||||
# Zmodem sz and rz commands
|
||||
|
||||
PRIORITY = SCHED_PRIORITY_DEFAULT
|
||||
STACKSIZE = 768
|
||||
PRIORITY = SCHED_PRIORITY_DEFAULT
|
||||
STACKSIZE = 768
|
||||
|
||||
ASRCS =
|
||||
CSRCS = sz_main.c rz_main.c
|
||||
ASRCS =
|
||||
|
||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||
CSRCS = sz_main.c
|
||||
CSRCS += rz_main.c
|
||||
CSRCS += zm_proto.c zm_watchdog.c zm_utils.c zm_dumpbuffer.c
|
||||
|
||||
SRCS = $(ASRCS) $(CSRCS)
|
||||
OBJS = $(AOBJS) $(COBJS)
|
||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||
|
||||
SRCS = $(ASRCS) $(CSRCS)
|
||||
OBJS = $(AOBJS) $(COBJS)
|
||||
|
||||
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
|
||||
BIN = ..\..\libapps$(LIBEXT)
|
||||
BIN = ..\..\libapps$(LIBEXT)
|
||||
else
|
||||
ifeq ($(WINTOOL),y)
|
||||
BIN = ..\\..\\libapps$(LIBEXT)
|
||||
BIN = ..\\..\\libapps$(LIBEXT)
|
||||
else
|
||||
BIN = ../../libapps$(LIBEXT)
|
||||
BIN = ../../libapps$(LIBEXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
ROOTDEPPATH = --dep-path .
|
||||
ROOTDEPPATH = --dep-path .
|
||||
|
||||
# Common build
|
||||
|
||||
VPATH =
|
||||
VPATH =
|
||||
|
||||
all: .built
|
||||
all: .built
|
||||
.PHONY: context depend clean distclean
|
||||
|
||||
$(AOBJS): %$(OBJEXT): %.S
|
||||
|
791
system/zmodem/zm.h
Normal file
791
system/zmodem/zm.h
Normal file
@ -0,0 +1,791 @@
|
||||
/****************************************************************************
|
||||
* apps/system/zmodem/zm.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_SYSTEM_XMODEM_ZM_H
|
||||
#define __APPS_SYSTEM_XMODEM_ZM_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/ascii.h>
|
||||
|
||||
#include <apps/zmodem.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* ZModem *******************************************************************/
|
||||
/* Zmodem ZRINIT flags. These bits describe the cababilities of the receiver.
|
||||
* Reference: Paragraph 11.2:
|
||||
*/
|
||||
|
||||
#define CANFDX (1 << 0) /* Rx can send and receive true FDX */
|
||||
#define CANOVIO (1 << 1) /* Rx can receive data during disk I/O */
|
||||
#define CANBRK (1 << 2) /* Rx can send a break signal */
|
||||
#define CANCRY (1 << 3) /* Receiver can decrypt */
|
||||
#define CANLZW (1 << 4) /* Receiver can uncompress */
|
||||
#define CANFC32 (1 << 5) /* Receiver can use 32 bit Frame Check */
|
||||
#define ESCCTL (1 << 6) /* Receiver expects ctl chars to be escaped */
|
||||
#define ESC8 (1 << 7) /* Receiver expects 8th bit to be escaped */
|
||||
|
||||
/* Zmodem ZSINIT flags. These bits describe the capabilities of the sender */
|
||||
|
||||
#define TESCCTL (1 << 6) /* Sender needs control chars escaped */
|
||||
#define TESC8 (1 << 7) /* Sender needs 8th bit escaped. */
|
||||
|
||||
/* ZFILE transfer flags */
|
||||
/* F0 */
|
||||
|
||||
#define ZCBIN 1 /* Binary transfer */
|
||||
#define ZCNL 2 /* Convert NL to local eol convention */
|
||||
#define ZCRESUM 3 /* Resume interrupted xfer or append to file. */
|
||||
|
||||
/* F1 */
|
||||
|
||||
#define ZMNEWL 1 /* Transfer if source newer or longer */
|
||||
#define ZMCRC 2 /* Transfer if different CRC or length */
|
||||
#define ZMAPND 3 /* Append to existing file, if any */
|
||||
#define ZMCLOB 4 /* Replace existing file */
|
||||
#define ZMNEW 5 /* Transfer if source is newer */
|
||||
#define ZMDIFF 6 /* Transfer if dates or lengths different */
|
||||
#define ZMPROT 7 /* Protect: transfer only if dest doesn't exist */
|
||||
#define ZMCHNG 8 /* Change filename if destination exists */
|
||||
#define ZMMASK 0x1f
|
||||
#define ZMSKNOLOC (1 << 7) /* Skip if not present at receiving end */
|
||||
|
||||
/* F2 */
|
||||
|
||||
#define ZTLZW 1 /* lzw compression */
|
||||
#define ZTRLE 3 /* Run-length encoding */
|
||||
|
||||
/* F3 */
|
||||
|
||||
#define ZCANVHDR 1 /* Variable headers ok */
|
||||
#define ZRWOVR 4 /* Byte position for receive window override/256 */
|
||||
#define ZXSPARS 64 /* Encoding for sparse file ops. */
|
||||
|
||||
/* ATTN string special characters. All other characters sent verbose */
|
||||
|
||||
#define ATTNBRK 0xdd /* Send break signal */
|
||||
#define ATTNPSE 0xde /* Pause for one second */
|
||||
|
||||
/* Zmodem header types */
|
||||
|
||||
#define ZRQINIT 0 /* Request receive init */
|
||||
#define ZRINIT 1 /* Receive init */
|
||||
#define ZSINIT 2 /* Send init sequence, define Attn */
|
||||
#define ZACK 3 /* ACK */
|
||||
#define ZFILE 4 /* File name, from sender */
|
||||
#define ZSKIP 5 /* Skip file command, from receiver */
|
||||
#define ZNAK 6 /* Last packet was garbled */
|
||||
#define ZABORT 7 /* Abort */
|
||||
#define ZFIN 8 /* Finish session */
|
||||
#define ZRPOS 9 /* Resume file from this position, from receiver */
|
||||
#define ZDATA 10 /* Data packets to follow, from sender */
|
||||
#define ZEOF 11 /* End of file, from sender */
|
||||
#define ZFERR 12 /* Fatal i/o error, from receiver */
|
||||
#define ZCRC 13 /* Request for file crc, from receiver */
|
||||
#define ZCHALLENGE 14 /* "Send this number back to me", from receiver */
|
||||
#define ZCOMPL 15 /* Request is complete */
|
||||
#define ZCAN 16 /* Other end cancelled with CAN-CAN-CAN-CAN-CAN */
|
||||
#define ZFREECNT 17 /* Request for free bytes on filesystem */
|
||||
#define ZCOMMAND 18 /* Command, from sending program */
|
||||
#define ZSTDERR 19 /* Output this message to stderr */
|
||||
|
||||
/* Zmodem character definitions */
|
||||
|
||||
#define ZDLE ASCII_CAN /* Zmodem escape is CAN */
|
||||
#define ZDLEE (ZDLE^0x40) /* Escaped ZDLE */
|
||||
#define ZPAD '*' /* pad */
|
||||
#define ZBIN 'A' /* 16-bit CRC binary header */
|
||||
#define ZHEX 'B' /* 16-bit CRC hex header */
|
||||
#define ZBIN32 'C' /* 32-bit CRC binary header */
|
||||
#define ZBINR32 'D' /* RLE packed binary frame w/32-bit CRC */
|
||||
#define ZVBIN 'a' /* Alternate ZBIN */
|
||||
#define ZVHEX 'b' /* Alternate ZHEX */
|
||||
#define ZVBIN32 'c' /* Alternate ZBIN32 */
|
||||
#define ZVBINR32 'd' /* Alternate ZBINR32 */
|
||||
#define ZRESC 0x7f /* RLE flag/escape character */
|
||||
|
||||
/* ZDLE escape sequences */
|
||||
|
||||
#define ZCRCE 'h' /* CRC next, frame ends, header follows */
|
||||
#define ZCRCG 'i' /* CRC next, frame continues nonstop */
|
||||
#define ZCRCQ 'j' /* CRC next, send ZACK, frame continues nonstop */
|
||||
#define ZCRCW 'k' /* CRC next, send ZACK, frame ends */
|
||||
#define ZRUB0 'l' /* Translate to 0x7f */
|
||||
#define ZRUB1 'm' /* Translate to 0xff */
|
||||
|
||||
/* Implementation ***********************************************************/
|
||||
/* Zmodem Events (same as frame type + data received and error events) */
|
||||
|
||||
#define ZME_RQINIT ZRQINIT /* Request receive init */
|
||||
#define ZME_RINIT ZRINIT /* Receive init */
|
||||
#define ZME_SINIT ZSINIT /* Send init sequence, define Attn */
|
||||
#define ZME_ACK ZACK /* ACK */
|
||||
#define ZME_FILE ZFILE /* File name, from sender */
|
||||
#define ZME_SKIP ZSKIP /* Skip file command, from receiver */
|
||||
#define ZME_NAK ZNAK /* Last packet was garbled */
|
||||
#define ZME_ABORT ZABORT /* Abort */
|
||||
#define ZME_FIN ZFIN /* Finish session */
|
||||
#define ZME_RPOS ZRPOS /* Resume file from this position, from receiver */
|
||||
#define ZME_DATA ZDATA /* Data packets to follow, from sender */
|
||||
#define ZME_EOF ZEOF /* End of file, from sender */
|
||||
#define ZME_FERR ZFERR /* Fatal i/o error, from receiver */
|
||||
#define ZME_CRC ZCRC /* Request for file CRC, from receiver */
|
||||
#define ZME_CHALLENGE ZCHALLENGE /* "send this number back to me", from receiver */
|
||||
#define ZME_COMPL ZCOMPL /* Request is complete */
|
||||
#define ZME_CAN ZCAN /* Other end cancelled with CAN-CAN-CAN-CAN-CAN */
|
||||
#define ZME_FREECNT ZFREECNT /* Request for free bytes on filesystem */
|
||||
#define ZME_COMMAND ZCOMMAND /* Command, from sending program */
|
||||
#define ZME_STDERR ZSTDERR /* Output this message to stderr */
|
||||
|
||||
#define ZME_DATARCVD 253 /* Data received */
|
||||
#define ZME_TIMEOUT 254 /* Timeout */
|
||||
#define ZME_ERROR 255 /* Protocol error */
|
||||
|
||||
/* Bit values for flags in struct zm_state_s */
|
||||
|
||||
#define ZM_FLAG_CRC32 (1 << 0) /* Use 32-bit CRC */
|
||||
#define ZM_FLAG_CRKOK (1 << 1) /* CRC is okay */
|
||||
#define ZM_FLAG_EOF (1 << 2) /* End of file reached */
|
||||
#define ZM_FLAG_ATSIGN (1 << 3) /* Last char was '@' */
|
||||
#define ZM_FLAG_ESCCTRL (1 << 4) /* Other end requests ctrl chars be escaped */
|
||||
#define ZM_FLAG_ESC (1 << 5) /* Next character is escaped */
|
||||
#define ZM_FLAG_INTERRUPT (1 << 6) /* Received attention signal */
|
||||
#define ZM_FLAG_WAIT (1 << 7) /* Next send should wait */
|
||||
#define ZM_FLAG_APPEND (1 << 8) /* Append to the existing file */
|
||||
#define ZM_FLAG_TIMEOUT (1 << 9) /* A timeout has been detected */
|
||||
|
||||
/* zm_parse() success/error return code definitions:
|
||||
*
|
||||
* < 0 : Transfer terminated due to an error
|
||||
* = 0 : Transfer still in progress
|
||||
* > 0 : Transfer completed successfully
|
||||
*/
|
||||
|
||||
#define ZM_XFRDONE 1 /* Success - Transfer complete */
|
||||
|
||||
/* Debug Definitions ********************************************************/
|
||||
|
||||
/* Non-standard debug selectable with CONFIG_DEBUG_ZMODEM. Debug output goes
|
||||
* to stderr (not syslog). Enabling this kind of debug output if your are
|
||||
* trying to use the console device I/O for file transfer is obviously a bad
|
||||
* idea (unless, perhaps, you redirect stdin and stdout).
|
||||
*
|
||||
* See also CONFIG_SYSTEM_ZMODEM_DUMPBUFFER.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_DEBUG_ZMODEM
|
||||
# define zmprintf(format, arg...) fprintf(stderr, format, ##arg)
|
||||
# define zmdbg(format, arg...) fprintf(stderr, EXTRA_FMT format EXTRA_ARG, ##arg)
|
||||
#else
|
||||
# undef CONFIG_SYSTEM_ZMODEM_DUMPBUFFER
|
||||
# ifdef CONFIG_CPP_HAVE_VARARGS
|
||||
# define zmprintf(x...)
|
||||
# define zmdbg(x...)
|
||||
# else
|
||||
# define zmprintf (void)
|
||||
# define zmdbg (void)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
/* The state of the parser */
|
||||
|
||||
enum parser_state_e
|
||||
{
|
||||
PSTATE_IDLE = 0, /* Nothing in progress */
|
||||
PSTATE_HEADER, /* Parsing a header following ZPAD ZDLE */
|
||||
PSTATE_DATA, /* Sending data */
|
||||
PSTATE_FINISH /* Waiting for termination handshake */
|
||||
};
|
||||
|
||||
/* PSTATE_IDLE substates */
|
||||
|
||||
enum pidle_substate_e
|
||||
{
|
||||
PIDLE_ZPAD = 0, /* Waiting for ZPAD */
|
||||
PIDLE_ZDLE, /* Waiting for ZDLE */
|
||||
PIDLE_ZDLEE /* Waiting for ZDLEE */
|
||||
};
|
||||
|
||||
/* PSTATE_HEADER substates */
|
||||
|
||||
enum pheader_substate_e
|
||||
{
|
||||
PHEADER_FORMAT = 0, /* Waiting for the header format {ZBIN, ZBIN32, ZHEX} */
|
||||
PHEADER_PAYLOAD, /* Waiting for header data {Type Pn/Fn CRC} */
|
||||
PHEADER_LSPAYLOAD, /* Waiting for LS nibble of header data (ZHEX only) */
|
||||
};
|
||||
|
||||
/* PSTATE_DATA substates */
|
||||
|
||||
enum pdata_substate_e
|
||||
{
|
||||
PDATA_READ = 0, /* Waiting for ZDLE <packet type> */
|
||||
PDATA_CRC /* Have the packet type, accumulating the CRC */
|
||||
};
|
||||
|
||||
/* PSTATE_FINISH substates */
|
||||
|
||||
enum pfinish_substate_e
|
||||
{
|
||||
PFINISH_1STO = 0, /* Waiting for first 'O' */
|
||||
PFINISH_2NDO /* Waiting for second 'O' */
|
||||
};
|
||||
|
||||
/* This type describes the method to perform actions at the time of
|
||||
* a state transition.
|
||||
*/
|
||||
|
||||
struct zm_state_s;
|
||||
typedef int (*action_t)(FAR struct zm_state_s *pzm);
|
||||
|
||||
/* State transition table entry. There is one row of the table per possible state.
|
||||
* Each row is a row of all reasonable events for this state and long the the
|
||||
* appropriate state transition and transition action.
|
||||
*/
|
||||
|
||||
struct zm_transition_s
|
||||
{
|
||||
uint8_t type; /* Event (Frame type) */
|
||||
uint8_t next; /* Next state */
|
||||
bool bdiscard; /* TRUE: discard buffered input */
|
||||
action_t action; /* Transition action */
|
||||
};
|
||||
|
||||
/* Common state information. This structure contains all of the top-level
|
||||
* information needed by the common Zmodem receive and transmit parsing.
|
||||
*/
|
||||
|
||||
struct zm_state_s
|
||||
{
|
||||
/* User-provided values ***************************************************/
|
||||
|
||||
/* These file/socket descriptors are used to interact with the remote end */
|
||||
|
||||
int fdin; /* Probably 0 (stdin) */
|
||||
int fdout; /* probably 1 (stdout) */
|
||||
|
||||
/* System internal values *************************************************/
|
||||
|
||||
/* evtable[] is the state transition table that controls the state for this
|
||||
* current action. Different state transitions tables are used for Zmodem
|
||||
* vs. XY modem and for receive and for tansmit.
|
||||
*/
|
||||
|
||||
FAR const struct zm_transition_s * const * evtable;
|
||||
|
||||
/* State information, common fields, plus parser-specific fields.
|
||||
* Notes:
|
||||
* (1) Only valid during parsing.
|
||||
*/
|
||||
|
||||
uint8_t pstate; /* Current parser state */
|
||||
uint8_t psubstate; /* Current parser sub-state (1) */
|
||||
uint8_t state; /* Current transfer state; index into evtable[] */
|
||||
uint8_t timeout; /* Timeout in seconds for incoming data */
|
||||
uint8_t ncrc; /* Number of bytes in CRC: 2 or 4 (1) */
|
||||
uint8_t ncan; /* Number of consecutive CAN chars received (1) */
|
||||
uint8_t hdrfmt; /* Header format {ZBIN, ZBIN32, or ZHEX} */
|
||||
uint8_t hdrndx; /* Index into hdrdata (1) */
|
||||
uint8_t hdrdata[9]; /* 1-byte + 4-byte payload + 2- or 4-byte CRC */
|
||||
uint8_t pkttype; /* Type of data packet {ZCRCW, ZCRCE, ZCRCG, ZCRCQ} */
|
||||
uint16_t rcvlen; /* Number valid bytes in rcvbuf[] */
|
||||
uint16_t rcvndx; /* Index to the next valid bytes in rcvbuf[] (1) */
|
||||
uint16_t pktlen; /* Number valid bytes in pktbuf[] */
|
||||
uint16_t flags; /* See ZM_FLAG_* definitions */
|
||||
uint16_t nerrors; /* Number of data errors */
|
||||
timer_t timer; /* Watchdog timer */
|
||||
int remfd; /* The R/W file descritor used for communication with remote */
|
||||
|
||||
/* Buffers.
|
||||
*
|
||||
* rcvbuf - Data from the remote peer is receive this buffer
|
||||
* pktbuf - un-escaped remote peer data is parsed into this buffer
|
||||
* scratch - Holds data sent to the remote peer. Since the data is this
|
||||
* buffer is short lived, this buffer may also be used for other
|
||||
* scratch purposes.
|
||||
*/
|
||||
|
||||
uint8_t rcvbuf[CONFIG_SYSTEM_ZMODEM_RCVBUFSIZE];
|
||||
uint8_t pktbuf[CONFIG_SYSTEM_ZMODEM_PKTBUFSIZE];
|
||||
uint8_t scratch[CONFIG_SYSTEM_ZMODEM_SNDBUFSIZE];
|
||||
};
|
||||
|
||||
/* Receive state information */
|
||||
|
||||
struct zmr_state_s
|
||||
{
|
||||
/* Common state data ******************************************************/
|
||||
|
||||
struct zm_state_s cmn;
|
||||
|
||||
/* State data unique to the Zmodem receive implementation *****************/
|
||||
|
||||
uint8_t rcaps; /* Receiver capabilities */
|
||||
uint8_t scaps; /* Sender capabilities */
|
||||
uint8_t f0; /* Transfer flag F0 */
|
||||
uint8_t f1; /* Transfer flag F1 */
|
||||
#if 0 /* Not used */
|
||||
uint8_t f2; /* Transfer flag F2 */
|
||||
uint8_t f3; /* Transfer flag F3 */
|
||||
#endif
|
||||
uint8_t pkttype; /* Type of packet */
|
||||
uint8_t ntimeouts; /* Number of timeouts */
|
||||
uint32_t crc; /* Remove file CRC */
|
||||
FAR char *filename; /* Local filename */
|
||||
FAR char *attn; /* Attention string received from remote peer */
|
||||
off_t offset; /* Current file offset */
|
||||
off_t filesize; /* Remote file size */
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_TIMESTAMPS
|
||||
time_t timestamp; /* Remote time stamp */
|
||||
#endif
|
||||
int outfd; /* Local output file descriptor */
|
||||
};
|
||||
|
||||
/* Send state information */
|
||||
|
||||
struct zms_state_s
|
||||
{
|
||||
/* Common state data ******************************************************/
|
||||
|
||||
struct zm_state_s cmn;
|
||||
|
||||
/* State data unique to the Zmodem send implementation ********************/
|
||||
|
||||
uint8_t strtype; /* Streaming type: ZCRCG or ZCRCQ */
|
||||
uint8_t fflags[4]; /* File xfer flags */
|
||||
uint16_t rcvmax; /* Max packet size the remote can receive. */
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_TIMESTAMPS
|
||||
uint32_t timestamp; /* Local file timestamp */
|
||||
#endif
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_SENDATTN
|
||||
FAR char *attn; /* Attention string */
|
||||
#endif
|
||||
FAR const char *filename; /* Local filename */
|
||||
FAR const char *rfilename; /* Remote filename */
|
||||
off_t offset; /* Current file offset */
|
||||
off_t lastoffs; /* Last acknowledged file offset */
|
||||
off_t zrpos; /* Last offset from ZRPOS */
|
||||
off_t filesize; /* Size of the file to send */
|
||||
int infd; /* Local input file descriptor */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* A handy sequence of 4 zeros */
|
||||
|
||||
EXTERN const uint8_t g_zeroes[4];
|
||||
|
||||
/* 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)
|
||||
|
||||
EXTERN const uint8_t g_canistr[CANISTR_SIZE];
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_bytobe32
|
||||
*
|
||||
* Description:
|
||||
* Convert a sequence of four bytes into a 32-bit value. The byte
|
||||
* sequence is assumed to be big-endian.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t zm_bytobe32(FAR const uint8_t *val8);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_bytobe32
|
||||
*
|
||||
* Description:
|
||||
* Convert a 32-bit value in a sequence of four bytes in big-endian byte
|
||||
* order.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void zm_be32toby(uint32_t val32, FAR uint8_t *val8);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_encnibble
|
||||
*
|
||||
* Description:
|
||||
* Encode an 4-bit binary value to a single hex "digit".
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
char zm_encnibble(uint8_t nibble);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_encnibble
|
||||
*
|
||||
* Description:
|
||||
* Decode an 4-bit binary value from a single hex "digit".
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t zm_decnibble(char hex);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_puthex8
|
||||
*
|
||||
* Description:
|
||||
* Convert an 8-bit binary value to 2 hex "digits".
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR uint8_t *zm_puthex8(FAR uint8_t *ptr, uint8_t ch);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_read
|
||||
*
|
||||
* Description:
|
||||
* Read a buffer of data from a read-able stream.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t zm_read(int fd, FAR uint8_t *buffer, size_t buflen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_getc
|
||||
*
|
||||
* Description:
|
||||
* Read a one byte of data from a read-able stream.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_getc(int fd);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_write
|
||||
*
|
||||
* Description:
|
||||
* Write a buffer of data to a write-able stream.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t zm_write(int fd, FAR const uint8_t *buffer, size_t buflen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_remwrite
|
||||
*
|
||||
* Description:
|
||||
* Write a buffer of data to the remote peer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_DUMPBUFFER
|
||||
ssize_t zm_remwrite(int fd, FAR const uint8_t *buffer, size_t buflen);
|
||||
#else
|
||||
# define zm_remwrite(f,b,s) zm_write(f,b,s)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_writefile
|
||||
*
|
||||
* Description:
|
||||
* Write a buffer of data to file, performing newline conversions as
|
||||
* necessary.
|
||||
*
|
||||
* NOTE: Not re-entrant. CR-LF sequences that span buffer boundaries are
|
||||
* not guaranteed to to be handled correctly.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_writefile(int fd, FAR const uint8_t *buffer, size_t buflen, bool zcnl);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_filecrc
|
||||
*
|
||||
* Description:
|
||||
* Perform CRC32 calculation on a file.
|
||||
*
|
||||
* Assumptions:
|
||||
* The allocated I/O buffer is available to buffer file data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t zm_filecrc(FAR struct zm_state_s *pzm, FAR const char *filename);
|
||||
|
||||
/****************************************************************************
|
||||
* 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);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_senddata
|
||||
*
|
||||
* Description:
|
||||
* Send data to the remote peer performing CRC operations as necessary
|
||||
* (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);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_sendhexhdr
|
||||
*
|
||||
* Description:
|
||||
* Send a ZHEX header to the remote peer performing CRC operations as
|
||||
* necessary.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_sendbin16hdr
|
||||
*
|
||||
* Description:
|
||||
* Send a ZBIN header to the remote peer performing CRC operations as
|
||||
* necessary. Normally called indirectly through zm_sendbinhdr().
|
||||
*
|
||||
* 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);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_sendbin32hdr
|
||||
*
|
||||
* Description:
|
||||
* Send a ZBIN32 header to the remote peer performing CRC operations as
|
||||
* necessary. Normally called indirectly through zm_sendbinhdr().
|
||||
*
|
||||
* 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);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_sendbinhdr
|
||||
*
|
||||
* Description:
|
||||
* Send a binary header to the remote peer. This is a simple wrapping
|
||||
* 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);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_parse
|
||||
*
|
||||
* Description:
|
||||
* New data from the remote peer is available in pzm->rcvbuf. The number
|
||||
* number of bytes of new data is given by rcvlen.
|
||||
*
|
||||
* This function will parse the data in the buffer and, based on the
|
||||
* current state and the contents of the buffer, will drive the Zmodem
|
||||
* state machine.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_parse(FAR struct zm_state_s *pzm, size_t rcvlen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_readstate
|
||||
*
|
||||
* Description:
|
||||
* Enter PSTATE_DATA.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void zm_readstate(FAR struct zm_state_s *pzm);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timeout
|
||||
*
|
||||
* Description:
|
||||
* Called by the watchdog logic if/when a timeout is detected.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timeout(FAR struct zm_state_s *pzm);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timerinit
|
||||
*
|
||||
* Description:
|
||||
* Create the POSIX timer used to manage timeouts and attach the SIGALRM
|
||||
* signal handler to catch the timeout events.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timerinit(FAR struct zm_state_s *pzm);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timerstart
|
||||
*
|
||||
* Description:
|
||||
* Start, restart, or stop the timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timerstart(FAR struct zm_state_s *pzm, unsigned int sec);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timerstop
|
||||
*
|
||||
* Description:
|
||||
* Stop the timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define zm_timerstop(p) zm_timerstart(p,0)
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timerrelease
|
||||
*
|
||||
* Description:
|
||||
* Destroy the timer and and detach the signal handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timerrelease(FAR struct zm_state_s *pzm);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_dumpbuffer
|
||||
*
|
||||
* Description:
|
||||
* Dump a buffer of zmodem data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_DUMPBUFFER
|
||||
void zm_dumpbuffer(FAR const char *msg, FAR const void *buffer, size_t buflen);
|
||||
#else
|
||||
# define zm_dumpbuffer(m,b,s)
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __APPS_SYSTEM_XMODEM_ZM_H */
|
119
system/zmodem/zm_dumpbuffer.c
Normal file
119
system/zmodem/zm_dumpbuffer.c
Normal file
@ -0,0 +1,119 @@
|
||||
/****************************************************************************
|
||||
* apps/system/zmodem/zm_dumpbuffer.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 "zm.h"
|
||||
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_DUMPBUFFER
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_dumpbuffer
|
||||
*
|
||||
* Description:
|
||||
* Dump a buffer of zmodem data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void zm_dumpbuffer(FAR const char *msg, FAR const void *buffer, size_t buflen)
|
||||
{
|
||||
FAR const uint8_t *ptr = (FAR const uint8_t *)buffer;
|
||||
size_t i;
|
||||
int j, k;
|
||||
|
||||
zmprintf("%s [%p]:\n", msg, ptr);
|
||||
for (i = 0; i < buflen; i += 32)
|
||||
{
|
||||
zmprintf("%04x: ", i);
|
||||
for (j = 0; j < 32; j++)
|
||||
{
|
||||
k = i + j;
|
||||
|
||||
if (j == 16)
|
||||
{
|
||||
zmprintf(" ");
|
||||
}
|
||||
|
||||
if (k < buflen)
|
||||
{
|
||||
zmprintf("%02x", ptr[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
zmprintf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
zmprintf(" ");
|
||||
for (j = 0; j < 32; j++)
|
||||
{
|
||||
k = i + j;
|
||||
|
||||
if (j == 16)
|
||||
{
|
||||
zmprintf(" ");
|
||||
}
|
||||
|
||||
if (k < buflen)
|
||||
{
|
||||
if (ptr[k] >= 0x20 && ptr[k] < 0x7f)
|
||||
{
|
||||
zmprintf("%c", ptr[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
zmprintf(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
zmprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SYSTEM_ZMODEM_DUMPBUFFER */
|
499
system/zmodem/zm_proto.c
Normal file
499
system/zmodem/zm_proto.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
450
system/zmodem/zm_utils.c
Normal file
450
system/zmodem/zm_utils.c
Normal file
@ -0,0 +1,450 @@
|
||||
/****************************************************************************
|
||||
* system/zmodem/zm_utils.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <crc32.h>
|
||||
|
||||
#include "zm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
const uint8_t g_zeroes[4] = { 0, 0, 0, 0 };
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Protypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_bytobe32
|
||||
*
|
||||
* Description:
|
||||
* Convert a sequence of four bytes into a 32-bit value. The byte
|
||||
* sequence is assumed to be big-endian.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t zm_bytobe32(FAR const uint8_t *val8)
|
||||
{
|
||||
return
|
||||
(uint32_t)val8[3] << 24 |
|
||||
(uint32_t)val8[2] << 16 |
|
||||
(uint32_t)val8[1] << 8 |
|
||||
(uint32_t)val8[0];
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_be32toby
|
||||
*
|
||||
* Description:
|
||||
* Convert a 32-bit value in a sequence of four bytes in big-endian byte
|
||||
* order.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void zm_be32toby(uint32_t val32, FAR uint8_t *val8)
|
||||
{
|
||||
val8[0] = (uint8_t)( val32 & 0xff);
|
||||
val8[1] = (uint8_t)((val32 >> 8) & 0xff);
|
||||
val8[2] = (uint8_t)((val32 >> 16) & 0xff);
|
||||
val8[3] = (uint8_t)((val32 >> 24) & 0xff);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_encnibble
|
||||
*
|
||||
* Description:
|
||||
* Encode an 4-bit binary value to a single hex "digit".
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
char zm_encnibble(uint8_t nibble)
|
||||
{
|
||||
if (nibble < 10)
|
||||
{
|
||||
return nibble + '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
return nibble + 'a' - 10;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_encnibble
|
||||
*
|
||||
* Description:
|
||||
* Decode an 4-bit binary value from a single hex "digit".
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t zm_decnibble(char hex)
|
||||
{
|
||||
if (hex <= '9')
|
||||
{
|
||||
return hex - '0';
|
||||
}
|
||||
else if (hex <= 'F')
|
||||
{
|
||||
return hex - 'A' + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return hex - 'a' + 10;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_puthex8
|
||||
*
|
||||
* Description:
|
||||
* Convert an 8-bit binary value to 2 hex "digits".
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR uint8_t *zm_puthex8(FAR uint8_t *ptr, uint8_t ch)
|
||||
{
|
||||
*ptr++ = zm_encnibble((ch >> 4) & 0xf);
|
||||
*ptr++ = zm_encnibble(ch & 0xf);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_read
|
||||
*
|
||||
* Description:
|
||||
* Read a buffer of data from a read-able stream.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t zm_read(int fd, FAR uint8_t *buffer, size_t buflen)
|
||||
{
|
||||
ssize_t nread;
|
||||
|
||||
/* Read reading as necessary until the requested buffer data is successfully
|
||||
* read or until an end of file indication or irrecoverable error is
|
||||
* encountered.
|
||||
*
|
||||
* This loop will only execute if the read is interrupted by a signal.
|
||||
*/
|
||||
|
||||
nread = 0;
|
||||
do
|
||||
{
|
||||
/* Get the next gulp of data from the file. On success, read will return
|
||||
* (1) nread > 0 and nread <= buflen, (2) nread == 0 on end of file, or
|
||||
* (3) nread < 0 on a read error.
|
||||
*/
|
||||
|
||||
nread = read(fd, buffer, buflen);
|
||||
|
||||
/* Did some error occur? */
|
||||
|
||||
if (nread < 0)
|
||||
{
|
||||
int errorcode = errno;
|
||||
|
||||
/* EINTR is not an error... it simply means that this read was
|
||||
* interrupted by an signal before it obtained in data.
|
||||
*/
|
||||
|
||||
if (errorcode != EINTR)
|
||||
{
|
||||
/* But anything else is bad and we will return the failure
|
||||
* in those cases.
|
||||
*/
|
||||
|
||||
zmdbg("ERROR: read failed: %d\n", errorcode);
|
||||
DEBUGASSERT(errorcode != 0);
|
||||
return -errorcode;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (nread < 0);
|
||||
|
||||
return (int)nread;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_getc
|
||||
*
|
||||
* Description:
|
||||
* Read a one byte of data from a read-able stream.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_getc(int fd)
|
||||
{
|
||||
ssize_t nread;
|
||||
uint8_t ch;
|
||||
|
||||
nread = zm_read(fd, &ch, 1);
|
||||
if (nread <= 0)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_write
|
||||
*
|
||||
* Description:
|
||||
* Write a buffer of data to a write-able stream.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t zm_write(int fd, FAR const uint8_t *buffer, size_t buflen)
|
||||
{
|
||||
ssize_t nwritten;
|
||||
size_t total = 0;
|
||||
|
||||
/* Read reading as necessary until the requested buffer is filled or until
|
||||
* an end of file indication or irrecoverable error is encountered.
|
||||
*/
|
||||
|
||||
while (total < buflen)
|
||||
{
|
||||
/* Get the next gulp of data from the file */
|
||||
|
||||
nwritten = write(fd, buffer, buflen);
|
||||
|
||||
if (nwritten < 0)
|
||||
{
|
||||
int errorcode = errno;
|
||||
|
||||
/* EINTR is not an error... it simply means that this read was
|
||||
* interrupted by an signal before it obtained in data.
|
||||
*/
|
||||
|
||||
if (errorcode != EINTR)
|
||||
{
|
||||
zmdbg("ERROR: write failed: %d\n", errorcode);
|
||||
DEBUGASSERT(errorcode != 0);
|
||||
return -errorcode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Updates counts and pointers for the next read */
|
||||
|
||||
total += nwritten;
|
||||
buffer += nwritten;
|
||||
buflen -= nwritten;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)total;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_remwrite
|
||||
*
|
||||
* Description:
|
||||
* Write a buffer of data to the remote peer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_DUMPBUFFER
|
||||
ssize_t zm_remwrite(int fd, FAR const uint8_t *buffer, size_t buflen)
|
||||
{
|
||||
zm_dumpbuffer("Sending", buffer, buflen);
|
||||
return zm_write(fd, buffer, buflen);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_putc
|
||||
*
|
||||
* Description:
|
||||
* Write a one byte of data to a write-able stream.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if 0 /* Not used */
|
||||
int zm_putc(int fd, uint8_t ch)
|
||||
{
|
||||
ssize_t nwritten;
|
||||
|
||||
nwritten = zm_write(fd, &ch, 1);
|
||||
if (nwritten <= 0)
|
||||
{
|
||||
return EOF
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_writefile
|
||||
*
|
||||
* Description:
|
||||
* Write a buffer of data to file, performing newline conversions as
|
||||
* necessary.
|
||||
*
|
||||
* NOTE: Not re-entrant. CR-LF sequences that span buffer boundaries are
|
||||
* not guaranteed to to be handled correctly.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_writefile(int fd, FAR const uint8_t *buffer, size_t buflen, bool zcnl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* If zcnl set, convert newlines to Unix convention */
|
||||
|
||||
if (zcnl)
|
||||
{
|
||||
static bool newline = false;
|
||||
FAR const uint8_t *start;
|
||||
uint8_t ch;
|
||||
int nbytes;
|
||||
|
||||
start = buffer;
|
||||
nbytes = 0;
|
||||
ret = OK;
|
||||
|
||||
/* Loop for each character in the buffer */
|
||||
|
||||
for (; buflen > 0 && ret == OK; buflen--)
|
||||
{
|
||||
/* Get the next character in the buffer */
|
||||
|
||||
ch = *buffer++;
|
||||
|
||||
/* Convert CR-LF, LF-CR, CR, and LF to LF */
|
||||
|
||||
if (ch == '\n' || ch == '\r')
|
||||
{
|
||||
if (nbytes > 0)
|
||||
{
|
||||
ret = zm_write(fd, start, nbytes);
|
||||
start = buffer;
|
||||
nbytes = 0;
|
||||
}
|
||||
|
||||
if (ret == OK && !newline)
|
||||
{
|
||||
ret = zm_write(fd, (FAR uint8_t *)"\n", 1);
|
||||
newline = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Increment the number of bytes we need to write beginning at
|
||||
* start. We want to write as many contiguous bytes as possible
|
||||
* for performance reasons.
|
||||
*/
|
||||
|
||||
nbytes++;
|
||||
newline = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write any trainling data that does not end with a newline */
|
||||
|
||||
if (ret == OK && nbytes > 0)
|
||||
{
|
||||
ret = zm_write(fd, start, nbytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are not modifying newlines, let zm_write() do the whole job */
|
||||
|
||||
ret = zm_write(fd, buffer, buflen);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* Name: zm_filecrc
|
||||
*
|
||||
* Description:
|
||||
* Perform CRC32 calculation on a file.
|
||||
*
|
||||
* Assumptions:
|
||||
* The allocated I/O buffer is available to buffer file data.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
uint32_t zm_filecrc(FAR struct zm_state_s *pzm, FAR const char *filename)
|
||||
{
|
||||
uint32_t crc;
|
||||
ssize_t nread;
|
||||
int fd;
|
||||
|
||||
/* Open the file for reading */
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
/* This should not happen */
|
||||
|
||||
zmdbg("ERROR: Failed to open %s: %d\n", filename, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the file CRC */
|
||||
|
||||
crc = 0xffffffff;
|
||||
while ((nread = zm_read(fd, pzm->scratch, CONFIG_SYSTEM_ZMODEM_SNDBUFSIZE)) > 0)
|
||||
{
|
||||
crc = crc32part(pzm->rcvbuf, nread, crc);
|
||||
}
|
||||
|
||||
/* Close the file and return the CRC */
|
||||
|
||||
close(fd);
|
||||
return ~crc;
|
||||
}
|
197
system/zmodem/zm_watchdog.c
Normal file
197
system/zmodem/zm_watchdog.c
Normal file
@ -0,0 +1,197 @@
|
||||
/****************************************************************************
|
||||
* system/zmodem/zm_watchdog.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 <signal.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "zm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_expiry
|
||||
*
|
||||
* Description:
|
||||
* SIGALRM signal handler. Simply posts the timeout event.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void zm_expiry(int signo, FAR siginfo_t *info, FAR void *context)
|
||||
{
|
||||
FAR struct zm_state_s *pzm = (FAR struct zm_state_s *)info->si_value.sival_ptr;
|
||||
|
||||
/* Just set the timeout flag. If the Zmodem logic was truly waiting, then
|
||||
* the signal should wake it up and it should then process the timeout
|
||||
* condition.
|
||||
*
|
||||
* REVISIT: This is a read-modify-write operation and has the potential
|
||||
* for atomicity issue. We might need to use a dedicated boolean value
|
||||
* to indicate to timeout!
|
||||
*/
|
||||
|
||||
pzm->flags |= ZM_FLAG_TIMEOUT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timerinit
|
||||
*
|
||||
* Description:
|
||||
* Create the POSIX timer used to manage timeouts and attach the SIGALRM
|
||||
* signal handler to catch the timeout events.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timerinit(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
struct sigevent toevent;
|
||||
struct sigaction act;
|
||||
int ret;
|
||||
|
||||
/* Create a POSIX timer to handle timeouts */
|
||||
|
||||
toevent.sigev_notify = SIGEV_SIGNAL;
|
||||
toevent.sigev_signo = SIGALRM;
|
||||
toevent.sigev_value.sival_ptr = pzm;
|
||||
|
||||
ret = timer_create(CLOCK_REALTIME, &toevent, &pzm->timer);
|
||||
if (ret < 0)
|
||||
{
|
||||
int errorcode = errno;
|
||||
zmdbg("ERROR: Failed to create a timer: %d\n", errorcode);
|
||||
return -errorcode;
|
||||
}
|
||||
|
||||
/* Attach a signal handler to catch the timeout */
|
||||
|
||||
act.sa_sigaction = zm_expiry;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&act.sa_mask);
|
||||
|
||||
ret = sigaction(SIGALRM, &act, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
int errorcode = errno;
|
||||
zmdbg("ERROR: Failed to attach a signal handler: %d\n", errorcode);
|
||||
return -errorcode;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timerstart
|
||||
*
|
||||
* Description:
|
||||
* Start, restart, or stop the timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timerstart(FAR struct zm_state_s *pzm, unsigned int sec)
|
||||
{
|
||||
struct itimerspec todelay;
|
||||
int ret;
|
||||
|
||||
/* Start, restart, or stop the timer */
|
||||
|
||||
todelay.it_interval.tv_sec = 0; /* Nonrepeating */
|
||||
todelay.it_interval.tv_nsec = 0;
|
||||
todelay.it_value.tv_sec = sec;
|
||||
todelay.it_value.tv_nsec = 0;
|
||||
|
||||
ret = timer_settime(pzm->timer, 0, &todelay, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
int errorcode = errno;
|
||||
zmdbg("ERROR: Failed to set the timer: %d\n", errorcode);
|
||||
return -errorcode;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timerrelease
|
||||
*
|
||||
* Description:
|
||||
* Destroy the timer and and detach the signal handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timerrelease(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
struct sigaction act;
|
||||
int result;
|
||||
int ret = OK;
|
||||
|
||||
/* Delete the POSIX timer */
|
||||
|
||||
result = timer_delete(pzm->timer);
|
||||
if (result < 0)
|
||||
{
|
||||
int errorcode = errno;
|
||||
zmdbg("ERROR: Failed to delete the timer: %d\n", errorcode);
|
||||
ret = -errorcode;
|
||||
}
|
||||
|
||||
/* Revert to the default signal behavior */
|
||||
|
||||
act.sa_handler = SIG_DFL;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset(&act.sa_mask);
|
||||
|
||||
result = sigaction(SIGALRM, &act, NULL);
|
||||
if (result < 0)
|
||||
{
|
||||
int errorcode = errno;
|
||||
zmdbg("ERROR: Failed to detach the signal handler: %d\n", errorcode);
|
||||
ret = -errorcode;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue
Block a user