Fix file write loop

This commit is contained in:
Gregory Nutt 2013-07-15 16:21:20 -06:00
parent 4d3e50b66f
commit b6778bf21d
10 changed files with 105 additions and 32 deletions

View File

@ -604,6 +604,9 @@
* apps/system/zmodem: Add configuration support and a build framework
for the Zmodem sz and rz command (which exist but have not yet been
checked in) (2013-7-12).
* apps/system/zmodem: The 'sz' command is not complete and seems
* apps/system/zmodem: The 'sz' command is now complete and seems
functional (given on light testing). The rz command logic exists but
is still untested and not yet checked in.
is still untested and not yet checked in (2013-7-13).
* apps/system/zmodem: The 'rz' command is now complete and functional
under certain conditaions. There are, however, some data overrun
issues that I am still uncertain how should be handled (2012-7-15).

View File

@ -135,6 +135,15 @@
# define CONFIG_SYSTEM_ZMODEM_RESPTIME 10
#endif
/* When rz starts, it must wait a for the remote end to start the file
* transfer. This may take longer than the normal response time. This
* value may be set to tune that longer timeout value.
*/
#ifndef CONFIG_SYSTEM_ZMODEM_CONNTIME
# define CONFIG_SYSTEM_ZMODEM_CONNTIME 30
#endif
/* Receiver serial number */
#ifndef CONFIG_SYSTEM_ZMODEM_SERIALNO

View File

@ -119,10 +119,18 @@ config SYSTEM_ZMODEM_SENDBRAK
Can not yet send BREAK
config SYSTEM_ZMODEM_RESPTIME
bool "Response time"
int "Response time"
default 10
---help---
Response time for sender to respond to requests.
Response time for remote peer to respond to requests.
config SYSTEM_ZMODEM_CONNTIME
int "Rz startup time"
default 30
---help---
When rz starts, it must wait a for the remote end to start the file
transfer. This may take longer than the normal response time. This
value may be set to tune that longer timeout value.
config SYSTEM_ZMODEM_SERIALNO
int "Serial number"

View File

@ -65,6 +65,7 @@ Using NuttX Zmodem with a Linux Host
using 9600 baud for the data transfers -- high rates may result in data
overruns):
$ sudo stty -F /dev/ttyS0 raw # Puts the TTY in raw transfer mode
$ sudo stty -F /dev/ttyS0 9600 # Select 9600 BAUD
$ sudo stty -F /dev/ttyS0 crtscts # Enables CTS/RTS handshaking
$ sudo stty -F /dev/ttyS0 # Show the TTY configuration
@ -105,6 +106,7 @@ Using NuttX Zmodem with a Linux Host
9600 baud for the data transfers -- high rates may result in data
overruns):
$ sudo stty -F /dev/ttyS0 raw # Puts the TTY in raw transfer mode
$ sudo stty -F /dev/ttyS0 9600 # Select 9600 BAUD
$ sudo stty -F /dev/ttyS0 crtscts # Enables CTS/RTS handshaking
$ sudo stty -F /dev/ttyS0 # Show the TTY configuration
@ -144,12 +146,39 @@ Using NuttX Zmodem with a Linux Host
the previously received data to the file and the serial driver's RX
buffer is overrun by a few bytes while the write is in progress.
As a result, when it reads the next buffer of data, a few bytes may
be missing (maybe 10). Either (1) we need a more courteous host
application, or (2) we need to greatly improve the target side
buffering capability!
be missing (maybe 10). The symptom of this missing data is a CRC check
failure.
Either (1) we need a more courteous host application, or (2) we
need to greatly improve the target side buffering capability!
Either (1) we need a more courteous host application, or (2) we
need to greatly improve the target side buffering capability!
My thought now is to implement the NuttX sz and rz commands as
PC side applications as well. Matching both sides and obeying
the handshaking will solve the issues. Another option might be
to fix the serial driver hardware flow control somehow.
sz has several command line options which one would think would
alleviate these problems. But as of yet, I have not found a
combination of options that does so:
-L N, --packetlen N
Use ZMODEM sub-packets of length N. A larger N (32 <= N <= 1024)
gives slightly higher throughput, a smaller N speeds error
recovery. The default is 128 below 300 baud, 256 above 300 baud,
or 1024 above 2400 baud.
-l N, --framelen N
Wait for the receiver to acknowledge correct data every N
(32 <= N <= 1024) characters. This may be used to avoid network
overrun when XOFF flow control is lacking.
-w N, --windowsize N
Limit the transmit window size to N bytes (ZMODEM).
UPDATE: I have verified that with debug off and at lower serial
BAUD (1200), the transfers of large fails succeed without errors.
You may need the Linux sz -O option to keep it from timing out
in these low BAUD transfers.

View File

@ -137,7 +137,7 @@ int rz_main(int argc, FAR char **argv)
ret = zmr_receive(handle);
if (ret < 0)
{
fprintf(stderr, "File reception failed: %d\n", ret);
fprintf(stderr, "ERROR: File reception failed: %d\n", ret);
goto errout_with_zmodem;
}

View File

@ -183,7 +183,8 @@
#define ZME_COMMAND ZCOMMAND /* Command, from sending program */
#define ZME_STDERR ZSTDERR /* Output this message to stderr */
#define ZME_OO 252 /* Received OO, termining the receiver */
#define ZME_CANCEL 251 /* Received the cancelation sequence */
#define ZME_OO 252 /* Received OO, terminating the receiver */
#define ZME_DATARCVD 253 /* Data received */
#define ZME_TIMEOUT 254 /* Timeout */
#define ZME_ERROR 255 /* Protocol error */

View File

@ -59,6 +59,8 @@
#include <assert.h>
#include <errno.h>
#include <apps/zmodem.h>
#include "zm.h"
/****************************************************************************
@ -130,7 +132,7 @@ static int zmr_filedata(FAR struct zm_state_s *pzm);
static int zmr_rcvto(FAR struct zm_state_s *pzm);
static int zmr_fileto(FAR struct zm_state_s *pzm);
static int zmr_cmddata(FAR struct zm_state_s *pzm);
static int zmr_eof(FAR struct zm_state_s *pzm);
static int zmr_zeof(FAR struct zm_state_s *pzm);
static int zmr_zfin(FAR struct zm_state_s *pzm);
static int zmr_finto(FAR struct zm_state_s *pzm);
static int zmr_oo(FAR struct zm_state_s *pzm);
@ -215,7 +217,7 @@ static const struct zm_transition_s g_zmr_readready[] =
{
{ZME_DATA, false, ZMR_READING, zmr_zdata},
{ZME_NAK, false, ZMR_READREADY, zmr_badrpos},
{ZME_EOF, false, ZMR_START, zmr_eof},
{ZME_EOF, false, ZMR_START, zmr_zeof},
{ZME_RQINIT, true, ZMR_START, zmr_zrinit},
{ZME_FILE, false, ZMR_READREADY, zmr_badrpos},
{ZME_FIN, true, ZMR_FINISH, zmr_zfin},
@ -232,7 +234,7 @@ static const struct zm_transition_s g_zmr_reading[] =
{ZME_NAK, true, ZMR_READREADY, zmr_badrpos},
{ZME_FIN, true, ZMR_FINISH, zmr_zfin},
{ZME_DATA, false, ZMR_READING, zmr_zdata},
{ZME_EOF, true, ZMR_START, zmr_eof},
{ZME_EOF, true, ZMR_START, zmr_zeof},
{ZME_DATARCVD, false, ZMR_READING, zmr_filedata},
{ZME_TIMEOUT, false, ZMR_READING, zmr_fileto},
{ZME_ERROR, false, ZMR_READING, zmr_error}
@ -717,7 +719,8 @@ static int zmr_filedata(FAR struct zm_state_s *pzm)
if ((pzm->flags & ZM_FLAG_CRKOK) == 0)
{
zmdbg("ERROR: Bad crc, send ZRPOS(%ld)\n", (unsigned long)pzmr->offset);
zmdbg("ERROR: Bad crc, send ZRPOS(%ld)\n",
(unsigned long)pzmr->offset);
/* No.. increment the count of errors */
@ -759,7 +762,8 @@ static int zmr_filedata(FAR struct zm_state_s *pzm)
/* Write the packet of data to the file */
ret = zm_writefile(pzmr->outfd, pzm->pktbuf, pzm->pktlen, pzmr->f0 == ZCNL);
ret = zm_writefile(pzmr->outfd, pzm->pktbuf, pzm->pktlen,
pzmr->f0 == ZCNL);
if (ret < 0)
{
int errorcode = errno;
@ -894,14 +898,14 @@ static int zmr_fileto(FAR struct zm_state_s *pzm)
}
/****************************************************************************
* Name: zmr_eof
* Name: zmr_zeof
*
* Description:
* Received ZEOF packet. File is now complete
*
****************************************************************************/
static int zmr_eof(FAR struct zm_state_s *pzm)
static int zmr_zeof(FAR struct zm_state_s *pzm)
{
FAR struct zmr_state_s *pzmr = (FAR struct zmr_state_s *)pzm;
@ -1652,7 +1656,13 @@ int zmr_receive(ZMRHANDLE handle)
{
FAR struct zmr_state_s *pzmr = (FAR struct zmr_state_s*)handle;
/* The state machine data pump will do the entire job */
/* The first thing that should happen is to receive ZRQINIT from the
* remote sender. This could take while so use a long timeout.
*/
pzmr->cmn.timeout = CONFIG_SYSTEM_ZMODEM_CONNTIME;
/* Then the state machine data pump will do the rest of the job */
return zm_datapump(&pzmr->cmn);
}

View File

@ -63,6 +63,7 @@
#include <crc32.h>
#include <nuttx/ascii.h>
#include <apps/zmodem.h>
#include "zm.h"

View File

@ -784,10 +784,10 @@ static int zm_parse(FAR struct zm_state_s *pzm, size_t rcvlen)
{
if (++pzm->ncan >= 5)
{
zmdbg("Remote end has cancelled");
zmdbg("Remote end has canceled\n");
pzm->rcvlen = 0;
pzm->rcvndx = 0;
return -EAGAIN;
return zm_event(pzm, ZME_CANCEL);
}
}
else

View File

@ -246,23 +246,23 @@ ssize_t zm_write(int fd, FAR const uint8_t *buffer, size_t buflen)
{
ssize_t nwritten;
size_t wrsize;
size_t total = 0;
size_t remaining;
/* 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)
for (remaining = buflen; remaining > 0; )
{
#if CONFIG_SYSTEM_ZMODEM_WRITESIZE > 0
if (buflen > CONFIG_SYSTEM_ZMODEM_WRITESIZE)
if (remaining > CONFIG_SYSTEM_ZMODEM_WRITESIZE)
{
wrsize = CONFIG_SYSTEM_ZMODEM_WRITESIZE;
}
else
#endif
{
wrsize = buflen;
wrsize = remaining;
}
/* Get the next gulp of data from the file */
@ -287,13 +287,12 @@ ssize_t zm_write(int fd, FAR const uint8_t *buffer, size_t buflen)
{
/* Updates counts and pointers for the next read */
total += nwritten;
buffer += nwritten;
buflen -= nwritten;
buffer += nwritten;
remaining -= nwritten;
}
}
return (int)total;
return (int)(buflen - remaining);
}
/****************************************************************************
@ -383,11 +382,24 @@ int zm_writefile(int fd, FAR const uint8_t *buffer, size_t buflen, bool zcnl)
nbytes = 0;
}
if (ret == OK && !newline)
if (ret == OK)
{
ret = zm_write(fd, (FAR uint8_t *)"\n", 1);
newline = true;
}
/* Skip one char of \r\n? */
if (newline)
{
/* Yes.. But don't skip if there is another */
newline = false;
}
else
{
/* Write one newline and skip the follow \r or \n */
ret = zm_write(fd, (FAR uint8_t *)"\n", 1);
newline = true;
}
}
}
else
{
@ -401,7 +413,7 @@ int zm_writefile(int fd, FAR const uint8_t *buffer, size_t buflen, bool zcnl)
}
}
/* Write any trainling data that does not end with a newline */
/* Write any trailing data that does not end with a newline */
if (ret == OK && nbytes > 0)
{