From ceeb75753a8594ceff6c1f34df03f8ae2c151d83 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 13 Jul 2013 19:57:04 -0600 Subject: Resolve a few Zmodem sender streaming issues --- apps/ChangeLog.txt | 7 +- apps/include/zmodem.h | 28 +++ apps/system/zmodem/Kconfig | 20 +- apps/system/zmodem/zm.h | 23 +- apps/system/zmodem/zm_send.c | 499 ++++++++++++++++++++++++------------------- 5 files changed, 350 insertions(+), 227 deletions(-) (limited to 'apps') diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 08d2cca32..9f49a3077 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -602,5 +602,8 @@ Change to prevent some false alarm debug assertions (From Chia Cheng Tao, 2013-7-9). * apps/system/zmodem: Add configuration support and a build framework - for the Zmodem sz and rz command (which don't actually exist yet). - (2013-7-12). + 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 + functional (given on light testing). The rz command logic exists but + is still untested and not yet checked in. diff --git a/apps/include/zmodem.h b/apps/include/zmodem.h index 101512f97..668875fd5 100644 --- a/apps/include/zmodem.h +++ b/apps/include/zmodem.h @@ -93,6 +93,34 @@ # define CONFIG_SYSTEM_ZMODEM_MOUNTPOINT "/tmp" #endif +/* CONFIG_SYSTEM_ZMODEM_RCVSAMPLE indicates the the local sender can sample + * reverse channel while sending. This means in particular, that Zmodem can + * detect if data is received from the remote receiver while streaming a file + * to the remote receiver. Support for such asychronous incoming data + * notification is needed to support interruption of the file transfer by + * the remote receiver. + * + * This capapability is not yet supported. There are only incomplete hooks + * in the code now! + */ + +#ifndef CONFIG_SYSTEM_ZMODEM_MOUNTPOINT +# warning CONFIG_SYSTEM_ZMODEM_RCVSAMPLE not yet support +# undef CONFIG_SYSTEM_ZMODEM_RCVSAMPLE +#endif + +/* CONFIG_SYSTEM_ZMODEM_SENDATTN indicates that the local sender retains + * an attention string that will be sent to the remote receiver + * + * This capapability is not yet supported. There are only incomplete hooks + * in the code now! + */ + +#ifndef CONFIG_SYSTEM_ZMODEM_SENDATTN +# warning CONFIG_SYSTEM_ZMODEM_SENDATTN not yet support +# undef CONFIG_SYSTEM_ZMODEM_SENDATTN +#endif + /* Response time for sender to respond to requests */ #ifndef CONFIG_SYSTEM_ZMODEM_RESPTIME diff --git a/apps/system/zmodem/Kconfig b/apps/system/zmodem/Kconfig index 64ab3a92e..a622e9e8e 100644 --- a/apps/system/zmodem/Kconfig +++ b/apps/system/zmodem/Kconfig @@ -50,17 +50,27 @@ config SYSTEM_ZMODEM_MOUNTPOINT Names of file send by the sz commond, on the other hand, must be absolute paths beginning with '/'. -config SYSTEM_ZMODEM_SENDSAMPLE +config SYSTEM_ZMODEM_RCVSAMPLE bool "Reverse channel" - default y + default n ---help--- - Sender can sample reverse channel + Local sender can sample reverse channel while sending. This means + in particular, that Zmodem can detect if data is received from the + remote receiver while streaming a file to the remote receiver. + Support for such asychronous incoming data notification is needed to + support interruption of the file transfer by the remote receiver. + + This capapability is not yet supported. There are only incomplete + hooks in the code now! Enable only if you want to see the warning. config SYSTEM_ZMODEM_SENDATTN bool "Attn interrupt" - default y + default n ---help--- - Sender can be interrupted with ATTN + Local sender retains an attention string that will be sent to the remote receiver + + This capapability is not yet supported. There are only incomplete + hooks in the code now! Enable only if you want to see the warning. config SYSTEM_ZMODEM_ALWAYSSINT bool "Send ZSINIT" diff --git a/apps/system/zmodem/zm.h b/apps/system/zmodem/zm.h index bb849d21d..fbfd7149c 100644 --- a/apps/system/zmodem/zm.h +++ b/apps/system/zmodem/zm.h @@ -195,10 +195,9 @@ #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 */ +#define ZM_FLAG_WAIT (1 << 6) /* Next send should wait */ +#define ZM_FLAG_APPEND (1 << 7) /* Append to the existing file */ +#define ZM_FLAG_TIMEOUT (1 << 8) /* A timeout has been detected */ /* The Zmodem parser success/error return code definitions: * @@ -400,7 +399,7 @@ struct zms_state_s /* State data unique to the Zmodem send implementation ********************/ - uint8_t strtype; /* Streaming type: ZCRCG or ZCRCQ */ + uint8_t dpkttype; /* Streaming data packet type: ZCRCG, ZCRCQ, or ZCRCW */ uint8_t fflags[4]; /* File xfer flags */ uint16_t rcvmax; /* Max packet size the remote can receive. */ #ifdef CONFIG_SYSTEM_ZMODEM_TIMESTAMPS @@ -726,6 +725,20 @@ void zm_readstate(FAR struct zm_state_s *pzm); int zm_timeout(FAR struct zm_state_s *pzm); +/**************************************************************************** + * Name: zm_rcvpending + * + * Description: + * Return true if data from the remote receiver is pending. In that case, + * the local sender should stop data streaming operations and process the + * incoming data. + * + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_ZMODEM_RCVSAMPLE +bool zm_rcvpending(FAR struct zm_state_s *pzm); +#endif + /**************************************************************************** * Name: zm_timerinit * diff --git a/apps/system/zmodem/zm_send.c b/apps/system/zmodem/zm_send.c index 5982834da..bfae8a31b 100644 --- a/apps/system/zmodem/zm_send.c +++ b/apps/system/zmodem/zm_send.c @@ -95,8 +95,8 @@ * <---- ZRPOS * ZCRC ----> ZMS_CRCWAIT * <---- ZRPOS - * ZDATA ----> ZMS_SENDING - * Data packets ----> [Perhaps ZMS_SENDWAIT<->ZMS_SENDING] + * ZDATA ----> + * Data packets ----> ZMS_SENDING /ZMS_SENDWAIT * Last packet ----> ZMS_SENDDONE * ZEOF ----> ZMS_SENDEOF * <---- ZRINIT @@ -116,7 +116,7 @@ enum zmodem_state_e ZMS_INITACK, /* Received ZRINIT, sent ZSINIT, waiting for ZACK */ ZMS_FILEWAIT, /* Sent file header, waiting for ZRPOS */ ZMS_CRCWAIT, /* Sent file CRC, waiting for ZRPOS */ - ZMS_SENDING, /* Sending data subpackets, ready for interrupt */ + ZMS_SENDING, /* Streaming data subpackets, ready for interrupt */ ZMS_SENDWAIT, /* Waiting for ZACK */ ZMS_SENDDONE, /* File finished, need to send ZEOF */ ZMS_SENDEOF, /* Sent ZEOF, waiting for ZACK */ @@ -180,7 +180,7 @@ static int zms_sendfile(FAR struct zms_state_s *pzms, FAR const char *filename, static const struct zm_transition_s g_zms_start[] = { {ZME_RINIT, true, ZMS_START, zms_rinit}, - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_CHALLENGE, true, ZMS_START, zms_challenge}, {ZME_ABORT, true, ZMS_FINISH, zms_abort}, {ZME_FERR, true, ZMS_FINISH, zms_abort}, @@ -197,7 +197,7 @@ static const struct zm_transition_s g_zms_start[] = static const struct zm_transition_s g_zms_init[] = { - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_ACK, true, ZMS_INITACK, zms_initdone}, {ZME_NAK, true, ZMS_INITACK, zms_sendzsinit}, {ZME_RINIT, true, ZMS_INITACK, zms_rinit}, @@ -214,7 +214,7 @@ static const struct zm_transition_s g_zms_init[] = static const struct zm_transition_s g_zms_filewait[] = { - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_RPOS, true, ZMS_SENDING, zms_sendfiledata}, {ZME_SKIP, true, ZMS_FILEWAIT, zms_fileskip}, {ZME_CRC, true, ZMS_FILEWAIT, zms_filecrc}, @@ -235,7 +235,7 @@ static const struct zm_transition_s g_zms_filewait[] = static const struct zm_transition_s g_zms_crcwait[] = { - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_RPOS, true, ZMS_SENDING, zms_sendfiledata}, {ZME_SKIP, true, ZMS_FILEWAIT, zms_fileskip}, {ZME_NAK, true, ZMS_CRCWAIT, zms_filecrc}, @@ -254,7 +254,7 @@ static const struct zm_transition_s g_zms_crcwait[] = * interrupt */ -static const struct zm_transition_s g_zms_sending[] = +static const struct zm_transition_s g_zms_streaming[] = { {ZME_SINIT, false, ZMS_START, zms_attention}, {ZME_ACK, false, ZMS_SENDING, zms_sendack}, @@ -288,7 +288,7 @@ static const struct zm_transition_s g_zms_sendwait[] = static const struct zm_transition_s g_zms_senddone[] = { - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_ACK, false, ZMS_SENDWAIT, zms_senddoneack}, {ZME_RPOS, true, ZMS_SENDING, zms_sendrpos}, {ZME_SKIP, true, ZMS_FILEWAIT, zms_fileskip}, @@ -315,7 +315,7 @@ static const struct zm_transition_s g_zms_senddone[] = const struct zm_transition_s g_zms_sendeof[] = { {ZME_RINIT, true, ZMS_START, zms_endoftransfer}, - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_ACK, false, ZMS_SENDEOF, zms_ignore}, {ZME_RPOS, true, ZMS_SENDWAIT, zms_sendrpos}, {ZME_SKIP, true, ZMS_START, zms_fileskip}, @@ -331,7 +331,7 @@ const struct zm_transition_s g_zms_sendeof[] = static const struct zm_transition_s g_zms_finish[] = { - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_FIN, true, ZMS_DONE, zms_xfrdone}, {ZME_NAK, true, ZMS_FINISH, zms_finish}, {ZME_RINIT, true, ZMS_FINISH, zms_finish}, @@ -345,7 +345,7 @@ static const struct zm_transition_s g_zms_finish[] = static struct zm_transition_s g_zms_command[] = { - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_DATARCVD, false, ZMS_COMMAND, zms_ignore}, {ZME_TIMEOUT, false, ZMS_COMMAND, zms_cmdto}, {ZME_ERROR, false, ZMS_COMMAND, zms_error} @@ -355,7 +355,7 @@ static struct zm_transition_s g_zms_command[] = static struct zm_transition_s g_zms_stderr[] = { - {ZME_SINIT, false, ZMS_START, zms_attention}, + {ZME_SINIT, false, ZMS_START, zms_ignore}, {ZME_DATARCVD, false, ZMS_MESSAGE, zms_stderrdata}, {ZME_TIMEOUT, false, ZMS_MESSAGE, zms_cmdto}, {ZME_ERROR, false, ZMS_MESSAGE, zms_error} @@ -375,18 +375,18 @@ static struct zm_transition_s g_zms_done[] = static FAR const struct zm_transition_s * const g_zms_evtable[] = { - g_zms_start, /* ZMS_START - ZRQINIT sent, waiting for ZRINIT from receiver */ - g_zms_init, /* ZMS_INITACK - Received ZRINIT, sent ZSINIT, waiting for ZACK */ - g_zms_filewait, /* ZMS_FILEWAIT - Sent file header, waiting for ZRPOS */ - g_zms_crcwait, /* ZMS_CRCWAIT - Sent file CRC, waiting for ZRPOS response */ - g_zms_sending, /* ZMS_SENDING - Sending data subpackets, ready for interrupt */ - g_zms_sendwait, /* ZMS_SENDWAIT - Waiting for ZACK */ - g_zms_senddone, /* ZMS_SENDDONE - File sent, need to send ZEOF */ - g_zms_sendeof, /* ZMS_SENDEOF - Sent ZEOF, waiting for ZACK */ - g_zms_finish, /* ZMS_FINISH - Sent ZFIN, waiting for ZFIN */ - g_zms_command, /* ZMS_COMMAND - Waiting for command data */ - g_zms_stderr, /* ZMS_MESSAGE - Waiting for message from receiver */ - g_zms_done /* ZMS_DONE - Finished with transfer */ + g_zms_start, /* ZMS_START - ZRQINIT sent, waiting for ZRINIT from receiver */ + g_zms_init, /* ZMS_INITACK - Received ZRINIT, sent ZSINIT, waiting for ZACK */ + g_zms_filewait, /* ZMS_FILEWAIT - Sent file header, waiting for ZRPOS */ + g_zms_crcwait, /* ZMS_CRCWAIT - Sent file CRC, waiting for ZRPOS response */ + g_zms_streaming, /* ZMS_SENDING - Sending data subpackets, ready for interrupt */ + g_zms_sendwait, /* ZMS_SENDWAIT - Waiting for ZACK */ + g_zms_senddone, /* ZMS_SENDDONE - File sent, need to send ZEOF */ + g_zms_sendeof, /* ZMS_SENDEOF - Sent ZEOF, waiting for ZACK */ + g_zms_finish, /* ZMS_FINISH - Sent ZFIN, waiting for ZFIN */ + g_zms_command, /* ZMS_COMMAND - Waiting for command data */ + g_zms_stderr, /* ZMS_MESSAGE - Waiting for message from receiver */ + g_zms_done /* ZMS_DONE - Finished with transfer */ }; /**************************************************************************** @@ -438,21 +438,56 @@ static int zms_rinit(FAR struct zm_state_s *pzm) (void)zms_hwflowcontrol(pzmr->cmn.remfd, true); #endif -#if defined(CONFIG_SYSTEM_ZMODEM_SENDSAMPLE) || defined(CONFIG_SYSTEM_ZMODEM_SENDATTN) + /* Check if the receiver supports full-duplex streaming + * + * ZCRCW: + * "If the receiver cannot overlap serial and disk I/O, it uses the + * ZRINIT frame to specify a buffer length which the sender will + * not overflow. The sending program sends a ZCRCW data subpacket + * and waits for a ZACK header before sending the next segment of + * the file. + * + * ZCRCG + * "A data subpacket terminated by ZCRCG and CRC does not elicit a + * response unless an error is detected; more data subpacket(s) + * follow immediately." + * + * + * In order to support ZCRCG, this logic must be able to sample the + * reverse channel while streaming to determine if the receiving wants + * interrupt the transfer (CONFIG_SYSTEM_ZMODEM_RCVSAMPLE). + * + * ZCRCQ + * "ZCRCQ data subpackets expect a ZACK response with the + * receiver's file offset if no error, otherwise a ZRPOS response + * with the last good file offset. Another data subpacket + * continues immediately. ZCRCQ subpackets are not used if the + * receiver does not indicate FDX ability with the CANFDX bit. + */ + +#ifdef CONFIG_SYSTEM_ZMODEM_RCVSAMPLE + /* We support CANFDX. We can do ZCRCG if the remote sender does too */ + if ((rcaps & (CANFDX | CANOVIO)) == (CANFDX | CANOVIO) && pzms->rcvmax == 0) { - pzms->strtype = ZCRCG; + pzms->dpkttype = ZCRCG; } - else #else + /* We don't support CANFDX. We can do ZCRCQ if the remote sender does */ + if ((rcaps & (CANFDX | CANOVIO)) == (CANFDX | CANOVIO) && pzms->rcvmax == 0) { - pzms->strtype = ZCRCQ; + /* For the local sender, this is just like ZCRCW */ + + pzms->dpkttype = ZCRCQ; } - else #endif + + /* Otherwise, we have to to ZCRCW */ + + else { - pzms->strtype = ZCRCG; + pzms->dpkttype = ZCRCW; } #ifdef CONFIG_SYSTEM_ZMODEM_ALWAYSSINT @@ -475,15 +510,33 @@ static int zms_rinit(FAR struct zm_state_s *pzm) * Name: zms_attention * * Description: - * Received ZSINIT. The receiver wants something. Set the interrupt flag - * and handle this later in zms_sendpacket(). + * Received ZSINIT while sending data. The receiver wants something. + * Switch tot he ZMS_SENDWAIT state and wait. A ZRPOS should be forth- + * coming. * ****************************************************************************/ static int zms_attention(FAR struct zm_state_s *pzm) { zmdbg("ZMS_STATE %d\n", pzm->state); - pzm->flags |= ZM_FLAG_INTERRUPT; + + /* In the case of full streaming, the presence of pending read data should + * cause the sending logic to break out of the loop and handle the received + * data, getting us to this point. + */ + + if (pzm->state == ZMS_SENDING || pzm->state == ZMS_SENDWAIT) + { + /* Enter a wait state and see what they want. Next header *should* be + * ZRPOS. + */ + + zmdbg("ZMS_STATE %d->%d: Interrupt\n", pzm->state, ZMS_SENDWAIT); + + pzm->state = ZMS_SENDWAIT; + pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; + } + return OK; } @@ -685,7 +738,7 @@ static int zms_sendfilename(FAR struct zm_state_s *pzm) ptr += len + 1; /* Paragraph 13: - * + * * Length * The file length ... is stored as a decimal string counting the * number of data bytes in the file. @@ -697,7 +750,7 @@ static int zms_sendfilename(FAR struct zm_state_s *pzm) * File Mode * A single space separates the file mode from the modification date. * The file mode is stored as an octal string. Unless the file - * originated from a Unix system, the file mode is set to 0. + * originated from a Unix system, the file mode is set to 0. * Serial Number * A single space separates the serial number from the file mode. * The serial number of the transmitting program is stored as an @@ -713,7 +766,7 @@ static int zms_sendfilename(FAR struct zm_state_s *pzm) * as a decimal number, and includes the current file * File Type * Iff the file type is sent, a single space separates this field from - * the previous field. This field is coded as a decimal number. + * the previous field. This field is coded as a decimal number. * Currently defined values are: * * 0 Sequential file - no special type @@ -821,242 +874,258 @@ static int zms_sendpacket(FAR struct zm_state_s *pzm) int ret; int i; - /* ZCRCE: CRC next, frame ends, header follows ZCRCG: CRC next, frame - * continues nonstop ZCRCQ: CRC next, send ZACK, frame continues nonstop - * ZCRCW: CRC next, send ZACK, frame ends, header follows. + /* Loop, sending packets while we can if the receiver supports streaming + * data. */ - if ((pzm->flags & ZM_FLAG_INTERRUPT) != 0) + do { - /* Receiver sent an interrupt. Enter a wait state and see what - * they want. Next header *should* be ZRPOS. - */ + /* This is the number of byte left in the file to be sent */ - zmdbg("ZMS_STATE %d->%d: Interrupt\n", pzm->state, ZMS_SENDWAIT); + sndsize = pzms->filesize - pzms->offset; - pzm->state = ZMS_SENDWAIT; - pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; - pzm->flags &= ~ZM_FLAG_INTERRUPT; - return 0; - } + /* This is the nubmer of bytes that have been sent but not yet ackowledged. */ - /* This is the number of byte left in the file to be sent */ + unacked = pzms->offset - pzms->lastoffs; - sndsize = pzms->filesize - pzms->offset; + /* Can we still send? If so, how much? If rcvmax is zero, then the + * remote can handle full streaming and we never have to wait. + * Otherwise, we have to restrict the total number of unacknowledged + * bytes to rcvmax. + */ - /* This is the nubmer of bytes that have been sent but not yet ackowledged. */ + zmdbg("sndsize: %d unacked: %d rcvmax: %d\n", + sndsize, unacked, pzms->rcvmax); - unacked = pzms->offset - pzms->lastoffs; + if (pzms->rcvmax != 0) + { + /* If we were to send 'sndsize' more bytes, would that exceed recvmax? */ - /* Can we still send? If so, how much? If rcvmax is zero, then the - * remote can handle full streaming and we never have to wait. Otherwise, - * we have to restrict the total number of unacknowledged bytes to rcvmax. - */ + if (sndsize + unacked > pzms->rcvmax) + { + /* Yes... clip the maximum so that we stay within that limit */ - zmdbg("sndsize: %d unacked: %d rcvmax: %d\n", - sndsize, unacked, pzms->rcvmax); + int maximum = pzms->rcvmax - unacked; + if (sndsize < maximum) + { + sndsize = maximum; + } - if (pzms->rcvmax != 0) - { - /* If we were to send 'sndsize' more bytes, would that exceed recvmax? */ + wait = true; + zmdbg("Clipped sndsize: %d\n", sndsize); + } + } + + /* Can we send anything? */ - if (sndsize + unacked > pzms->rcvmax) + if (sndsize <= 0) { - /* Yes... clip the maximum so that we stay within that limit */ + /* No, not now. Keep waiting */ - int maximum = pzms->rcvmax - unacked; - if (sndsize < maximum) - { - sndsize = maximum; - } - - wait = true; - zmdbg("Clipped sndsize: %d\n", sndsize); + zmdbg("ZMS_STATE %d->%d\n", pzm->state, ZMS_SENDWAIT); + + pzm->state = ZMS_SENDWAIT; + pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; + return OK; } - } - /* Can we send anything? */ + /* Determine what kind of packet to send + * + * ZCRCW: + * "If the receiver cannot overlap serial and disk I/O, it uses the + * ZRINIT frame to specify a buffer length which the sender will + * not overflow. The sending program sends a ZCRCW data subpacket + * and waits for a ZACK header before sending the next segment of + * the file. + * + * ZCRCG + * "A data subpacket terminated by ZCRCG and CRC does not elicit a + * response unless an error is detected; more data subpacket(s) + * follow immediately." + * + * ZCRCQ + * "ZCRCQ data subpackets expect a ZACK response with the + * receiver's file offset if no error, otherwise a ZRPOS response + * with the last good file offset. Another data subpacket + * continues immediately. ZCRCQ subpackets are not used if the + * receiver does not indicate FDX ability with the CANFDX bit. + */ - if (sndsize <= 0) - { - /* No, not now. Keep waiting */ + if ((pzm->flags & ZM_FLAG_WAIT) != 0) + { + type = ZCRCW; + pzm->flags &= ~ZM_FLAG_WAIT; + } + else if (wait) + { + type = ZCRCW; + } + else + { + type = pzms->dpkttype; + } - zmdbg("ZMS_STATE %d->%d\n", pzm->state, ZMS_SENDWAIT); + /* Read characters from file and put into buffer until buffer is full + * or file is exhausted + */ - pzm->state = ZMS_SENDWAIT; - pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; - return OK; - } + bcrc32 = ((pzm->flags & ZM_FLAG_CRC32) != 0); + crc = bcrc32 ? 0xffffffff : 0; + pzm->flags &= ~ZM_FLAG_ATSIGN; - /* Determine what kind of packet to send */ + ptr = pzm->scratch; + pktsize = 0; - if ((pzm->flags & ZM_FLAG_WAIT) != 0) - { - type = ZCRCW; - pzm->flags &= ~ZM_FLAG_WAIT; - } - else if (wait) - { - type = ZCRCW; - } - else - { - type = pzms->strtype; - } + while (pktsize <= (CONFIG_SYSTEM_ZMODEM_SNDBUFSIZE - 10) && + (ret = zm_getc(pzms->infd)) != EOF) + { + /* Add the new value to the accumulated CRC */ - /* Read characters from file and put into buffer until buffer is full or - * file is exhausted - */ + uint8_t ch = (uint8_t)ret; + if (!bcrc32) + { + crc = (uint32_t)crc16part(&ch, 1, (uint16_t)crc); + } + else + { + crc = crc32part(&ch, 1, crc); + } - bcrc32 = ((pzm->flags & ZM_FLAG_CRC32) != 0); - crc = bcrc32 ? 0xffffffff : 0; - pzm->flags &= ~ZM_FLAG_ATSIGN; + /* Put the character into the buffer, escaping as necessary */ - ptr = pzm->scratch; - pktsize = 0; + ptr = zm_putzdle(pzm, ptr, ch); - while (pktsize <= (CONFIG_SYSTEM_ZMODEM_SNDBUFSIZE - 10) && - (ret = zm_getc(pzms->infd)) != EOF) - { - /* Add the new value to the accumulated CRC */ + /* Recalculate the accumulated packet size to handle expansion due + * to escaping. + */ - uint8_t ch = (uint8_t)ret; - if (!bcrc32) - { - crc = (uint32_t)crc16part(&ch, 1, (uint16_t)crc); - } - else - { - crc = crc32part(&ch, 1, crc); - } + pktsize = (int32_t)(ptr - pzm->scratch); - /* Put the character into the buffer, escaping as necessary */ + /* And increment the file offset */ - ptr = zm_putzdle(pzm, ptr, ch); + pzms->offset++; + } - /* Recalculate the accumulated packet size to handle expansion due to - * escaping. + /* If we've reached file end, a ZEOF header will follow. If there's + * room in the outgoing buffer for it, end the packet with ZCRCE and + * append the ZEOF header. If there isn't room, we'll have to do a + * ZCRCW */ - - pktsize = (int32_t)(ptr - pzm->scratch); - /* And increment the file offset */ + pzm->flags &= ~ZM_FLAG_EOF; + if (ret == EOF) + { + pzm->flags |= ZM_FLAG_EOF; + if (wait || (pzms->rcvmax != 0 && pktsize < 24)) + { + type = ZCRCW; + } + else + { + type = ZCRCE; + } + } + + /* Save the ZDLE in the transmit buffer */ - pzms->offset++; - } + *ptr++ = ZDLE; - /* If we've reached file end, a ZEOF header will follow. If there's room - * in the outgoing buffer for it, end the packet with ZCRCE and append the - * ZEOF header. If there isn't room, we'll have to do a ZCRCW - */ + /* Save the type */ - pzm->flags &= ~ZM_FLAG_EOF; - if (ret == EOF) - { - pzm->flags |= ZM_FLAG_EOF; - if (wait || (pzms->rcvmax != 0 && pktsize < 24)) + if (!bcrc32) { - type = ZCRCW; + crc = (uint32_t)crc16part(&type, 1, (uint16_t)crc); } else { - type = ZCRCE; + crc = crc32part(&type, 1, crc); } - } - - /* Save the ZDLE in the transmit buffer */ - *ptr++ = ZDLE; + *ptr++ = type; - /* Save the type */ + /* Update the CRC and put the CRC in the transmit buffer */ - if (!bcrc32) - { - crc = (uint32_t)crc16part(&type, 1, (uint16_t)crc); - } - else - { - crc = crc32part(&type, 1, crc); - } - - *ptr++ = type; - - /* Update the CRC and put the CRC in the transmit buffer */ - - if (!bcrc32) - { - 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 (i = 0; i < 4; i++, crc >>= 8) + if (!bcrc32) { + 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 (i = 0; i < 4; i++, crc >>= 8) + { + ptr = zm_putzdle(pzm, ptr, crc & 0xff); + } + } - /* Get the final packet size */ + /* Get the final packet size */ - pktsize = ptr - pzm->scratch; - DEBUGASSERT(pktsize < CONFIG_SYSTEM_ZMODEM_SNDBUFSIZE); + pktsize = ptr - pzm->scratch; + DEBUGASSERT(pktsize < CONFIG_SYSTEM_ZMODEM_SNDBUFSIZE); - /* And send the packet */ + /* And send the packet */ - dbg("Sending %d bytes. New offset: %ld\n", - pktsize, (unsigned long)pzms->offset); + dbg("Sending %d bytes. New offset: %ld\n", + pktsize, (unsigned long)pzms->offset); - nwritten = zm_remwrite(pzm->remfd, pzm->scratch, pktsize); - if (nwritten < 0) - { - zmdbg("ERROR: zm_remwrite failed: %d\n", (int)nwritten); - return (int)nwritten; - } + nwritten = zm_remwrite(pzm->remfd, pzm->scratch, pktsize); + if (nwritten < 0) + { + zmdbg("ERROR: zm_remwrite failed: %d\n", (int)nwritten); + return (int)nwritten; + } - /* Then do what? That depends on the type of the transfer */ + /* Then do what? That depends on the type of the transfer */ - switch (type) - { - /* That was the last packet. Send ZCRCE to indicate the end of file */ + switch (type) + { + /* That was the last packet. Send ZCRCE to indicate the end of + * file. + */ - case ZCRCE: /* CRC next, frame ends, header follows */ - zmdbg("ZMS_STATE %d->%d: ZCRCE\n", pzm->state, ZMS_SENDEOF); + case ZCRCE: /* CRC next, transfer ends, ZEOF follows */ + zmdbg("ZMS_STATE %d->%d: ZCRCE\n", pzm->state, ZMS_SENDEOF); - pzm->state = ZMS_SENDEOF; - pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; - zm_be32toby(pzms->offset, by); - return zm_sendhexhdr(pzm, ZEOF, by); + pzm->state = ZMS_SENDEOF; + pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; + zm_be32toby(pzms->offset, by); + return zm_sendhexhdr(pzm, ZEOF, by); - /* We need to want for ZACK */ + /* We need to want for ZACK */ - case ZCRCW: /* CRC next, send ZACK, frame ends */ - if ((pzm->flags & ZM_FLAG_EOF) != 0) - { - zmdbg("ZMS_STATE %d->%d: EOF\n", pzm->state, ZMS_SENDDONE); - pzm->state = ZMS_SENDDONE; - } - else - { - zmdbg("ZMS_STATE %d->%d: Not EOF\n", pzm->state, ZMS_SENDWAIT); - pzm->state = ZMS_SENDWAIT; - } + case ZCRCW: /* CRC next, send ZACK, transfer ends */ + if ((pzm->flags & ZM_FLAG_EOF) != 0) + { + zmdbg("ZMS_STATE %d->%d: EOF\n", pzm->state, ZMS_SENDDONE); + pzm->state = ZMS_SENDDONE; + } + else + { + zmdbg("ZMS_STATE %d->%d: Not EOF\n", pzm->state, ZMS_SENDWAIT); + pzm->state = ZMS_SENDWAIT; + } - pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; - break; + pzm->timeout = CONFIG_SYSTEM_ZMODEM_RESPTIME; + break; - /* No response is expected */ + /* No response is expected -- we are streaming */ - case ZCRCG: /* CRC next, frame continues nonstop */ - case ZCRCQ: /* CRC next, send ZACK, frame continues nonstop */ - default: - zmdbg("ZMS_STATE %d->%d: Default\n", pzm->state, ZMS_SENDING); + case ZCRCG: /* Transfer continues non-stop */ + case ZCRCQ: /* Expect ZACK, transfer may continues non-stop */ + default: + zmdbg("ZMS_STATE %d->%d: Default\n", pzm->state, ZMS_SENDING); - pzm->state = ZMS_SENDING; - pzm->timeout = 0; - break; + pzm->state = ZMS_SENDING; + break; + } } +#ifdef CONFIG_SYSTEM_ZMODEM_RCVSAMPLE + while (pzm->state != ZMS_SENDING && !zm_rcvpending(pzm)); +#else + while (0); +#endif return OK; } @@ -1096,7 +1165,7 @@ static int zms_sendack(FAR struct zm_state_s *pzm) FAR struct zms_state_s *pzms = (FAR struct zms_state_s *)pzm; off_t offset; - /* Paragraph 11.4 ZACK. Acknowledgment to a ZSINIT frame, ..., ZCRCQ or + /* Paragraph 11.4 ZACK. Acknowledgment to a ZSINIT , ..., ZCRCQ or * ZCRCW data subpacket. ZP0 to ZP3 contain file offset. */ @@ -1127,8 +1196,8 @@ static int zms_sendwaitack(FAR struct zm_state_s *pzm) off_t offset; int ret; - /* Paragraph 11.4 ZACK. Acknowledgment to a ZSINIT frame, ..., ZCRCQ or - * ZCRCW data subpacket. ZP0 to ZP3 contain file offset. + /* Paragraph 11.4 ZACK. ?Acknowledgment to a ZSINIT frame, ..., ZCRCQ or + * ZCRCW data subpacket. ZP0 to ZP3 contain file offset." */ offset = zm_bytobe32(pzm->hdrdata + 1); @@ -1524,7 +1593,7 @@ ZMSHANDLE zms_initialize(int remfd) pzm->remfd = remfd; /* Create a timer to handle timeout events */ - + ret = zm_timerinit(pzm); if (ret < 0) { -- cgit v1.2.3