mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-02 04:39:01 +00:00
More Zmodem bugfixes and new files
This commit is contained in:
parent
ac1efbab61
commit
7576163ff6
9 changed files with 2806 additions and 26 deletions
|
|
@ -53,6 +53,15 @@
|
|||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************/
|
||||
|
||||
/* The default device used by the Zmodem commands if the -d option is not
|
||||
* provided on the sz or rz command line.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_SYSTEM_ZMODEM_DEVNAME
|
||||
# define CONFIG_SYSTEM_ZMODEM_DEVNAME "/dev/console"
|
||||
#endif
|
||||
|
||||
/* The size of one buffer used to read data from the remote peer */
|
||||
|
||||
#ifndef CONFIG_SYSTEM_ZMODEM_RCVBUFSIZE
|
||||
|
|
@ -165,16 +174,41 @@ extern "C"
|
|||
* remfd - The R/W file/socket descriptor to use for communication with the
|
||||
* remote peer.
|
||||
*
|
||||
* Returned Value:
|
||||
* An opaque handle that can be use with zmr_receive() and zmr_release().
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ZMRHANDLE zmr_initialize(int remfd);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zmr_receive
|
||||
*
|
||||
* Description:
|
||||
* Receive file(s) sent from the remote peer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The handler created by zmr_initialize().
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zmr_receive(ZMRHANDLE handle);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zmr_release
|
||||
*
|
||||
* Description:
|
||||
* Called by the user when there are no more files to receive.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The handler created by zmr_initialize().
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zmr_release(ZMRHANDLE);
|
||||
|
|
@ -198,6 +232,9 @@ int zmr_release(ZMRHANDLE);
|
|||
* remfd - The R/W file/socket descriptor to use for communication with the
|
||||
* remote peer.
|
||||
*
|
||||
* Returned Value:
|
||||
* An opaque handle that can be use with zmx_send() and zms_release()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ZMSHANDLE zms_initialize(int remfd);
|
||||
|
|
@ -209,12 +246,15 @@ ZMSHANDLE zms_initialize(int remfd);
|
|||
* Send a file.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - Handle previoulsy returned by xms_initialize()
|
||||
* filename - The name of the local file to transfer
|
||||
* handle - Handle previoulsy returned by xms_initialize()
|
||||
* filename - The name of the local file to transfer
|
||||
* rfilename - The name of the remote file name to create
|
||||
* option - Describes optional transfer behavior
|
||||
* f1 - The F1 transfer flags
|
||||
* skip - True: Skip if file not present at receiving end.
|
||||
* option - Describes optional transfer behavior
|
||||
* f1 - The F1 transfer flags
|
||||
* skip - True: Skip if file not present at receiving end.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
|
@ -228,6 +268,12 @@ int zms_send(ZMSHANDLE handle, FAR const char *filename,
|
|||
* Description:
|
||||
* Called by the user when there are no more files to send.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The handler created by zms_initialize().
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zms_release(ZMSHANDLE handle);
|
||||
|
|
@ -240,6 +286,9 @@ int zms_release(ZMSHANDLE handle);
|
|||
* must provide the following interface in order to enable/disable hardware
|
||||
* flow control on the device used to communicate with the remote peer.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SYSTEM_ZMODEM_FULLSTREAMING
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@ config SYSTEM_ZMODEM
|
|||
|
||||
if SYSTEM_ZMODEM
|
||||
|
||||
config SYSTEM_ZMODEM_DEVNAME
|
||||
string "Default Zmodem device"
|
||||
default "/dev/console"
|
||||
---help--
|
||||
The default device used by the Zmodem commands if the -d option is
|
||||
not provided on the sz or rz command line. Default: "/dev/console".
|
||||
|
||||
config SYSTEM_ZMODEM_RCVBUFSIZE
|
||||
int "Receive buffer size"
|
||||
default 512
|
||||
|
|
@ -36,9 +43,12 @@ config SYSTEM_ZMODEM_MOUNTPOINT
|
|||
string "Zmodem sandbox"
|
||||
default "/tmp"
|
||||
---help---
|
||||
Absolute pathes are not accepted. This configuration value must be
|
||||
set to provide the path to the file storage directory (such as a
|
||||
mountpoint directory).
|
||||
Absolute pathes in received file names are not accepted. This
|
||||
configuration value must be set to provide the path to the file
|
||||
storage directory (such as a mountpoint directory).
|
||||
|
||||
Names of file send by the sz commond, on the other hand, must be
|
||||
absolute paths beginning with '/'.
|
||||
|
||||
config SYSTEM_ZMODEM_SENDSAMPLE
|
||||
bool "Reverse channel"
|
||||
|
|
|
|||
|
|
@ -44,13 +44,13 @@ endif
|
|||
# Zmodem sz and rz commands
|
||||
|
||||
PRIORITY = SCHED_PRIORITY_DEFAULT
|
||||
STACKSIZE = 768
|
||||
STACKSIZE = 1536
|
||||
|
||||
ASRCS =
|
||||
|
||||
CSRCS = sz_main.c
|
||||
CSRCS = sz_main.c zm_send.c
|
||||
CSRCS += rz_main.c
|
||||
CSRCS += zm_proto.c zm_watchdog.c zm_utils.c zm_dumpbuffer.c
|
||||
CSRCS += zm_state.c zm_proto.c zm_watchdog.c zm_utils.c zm_dumpbuffer.c
|
||||
|
||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||
|
|
|
|||
41
system/zmodem/README.txt
Executable file
41
system/zmodem/README.txt
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
README
|
||||
======
|
||||
|
||||
Using NuttX Zmodem with a Linux Host
|
||||
====================================
|
||||
|
||||
The NuttX Zmodem commands have been verified against the rzsz programs
|
||||
running on a Linux PC. To send a file to the PC, first make sure that
|
||||
the serial port is configured to work with the board:
|
||||
|
||||
$ sudo stty -F /dev/ttyS0 57600
|
||||
$ sudo stty -F /dev/ttyS0
|
||||
|
||||
start rz on the Linux host:
|
||||
|
||||
$ sudo rz </dev/ttyS0 >/dev/ttyS0
|
||||
|
||||
You can add the rz -v option multiple times, each increases the level
|
||||
of debug output. If you want to capture the Linux rz output, then
|
||||
re-direct stderr to a log file by adding 2>rz.log to the end of the
|
||||
rz command.
|
||||
|
||||
NOTE: The NuttX Zmodem does sends rz\n when it starts in compliance with
|
||||
the Zmodem specification. On Linux this, however, seems to start some
|
||||
other, incompatible version of rz. You need to start rz manually to
|
||||
make sure that the correct version is selected. You can tell when this
|
||||
evil rz/sz has inserted itself because you will see the '^' (0x5e)
|
||||
character replacing the standard Zmodem ZDLE character (0x19) in the
|
||||
binary data stream.
|
||||
|
||||
If you don't have the rz command on your Linux box, the package to
|
||||
install rzsz (or possibily lrzsz).
|
||||
|
||||
Then on the target:
|
||||
|
||||
> sz -d /dev/ttyS1 <filename>
|
||||
|
||||
Where filename is the full path to the file to send (i.e., it begins
|
||||
with the '/' character).
|
||||
|
||||
|
||||
|
|
@ -42,8 +42,10 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
|
@ -55,11 +57,13 @@
|
|||
|
||||
static void show_usage(FAR const char *progname, int errcode)
|
||||
{
|
||||
fprintf(stderr, "USAGE: %s [OPTIONS] <lname> [<lname> [<lname> ...]]\n", progname);
|
||||
fprintf(stderr, "USAGE: %s [OPTIONS] <lname> [<lname> [<lname> ...]]\n",
|
||||
progname);
|
||||
fprintf(stderr, "\nWhere:\n");
|
||||
fprintf(stderr, "\t<lname> is the local file name\n");
|
||||
fprintf(stderr, "\nand OPTIONS include the following:\n");
|
||||
fprintf(stderr, "\t-d <device>: Communication device to use. Default /dev/console\n");
|
||||
fprintf(stderr, "\t-d <device>: Communication device to use. Default: %s\n",
|
||||
CONFIG_SYSTEM_ZMODEM_DEVNAME);
|
||||
fprintf(stderr, "\t-r <rname>: Remote file name. Default <lname>\n");
|
||||
fprintf(stderr, "\t-x <mode>: Transfer type\n");
|
||||
fprintf(stderr, "\t\t0: Normal file (default)\n");
|
||||
|
|
@ -91,7 +95,7 @@ int sz_main(int argc, FAR char **argv)
|
|||
enum zm_option_e xfroption = XM_OPTION_REPLACE;
|
||||
ZMSHANDLE handle;
|
||||
FAR const char *rname = NULL;
|
||||
FAR const char *devname = "/dev/console";
|
||||
FAR const char *devname = CONFIG_SYSTEM_ZMODEM_DEVNAME;
|
||||
FAR char *endptr;
|
||||
bool skip = false;
|
||||
long tmp;
|
||||
|
|
@ -197,11 +201,44 @@ int sz_main(int argc, FAR char **argv)
|
|||
*/
|
||||
|
||||
FAR const char *nextlname = argv[optind];
|
||||
FAR const char *nextrname = rname ? rname : nextlname;
|
||||
FAR const char *nextrname;
|
||||
FAR char *ralloc;
|
||||
|
||||
/* Get the next remote file name */
|
||||
|
||||
nextrname = rname;
|
||||
ralloc = NULL;
|
||||
|
||||
if (!nextrname)
|
||||
{
|
||||
/* No remote filename, use the basename of the local filename.
|
||||
* NOTE: that we have to duplicate the local filename to do this
|
||||
* because basename() modifies the original string.
|
||||
*/
|
||||
|
||||
ralloc = strdup(nextlname);
|
||||
if (!ralloc)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Out-of-memory\n");
|
||||
goto errout_with_device;
|
||||
}
|
||||
|
||||
nextrname = basename(ralloc);
|
||||
}
|
||||
|
||||
/* Transfer the file */
|
||||
|
||||
ret = zms_send(handle, nextlname, nextrname, xfrtype, xfroption, skip);
|
||||
|
||||
/* Free any allocations made for the remote file name */
|
||||
|
||||
if (ralloc)
|
||||
{
|
||||
free(ralloc);
|
||||
}
|
||||
|
||||
/* Check if the transfer was successful */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Transfer of %s failed: %d\n",
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@
|
|||
#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:
|
||||
/* The Zmodem parser success/error return code definitions:
|
||||
*
|
||||
* < 0 : Transfer terminated due to an error
|
||||
* = 0 : Transfer still in progress
|
||||
|
|
@ -694,19 +694,17 @@ int zm_sendbinhdr(FAR struct zm_state_s *pzm, int type,
|
|||
FAR const uint8_t *buffer);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_parse
|
||||
* Name: zm_datapump
|
||||
*
|
||||
* 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.
|
||||
* Drive the Zmodem state machine by reading data from the remote peer and
|
||||
* providing that data to the parser. This loop runs until a fatal error
|
||||
* is detected or until the state machine reports that the transfer has
|
||||
* completed successfully.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_parse(FAR struct zm_state_s *pzm, size_t rcvlen);
|
||||
int zm_datapump(FAR struct zm_state_s *pzm);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_readstate
|
||||
|
|
|
|||
|
|
@ -199,7 +199,8 @@ int zm_senddata(FAR struct zm_state_s *pzm, FAR const uint8_t *buffer,
|
|||
}
|
||||
|
||||
term = ZCRCW;
|
||||
zmdbg("zbin=%c, buflen=%d, term=%c\n", zbin, buflen, term);
|
||||
zmdbg("zbin=%c, buflen=%d, term=%c flags=%04x\n",
|
||||
zbin, buflen, term, pzm->flags);
|
||||
|
||||
/* Transfer the data to the I/O buffer, accumulating the CRC */
|
||||
|
||||
|
|
@ -496,6 +497,6 @@ int zm_sendbinhdr(FAR struct zm_state_s *pzm, int type,
|
|||
}
|
||||
else
|
||||
{
|
||||
return zm_sendbin16hdr(pzm, type, buffer);
|
||||
return zm_sendbin32hdr(pzm, type, buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1684
system/zmodem/zm_send.c
Normal file
1684
system/zmodem/zm_send.c
Normal file
File diff suppressed because it is too large
Load diff
960
system/zmodem/zm_state.c
Normal file
960
system/zmodem/zm_state.c
Normal file
|
|
@ -0,0 +1,960 @@
|
|||
/****************************************************************************
|
||||
* system/zmodem/zm_state.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
|
||||
*
|
||||
* This is an original work, but I want to make sure that credit is given
|
||||
* where due: Parts of the state machine design were inspired by the
|
||||
* Zmodem library of Edward A. Falk, dated January, 1995. License
|
||||
* unspecified.
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <crc16.h>
|
||||
#include <crc32.h>
|
||||
|
||||
#include <nuttx/ascii.h>
|
||||
|
||||
#include "zm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* State-specific data receipt handlers */
|
||||
|
||||
static int zm_idle(FAR struct zm_state_s *pzm, uint8_t ch);
|
||||
static int zm_header(FAR struct zm_state_s *pzm, uint8_t ch);
|
||||
static int zm_data(FAR struct zm_state_s *pzm, uint8_t ch);
|
||||
static int zm_finish(FAR struct zm_state_s *pzm, uint8_t ch);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_event
|
||||
*
|
||||
* Description:
|
||||
* This is the heart of the Zmodem state machine. Logic initiated by
|
||||
* zm_parse() will detect events and, eventually call this function.
|
||||
* This function will make the state transition, performing any action
|
||||
* associated with the event.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_event(FAR struct zm_state_s *pzm, int event)
|
||||
{
|
||||
FAR const struct zm_transition_s *ptr;
|
||||
|
||||
zmdbg("ZM[R|S]_state: %d event: %d\n", pzm->state, event);
|
||||
|
||||
/* Look up the entry associated with the event in the current state
|
||||
* transition table. NOTE that each state table must be termined with a
|
||||
* ZME_ERROR entry that provides indicates that the event was not
|
||||
* expected. Thus, the following search will always be successful.
|
||||
*/
|
||||
|
||||
ptr = pzm->evtable[pzm->state];
|
||||
while (ptr->type != ZME_ERROR && ptr->type != event)
|
||||
{
|
||||
/* Skip to the next entry */
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
zmdbg("Transition ZM[R|S]_state %d->%d discard: %d action: %p\n",
|
||||
pzm->state, ptr->next, ptr->bdiscard, ptr->action);
|
||||
|
||||
/* Perform the state transition */
|
||||
|
||||
pzm->state = ptr->next;
|
||||
|
||||
/* Discard buffered data if so requrested */
|
||||
|
||||
if (ptr->bdiscard)
|
||||
{
|
||||
pzm->rcvlen = 0;
|
||||
pzm->rcvndx = 0;
|
||||
}
|
||||
|
||||
/* And, finally, perform the associated action */
|
||||
|
||||
return ptr->action(pzm);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_nakhdr
|
||||
*
|
||||
* Description:
|
||||
* Send a NAK in response to a malformed or unsupported header.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_nakhdr(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
zmdbg("PSTATE %d:%d->%d.%d: NAKing\n",
|
||||
pzm->pstate, pzm->psubstate, PSTATE_IDLE, PIDLE_ZPAD);
|
||||
|
||||
/* Revert to the IDLE state */
|
||||
|
||||
pzm->pstate = PSTATE_IDLE;
|
||||
pzm->psubstate = PIDLE_ZPAD;
|
||||
|
||||
/* And NAK the header */
|
||||
|
||||
return zm_sendhexhdr(pzm, ZNAK, g_zeroes);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_hdrevent
|
||||
*
|
||||
* Description:
|
||||
* Process an event associated with a header.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_hdrevent(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
zmdbg("Received type: %d data: %02x %02x %02x %02x\n",
|
||||
pzm->hdrdata[0],
|
||||
pzm->hdrdata[1], pzm->hdrdata[2], pzm->hdrdata[3], pzm->hdrdata[4]);
|
||||
zmdbg("PSTATE %d:%d->%d.%d\n",
|
||||
pzm->pstate, pzm->psubstate, PSTATE_IDLE, PIDLE_ZPAD);
|
||||
|
||||
/* Revert to the IDLE state */
|
||||
|
||||
pzm->pstate = PSTATE_IDLE;
|
||||
pzm->psubstate = PIDLE_ZPAD;
|
||||
|
||||
/* Verify the checksum. 16- or 32-bit? */
|
||||
|
||||
if (pzm->hdrfmt == ZBIN32)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
/* Checksum is over 9 bytes: The header type, 4 data bytes, plus 4 CRC bytes */
|
||||
|
||||
crc = crc32part(pzm->hdrdata, 9, 0xffffffff);
|
||||
if (crc != 0xdebb20e3)
|
||||
{
|
||||
zmdbg("ERROR: ZBIN32 CRC32 failure: %08x vs debb20e3\n", crc);
|
||||
return zm_nakhdr(pzm);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t crc;
|
||||
|
||||
/* Checksum is over 7 bytes: The header type, 4 data bytes, plus 2 CRC bytes */
|
||||
|
||||
crc = crc16part(pzm->hdrdata, 7, 0);
|
||||
if (crc != 0)
|
||||
{
|
||||
zmdbg("ERROR: ZBIN/ZHEX CRC16 failure: %04x vs 0000\n", crc);
|
||||
return zm_nakhdr(pzm);
|
||||
}
|
||||
}
|
||||
|
||||
return zm_event(pzm, pzm->hdrdata[0]);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_dataevent
|
||||
*
|
||||
* Description:
|
||||
* Process an event associated with a header.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_dataevent(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
zmdbg("Received type: %d length: %d\n", pzm->pkttype, pzm->pktlen);
|
||||
zmdbg("PSTATE %d:%d->%d.%d\n",
|
||||
pzm->pstate, pzm->psubstate, PSTATE_IDLE, PIDLE_ZPAD);
|
||||
|
||||
/* Revert to the IDLE state */
|
||||
|
||||
pzm->pstate = PSTATE_IDLE;
|
||||
pzm->psubstate = PIDLE_ZPAD;
|
||||
|
||||
/* Verify the checksum. 16- or 32-bit? */
|
||||
|
||||
if (pzm->hdrfmt == ZBIN32)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
crc = crc32part(pzm->pktbuf, pzm->pktlen, 0xffffffff);
|
||||
if (crc != 0xdebb20e3)
|
||||
{
|
||||
zmdbg("ERROR: ZBIN32 CRC32 failure: %08x vs debb20e3\n", crc);
|
||||
pzm->flags &= ~ZM_FLAG_CRKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
pzm->flags |= ZM_FLAG_CRKOK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t crc;
|
||||
|
||||
crc = crc16part(pzm->pktbuf, pzm->pktlen, 0);
|
||||
if (crc != 0)
|
||||
{
|
||||
zmdbg("ERROR: ZBIN/ZHEX CRC16 failure: %04x vs 0000\n", crc);
|
||||
pzm->flags &= ~ZM_FLAG_CRKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
pzm->flags |= ZM_FLAG_CRKOK;
|
||||
}
|
||||
}
|
||||
|
||||
return zm_event(pzm, ZME_DATARCVD);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_idle
|
||||
*
|
||||
* Description:
|
||||
* Data has been received in state PSTATE_IDLE. In this state we are
|
||||
* looking for the beginning of a header indicated by the receipt of
|
||||
* ZDLE. We skip over ZPAD characters and flush the received buffer in
|
||||
* the case where anything else is received.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_idle(FAR struct zm_state_s *pzm, uint8_t ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
/* One or more ZPAD characters must precede the ZDLE */
|
||||
|
||||
case ZPAD:
|
||||
{
|
||||
/* The ZDLE character is expected next */
|
||||
|
||||
zmdbg("PSTATE %d:%d->%d.%d\n",
|
||||
pzm->pstate, pzm->psubstate, pzm->pstate, PIDLE_ZDLE);
|
||||
|
||||
pzm->psubstate = PIDLE_ZDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
/* ZDLE indicates the beginning of a header. */
|
||||
|
||||
case ZDLE:
|
||||
|
||||
/* Was the ZDLE preceded by ZPAD[s]? If not, fall through and treat
|
||||
* as the default case.
|
||||
*/
|
||||
|
||||
if (pzm->psubstate == PIDLE_ZDLE)
|
||||
{
|
||||
zmdbg("PSTATE %d:%d->%d.%d\n",
|
||||
pzm->pstate, pzm->psubstate, PSTATE_HEADER, PHEADER_FORMAT);
|
||||
|
||||
pzm->pstate = PSTATE_HEADER;
|
||||
pzm->psubstate = PHEADER_FORMAT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unexpected character. Wait for the next ZPAD to get us */
|
||||
|
||||
default:
|
||||
if (pzm->psubstate != PIDLE_ZPAD)
|
||||
{
|
||||
zmdbg("PSTATE %d:%d->%d.%d\n",
|
||||
pzm->pstate, pzm->psubstate, pzm->pstate, PIDLE_ZPAD);
|
||||
|
||||
pzm->psubstate = PIDLE_ZPAD;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_header
|
||||
*
|
||||
* Description:
|
||||
* Data has been received in state PSTATE_HEADER (i.e., ZDLE was received
|
||||
* in PSTAT_IDLE).
|
||||
*
|
||||
* The following headers are supported:
|
||||
*
|
||||
* 16-bit Binary:
|
||||
* 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)
|
||||
* 32-bit Binary:
|
||||
* 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)
|
||||
* Hex:
|
||||
* 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)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_header(FAR struct zm_state_s *pzm, uint8_t ch)
|
||||
{
|
||||
/* ZDLE encountered in this state means that the following character is
|
||||
* escaped.
|
||||
*/
|
||||
|
||||
if (ch == ZDLE && (pzm->flags & ZM_FLAG_ESC) == 0)
|
||||
{
|
||||
/* Indicate that we are beginning the escape sequence and return */
|
||||
|
||||
pzm->flags |= ZM_FLAG_ESC;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Handle the escaped character in an escape sequence */
|
||||
|
||||
if ((pzm->flags & ZM_FLAG_ESC) != 0)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
/* Two special cases */
|
||||
|
||||
case ZRUB0:
|
||||
ch = ASCII_DEL;
|
||||
break;
|
||||
|
||||
case ZRUB1:
|
||||
ch = 0xff;
|
||||
break;
|
||||
|
||||
/* The typical case: Toggle bit 6 */
|
||||
|
||||
default:
|
||||
ch ^= 0x40;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are no longer in an escape sequence */
|
||||
|
||||
pzm->flags &= ~ZM_FLAG_ESC;
|
||||
}
|
||||
|
||||
/* Now handle the next character, escaped or not, according to the current
|
||||
* PSTATE_HEADER substate.
|
||||
*/
|
||||
|
||||
switch (pzm->psubstate)
|
||||
{
|
||||
/* Waiting for the header format {ZBIN, ZBIN32, ZHEX} */
|
||||
|
||||
case PHEADER_FORMAT:
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
/* Supported header formats */
|
||||
|
||||
case ZHEX:
|
||||
case ZBIN:
|
||||
case ZBIN32:
|
||||
{
|
||||
/* Save the header format character. Next we expect the header
|
||||
* data payload beginning with the header type.
|
||||
*/
|
||||
|
||||
pzm->hdrfmt = ch;
|
||||
pzm->psubstate = PHEADER_PAYLOAD;
|
||||
pzm->hdrndx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
/* Unrecognized header format. */
|
||||
|
||||
return zm_nakhdr(pzm);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Waiting for header payload */
|
||||
|
||||
case PHEADER_PAYLOAD:
|
||||
{
|
||||
int ndx = pzm->hdrndx;
|
||||
|
||||
switch (pzm->hdrfmt)
|
||||
{
|
||||
/* Supported header formats */
|
||||
|
||||
case ZHEX:
|
||||
{
|
||||
if (!isxdigit(ch))
|
||||
{
|
||||
return zm_nakhdr(pzm);
|
||||
}
|
||||
|
||||
/* Save the MS nibble; setup to receive the LS nibble. Index
|
||||
* is not incremented.
|
||||
*/
|
||||
|
||||
pzm->hdrdata[ndx] = zm_decnibble(ch) << 4;
|
||||
pzm->psubstate = PHEADER_LSPAYLOAD;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZBIN:
|
||||
case ZBIN32:
|
||||
{
|
||||
/* Save the payload byte and increment the index. */
|
||||
|
||||
pzm->hdrdata[ndx] = ch;
|
||||
ndx++;
|
||||
|
||||
/* Check if the full header payload has bee buffered.
|
||||
*
|
||||
* The ZBIN format uses 16-bit CRC so the binary length of the
|
||||
* full payload is 1+4+2 = 7 bytes; the ZBIN32 uses a 32-bit CRC
|
||||
* so the binary length of the payload is 1+4+4 = 9 bytes;
|
||||
*/
|
||||
|
||||
if (ndx >= 9 || (pzm->hdrfmt == ZBIN && ndx >= 7))
|
||||
{
|
||||
return zm_hdrevent(pzm);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Setup to receive the next byte */
|
||||
|
||||
pzm->psubstate = PHEADER_PAYLOAD;
|
||||
pzm->hdrndx = ndx;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* Should not happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Waiting for LS nibble header type (ZHEX only) */
|
||||
|
||||
case PHEADER_LSPAYLOAD:
|
||||
{
|
||||
int ndx = pzm->hdrndx;
|
||||
|
||||
if (pzm->hdrfmt == ZHEX && isxdigit(ch))
|
||||
{
|
||||
/* Save the LS nibble and increment the index. */
|
||||
|
||||
pzm->hdrdata[ndx] |= zm_decnibble(ch);
|
||||
ndx++;
|
||||
|
||||
/* The ZHEX format uses 16-bit CRC. So the binary length
|
||||
* of the sequence is 1+4+2 = 7 bytes.
|
||||
*/
|
||||
|
||||
if (ndx >= 7)
|
||||
{
|
||||
return zm_hdrevent(pzm);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Setup to receive the next MS nibble */
|
||||
|
||||
pzm->psubstate = PHEADER_PAYLOAD;
|
||||
pzm->hdrndx = ndx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return zm_nakhdr(pzm);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_data
|
||||
*
|
||||
* Description:
|
||||
* Data has been received in state PSTATE_DATA. PSTATE_DATA is set by
|
||||
* Zmodem transfer logic when it exepects to received data from the
|
||||
* remote peer.
|
||||
*
|
||||
* FORMAT:
|
||||
* xx xx xx xx ... xx ZDLE <type> crc-1 crc-2 [crc-3 crc-4]
|
||||
*
|
||||
* Where xx is binary data (that may be escaped). The 16- or 32-bit CRC
|
||||
* is selected based on a preceding header. ZHEX data packets are not
|
||||
* supported.
|
||||
*
|
||||
* When setting pstate to PSTATE_DATA, it is also expected that the
|
||||
* following initialization is performed:
|
||||
*
|
||||
* - The crc value is initialized appropriately
|
||||
* - ncrc is set to zero.
|
||||
* - pktlen is set to zero
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_data(FAR struct zm_state_s *pzm, uint8_t ch)
|
||||
{
|
||||
/* ZDLE encountered in this state means that the following character is
|
||||
* escaped. Escaped characters may appear anywhere within the data packet.
|
||||
*/
|
||||
|
||||
if (ch == ZDLE && (pzm->flags & ZM_FLAG_ESC) == 0)
|
||||
{
|
||||
/* Indicate that we are beginning the escape sequence and return */
|
||||
|
||||
pzm->flags |= ZM_FLAG_ESC;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Make sure that there is space for another byte in the packet buffer */
|
||||
|
||||
if (pzm->pktlen >= CONFIG_SYSTEM_ZMODEM_PKTBUFSIZE)
|
||||
{
|
||||
zmdbg("ERROR: The packet buffer is full\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* Handle the escaped character in an escape sequence */
|
||||
|
||||
if ((pzm->flags & ZM_FLAG_ESC) != 0)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
/* The data packet type may immediately follow the ZDLE in PDATA_READ
|
||||
* substate.
|
||||
*/
|
||||
|
||||
case ZCRCW: /* Data packet (Non-streaming, ZACK response expected) */
|
||||
case ZCRCE: /* Data packet (End-of-file, no response unless an error occurs) */
|
||||
case ZCRCG: /* Data packet (Full streaming, no response) */
|
||||
case ZCRCQ: /* Data packet (ZACK response expected) */
|
||||
{
|
||||
/* Save the packet type, change substates, and set of count that
|
||||
* indicates the nubmer of bytes still to be added to the packet
|
||||
* buffer:
|
||||
*
|
||||
* ZBIN: 1+2 = 3
|
||||
* ZBIN32: 1+4 = 5
|
||||
*/
|
||||
|
||||
pzm->pkttype = ch;
|
||||
pzm->psubstate = PDATA_CRC;
|
||||
pzm->ncrc = (pzm->hdrfmt == ZBIN32) ? 5 : 3;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Some special cases */
|
||||
|
||||
case ZRUB0:
|
||||
ch = ASCII_DEL;
|
||||
break;
|
||||
|
||||
case ZRUB1:
|
||||
ch = 0xff;
|
||||
break;
|
||||
|
||||
/* The typical case: Toggle bit 6 */
|
||||
|
||||
default:
|
||||
ch ^= 0x40;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are no longer in an escape sequence */
|
||||
|
||||
pzm->flags &= ~ZM_FLAG_ESC;
|
||||
}
|
||||
|
||||
/* Transfer received data from the I/O buffer to the packet buffer.
|
||||
* Accumulate the CRC for the received data. This includes the data
|
||||
* payload plus the packet type code plus the CRC itself.
|
||||
*/
|
||||
|
||||
pzm->pktbuf[pzm->pktlen++] = ch;
|
||||
if (pzm->ncrc == 1)
|
||||
{
|
||||
/* We are at the end of the packet. Check the CRC and post the event */
|
||||
|
||||
zm_dataevent(pzm);
|
||||
}
|
||||
else if (pzm->ncrc > 1)
|
||||
{
|
||||
/* We are still parsing the CRC. Decrement the count of CRC bytes
|
||||
* remaining.
|
||||
*/
|
||||
|
||||
pzm->ncrc--;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_finish
|
||||
*
|
||||
* Description:
|
||||
* Data has been received in state PSTATE_FINISH. Juse wait for "OO"
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_finish(FAR struct zm_state_s *pzm, uint8_t ch)
|
||||
{
|
||||
/* Wait for "OO" */
|
||||
|
||||
if (ch == 'O')
|
||||
{
|
||||
/* Have we seen the second '0'? */
|
||||
|
||||
if (pzm->psubstate == PFINISH_2NDO)
|
||||
{
|
||||
/* Yes.. then we are finished */
|
||||
|
||||
return ZM_XFRDONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. this was the first */
|
||||
|
||||
pzm->psubstate = PFINISH_2NDO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset. We have not seen the first 'O' of the pair */
|
||||
|
||||
pzm->psubstate = PFINISH_1STO;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int zm_parse(FAR struct zm_state_s *pzm, size_t rcvlen)
|
||||
{
|
||||
uint8_t ch;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(pzm && rcvlen < CONFIG_SYSTEM_ZMODEM_RCVBUFSIZE);
|
||||
zm_dumpbuffer("Received", pzm->rcvbuf, rcvlen);
|
||||
|
||||
/* We keep a copy of the length and buffer index in the state structure.
|
||||
* This is only so that deeply nested logic can use these values.
|
||||
*/
|
||||
|
||||
pzm->rcvlen = rcvlen;
|
||||
pzm->rcvndx = 0;
|
||||
|
||||
/* Process each byte until we reach the end of the buffer (or until the
|
||||
* data is discarded.
|
||||
*/
|
||||
|
||||
while (pzm->rcvndx < pzm->rcvlen)
|
||||
{
|
||||
/* Get the next byte from the buffer */
|
||||
|
||||
ch = pzm->rcvbuf[pzm->rcvndx];
|
||||
pzm->rcvndx++;
|
||||
|
||||
/* Handle sequences of CAN characters. When we encounter 5 in a row,
|
||||
* then we consider this a request to cancel the file transfer.
|
||||
*/
|
||||
|
||||
if (ch == ASCII_CAN)
|
||||
{
|
||||
if (++pzm->ncan >= 5)
|
||||
{
|
||||
zmdbg("Remote end has cancelled");
|
||||
pzm->rcvlen = 0;
|
||||
pzm->rcvndx = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not CAN... reset the sequence count */
|
||||
|
||||
pzm->ncan = 0;
|
||||
}
|
||||
|
||||
/* Skip over XON and XOFF */
|
||||
|
||||
if (ch != ASCII_XON && ch != ASCII_XOFF)
|
||||
{
|
||||
/* And process what follows based on the current parsing state */
|
||||
|
||||
switch (pzm->pstate)
|
||||
{
|
||||
case PSTATE_IDLE:
|
||||
ret = zm_idle(pzm, ch);
|
||||
break;
|
||||
|
||||
case PSTATE_HEADER:
|
||||
ret = zm_header(pzm, ch);
|
||||
break;
|
||||
|
||||
case PSTATE_DATA:
|
||||
ret = zm_data(pzm, ch);
|
||||
break;
|
||||
|
||||
case PSTATE_FINISH:
|
||||
ret = zm_finish(pzm, ch);
|
||||
break;
|
||||
|
||||
/* This should not happen */
|
||||
|
||||
default:
|
||||
zmdbg("ERROR: Invalid state: %d\n", pzm->pstate);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle end-of-transfer and irrecoverable errors by breaking out
|
||||
* of the loop and return a non-zero return value to indicate that
|
||||
* transfer is complete.
|
||||
*/
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
zmdbg("Aborting: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we made it through the entire buffer with no errors detected, then
|
||||
* return OK == 0 meaning that everything is okay, but we are not finished
|
||||
* with the transfer.
|
||||
*/
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_datapump
|
||||
*
|
||||
* Description:
|
||||
* Drive the Zmodem state machine by reading data from the remote peer and
|
||||
* providing that data to the parser. This loop runs until a fatal error
|
||||
* is detected or until the state machine reports that the transfer has
|
||||
* completed successfully.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_datapump(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
int ret = OK;
|
||||
ssize_t nread;
|
||||
|
||||
/* Loop until either a read error occurs or until a non-zero value is
|
||||
* returned by the parser.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Start/restart the timer. Whenever we read data from the peer we
|
||||
* must anticipate a timeout because we can never be sure that the peer
|
||||
* is still responding.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
zm_timerstart(pzm, pzm->timeout);
|
||||
|
||||
/* Read a block of data. read() will return: (1) nread > 0 and nread
|
||||
* <= CONFIG_SYSTEM_ZMODEM_RCVBUFSIZE on success, (2) nread == 0 on end
|
||||
* of file, or (3) nread < 0 on a read error or interruption by a
|
||||
* signal.
|
||||
*/
|
||||
|
||||
nread = read(pzm->remfd, pzm->rcvbuf, CONFIG_SYSTEM_ZMODEM_RCVBUFSIZE);
|
||||
|
||||
/* Stop the timer */
|
||||
|
||||
(void)zm_timerstop(pzm);
|
||||
sched_unlock();
|
||||
|
||||
/* EOF from the remote peer can only mean that we lost the connection
|
||||
* somehow.
|
||||
*/
|
||||
|
||||
if (nread == 0)
|
||||
{
|
||||
zmdbg("ERROR: Unexpected end-of-file\n");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* Did some error occur? */
|
||||
|
||||
else 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. However,
|
||||
* the signal may be SIGALRM indicating an timeout condition.
|
||||
* We will know in this case because the signal handler will set
|
||||
* ZM_FLAG_TIMEOUT.
|
||||
*/
|
||||
|
||||
if (errorcode == EINTR)
|
||||
{
|
||||
/* Check for a timeout */
|
||||
|
||||
if ((pzm->flags & ZM_FLAG_TIMEOUT) != 0)
|
||||
{
|
||||
/* Yes... a timeout occurred */
|
||||
|
||||
zm_timeout(pzm);
|
||||
}
|
||||
|
||||
/* No.. then just ignore the EINTR. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* But anything else is bad and we will return the failure
|
||||
* in those cases.
|
||||
*/
|
||||
|
||||
zmdbg("ERROR: read failed: %d\n", errorcode);
|
||||
return -errorcode;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then provide that data to the state machine via zm_parse().
|
||||
* zm_parse() will return a non-zero value if we need to terminate
|
||||
* the loop (with a negative value indicating a failure).
|
||||
*/
|
||||
|
||||
else /* nread > 0 */
|
||||
{
|
||||
ret = zm_parse(pzm, nread);
|
||||
if (ret < 0)
|
||||
{
|
||||
zmdbg("ERROR: zm_parse failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ret == OK);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_readstate
|
||||
*
|
||||
* Description:
|
||||
* Enter PSTATE_DATA.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void zm_readstate(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
zmdbg("PSTATE %d:%d->%d.%d\n",
|
||||
pzm->pstate, pzm->psubstate, PSTATE_DATA, PDATA_READ);
|
||||
|
||||
pzm->pstate = PSTATE_DATA;
|
||||
pzm->psubstate = PDATA_READ;
|
||||
pzm->pktlen = 0;
|
||||
pzm->ncrc = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: zm_timeout
|
||||
*
|
||||
* Description:
|
||||
* Called by the watchdog logic if/when a timeout is detected.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int zm_timeout(FAR struct zm_state_s *pzm)
|
||||
{
|
||||
return zm_event(pzm, ZME_TIMEOUT);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue