nuttx-apps/system/zmodem/zm_state.c
Xiang Xiao 857158451b Unify the void cast usage
1.Remove void cast for function because many place ignore the returned value witout cast
2.Replace void cast for variable with UNUSED macro

Change-Id: Ie644129a563244a6397036789c4c3ea83c4e9b09
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2020-01-02 23:21:01 +08:00

994 lines
27 KiB
C

/****************************************************************************
* 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 <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);
/****************************************************************************
* 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;
}
/* Adjust the back length to exclude the packet type length of the 4-
* byte checksum.
*/
pzm->pktlen -= 5;
}
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;
}
/* Adjust the back length to exclude the packet type length of the 2-
* byte checksum.
*/
pzm->pktlen -= 3;
}
/* Then handle the data received event */
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, revert to the PIDLE_ZPAD
* substate.
*/
if (pzm->psubstate == PIDLE_ZDLE)
{
zmdbg("PSTATE %d:%d->%d:%d\n",
pzm->pstate, pzm->psubstate, PSTATE_HEADER, PHEADER_FORMAT);
pzm->flags &= ~ZM_FLAG_OO;
pzm->pstate = PSTATE_HEADER;
pzm->psubstate = PHEADER_FORMAT;
break;
}
else
{
zmdbg("PSTATE %d:%d->%d:%d\n",
pzm->pstate, pzm->psubstate, pzm->pstate, PIDLE_ZPAD);
pzm->psubstate = PIDLE_ZPAD;
}
/* O might be the first character of "OO". "OO" might be part of the file
* receiver protocol. After receiving on e file in a group of files, the
* receiver expected either "OO" indicating that all files have been sent,
* or a ZRQINIT header indicating the start of the next file.
*/
case 'O':
/* Is "OO" a possibility in this context? Fall through to the default
* case if not.
*/
if ((pzm->flags & ZM_FLAG_OO) != 0)
{
/* Yes... did we receive an 'O' before this one? */
if (pzm->psubstate == PIDLE_OO)
{
/* This is the second 'O' of "OO". the receiver operation is
* finished.
*/
zmdbg("PSTATE %d:%d->%d:%d\n",
pzm->pstate, pzm->psubstate, pzm->pstate, PIDLE_ZPAD);
pzm->flags &= ~ZM_FLAG_OO;
pzm->psubstate = PIDLE_ZPAD;
return zm_event(pzm, ZME_OO);
}
else
{
/* No... then this is the first 'O' that we have seen */
zmdbg("PSTATE %d:%d->%d:%d\n",
pzm->pstate, pzm->psubstate, pzm->pstate, PIDLE_OO);
pzm->psubstate = PIDLE_OO;
}
break;
}
/* Unexpected character. Wait for the next ZPAD to get us back in sync. */
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)
{
int ret;
/* 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 >= ZM_PKTBUFSIZE)
{
zmdbg("ERROR: The packet buffer is full\n");
zmdbg(" ch=%c[%02x] pktlen=%d ptktype=%02x ncrc=%d\n",
isprint(ch) ? ch : '.', ch, pzm->pktlen, pzm->pkttype, pzm->ncrc);
zmdbg(" rcvlen=%d rcvndx=%d\n",
pzm->rcvlen, pzm->rcvndx);
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 */
ret = zm_dataevent(pzm);
/* The packet data has been processed. Discard the old buffered
* packet data.
*/
pzm->pktlen = 0;
pzm->ncrc = 0;
return ret;
}
else if (pzm->ncrc > 1)
{
/* We are still parsing the CRC. Decrement the count of CRC bytes
* remaining.
*/
pzm->ncrc--;
}
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 canceled\n");
pzm->rcvlen = 0;
pzm->rcvndx = 0;
return zm_event(pzm, ZME_CANCEL);
}
}
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;
/* 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("%s: %d\n", ret < 0 ? "Aborting" : "Done", 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 */
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 */
ret = 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);
}