summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Van Doorn <vandoorn.nick@gmail.com>2018-09-11 18:57:15 -0700
committerNick Van Doorn <vandoorn.nick@gmail.com>2018-09-11 18:57:15 -0700
commitecde0e8def9473be4095261bc3d242eef22c18c4 (patch)
tree4e67bddba71d6722fa62b0583b5caf1d24b21523
parentdd19abb0dab39605777dc9cf0b8f3073f7fae8c1 (diff)
Swap for xmodem1k
-rw-r--r--upload/xmodem.c2084
-rw-r--r--upload/xmodem.h308
2 files changed, 241 insertions, 2151 deletions
diff --git a/upload/xmodem.c b/upload/xmodem.c
index dd471d7..a97327c 100644
--- a/upload/xmodem.c
+++ b/upload/xmodem.c
@@ -1,1879 +1,269 @@
-//////////////////////////////////////////////////////////////////////////////
-// //
-// _ //
-// __ __ _ __ ___ ___ __| | ___ _ __ ___ ___ //
-// \ \/ /| '_ ` _ \ / _ \ / _` | / _ \| '_ ` _ \ / __| //
-// > < | | | | | || (_) || (_| || __/| | | | | | _| (__ //
-// /_/\_\|_| |_| |_| \___/ \__,_| \___||_| |_| |_|(_)\___| //
-// //
-// //
-//////////////////////////////////////////////////////////////////////////////
-// //
-// Copyright (c) 2012 by S.F.T. Inc. - All rights reserved //
-// Use, copying, and distribution of this software are licensed according //
-// to the GPLv2, LGPLv2, or BSD license, as appropriate (see COPYING) //
-// //
-//////////////////////////////////////////////////////////////////////////////
-
-// XMODEM adapted for arduino and POSIX systems. Windows code incomplete
-
+/*
+ * Copyright 2001-2010 Georges Menie (www.menie.org)
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the University of California, Berkeley 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 REGENTS 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 REGENTS AND 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.
+ */
+
+/* this code needs standard functions memcpy() and memset()
+ and input/output functions _inbyte() and _outbyte().
+ the prototypes of the input/output functions are:
+ int _inbyte(unsigned short timeout); // msec timeout
+ void _outbyte(int c);
+ */
+
+#include "crc16.h"
#include "xmodem.h"
-// special I/O when linked into 'SFTARDCAL' application
-#ifdef SFTARDCAL
-int my_read(SERIAL_TYPE iFile, void* pBuf, int cbBuf);
-int my_write(SERIAL_TYPE iFile, const void* pBuf, int cbBuf);
-void my_flush(SERIAL_TYPE iFile);
-#endif // SFTARDCAL
-
-// internal structure definitions
-
-// Windows requires a different way of specifying structure packing
-#ifdef WIN32
-#define PACKED
-#pragma pack(push, 1)
-#else // POSIX, ARDUINO
-#define PACKED __attribute__((__packed__))
-#endif // WIN32 vs THE REST OF THE WORLD
-
-#define _SOH_ 1 /* start of packet - note XMODEM-1K uses '2' */
-#define _EOT_ 4
-#define _ENQ_ 5
-#define _ACK_ 6
-#define _NAK_ 21 /* NAK character */
-#define _CAN_ 24 /* CAN character CTRL+X */
-
-/** \file xmodem.c
- * \brief main source file for S.F.T. XMODEM library
- *
- * S.F.T. XMODEM library
-**/
-
-/** \ingroup xmodem_internal
- * \brief Structure defining an XMODEM CHECKSUM packet
- *
-\code
-typedef struct _XMODEM_BUF_
-{
- char cSOH; // ** SOH byte goes here **
- unsigned char aSEQ, aNotSEQ; // ** 1st byte = seq#, 2nd is ~seq# **
- char aDataBuf[128]; // ** the actual data itself! **
- unsigned char bCheckSum; // ** checksum gets 1 byte **
-} PACKED XMODEM_BUF;
-\endcode
- *
-**/
-typedef struct _XMODEM_BUF_ {
- char cSOH; ///< SOH byte goes here
- unsigned char aSEQ, aNotSEQ; ///< 1st byte = seq#, 2nd is ~seq#
- char aDataBuf[128]; ///< the actual data itself!
- unsigned char bCheckSum; ///< checksum gets 1 byte
-} PACKED XMODEM_BUF;
-
-/** \ingroup xmodem_internal
- * \brief Structure defining an XMODEM CRC packet
- *
-\code
-typedef struct _XMODEMC_BUF_
-{
- char cSOH; // ** SOH byte goes here **
- unsigned char aSEQ, aNotSEQ; // ** 1st byte = seq#, 2nd is ~seq# **
- char aDataBuf[128]; // ** the actual data itself! **
- unsigned short wCRC; // ** CRC gets 2 bytes, high endian **
-} PACKED XMODEMC_BUF;
-\endcode
- *
-**/
-typedef struct _XMODEMC_BUF_ {
- char cSOH; ///< SOH byte goes here
- unsigned char aSEQ, aNotSEQ; ///< 1st byte = seq#, 2nd is ~seq#
- char aDataBuf[128]; ///< the actual data itself!
- unsigned short wCRC; ///< CRC gets 2 bytes, high endian
-} PACKED XMODEMC_BUF;
-
-#ifdef WIN32
-// restore default packing
-#pragma pack(pop)
-#endif // WIN32
-
-/** \ingroup xmodem_internal
- * \brief Structure that identifies the XMODEM communication state
- *
-\code
-typedef struct _XMODEM_
-{
- SERIAL_TYPE ser; // identifies the serial connection, data type is
-OS-dependent
- FILE_TYPE file; // identifies the file handle, data type is OS-dependent
- union
- {
- XMODEM_BUF xbuf; // XMODEM CHECKSUM buffer
- XMODEMC_BUF xcbuf; // XMODEM CRC buffer
- } buf; // union of both buffers, total length 133 bytes
- unsigned char bCRC; // non-zero for CRC, zero for checksum
-} XMODEM;
-\endcode
- *
-**/
-typedef struct _XMODEM_ {
- SERIAL_TYPE
- ser; ///< identifies the serial connection, data type is OS-dependent
- FILE_TYPE file; ///< identifies the file handle, data type is OS-dependent
-
- union {
- XMODEM_BUF xbuf; ///< XMODEM CHECKSUM buffer
- XMODEMC_BUF xcbuf; ///< XMODEM CRC buffer
- } buf; ///< union of both buffers, total length 133 bytes
-
- unsigned char bCRC; ///< non-zero for CRC, zero for checksum
-
-} XMODEM;
-
-#ifdef DEBUG_CODE
-static char szERR[32]; // place for error messages, up to 16 characters
-
-const char* XMGetError(void) {
- return szERR;
-}
-#endif // DEBUG_CODE
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
-void debug_dump_buffer(int iDir, const void* pBuf, int cbBuf) {
- int i1, i2;
- const unsigned char *p1, *p2;
-
- if (cbBuf <= 0) {
- return;
- }
-
- p1 = p2 = (const unsigned char*)pBuf;
-
- for (i1 = 0, i2 = 0; i1 <= cbBuf; i1++, p1++) {
- if (!i1 || i2 >= 16 || i1 == cbBuf) {
- if (i1) {
- while (i2 < 16) {
- fputs(" ", stderr); // fill up spaces where data would be
- i2++;
- }
-
- fputs(" : ", stderr);
-
- while (p2 < p1) {
- if (*p2 >= 32 && *p2 <= 127) {
- fputc(*p2, stderr);
- } else {
- fputc('.', stderr);
- }
-
- p2++;
- }
-
- fputc('\n', stderr);
- }
-
- if (!i1 && iDir > 0) {
- fputs("--> ", stderr);
- } else if (!i1 && iDir < 0) {
- fputs("<-- ", stderr);
- } else {
- fputs(" ", stderr);
- }
-
- i2 = 0;
- p2 = p1; // make sure
- }
-
- if (i1 < cbBuf) {
- if (!i2) {
- fprintf(stderr, "%02x: %02x", i1, *p1);
- } else {
- fprintf(stderr, ", %02x", *p1);
- }
-
- i2++;
+#define SOH 0x01
+#define STX 0x02
+#define EOT 0x04
+#define ACK 0x06
+#define NAK 0x15
+#define CAN 0x18
+#define CTRLZ 0x1A
+
+#define DLY_1S 1000
+#define MAXRETRANS 25
+#define TRANSMIT_XMODEM_1K
+
+static int check(int crc, const unsigned char* buf, int sz) {
+ if (crc) {
+ unsigned short crc = crc16_ccitt(buf, sz);
+ unsigned short tcrc = (buf[sz] << 8) + buf[sz + 1];
+ if (crc == tcrc)
+ return 1;
+ } else {
+ int i;
+ unsigned char cks = 0;
+ for (i = 0; i < sz; ++i) {
+ cks += buf[i];
}
+ if (cks == buf[sz])
+ return 1;
}
- fputc('\n', stderr);
- fflush(stderr);
+ return 0;
}
-#endif // STAND_ALONE, DEBUG_CODE
-
-// char iBinaryTransfer = 0, iDisableRXOVER = 0;
-
-/** \ingroup xmodem_internal
- * \brief Calculate checksum for XMODEM packet
- *
- * \param lpBuf A pointer to the XMODEM data buffer
- * \param cbBuf The length of the XMODEM data buffer (typically 128)
- * \return An unsigned char value to be assigned to the 'checksum' element in
- *the XMODEM packet
- *
-**/
-unsigned char CalcCheckSum(const char* lpBuf, short cbBuf) {
- short iC, i1;
- iC = 0;
-
- for (i1 = 0; i1 < cbBuf; i1++) {
- iC += lpBuf[i1];
- }
-
- return (unsigned char)(iC & 0xff);
+static void flushinput(void) {
+ while (_inbyte(((DLY_1S)*3) >> 1) >= 0)
+ ;
}
-/** \ingroup xmodem_internal
- * \brief Calculate checksum for XMODEM packet
- *
- * \param sVal An unsigned short integer to be made 'high endian' by flipping
- *bytes (as needed)
- * \return A (possibly) byte-flipped high-endian unsigned short integer
- *
- * This function assumes low-endian for Arduino, and performs a universal
- *operation
- * for 'indeterminate' architectures.
-**/
-static unsigned short my_htons(unsigned short sVal) {
- union {
- unsigned char aVal[2];
- unsigned short sVal;
- } a, b;
-
- // tweeked for size and speed. enjoy.
-
- b.sVal = sVal;
-
-#ifdef ARDUINO
-
- a.aVal[0] = b.aVal[1]; // no math involved, pre-optimized code
- a.aVal[1] = b.aVal[0];
-
-#else
-
- a.aVal[0] = (unsigned char)(sVal >> 8); // less optimized but universal code
- a.aVal[1] = (unsigned char)(sVal & 0xff);
-
-#endif // ARDUINO
-
- return a.sVal;
-}
-
-/** \ingroup xmodem_internal
- * \brief Calculate 16-bit CRC for XMODEM packet
- *
- * \param lpBuf A pointer to the XMODEM data buffer
- * \param cbBuf The length of the XMODEM data buffer (typically 128)
- * \return A high-endian 16-bit (unsigned short) value to be assigned to the
- *'CRC' element in the XMODEM packet
- *
- * This method uses the 'long way' which is SMALLER CODE for microcontrollers,
- *but eats up a bit more CPU.
- * Otherwise, you'd have to pre-build the 256 byte table and use "the table
- *lookup" method.
-**/
-unsigned short CalcCRC(const char* lpBuf, short cbBuf) {
- unsigned short wCRC;
- short i1, i2, iAX;
- char cAL;
-
- // ** this function returns 2-byte string containing
- // ** the CRC calculation result, as high endian
-
- wCRC = 0;
-
- for (i1 = 0; i1 < cbBuf; i1++) {
- cAL = lpBuf[i1];
-
- iAX = (unsigned short)cAL << 8;
-
- wCRC = iAX ^ wCRC;
-
- for (i2 = 0; i2 < 8; i2++) {
- iAX = wCRC;
-
- if (iAX & 0x8000) {
- wCRC <<= 1;
- wCRC ^= 0x1021;
- } else {
- wCRC <<= 1;
+int xmodemReceive(unsigned char* dest, int destsz) {
+ unsigned char
+ xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
+ unsigned char* p;
+ int bufsz, crc = 0;
+ unsigned char trychar = 'C';
+ unsigned char packetno = 1;
+ int i, c, len = 0;
+ int retry, retrans = MAXRETRANS;
+
+ for (;;) {
+ for (retry = 0; retry < 16; ++retry) {
+ if (trychar)
+ _outbyte(trychar);
+ if ((c = _inbyte((DLY_1S) << 1)) >= 0) {
+ switch (c) {
+ case SOH:
+ bufsz = 128;
+ goto start_recv;
+ case STX:
+ bufsz = 1024;
+ goto start_recv;
+ case EOT:
+ flushinput();
+ _outbyte(ACK);
+ return len; /* normal end */
+ case CAN:
+ if ((c = _inbyte(DLY_1S)) == CAN) {
+ flushinput();
+ _outbyte(ACK);
+ return -1; /* canceled by remote */
+ }
+ break;
+ default:
+ break;
+ }
}
}
- }
-
- return my_htons(wCRC);
-}
-
-// void WaitASecond()
-//{
-//#ifdef ARDUINO
-// delay(1000);
-//#elif defined(WIN32)
-// Sleep(1000);
-//#else //
-// usleep(1000000);
-//#endif // ARDUINO
-//}
-
-#ifndef ARDUINO
-#ifdef WIN32
-#define MyMillis GetTickCount
-#else // WIN32
-
-/** \ingroup xmodem_internal
- * \brief Return internal 'milliseconds' value for timing purposes
- *
- * \return A calculated 'milliseconds' value as an unsigned long integer
- *
- * This function returns the 'unsigned long' integer value for elapsed time
- *based
- * on the result of the 'gettimeofday()' API function. On 32-bit and Windows
- *systems
- * the value might wrap around, so you should be careful with your time
- *comparisons (see the
- * code _I_ wrote for the right way to do it). On 64-bit POSIX systems, this
- *value will
- * always increase.\n
- * NOTE: Win32 defines this as a macro (see above) for the 'GetTickCount()'
- *api, which
- * returns a 32-bit value. POSIX x86 returns 32-bit, x64 returns
- *64-bit. YMMV.
-**/
-unsigned long MyMillis(void) {
- struct timeval tv;
-
- gettimeofday(&tv, NULL); // 2nd parameter is obsolete anyway
-
- // NOTE: this won't roll over the way 'GetTickCount' does in WIN32 so I'll
- // truncate it
- // down to a 32-bit value to make it happen. Everything that uses
- // 'MyGetTickCount'
- // must handle this rollover properly using 'int' and not 'long' (or
- // cast afterwards)
- return ((unsigned int)((unsigned long)tv.tv_sec * 1000L +
- (unsigned long)tv.tv_usec / 1000L));
-}
-#endif // WIN32
-#endif // ARDUINO
-
-// Function GenerateSEQ (wSeq%) As String
-//
-// GenerateSEQ = Chr$(wSeq%) + Chr$(Not (wSeq%) And &HFF)
-//
-// End Function
-
-/** \ingroup xmodem_internal
- * \brief Generate a sequence number pair, place into XMODEM_BUF
- *
- * \param pBuf A pointer to an XMODEM_BUF structure
- * \param bSeq An unsigned char, typically cast from an unsigned long 'block
- *number'
- *
- * This function generates the sequence pair for the XMODEM packet. The 'block
- *number'
- * is initially assigned a value of '1', and increases by 1 for each successful
- *packet.
- * That value is 'truncated' to a single byte and assigned as a sequence number
- *for the
- * packet itself.
-**/
-void GenerateSEQ(XMODEM_BUF* pBuf, unsigned char bSeq) {
- pBuf->aSEQ = bSeq;
- pBuf->aNotSEQ = ~bSeq;
-}
-
-/** \ingroup xmodem_internal
- * \brief Generate a sequence number pair, place into XMODEMC_BUF (the CRC
- *version)
- *
- * \param pBuf A pointer to an XMODEM_BUF structure
- * \param bSeq An unsigned char, typically cast from an unsigned long 'block
- *number'
- *
- * This function generates the sequence pair for the XMODEM packet. The 'block
- *number'
- * is initially assigned a value of '1', and increases by 1 for each successful
- *packet.
- * That value is 'truncated' to a single byte and assigned as a sequence number
- *for the
- * packet itself.
-**/
-void GenerateSEQC(XMODEMC_BUF* pBuf, unsigned char bSeq) {
- pBuf->aSEQ = bSeq;
- pBuf->aNotSEQ =
- (255 - bSeq); //~bSeq; these should be the same but for now I do this...
-}
-
-/** \ingroup xmodem_internal
- * \brief Get an XMODEM block from the serial device
- *
- * \param ser A 'SERIAL_TYPE' identifier for the serial connection
- * \param pBuf A pointer to the buffer that receives the data
- * \param cbSize The number of bytes/chars to read
- * \return The number of bytes/chars read, 0 if timed out (no data), < 0 on
- *error
- *
- * Call this function to read data from the serial port, specifying the number
- *of
- * bytes to read. This function times out after no data transferred (silence)
- *for
- * a period of 'SILENCE_TIMEOUT' milliseconds. This allows spurious data
- *transfers
- * to continue as long as there is LESS THAN 'SILENCE_TIMEOUT' between bytes,
- *and
- * also allows VERY SLOW BAUD RATES (as needed). However, if the transfer
- *takes longer
- * than '10 times SILENCE_TIMEOUT', the function will return the total number
- *of bytes
- * that were received within that time.\n
- * The default value of 5 seconds, extended to 50 seconds, allows a worst-case
- *baud
- * rate of about 20. This should not pose a problem. If it does, edit the
- *code.
-**/
-short GetXmodemBlock(SERIAL_TYPE ser, char* pBuf, short cbSize) {
- unsigned long ulCur;
- short cb1;
-// ** This function obtains a buffer of 'cbSize' bytes, **
-// ** waiting a maximum of 5 seconds (of silence) to get it. **
-// ** It returns the data within 'pBuf', returning the actual **
-// ** number of bytes transferred. **
-
-#ifdef ARDUINO
- char* p1;
- short i1;
-
- p1 = pBuf;
- cb1 = 0;
-
- ulCur = millis();
- ser->setTimeout(SILENCE_TIMEOUT); // 5 seconds [of silence]
-
- for (i1 = 0; i1 < cbSize; i1++) {
- if (ser->readBytes(p1, 1) !=
- 1) // 5 seconds of "silence" is what fails this
- {
- break;
- }
-
- cb1++;
- p1++;
-
- if ((millis() - ulCur) >
- (unsigned long)(10L * SILENCE_TIMEOUT)) // 10 times SILENCE TIMEOUT for
- // TOTAL TIMEOUT
- {
- break; // took too long, I'm going now
- }
- }
-
-#elif defined(SFTARDCAL)
-#ifndef WIN32
- struct pollfd aFD[2];
-#endif // WIN32
- int i1;
- unsigned long ulStart;
-
- ulStart = ulCur = MyMillis();
-
- cb1 = 0;
-
- do {
-#ifndef WIN32
- aFD[0].fd = ser;
- aFD[0].events = POLLIN | POLLERR;
- aFD[0].revents = 0;
-
- i1 = poll(aFD, 1, 100);
- if (!i1) {
+ if (trychar == 'C') {
+ trychar = NAK;
continue;
}
-
- if (i1 < 0) {
- fprintf(stderr, "poll error %d\n", errno);
- return -1;
- }
-#endif // WIN32
-
-#ifdef WIN32
- if (my_pollin(ser) > 0)
-#else // WIN32
- if (aFD[0].revents & POLLIN)
-#endif // WIN32
- {
- i1 = my_read(ser, pBuf + cb1, cbSize - cb1);
-
- if (i1 > 0) {
- cb1 += i1;
- ulCur = MyMillis();
- }
- } else {
- MySleep(1);
- }
- } while (!QuitFlag() && cb1 < cbSize &&
- (MyMillis() - ulCur) < SILENCE_TIMEOUT &&
- (MyMillis() - ulStart) < (unsigned long)10L * SILENCE_TIMEOUT);
-
-#elif defined(WIN32)
-
-#error no win32 code yet
-
-#else // POSIX
- unsigned long ulStart;
- char* p1;
- int i1, i2;
-
- if (fcntl(ser, F_SETFL, O_NONBLOCK) == -1) {
- static int iFailFlag = 0;
-
- if (!iFailFlag) {
- fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n",
- errno);
- fflush(stderr);
- iFailFlag = 1;
- }
- }
-
- p1 = pBuf;
- cb1 = 0;
-
- ulStart = ulCur = MyMillis();
-
- for (i1 = 0; i1 < cbSize; i1++) {
- while ((i2 = read(ser, p1, 1)) != 1) {
- if (i2 < 0 && errno != EAGAIN) {
- // read error - exit now
- // return cb1; // how many bytes I actually read
- goto the_end;
- } else {
- usleep(1000); // 1 msec
-
- if ((MyMillis() - ulCur) > SILENCE_TIMEOUT || // too much silence?
- (MyMillis() - ulStart) >
- 10 * SILENCE_TIMEOUT) // too long for transfer
- {
- // return cb1; // finished (return how many bytes I actually
- // read)
- goto the_end;
+ flushinput();
+ _outbyte(CAN);
+ _outbyte(CAN);
+ _outbyte(CAN);
+ return -2; /* sync error */
+
+ start_recv:
+ if (trychar == 'C')
+ crc = 1;
+ trychar = 0;
+ p = xbuff;
+ *p++ = c;
+ for (i = 0; i < (bufsz + (crc ? 1 : 0) + 3); ++i) {
+ if ((c = _inbyte(DLY_1S)) < 0)
+ goto reject;
+ *p++ = c;
+ }
+
+ if (xbuff[1] == (unsigned char)(~xbuff[2]) &&
+ (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno - 1) &&
+ check(crc, &xbuff[3], bufsz)) {
+ if (xbuff[1] == packetno) {
+ register int count = destsz - len;
+ if (count > bufsz)
+ count = bufsz;
+ if (count > 0) {
+ memcpy(&dest[len], &xbuff[3], count);
+ len += count;
}
+ ++packetno;
+ retrans = MAXRETRANS + 1;
}
- }
-
- // here it succeeds
-
- cb1++;
- p1++;
-
- if ((MyMillis() - ulStart) >
- 10 * SILENCE_TIMEOUT) // 10 times SILENCE TIMEOUT for TOTAL TIMEOUT
- {
- break; // took too long, I'm going now
- }
- }
-
-the_end:
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- fprintf(stderr, "GetXmodemBlock - request %d, read %d errno=%d\n", cbSize,
- cb1, errno);
- fflush(stderr);
- //#ifdef DEBUG_CODE
- debug_dump_buffer(-1, pBuf, cb1);
-//#endif // DEBUG_CODE
-#endif // STAND_ALONE
-
-#endif // ARDUINO
-
- return cb1; // what I actually read
-}
-
-/** \ingroup xmodem_internal
- * \brief Write a single character to the serial device
- *
- * \param ser A 'SERIAL_TYPE' identifier for the serial connection
- * \param bVal The byte to send
- * \return The number of bytes/chars written, or < 0 on error
- *
- * Call this function to write one byte of data to the serial port. Typically
- * this is used to send things like an ACK or NAK byte.
-**/
-int WriteXmodemChar(SERIAL_TYPE ser, unsigned char bVal) {
- int iRval;
-#ifdef ARDUINO
-
- iRval = ser->write(bVal);
-// ser->flush(); // force sending it
-
-#elif defined(SFTARDCAL)
- char buf[2]; // use size of '2' to avoid warnings about array size of '1'
-
- buf[0] = (char)bVal;
- return (short)my_write(ser, buf, 1);
-
-#elif defined(WIN32)
-
-#error no win32 code yet
-
-#else // POSIX
- char buf[2]; // use size of '2' to avoid warnings about array size of '1'
-
- if (fcntl(ser, F_SETFL, 0) == -1) // set blocking mode
- {
- static int iFailFlag = 0;
-
- if (!iFailFlag) {
- fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n",
- errno);
- iFailFlag = 1;
- }
- }
-
- buf[0] = bVal; // in case args are passed by register
-
- iRval = write(ser, buf, 1);
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- fprintf(stderr, "WriteXmodemChar - returns %d\n", iRval);
- if (iRval > 0) {
- debug_dump_buffer(1, buf, 1);
- }
-#endif // STAND_ALONE, DEBUG_CODE
-#endif // ARDUINO
-
- return iRval;
-}
-
-/** \ingroup xmodem_internal
- * \brief Send an XMODEM block via the serial device
- *
- * \param ser A 'SERIAL_TYPE' identifier for the serial connection
- * \param pBuf A pointer to the buffer that receives the data
- * \param cbSize The number of bytes/chars to write
- * \return The number of bytes/chars written, < 0 on error
- *
- * Call this function to write data via the serial port, specifying the number
- *of
- * bytes to write.
-**/
-int WriteXmodemBlock(SERIAL_TYPE ser, const void* pBuf, int cbSize) {
- int iRval;
-#ifdef ARDUINO
-
- iRval = ser->write((const uint8_t*)pBuf, cbSize);
-// ser->flush(); // force sending it before returning
-
-#elif defined(SFTARDCAL)
-
- return (short)my_write(ser, pBuf, cbSize);
-
-#elif defined(WIN32)
-
-#error no win32 code yet
-
-#else // POSIX
-
- if (fcntl(ser, F_SETFL, 0) == -1) // set blocking mode
- {
- static int iFailFlag = 0;
-
- if (!iFailFlag) {
- fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n",
- errno);
- fflush(stderr);
- iFailFlag = 1;
- }
- }
-
- iRval = write(ser, pBuf, cbSize);
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- fprintf(stderr, "\r\nWriteXmodemBlock - returns %d\n", iRval);
- fflush(stderr);
-
- if (iRval > 0) {
- debug_dump_buffer(1, pBuf, cbSize);
- }
-#endif // STAND_ALONE, DEBUG_CODE
-#endif
-
- return iRval;
-}
-
-/** \ingroup xmodem_internal
- * \brief Read all input from the serial port until there is 1 second of
- *'silence'
- *
- * \param ser A 'SERIAL_TYPE' identifier for the serial connection
- *
- * Call this function to read ALL data from the serial port, until there is a
- *period
- * with no data (i.e. 'silence') for 1 second. At that point the function will
- *return.\n
- * Some operations require that any bad data be flushed out of the input to
- *prevent
- * synchronization problems. By using '1 second of silence' it forces
- *re-synchronization
- * to occur in one shot, with the possible exception of VERY noisy lines. The
- *down side
- * is that it may slow down transfers with a high data rate.
-**/
-void XModemFlushInput(SERIAL_TYPE ser) {
-#ifdef ARDUINO
- unsigned long ulStart;
-
- ulStart = millis();
-
- do {
- if (ser->available()) {
- ser->read(); // don't care about the data
- ulStart = millis(); // reset time
- } else {
- delay(1);
- }
-
- } while ((millis() - ulStart) < 1000);
-
-#elif defined(SFTARDCAL)
-
- my_flush(ser);
-
-#elif defined(WIN32)
-
-#error no win32 code yet
-
-#else // POSIX
- unsigned long ulStart;
- int i1;
-#ifdef DEBUG_CODE
- unsigned char buf[16];
- int cbBuf;
-#else // DEBUG_CODE
- unsigned char buf[2];
-#endif // DEBUG_CODE
-
- if (fcntl(ser, F_SETFL, O_NONBLOCK) == -1) {
- static int iFailFlag = 0;
-
- if (!iFailFlag) {
- fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n",
- errno);
- iFailFlag = 1;
- }
- }
-
- ulStart = MyMillis();
-#ifdef DEBUG_CODE
- cbBuf = 0;
-#endif // DEBUG_CODE
- while ((MyMillis() - ulStart) < 1000) {
-#ifdef DEBUG_CODE
- i1 = read(ser, &(buf[cbBuf]), 1);
-#else // DEBUG_CODE
- i1 = read(ser, buf, 1);
-#endif // DEBUG_CODE
- if (i1 == 1) {
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- cbBuf++;
- if (cbBuf >= sizeof(buf)) {
- debug_dump_buffer(-1, buf, cbBuf);
- cbBuf = 0;
+ if (--retrans <= 0) {
+ flushinput();
+ _outbyte(CAN);
+ _outbyte(CAN);
+ _outbyte(CAN);
+ return -3; /* too many retry error */
}
-#endif // STAND_ALONE, DEBUG_CODE
- ulStart = MyMillis();
- } else {
- usleep(1000);
+ _outbyte(ACK);
+ continue;
}
+ reject:
+ flushinput();
+ _outbyte(NAK);
}
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- if (cbBuf > 0) {
- debug_dump_buffer(-1, buf, cbBuf);
- }
-#endif // STAND_ALONE, DEBUG_CODE
-
-#endif // ARDUINO
-}
-
-/** \ingroup xmodem_internal
- * \brief Terminate the XMODEM connection
- *
- * \param pX A pointer to the 'XMODEM' object identifying the transfer
- *
- * Call this function prior to ending the XMODEM transfer. Currently the only
- * thing it does is flush the input.
-**/
-void XmodemTerminate(XMODEM* pX) {
- XModemFlushInput(pX->ser);
-
- // TODO: close files?
-}
-
-/** \ingroup xmodem_internal
- * \brief Validate the sequence number of a received XMODEM block
- *
- * \param pX A pointer to an 'XMODEM_BUF'
- * \param bSeq The expected sequence number (block & 255)
- * \return A zero value on success, non-zero otherwise
- *
- * Call this function to validate a packet's sequence number against the block
- *number
-**/
-short ValidateSEQ(XMODEM_BUF* pX, unsigned char bSeq) {
- return pX->aSEQ != 255 - pX->aNotSEQ || // ~(pX->aNotSEQ) ||
- pX->aSEQ != bSeq; // returns TRUE if not valid
}
-/** \ingroup xmodem_internal
- * \brief Validate the sequence number of a received XMODEM block (CRC version)
- *
- * \param pX A pointer to an 'XMODEMC_BUF'
- * \param bSeq The expected sequence number (block & 255)
- * \return A zero value on success, non-zero otherwise
- *
- * Call this function to validate a packet's sequence number against the block
- *number
-**/
-short ValidateSEQC(XMODEMC_BUF* pX, unsigned char bSeq) {
- return pX->aSEQ != 255 - pX->aNotSEQ || // ~(pX->aNotSEQ) ||
- pX->aSEQ != bSeq; // returns TRUE if not valid
-}
-
-/** \ingroup xmodem_internal
- * \brief Generic function to receive a file via XMODEM (CRC or Checksum)
- *
- * \param pX A pointer to an 'XMODEM_BUF' with valid bCRC, ser, and file
- *members
- * \return A zero value on success, negative on error, positive on cancel
- *
- * The calling function will need to poll for an SOH from the server using 'C'
- *and 'NAK'
- * characters (as appropriate) until an SOH is received. That value must be
- *assigned
- * to the 'buf' union (as appropriate), and the bCRC member assigned to
- *non-zero if
- * the server responded to 'C', or zero if it responded to 'NAK'. With the
- *bCRC,
- * ser, and file members correctly assigned, call THIS function to receive
- *content
- * via XMODEM and write it to 'file'.\n
- * This function will return zero on success, a negative value on error, and a
- *positive
- * value if the transfer was canceled by the server.
-**/
-int ReceiveXmodem(XMODEM* pX) {
-#ifdef WIN32
- DWORD cbWrote;
-#endif // WIN32
- int ecount, ec2;
- long etotal, filesize, block;
- unsigned char cY; // the char to send in response to a packet
-// NOTE: to allow debugging the CAUSE of an xmodem block's failure, i1, i2, and
-// i3
-// are assigned to function return values and reported in error messages.
-#ifdef DEBUG_CODE
- short i1, i2, i3;
-#define DEBUG_I1 i1 =
-#define DEBUG_I2 i2 =
-#define DEBUG_I3 i3 =
-#else // DEBUG_CODE
-#define DEBUG_I1 /*normally does nothing*/
-#define DEBUG_I2 /*normally does nothing*/
-#define DEBUG_I3 /*normally does nothing*/
-#endif // DEBUG_CODE
-
- ecount = 0;
- etotal = 0;
- filesize = 0;
- block = 1;
-
- // ** already got the first 'SOH' character on entry to this function **
-
- // Form2.Show 0 '** modeless show of form2 (CANSEND) **
- // Form2!Label1.FloodType = 0
- // Form2.Caption = "* XMODEM(Checksum) BINARY RECEIVE *"
- // Form2!Label1.Caption = "Errors: 0 Bytes: 0"
-
- pX->buf.xbuf.cSOH = (char)1; // assumed already got this, put into buffer
-
- do {
- if (!pX->bCRC &&
- ((DEBUG_I1 GetXmodemBlock(pX->ser, ((char*)&(pX->buf.xbuf)) + 1,
- sizeof(pX->buf.xbuf) - 1)) !=
- sizeof(pX->buf.xbuf) - 1 ||
- (DEBUG_I2 ValidateSEQ(&(pX->buf.xbuf), block & 255)) ||
- (DEBUG_I3 CalcCheckSum(pX->buf.xbuf.aDataBuf,
- sizeof(pX->buf.xbuf.aDataBuf)) !=
- pX->buf.xbuf.bCheckSum))) {
-// did not receive properly
-// TODO: deal with repeated packet, sequence number for previous packet
-
-#ifdef DEBUG_CODE
- sprintf(szERR, "A%ld,%d,%d,%d,%d,%d", block, i1, i2, i3,
- pX->buf.xbuf.aSEQ, pX->buf.xbuf.aNotSEQ);
-//#ifdef STAND_ALONE
-// fprintf(stderr, "TEMPORARY (csum): seq=%x, ~seq=%x i1=%d, i2=%d,
-// i3=%d\n", pX->buf.xbuf.aSEQ, pX->buf.xbuf.aNotSEQ, i1, i2, i3);
-//#endif // STAND_ALONE
-#endif // DEBUG_CODE
-
- XModemFlushInput(pX->ser); // necessary to avoid problems
-
- cY = _NAK_; // send NAK (to get the checksum version)
- ecount++; // for this packet
- etotal++;
- } else if (pX->bCRC &&
- ((DEBUG_I1 GetXmodemBlock(pX->ser, ((char*)&(pX->buf.xcbuf)) + 1,
- sizeof(pX->buf.xcbuf) - 1)) !=
- sizeof(pX->buf.xcbuf) - 1 ||
- (DEBUG_I2 ValidateSEQC(&(pX->buf.xcbuf), block & 255)) ||
- (DEBUG_I3 CalcCRC(pX->buf.xcbuf.aDataBuf,
- sizeof(pX->buf.xbuf.aDataBuf)) !=
- pX->buf.xcbuf.wCRC))) {
-// did not receive properly
-// TODO: deal with repeated packet, sequence number for previous packet
-
-#ifdef DEBUG_CODE
- sprintf(szERR, "B%ld,%d,%d,%d,%d,%d", block, i1, i2, i3,
- pX->buf.xcbuf.aSEQ, pX->buf.xcbuf.aNotSEQ);
-//#ifdef STAND_ALONE
-// fprintf(stderr, "TEMPORARY (CRC): seq=%x, ~seq=%x i1=%d, i2=%d,
-// i3=%d\n", pX->buf.xcbuf.aSEQ, pX->buf.xcbuf.aNotSEQ, i1, i2, i3);
-//#endif // STAND_ALONE
-#endif // DEBUG_CODE
-
- XModemFlushInput(pX->ser); // necessary to avoid problems
-
- if (block > 1) {
- cY = _NAK_; // TODO do I need this?
- } else {
- cY =
- 'C'; // send 'CRC' NAK (the character 'C') (to get the CRC version)
- }
- ecount++; // for this packet
- etotal++;
- } else {
-#ifdef ARDUINO
- if (pX->file.write((const uint8_t*)&(pX->buf.xbuf.aDataBuf),
- sizeof(pX->buf.xbuf.aDataBuf)) !=
- sizeof(pX->buf.xbuf.aDataBuf)) {
- return -2; // write error on output file
- }
-#elif defined(WIN32)
- cbWrote = 0;
- if (!WriteFile(pX->file, &(pX->buf.xbuf.aDataBuf),
- sizeof(pX->buf.xbuf.aDataBuf), &cbWrote, NULL) ||
- cbWrote != sizeof(pX->buf.xbuf.aDataBuf)) {
- XmodemTerminate(pX);
- return -2; // write error on output file
- }
-#else // ARDUINO
- if (write(pX->file, &(pX->buf.xbuf.aDataBuf),
- sizeof(pX->buf.xbuf.aDataBuf)) !=
- sizeof(pX->buf.xbuf.aDataBuf)) {
- XmodemTerminate(pX);
- return -2; // write error on output file
+int xmodemTransmit(unsigned char* src, int srcsz) {
+ unsigned char
+ xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
+ int bufsz, crc = -1;
+ unsigned char packetno = 1;
+ int i, c, len = 0;
+ int retry;
+
+ for (;;) {
+ for (retry = 0; retry < 16; ++retry) {
+ if ((c = _inbyte((DLY_1S) << 1)) >= 0) {
+ switch (c) {
+ case 'C':
+ crc = 1;
+ goto start_trans;
+ case NAK:
+ crc = 0;
+ goto start_trans;
+ case CAN:
+ if ((c = _inbyte(DLY_1S)) == CAN) {
+ _outbyte(ACK);
+ flushinput();
+ return -1; /* canceled by remote */
+ }
+ break;
+ default:
+ break;
+ }
}
-#endif // ARDUINO
- cY = _ACK_; // send ACK
- block++;
- filesize += sizeof(pX->buf.xbuf.aDataBuf); // TODO: need method to avoid
- // extra crap at end of file
- ecount = 0; // zero out error count for next packet
}
-
-#if defined(STAND_ALONE) || defined(SFTARDCAL)
- fprintf(stderr,
- "block %ld %ld bytes %d errors\r"
-#ifndef SFTARDCAL
- "\n"
-#endif // SFTARDCAL
- ,
- block - 1, filesize, ecount);
-#endif // STAND_ALONE
-
- ec2 = 0; // ** error count #2 **
-
- while (ecount < TOTAL_ERROR_COUNT &&
- ec2 < ACK_ERROR_COUNT) // ** loop to get SOH or EOT character **
- {
- WriteXmodemChar(pX->ser, cY); // ** output appropriate command char **
-
- if (GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) {
- if (pX->buf.xbuf.cSOH == _CAN_) // ** CTRL-X 'CAN' - terminate
- {
- XmodemTerminate(pX);
- return 1; // terminated
- } else if (pX->buf.xbuf.cSOH == _EOT_) // ** EOT - end
- {
- WriteXmodemChar(
- pX->ser,
- _ACK_); // ** send an ACK (most XMODEM protocols expect THIS)
- // WriteXmodemChar(pX->ser, _ENQ_); // ** send an ENQ
-
- return 0; // I am done
- } else if (pX->buf.xbuf.cSOH == _SOH_) // ** SOH - sending next packet
- {
- break; // leave this loop
+ _outbyte(CAN);
+ _outbyte(CAN);
+ _outbyte(CAN);
+ flushinput();
+ return -2; /* no sync */
+
+ for (;;) {
+ start_trans:
+#ifdef TRANSMIT_XMODEM_1K
+ xbuff[0] = STX;
+ bufsz = 1024;
+#else
+ xbuff[0] = SOH;
+ bufsz = 128;
+#endif
+ xbuff[1] = packetno;
+ xbuff[2] = ~packetno;
+ c = srcsz - len;
+ if (c > bufsz)
+ c = bufsz;
+ if (c > 0) {
+ memset(&xbuff[3], 0, bufsz);
+ memcpy(&xbuff[3], &src[len], c);
+ if (c < bufsz)
+ xbuff[3 + c] = CTRLZ;
+ if (crc) {
+ unsigned short ccrc = crc16_ccitt(&xbuff[3], bufsz);
+ xbuff[bufsz + 3] = (ccrc >> 8) & 0xFF;
+ xbuff[bufsz + 4] = ccrc & 0xFF;
} else {
- // TODO: deal with repeated packet, i.e. previous sequence number
-
- XModemFlushInput(pX->ser); // necessary to avoid problems (since the
- // character was unexpected)
- // if I was asking for the next block, and got an unexpected
- // character, do a NAK; otherwise,
- // just repeat what I did last time
-
- if (cY == _ACK_) // ACK
- {
- cY = _NAK_; // NACK
+ unsigned char ccks = 0;
+ for (i = 3; i < bufsz + 3; ++i) {
+ ccks += xbuff[i];
}
-
- ec2++;
+ xbuff[bufsz + 3] = ccks;
}
- } else {
- ecount++; // increase total error count, and try writing the 'ACK' or
- // 'NACK' again
- }
- }
-
- if (ec2 >= ACK_ERROR_COUNT) // wasn't able to get a packet
- {
- break;
- }
-
- } while (ecount < TOTAL_ERROR_COUNT);
-
- XmodemTerminate(pX);
- return 1; // terminated
-}
-
-/** \ingroup xmodem_internal
- * \brief Generic function to send a file via XMODEM (CRC or Checksum)
- *
- * \param pX A pointer to an 'XMODEM_BUF' with valid ser, and file members, and
- *the polled
- * 'NAK' value assigned to the cSOH member (first byte) within the 'buf' union.
- * \return A zero value on success, negative on error, positive on cancel
- *
- * The calling function will need to poll for a 'C' or NAK from the client (as
- *appropriate)
- * and assign that character to the cSOH member in the 'buf' union (either xbuf
- *or xcbuf since
- * the 'cSOH' will always be the first byte). Then call this function to send
- *content
- * via XMODEM from 'file'.\n
- * It is important to record the NAK character before calling this function
- *since the 'C' or
- * 'NAK' value will be used to determine whether to use CRC or CHECKSUM.\n
- * This function will return zero on success, a negative value on error, and a
- *positive
- * value if the transfer was canceled by the receiver.
-**/
-int SendXmodem(XMODEM* pX) {
-#ifdef WIN32
- DWORD cbRead;
-#endif // WIN32
- int ecount, ec2;
- short i1;
- long etotal, filesize, filepos, block;
-
- ecount = 0;
- etotal = 0;
- filesize = 0;
- filepos = 0;
- block = 1;
-
- pX->bCRC =
- 0; // MUST ASSIGN TO ZERO FIRST or XMODEM-CHECKSUM may not work properly
-
-// ** already got first 'NAK' character on entry as pX->buf.xbuf.cSOH **
-
-#ifdef ARDUINO
-
- filesize = pX->file.size();
-
-#else // ARDUINO
-
-#ifdef WIN32
- filesize = (long)SetFilePointer(pX->file, 0, NULL, FILE_END);
-#else // WIN32
- filesize = (long)lseek(pX->file, 0, SEEK_END);
-#endif // WIN32
- if (filesize < 0) // not allowed
- {
-#ifdef STAND_ALONE
- fputs("SendXmodem fail (file size)\n", stderr);
-#endif // STAND_ALONE
- return -1;
- }
-
-#ifdef WIN32
- SetFilePointer(pX->file, 0, NULL, FILE_BEGIN);
-#else // WIN32
- lseek(pX->file, 0, SEEK_SET); // position at beginning
-#endif // WIN32
-
-#endif // ARDUINO
-
- do {
- // ** depending on type of transfer, place the packet
- // ** into pX->buf with all fields appropriately filled.
-
- if (filepos >= filesize) // end of transfer
- {
- for (i1 = 0; i1 < 8; i1++) {
- WriteXmodemChar(pX->ser,
- _EOT_); // ** send an EOT marking end of transfer
-
- if (GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) !=
- 1) // this takes up to 5 seconds
- {
- // nothing returned - try again?
- // break; // for now I loop, uncomment to bail out
- } else if (pX->buf.xbuf.cSOH ==
- _ENQ_ // an 'ENQ' (apparently some expect this)
- || pX->buf.xbuf.cSOH == _ACK_ // an 'ACK' (most XMODEM
- // implementations expect
- // this)
- || pX->buf.xbuf.cSOH == _CAN_) // CTRL-X = TERMINATE
- {
- // both normal and 'abnormal' termination.
- break;
+ for (retry = 0; retry < MAXRETRANS; ++retry) {
+ for (i = 0; i < bufsz + 4 + (crc ? 1 : 0); ++i) {
+ _outbyte(xbuff[i]);
+ }
+ if ((c = _inbyte(DLY_1S)) >= 0) {
+ switch (c) {
+ case ACK:
+ ++packetno;
+ len += bufsz;
+ goto start_trans;
+ case CAN:
+ if ((c = _inbyte(DLY_1S)) == CAN) {
+ _outbyte(ACK);
+ flushinput();
+ return -1; /* canceled by remote */
+ }
+ break;
+ case NAK:
+ default:
+ break;
+ }
+ }
}
- }
-
- XmodemTerminate(pX);
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- fprintf(stderr, "SendXmodem return %d\n", i1 >= 8 ? 1 : 0);
-#endif // STAND_ALONE
- return i1 >= 8 ? 1 : 0; // return 1 if receiver choked on the 'EOT'
- // marker, else 0 for 'success'
- }
-
-// TODO: progress indicator [can be LCD for arduino, blinky lights, ??? and
-// of course stderr for everyone else]
-// If filesize& <> 0 Then Form2!Label1.FloodPercent = 100 * filepos& /
-// filesize&
-
-#if defined(STAND_ALONE) || defined(SFTARDCAL)
- fprintf(stderr,
- "block %ld %ld of %ld bytes %d errors\r"
-#ifndef SFTARDCAL
- "\n"
-#endif // SFTARDCAL
- ,
- block, filepos, filesize, ecount);
-#endif // STAND_ALONE
-
- if (pX->buf.xbuf.cSOH != 'C' // XMODEM CRC
- && pX->buf.xbuf.cSOH != (char)_NAK_) // NAK
- {
- // increase error count, bail if it's too much
-
- ec2++;
- }
-
-#ifdef ARDUINO
- pX->file.seek(filepos); // in case I'm doing a 'retry' and I have to
- // re-read part of the file
-#elif defined(WIN32)
- SetFilePointer(pX->file, filepos, NULL, FILE_BEGIN);
-#else // ARDUINO
- lseek(pX->file, filepos, SEEK_SET); // same reason as above
-#endif // ARDUINO
-
- // fortunately, xbuf and xcbuf are the same through the end of 'aDataBuf' so
- // I can read the file NOW using 'xbuf' for both CRC and CHECKSUM versions
-
- if ((filesize - filepos) >= sizeof(pX->buf.xbuf.aDataBuf)) {
-#ifdef ARDUINO
- i1 = pX->file.read(pX->buf.xbuf.aDataBuf, sizeof(pX->buf.xcbuf.aDataBuf));
-#elif defined(WIN32)
- cbRead = 0;
- if (!ReadFile(pX->file, pX->buf.xbuf.aDataBuf,
- sizeof(pX->buf.xbuf.aDataBuf), &cbRead, NULL)) {
- i1 = -1;
- } else {
- i1 = (int)cbRead;
- }
-#else // ARDUINO
- i1 =
- read(pX->file, pX->buf.xbuf.aDataBuf, sizeof(pX->buf.xcbuf.aDataBuf));
-#endif // ARDUINO
-
- if (i1 != sizeof(pX->buf.xcbuf.aDataBuf)) {
- // TODO: read error - send a ctrl+x ?
- }
- } else {
- memset(pX->buf.xcbuf.aDataBuf, '\x1a',
- sizeof(pX->buf.xcbuf.aDataBuf)); // fill with ctrl+z which is what
- // the spec says
-#ifdef ARDUINO
- i1 = pX->file.read(pX->buf.xbuf.aDataBuf, filesize - filepos);
-#elif defined(WIN32)
- cbRead = 0;
- if (!ReadFile(pX->file, pX->buf.xbuf.aDataBuf, filesize - filepos,
- &cbRead, NULL)) {
- i1 = -1;
+ _outbyte(CAN);
+ _outbyte(CAN);
+ _outbyte(CAN);
+ flushinput();
+ return -4; /* xmit error */
} else {
- i1 = (int)cbRead;
- }
-#else // ARDUINO
- i1 = read(pX->file, pX->buf.xbuf.aDataBuf, filesize - filepos);
-#endif // ARDUINO
-
- if (i1 != (filesize - filepos)) {
- // TODO: read error - send a ctrl+x ?
- }
- }
-
- if (pX->buf.xbuf.cSOH ==
- 'C' || // XMODEM CRC 'NAK' (first time only, typically)
- ((pX->buf.xbuf.cSOH == _ACK_ || pX->buf.xbuf.cSOH == _NAK_) &&
- pX->bCRC)) // identifies ACK/NACK with XMODEM CRC
- {
- pX->bCRC = 1; // make sure (only matters the first time, really)
-
- // calculate the CRC, assign to the packet, and then send it
-
- pX->buf.xcbuf.cSOH = 1; // must send SOH as 1st char
- pX->buf.xcbuf.wCRC =
- CalcCRC(pX->buf.xcbuf.aDataBuf, sizeof(pX->buf.xcbuf.aDataBuf));
-
- GenerateSEQC(&(pX->buf.xcbuf), (unsigned char)block);
-
- // send it
-
- i1 = WriteXmodemBlock(pX->ser, &(pX->buf.xcbuf), sizeof(pX->buf.xcbuf));
- if (i1 != sizeof(pX->buf.xcbuf)) // write error
- {
- // TODO: handle write error (send ctrl+X ?)
- }
- } else if (pX->buf.xbuf.cSOH == _NAK_ || // 'NAK' (checksum method, may
- // also be with CRC method)
- (pX->buf.xbuf.cSOH == _ACK_ &&
- !pX->bCRC)) // identifies ACK with XMODEM CHECKSUM
- {
- pX->bCRC = 0; // make sure (this ALSO allows me to switch modes on error)
-
- // calculate the CHECKSUM, assign to the packet, and then send it
-
- pX->buf.xbuf.cSOH = 1; // must send SOH as 1st char
- pX->buf.xbuf.bCheckSum =
- CalcCheckSum(pX->buf.xbuf.aDataBuf, sizeof(pX->buf.xbuf.aDataBuf));
-
- GenerateSEQ(&(pX->buf.xbuf), (unsigned char)block);
-
- // send it
-
- i1 = WriteXmodemBlock(pX->ser, &(pX->buf.xbuf), sizeof(pX->buf.xbuf));
- if (i1 != sizeof(pX->buf.xbuf)) // write error
- {
- // TODO: handle write error (send ctrl+X ?)
- }
- }
-
- ec2 = 0;
-
- while (ecount < TOTAL_ERROR_COUNT &&
- ec2 < ACK_ERROR_COUNT) // loop to get ACK or NACK
- {
- if (GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) {
- if (pX->buf.xbuf.cSOH == _CAN_) // ** CTRL-X - terminate
- {
- XmodemTerminate(pX);
-
- return 1; // terminated
- } else if (pX->buf.xbuf.cSOH == _NAK_ || // ** NACK
- pX->buf.xbuf.cSOH == 'C') // ** CRC NACK
- {
- break; // exit inner loop and re-send packet
- } else if (pX->buf.xbuf.cSOH == _ACK_) // ** ACK - sending next packet
- {
- filepos += sizeof(pX->buf.xbuf.aDataBuf);
- block++; // increment file position and block count
-
- break; // leave inner loop, send NEXT packet
- } else {
- XModemFlushInput(pX->ser); // for now, do this here too
- ec2++;
+ for (retry = 0; retry < 10; ++retry) {
+ _outbyte(EOT);
+ if ((c = _inbyte((DLY_1S) << 1)) == ACK)
+ break;
}
- } else {
- ecount++; // increase total error count, then loop back and re-send
- // packet
- break;
+ flushinput();
+ return (c == ACK) ? len : -5;
}
}
-
- if (ec2 >= ACK_ERROR_COUNT) {
- break; // that's it, I'm done with this
- }
-
- } while (
- ecount <
- TOTAL_ERROR_COUNT /* * 2 */); // twice error count allowed for sending
-
- // TODO: progress indicator
- // If filesize& <> 0 And filepos& <= filesize& Then
- // Form2!Label1.FloodPercent = 100 * filepos& / filesize&
- // Else
- // Form2!Label1.FloodPercent = 100
- // End If
-
- // ** at this point it is important to indicate the errors
- // ** and flush all buffers, and terminate process!
-
- XmodemTerminate(pX);
-#ifdef STAND_ALONE
- fputs("SendXmodem fail (total error count)\n", stderr);
-#endif // STAND_ALONE
- return -2; // exit on error
-}
-
-/** \ingroup xmodem_internal
- * \brief Calling function for ReceiveXmodem
- *
- * \param pX A pointer to an 'XMODEM_BUF' with valid ser, and file members
- * \return A zero value on success, negative on error, positive on cancel
- *
- * This is a generic 'calling function' for ReceiveXmodem that checks for
- * a response to 'C' and 'NAK' characters, and sets up the XMODEM transfer
- * for either CRC or CHECKSUM mode.\n
- * This function will return zero on success, a negative value on error, and a
- *positive
- * value if the transfer was canceled by the receiver.
-**/
-int XReceiveSub(XMODEM* pX) {
- int i1;
-
- // start with CRC mode [try 8 times to get CRC]
-
- pX->bCRC = 1;
-
- for (i1 = 0; i1 < 8; i1++) {
- WriteXmodemChar(pX->ser, 'C'); // start with NAK for XMODEM CRC
-
- if (GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) {
- if (pX->buf.xbuf.cSOH == _SOH_) // SOH - packet is on its way
- {
- return ReceiveXmodem(pX);
- } else if (pX->buf.xbuf.cSOH ==
- _EOT_) // an EOT [blank file? allow this?]
- {
- return 0; // for now, do this
- } else if (pX->buf.xbuf.cSOH == _CAN_) // cancel
- {
- return 1; // canceled
- }
- }
- }
-
- pX->bCRC = 0;
-
- // try again, this time using XMODEM CHECKSUM
- for (i1 = 0; i1 < 8; i1++) {
- WriteXmodemChar(pX->ser, _NAK_); // switch to NAK for XMODEM Checksum
-
- if (GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) {
- if (pX->buf.xbuf.cSOH == _SOH_) // SOH - packet is on its way
- {
- return ReceiveXmodem(pX);
- } else if (pX->buf.xbuf.cSOH ==
- _EOT_) // an EOT [blank file? allow this?]
- {
- return 0; // for now, do this
- } else if (pX->buf.xbuf.cSOH == _CAN_) // cancel
- {
- return 1; // canceled
- }
- }
- }
-
- XmodemTerminate(pX);
-
- return -3; // fail
-}
-
-/** \ingroup xmodem_internal
- * \brief Calling function for SendXmodem
- *
- * \param pX A pointer to an 'XMODEM_BUF' with valid ser, and file members
- * \return A zero value on success, negative on error, positive on cancel
- *
- * This is a generic 'calling function' for SendXmodem that checks for polls by
- *the
- * receiver, and places the 'NAK' or 'C' character into the 'buf' member of the
- *XMODEM
- * structure so that SendXmodem can use the correct method, either CRC or
- *CHECKSUM mode.\n
- * This function will return zero on success, a negative value on error, and a
- *positive
- * value if the transfer was canceled by the receiver.
-**/
-int XSendSub(XMODEM* pX) {
- unsigned long ulStart;
-
-// waiting up to 30 seconds for transfer to start. this is part of the spec?
-
-#ifdef ARDUINO
- ulStart = millis();
-#else // ARDUINO
- ulStart = MyMillis();
-#endif // ARDUINO
-
- do {
- if (GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) {
- if (pX->buf.xbuf.cSOH == 'C' || // XMODEM CRC
- pX->buf.xbuf.cSOH == _NAK_) // NAK - XMODEM CHECKSUM
- {
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- fprintf(stderr, "Got %d, continuing\n", pX->buf.xbuf.cSOH);
-#endif // STAND_ALONE
- return SendXmodem(pX);
- } else if (pX->buf.xbuf.cSOH == _CAN_) // cancel
- {
-#ifdef STAND_ALONE
- fputs("XSendSub fail (cancel)\n", stderr);
-#endif // STAND_ALONE
- return 1; // canceled
- }
- }
- }
-#ifdef ARDUINO
- while ((short)(millis() - ulStart) < 30000); // 30 seconds
-#else // ARDUINO
- while ((int)(MyMillis() - ulStart) < 30000);
-#endif // ARDUINO
-
- XmodemTerminate(pX);
-
-#ifdef STAND_ALONE
- fputs("XSendSub fail (timeout)\n", stderr);
-#endif // STAND_ALONE
- return -3; // fail
-}
-
-// typedef struct _XMODEM_
-//{
-// SERIAL_TYPE ser;
-// FILE_TYPE file;
-//
-// union
-// {
-// XMODEM_BUF xbuf;
-// XMODEMC_BUF xcbuf;
-// } buf; // 133 bytes
-//
-// unsigned char bCRC; // non-zero for CRC, zero for checksum
-//
-//} __attribute__((__packed__)) XMODEM;
-
-#ifdef ARDUINO
-
-short XReceive(SDClass* pSD, HardwareSerial* pSer, const char* szFilename) {
- short iRval;
- XMODEM xx;
-
- memset(&xx, 0, sizeof(xx));
-
- xx.ser = pSer;
-
- if (pSD->exists((char*)szFilename)) {
- pSD->remove((char*)szFilename);
- }
-
- xx.file = pSD->open((char*)szFilename, FILE_WRITE);
- if (!xx.file) {
- return -9; // can't create file
- }
-
- iRval = XReceiveSub(&xx);
-
- xx.file.close();
-
- if (iRval) {
- WriteXmodemChar(pSer, _CAN_); // cancel (make sure)
-
- pSD->remove((char*)szFilename); // delete file on error
}
-
- return iRval;
-}
-
-int XSend(SDClass* pSD, HardwareSerial* pSer, const char* szFilename) {
- short iRval;
- XMODEM xx;
-
- memset(&xx, 0, sizeof(xx));
-
- xx.ser = pSer;
-
- xx.file = pSD->open(szFilename, FILE_READ);
- if (!xx.file) {
- return -9; // can't open file
- }
-
- iRval = XSendSub(&xx);
-
- xx.file.close();
-
- return iRval;
-}
-
-#else // ARDUINO
-
-int XReceive(SERIAL_TYPE hSer, const char* szFilename, int nMode) {
- int iRval;
- XMODEM xx;
-#if !defined(ARDUINO) && !defined(WIN32)
- int iFlags;
-#endif // !ARDUINO
-
-#ifdef DEBUG_CODE
- szERR[0] = 0;
-#endif // DEBUG_CODE
- memset(&xx, 0, sizeof(xx));
-
- xx.ser = hSer;
-
-#ifdef WIN32
- DeleteFile(szFilename);
-
- nMode = nMode; // to avoid unused parameter warnings
- // TODO: translate 'nMode' into file attributes? for now ignore it
- xx.file = CreateFile(szFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (xx.file == INVALID_HANDLE_VALUE)
-#else // WIN32
- unlink(szFilename); // make sure it does not exist, first
- xx.file = open(szFilename, O_CREAT | O_TRUNC | O_WRONLY, nMode);
-
- if (xx.file == -1) // bad file handle on POSIX systems
-#endif // WIN32
- {
-#ifdef STAND_ALONE
- fprintf(stderr, "XReceive fail \"%s\" errno=%d\n", szFilename, errno);
-#endif // STAND_ALONE
- return -9; // can't create file
- }
-
-#if !defined(ARDUINO) && !defined(WIN32)
- iFlags = fcntl(hSer, F_GETFL);
-#endif // !ARDUINO
-
- iRval = XReceiveSub(&xx);
-
-#if !defined(ARDUINO) && !defined(WIN32)
- if (iFlags == -1 || fcntl(hSer, F_SETFL, iFlags) == -1) {
- fprintf(stderr,
- "Warning: 'fcntl' call to restore flags failed, errno=%d\n",
- errno);
- }
-#endif // !ARDUINO
-
-#ifdef WIN32
- CloseHandle(xx.file);
-#else // WIN32
- close(xx.file);
-#endif // WIN32
-
- if (iRval) {
-#ifdef WIN32
- DeleteFile(szFilename);
-#else // WIN32
- unlink(szFilename); // delete file on error
-#endif // WIN32
- }
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- fprintf(stderr, "XReceive returns %d\n", iRval);
-#endif // STAND_ALONE
- return iRval;
-}
-
-int XSend(SERIAL_TYPE hSer, const char* szFilename) {
- int iRval;
- XMODEM xx;
-#if !defined(ARDUINO) && !defined(WIN32)
- int iFlags;
-#endif // !ARDUINO
-
-#ifdef DEBUG_CODE
- szERR[0] = 0;
-#endif // DEBUG_CODE
- memset(&xx, 0, sizeof(xx));
-
- xx.ser = hSer;
-
-#ifdef WIN32
- xx.file =
- CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
-
- if (xx.file == INVALID_HANDLE_VALUE)
-#else // WIN32
- xx.file = open(szFilename, O_RDONLY, 0);
-
- if (xx.file == -1) // bad file handle on POSIX systems
-#endif // WIN32
- {
-#ifdef STAND_ALONE
- fprintf(stderr, "XSend fail \"%s\" errno=%d\n", szFilename, errno);
-#endif // STAND_ALONE
- return -9; // can't open file
- }
-
-#if !defined(ARDUINO) && !defined(WIN32)
- iFlags = fcntl(hSer, F_GETFL);
-#endif // !ARDUINO
-
- iRval = XSendSub(&xx);
-
-#if !defined(ARDUINO) && !defined(WIN32)
- if (iFlags == -1 || fcntl(hSer, F_SETFL, iFlags) == -1) {
- fprintf(stderr,
- "Warning: 'fcntl' call to restore flags failed, errno=%d\n",
- errno);
- }
-#endif // !ARDUINO
-
-#ifdef WIN32
- CloseHandle(xx.file);
-#else // WIN32
- close(xx.file);
-#endif // WIN32
-
-#if defined(STAND_ALONE) && defined(DEBUG_CODE)
- fprintf(stderr, "XSend returning %d\n", iRval);
-#endif // STAND_ALONE
- return iRval;
-}
-
-#endif // ARDUINO
-
-#if defined(STAND_ALONE) && !defined(SFTARDCAL)
-
-static const char szSER[] = "/dev/ttyU0";
-
-#include <termios.h>
-
-/** \ingroup xmodem_standalone
- * \brief Terminal configuration (POSIX only)
- *
- * \param iFile The open file handle for the serial connection
- * \param iBaud The baud rate for the connection
- * \param iParity The parity, < 0 for even, > 0 for odd, 0 for none
- * \param iBits The number of bits (5, 6, 7, 8)
- * \param iStop The number of stop bits (1 or 2)
- *
- * This is a sample tty config function to CORRECTLY set up a serial connection
- * to allow XMODEM transfer. The important details here are the use of the
- * 'termios' structure and utility functions to DISABLE all of the things that
- * would otherwise cause trouble, like CRLF translation, CTRL+C handling, etc.
-**/
-void ttyconfig(int iFile, int iBaud, int iParity, int iBits, int iStop) {
- int i1;
- struct termios sIOS;
-
- i1 = fcntl(iFile, F_GETFL);
-
- i1 |= O_NONBLOCK; // i1 &= ~O_NONBLOCK); // turn OFF non-blocking?
-
- fcntl(iFile, F_SETFL, i1);
-
- if (!tcgetattr(iFile, &sIOS)) {
- cfsetspeed(&sIOS, iBaud);
- sIOS.c_cflag &= ~(CSIZE | PARENB | CS5 | CS6 | CS7 | CS8);
- sIOS.c_cflag |=
- iBits == 5 ? CS5 : iBits == 6 ? CS6 : iBits == 7 ? CS7
- : CS8; // 8 is default
- if (iStop == 2) {
- sIOS.c_cflag |= CSTOPB;
- } else {
- sIOS.c_cflag &= ~CSTOPB;
- }
-
- sIOS.c_cflag &=
- ~CRTSCTS; // hardware flow control _DISABLED_ (so I can do the reset)
- sIOS.c_cflag |= CLOCAL; // ignore any modem status lines
-
- if (!iParity) {
- sIOS.c_cflag &= ~(PARENB | PARODD);
- } else if (iParity > 0) // odd
- {
- sIOS.c_cflag |= (PARENB | PARODD);
- } else // even (negative)
- {
- sIOS.c_cflag &= PARODD;
- sIOS.c_cflag |= PARENB;
- }
-
- // sIOS.c_iflag |= IGNCR; // ignore CR
-
- // do not translate characters or xon/xoff and ignore break
- sIOS.c_iflag &= ~(IGNBRK | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
- IMAXBEL | ISTRIP); // turn these off
-
-#if defined(__FreeBSD__)
- sIOS.c_oflag &= ~(OPOST | ONLCR | OCRNL | TABDLY | ONOEOT | ONOCR |
- ONLRET); // FreeBSD version
-#else // Linux? YMMV
- sIOS.c_oflag &= ~(OPOST | ONLCR | OCRNL | TABDLY | ONOCR |
- ONLRET); // turn these off too (see man termios)
-#endif // FBSD vs Linux
-
-// make sure echoing is disabled and control chars aren't translated or omitted
-#if defined(__FreeBSD__)
- sIOS.c_lflag &= ~(ECHO | ECHOKE | ECHOE | ECHONL | ECHOPRT | ECHOCTL |
- ICANON | IEXTEN | ISIG | ALTWERASE);
-#else // Linux? YMMV
- sIOS.c_lflag &= ~(ECHO | ECHOKE | ECHOE | ECHONL | ECHOPRT | ECHOCTL |
- ICANON | IEXTEN | ISIG);
-#endif // FBSD vs Linux
- sIOS.c_cc[VMIN] = 0; // ensures no 'grouping' of input
- sIOS.c_cc[VTIME] = 0; // immediate return
-
- if (tcsetattr(iFile, TCSANOW, &sIOS)) {
- fprintf(stderr, "error %d setting attributes\n", errno);
- }
- } else {
- fprintf(stderr, "error %d getting attributes\n", errno);
- }
-}
-
-/** \ingroup xmodem_standalone
- * \brief Arduino 'reset' function
- *
- * \param iFile The open file handle for the serial connection
- *
- * The Arduino serial port typically has the DTR/RTS lines configured so that
- * a proper 'pulse' will cause a hardware reset of the device. This function
- *will
- * send that pulse to the Arduino, and wait for a short time afterwards for the
- * hardware reset to take place.
-**/
-void reset_arduino(int iFile) {
- unsigned int sFlags;
- unsigned long ulStart;
- int i1;
-
- // toggle the RTS and DTR high, low, then high - so much easier via
- // POSIX-compatible OS!
-
- ioctl(iFile, TIOCMGET, &sFlags);
-
- sFlags &= ~(TIOCM_DTR | TIOCM_RTS); // the high to low transition discharges
- // the capacitor (signal is inverted on
- // board)
- if (ioctl(iFile, TIOCMSET, &sFlags) < 0) {
- fprintf(stderr, "WARNING: ioctl() returns < 0, errno=%d (%xH)\n", errno,
- errno);
- }
-
- usleep(
- 250000); // avrdude does this for 50 msecs, my change has it at 50msecs
-
- sFlags |= TIOCM_DTR | TIOCM_RTS; // leave it in THIS state when I'm done
- if (ioctl(iFile, TIOCMSET, &sFlags) < 0) {
- fprintf(stderr, "WARNING: ioctl() returns < 0, errno=%d (%xH)\n", errno,
- errno);
- }
-
- usleep(50000); // avrdude does this for 50 msecs (no change)
-
- ulStart = MyMillis();
-
- // flush whatever is there, (5 seconds)
-
- while ((MyMillis() - ulStart) < 5000) {
- i1 = read(iFile, &i1, 1);
- if (i1 == 1) {
- ulStart = MyMillis();
- } else {
- usleep(1000);
- }
- }
-}
-
-int main(int argc, char* argv[]) {
- int hSer;
- char tbuf[256];
- int i1, iSR = 0;
-
- if (argc < 3) {
- fputs("Usage: [prog] [S|R] filename\n", stderr);
- return 1;
- }
-
- if (argv[1][0] == 'R' || argv[1][1] == 'r') {
- iSR = -1;
- } else if (argv[1][0] == 'S' || argv[1][1] == 's') {
- iSR = 1;
- } else if (argv[1][0] == 'X' || argv[1][1] == 'x') {
- iSR = 0; // test function
- } else {
- fputs("Usage: [prog] [S|R] filename (b)\n", stderr);
- return 1;
- }
-
- hSer = open(szSER, (O_RDWR | O_NONBLOCK), 0);
- if (hSer == -1) {
- fprintf(stderr, "Unable to open \"%s\" errno=%d\n", szSER, errno);
- return 3;
- }
-
- fputs("TTYCONFIG\n", stderr);
- ttyconfig(hSer, 9600, 0, 8, 1);
-
- reset_arduino(hSer);
-
- fprintf(stderr, "Sleeping for 10 seconds to allow reset\n");
-
- // usleep(10000000);
- for (i1 = 0; i1 < 10; i1++) {
- XModemFlushInput(hSer);
- }
-
- for (i1 = 0; i1 < 3; i1++) {
- sprintf(tbuf, "X%c%s", argv[1][0], argv[2]);
-
- fprintf(stderr, "writing: \"%s\"\n", tbuf);
- strcat(tbuf, "\r");
- WriteXmodemBlock(hSer, tbuf, strlen(tbuf));
-
- fputs("flush input\n", stderr);
- XModemFlushInput(hSer);
-
- // wait for an LF response
-
- if (iSR > 0) {
- fputs("XSEND\n", stderr);
- if (XSend(hSer, argv[2])) {
- fputs("ERROR\n", stderr);
- } else {
- fputs("SUCCESS!\n", stderr);
- i1 = 0;
- break;
- }
- } else if (iSR < 0) {
- fputs("XRECEIVE\n", stderr);
- if (XReceive(hSer, argv[2], 0664)) {
- fputs("ERROR\n", stderr);
- } else {
- fputs("SUCCESS!\n", stderr);
- i1 = 0;
- break;
- }
- } else {
- // test function
- XModemFlushInput(hSer); // continue doing this
- break; // done (once only)
- }
- }
-
- fputs("EXIT\n", stderr);
- close(hSer);
-
- return i1 ? 1 : -1;
}
-#endif // STAND_ALONE
diff --git a/upload/xmodem.h b/upload/xmodem.h
index 37bed1a..62346f1 100644
--- a/upload/xmodem.h
+++ b/upload/xmodem.h
@@ -1,310 +1,10 @@
#ifndef XMODEM_H
#define XMODEM_H
-//////////////////////////////////////////////////////////////////////////////
-// //
-// _ _ //
-// __ __ _ __ ___ ___ __| | ___ _ __ ___ | |__ //
-// \ \/ /| '_ ` _ \ / _ \ / _` | / _ \| '_ ` _ \ | '_ \ //
-// > < | | | | | || (_) || (_| || __/| | | | | | _ | | | | //
-// /_/\_\|_| |_| |_| \___/ \__,_| \___||_| |_| |_|(_)|_| |_| //
-// //
-// //
-//////////////////////////////////////////////////////////////////////////////
-// //
-// Copyright (c) 2012 by S.F.T. Inc. - All rights reserved //
-// Use, copying, and distribution of this software are licensed according //
-// to the LGPLv2.1, or a BSD-like license, as appropriate (see below) //
-// //
-//////////////////////////////////////////////////////////////////////////////
+#include "legato.h"
-#ifdef ARDUINO
-/** \mainpage S.F.T. XMODEM library (ARDUINO version)
- *
- * Copyright (c) 2012 by S.F.T. Inc. - All rights reserved\n
- *
- * The source files include DOXYGEN SUPPORT to properly document the library
- * Please excuse the additional comments necessary to make this work.
- * Instead, build the doxygen output and view the documentation, as
- * well as the code itself WITHOUT all of the doxygen markup comments.
- * \n
- * \n
- * This library was designed to work with POSIX-compliant operating systems
- * such as Linux, FreeBSD, and OSX, and also on Arduino microcontrollers.
- * The intent was to provide an identical code base for both ends of the
- * XMODEM transfer, compilable as either C or C++ code for maximum flexibility.
- *
- * Normally you will only need to use one of these two functions:\n
- * \n
- * \ref XSend() - send a file via XMODEM\n
- * \ref XReceive() - receive a file via XMODEM\n
- * \n
- * The rest of the documentation was provided to help you debug any problems,
- * or even to write your own library (as appropriate).\n
- *
- * LICENSE
- *
- * This software is licensed under either the LGPLv2 or a BSD-like license.
- * For more information, see\n
- * http://opensource.org/licenses/BSD-2-Clause\n
- * http://www.gnu.org/licenses/lgpl-2.1.html\n
- * and the above copyright notice.\n
- * \n
- * In short, you may use this software anyway you like, provided that you
- * do not hold S.F.T. Inc. responsible for consequential or inconsequential
- * damages resulting from use, modification, abuse, or anything else done
- * with this software, and you include the appropriate license (either LGPLv2
- * or a BSD-like license) and comply with the requirements of said license.\n
- * So, if you use a BSD-like license, you can copy the license template at
- * the abovementioned URL and sub in the copyright notice as shown above.
- * Or, you may use an LGPLv2 license, and then provide source files with a
- * re-distributed or derived work (including a complete re-write with this
- * library as a template). A link back to the original source, of course,
- * would be appreciated but is not required.
-**/
-#else // ARDUINO
-/** \mainpage S.F.T. XMODEM library
- *
- * Copyright (c) 2012 by S.F.T. Inc. - All rights reserved\n
- *
- * The source files include DOXYGEN SUPPORT to properly document the library
- * Please excuse the additional comments necessary to make this work.
- * Instead, build the doxygen output and view the documentation, as
- * well as the code itself WITHOUT all of the doxygen markup comments.
- * \n
- * \n
- * This library was designed to work with POSIX-compliant operating systems
- * such as Linux, FreeBSD, and OSX, and also on Arduino microcontrollers.
- * The intent was to provide an identical code base for both ends of the
- * XMODEM transfer, compilable as either C or C++ code for maximum flexibility.
- *
- * Normally you will only need to use one of these two functions:\n
- * \n
- * \ref XSend() - send a file via XMODEM\n
- * \ref XReceive() - receive a file via XMODEM\n
- * \n
- * The rest of the documentation was provided to help you debug any problems,
- * or even to write your own library (as appropriate).\n
- *
- * LICENSE
- *
- * This software is licensed under either the LGPLv2 or a BSD-like license.
- * For more information, see\n
- * http://opensource.org/licenses/BSD-2-Clause\n
- * http://www.gnu.org/licenses/lgpl-2.1.html\n
- * and the above copyright notice.\n
- * \n
- * In short, you may use this software anyway you like, provided that you
- * do not hold S.F.T. Inc. responsible for consequential or inconsequential
- * damages resulting from use, modification, abuse, or anything else done
- * with this software, and you include the appropriate license (either LGPLv2
- * or a BSD-like license) and comply with the requirements of said license.\n
- * So, if you use a BSD-like license, you can copy the license template at
- * the abovementioned URL and sub in the copyright notice as shown above.
- * Or, you may use an LGPLv2 license, and then provide source files with a
- * re-distributed or derived work (including a complete re-write with this
- * library as a template). A link back to the original source, of course,
- * would be appreciated but is not required.
-**/
-#endif // ARDUINO
-
-/** \file xmodem.h
- * \brief main header file for S.F.T. XMODEM library
- *
- * S.F.T. XMODEM library
-**/
-
-/** \defgroup xmodem_api XModem API
- * high-level API functions
-*/
-
-/** \defgroup xmodem_internal XModem Internal
- * internal support functions
-*/
-
-#ifdef STANDALONE
-/** \defgroup xmodem_standalone XModem Stand-alone
- * internal 'standalone' functions, an example for POSIX implementation
-*/
-#endif // STANDALONE
-
-// determine if arduino build, define ARDUINO if not already done
-
-#if defined(__AVR__) || defined(AVR) || defined(__AVR) || defined(__AVR_ARCH__)
-#ifndef ARDUINO
-#define ARDUINO /* hopefully I cover all compiler variations */
-#endif // ARDUINO
-#endif // __AVR__
-
-#include <stdlib.h>
-
-// required include files
-#ifdef ARDUINO
-// arduino includes
-#include <Arduino.h>
-#include <SD.h>
-#include <HardwareSerial.h> /* may already be included by 'Arduino.h' */
-#include <avr/pgmspace.h>
-
-#elif WIN32
-// win32 includes
-#include <Windows.h>
-#include <io.h>
-#else // POSIX
-// posix includes
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <sys/ioctl.h> // for IOCTL definitions
-#include <memory.h>
-#endif // OS-dependent includes
-
-// required per-OS definitions
-#ifdef ARDUINO
-
-// file and serial types for Arduino
-#define FILE_TYPE File
-#define SERIAL_TYPE HardwareSerial*
-
-#elif defined(WIN32) // WINDOWS
-
-// file and serial types for WIN32
-#define FILE_TYPE HANDLE
-#define SERIAL_TYPE HANDLE
-
-#else // POSIX
-
-// file and serial types for POSIX
-#define FILE_TYPE int
-#define SERIAL_TYPE int
-
-#endif // ARDUINO
-
-// common definitions
-
-#define SILENCE_TIMEOUT 5000 /* 5 seconds */
-#define TOTAL_ERROR_COUNT 32
-#define ACK_ERROR_COUNT 8
-
-// Arduino build uses C++ so I must define functions properly
-
-#ifdef ARDUINO
-
-/** \ingroup xmodem_api
- * \brief Receive a file using XMODEM protocol (ARDUINO version)
- *
- * \param pSD A pointer to an SDClass object, such as &SD (the default SD
- *library object is 'SD')
- * \param pSer A pointer to a HardwareSerial object, such as &Serial
- * \param szFilename A pointer to a (const) 0-byte terminated string containing
- *the file name
- * \return A value of zero on success, negative on failure, positive if
- *canceled
- *
- * Call this function to receive a file, passing the SD card's initialized
- *SDClass object pointer,
- * and the pointer to the 'HardwareSerial' object to be used for serial
- *communication, and the
- * name of the file to create from the XMODEM stream. The function will return
- *a value of zero on
- * success. On failure or cancelation, the file will be deleted.\n
- * If the specified file exists before calling this function, it will be
- *overwritten. If you do not
- * want to unconditionally overwrite an existing file, you should test to see
- *if it exists first
- * using the SD library.
- *
-**/
-short XReceive(SDClass* pSD, HardwareSerial* pSer, const char* szFilename);
-
-/** \ingroup xmodem_api
- * \brief Send a file using XMODEM protocol (ARDUINO version)
- *
- * \param pSD A pointer to an SDClass object, such as &SD (the default SD
- *library object is 'SD')
- * \param pSer A pointer to a HardwareSerial object, such as &Serial
- * \param szFilename A pointer to a (const) 0-byte terminated string containing
- *the file name
- * \return A value of zero on success, negative on failure, positive if
- *canceled
- *
- * Call this function to send a file, passing the SD card's initialized SDClass
- *object pointer,
- * and the pointer to the 'HardwareSerial' object to be used for serial
- *communication, and the
- * name of the file to send via the XMODEM stream. The function will return a
- *value of zero on
- * success. If the file does not exist, the function will return a 'failure'
- *value and cancel
- * the transfer.
- *
-**/
-int XSend(SDClass* pSD, HardwareSerial* pSer, const char* szFilename);
-
-#ifdef DEBUG_CODE
-const char* XMGetError(void);
-#endif // DEBUG_CODE
-
-#else // ARDUINO
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-/** \ingroup xmodem_api
- * \brief Receive a file using XMODEM protocol
- *
- * \param hSer A 'HANDLE' for the open serial connection
- * \param szFilename A pointer to a (const) 0-byte terminated string containing
- *the file name
- * \param nMode The file mode to be used on create (RWX bits)
- * \return A value of zero on success, negative on failure, positive if
- *canceled
- *
- * Call this function to receive a file, passing the handle to the open serial
- *connection, and the
- * name and mode of the file to create from the XMODEM stream. The function
- *will return a value of zero on
- * success. On failure or cancelation, the file will be deleted.\n
- * If the specified file exists before calling this function, it will be
- *overwritten. If you do not
- * want to unconditionally overwrite an existing file, you should test to see
- *if it exists first.
- *
-**/
-int XReceive(SERIAL_TYPE hSer, const char* szFilename, int nMode);
-
-/** \ingroup xmodem_api
- * \brief Send a file using XMODEM protocol
- *
- * \param hSer A 'HANDLE' for the open serial connection
- * \param szFilename A pointer to a (const) 0-byte terminated string containing
- *the file name
- * \return A value of zero on success, negative on failure, positive if
- *canceled
- *
- * Call this function to receive a file, passing the handle to the open serial
- *connection, and the
- * name and mode of the file to send via the XMODEM stream. The function will
- *return a value of zero on
- * success. If the file does not exist, the function will return a 'failure'
- *value and cancel
- * the transfer.
- *
-**/
-int XSend(SERIAL_TYPE hSer, const char* szFilename);
-
-#ifdef DEBUG_CODE
-const char* XMGetError(void);
-#endif // DEBUG_CODE
-
-#ifdef __cplusplus
-};
-#endif // __cplusplus
-
-#endif // ARDUINO
+int xmodemTransmit(unsigned char* src, int srcsz);
+uint8_t _inbyte(unsigned short timeout);
+void _outbyte(uint8_t c);
#endif