├── .gitattributes ├── .gitignore └── zmodem ├── zmodem.h ├── zmodem.ino ├── zmodem_config.h ├── zmodem_crc16.cpp ├── zmodem_fixes.h ├── zmodem_rz.cpp ├── zmodem_sz.cpp ├── zmodem_zm.cpp └── zmodem_zm.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /zmodem/zmodem.h: -------------------------------------------------------------------------------- 1 | // From: http://www.raspberryginger.com/jbailey/minix/html/zmodem_8h-source.html 2 | #ifndef ZMODEM_H 3 | #define ZMODEM_H 4 | #include "zmodem_config.h" 5 | #include "zmodem_fixes.h" 6 | /* 7 | * Z M O D E M . H Manifest constants for ZMODEM 8 | * application to application file transfer protocol 9 | * 05-23-87 Chuck Forsberg Omen Technology Inc 10 | */ 11 | #define ZPAD '*' /* 052 Padding character begins frames */ 12 | #define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ 13 | #define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ 14 | #define ZBIN 'A' /* Binary frame indicator */ 15 | #define ZHEX 'B' /* HEX frame indicator */ 16 | #define ZBIN32 'C' /* Binary frame with 32 bit FCS */ 17 | 18 | /* Frame types (see array "frametypes" in zm.c) */ 19 | #define ZRQINIT 0 /* Request receive init */ 20 | #define ZRINIT 1 /* Receive init */ 21 | #define ZSINIT 2 /* Send init sequence (optional) */ 22 | #define ZACK 3 /* ACK to above */ 23 | #define ZFILE 4 /* File name from sender */ 24 | #define ZSKIP 5 /* To sender: skip this file */ 25 | #define ZNAK 6 /* Last packet was garbled */ 26 | #define ZABORT 7 /* Abort batch transfers */ 27 | #define ZFIN 8 /* Finish session */ 28 | #define ZRPOS 9 /* Resume data trans at this position */ 29 | #define ZDATA 10 /* Data packet(s) follow */ 30 | #define ZEOF 11 /* End of file */ 31 | #define ZFERR 12 /* Fatal Read or Write error Detected */ 32 | #define ZCRC 13 /* Request for file CRC and response */ 33 | #define ZCHALLENGE 14 /* Receiver's Challenge */ 34 | #define ZCOMPL 15 /* Request is complete */ 35 | #define ZCAN 16 /* Other end canned session with CAN*5 */ 36 | #define ZFREECNT 17 /* Request for free bytes on filesystem */ 37 | #define ZCOMMAND 18 /* Command from sending program */ 38 | #define ZSTDERR 19 /* Output to standard error, data follows */ 39 | 40 | /* ZDLE sequences */ 41 | #define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ 42 | #define ZCRCG 'i' /* CRC next, frame continues nonstop */ 43 | #define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ 44 | #define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ 45 | #define ZRUB0 'l' /* Translate to rubout 0177 */ 46 | #define ZRUB1 'm' /* Translate to rubout 0377 */ 47 | 48 | /* zdlread return values (internal) */ 49 | /* -1 is general error, -2 is timeout */ 50 | #define GOTOR 0400 51 | #define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ 52 | #define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ 53 | #define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ 54 | #define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ 55 | #define GOTCAN (GOTOR|030) /* CAN*5 seen */ 56 | 57 | /* Byte positions within header array */ 58 | #define ZF0 3 /* First flags byte */ 59 | #define ZF1 2 60 | #define ZF2 1 61 | #define ZF3 0 62 | #define ZP0 0 /* Low order 8 bits of position */ 63 | #define ZP1 1 64 | #define ZP2 2 65 | #define ZP3 3 /* High order 8 bits of file position */ 66 | 67 | /* Bit Masks for ZRINIT flags byte ZF0 */ 68 | #define CANFDX 01 /* Rx can send and receive true FDX */ 69 | #define CANOVIO 02 /* Rx can receive data during disk I/O */ 70 | #define CANBRK 04 /* Rx can send a break signal */ 71 | #define CANCRY 010 /* Receiver can decrypt */ 72 | #define CANLZW 020 /* Receiver can uncompress */ 73 | #define CANFC32 040 /* Receiver can use 32 bit Frame Check */ 74 | #define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */ 75 | #define ESC8 0200 /* Receiver expects 8th bit to be escaped */ 76 | 77 | /* Parameters for ZSINIT frame */ 78 | //#define ZATTNLEN 32 /* Max length of attention string */ 79 | #define ZATTNLEN 4 /* Need to take back as many bytes as possible, hopefully no one really sends a lengthy ATTN */ 80 | 81 | /* Bit Masks for ZSINIT flags byte ZF0 */ 82 | #define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ 83 | #define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ 84 | 85 | /* Parameters for ZFILE frame */ 86 | /* Conversion options one of these in ZF0 */ 87 | #define ZCBIN 1 /* Binary transfer - inhibit conversion */ 88 | #define ZCNL 2 /* Convert NL to local end of line convention */ 89 | #define ZCRESUM 3 /* Resume interrupted file transfer */ 90 | /* Management include options, one of these ored in ZF1 */ 91 | #define ZMSKNOLOC 0200 /* Skip file if not present at rx */ 92 | /* Management options, one of these ored in ZF1 */ 93 | #define ZMMASK 037 /* Mask for the choices below */ 94 | #define ZMNEWL 1 /* Transfer if source newer or longer */ 95 | #define ZMCRC 2 /* Transfer if different file CRC or length */ 96 | #define ZMAPND 3 /* Append contents to existing file (if any) */ 97 | #define ZMCLOB 4 /* Replace existing file */ 98 | #define ZMNEW 5 /* Transfer if source newer */ 99 | /* Number 5 is alive ... */ 100 | #define ZMDIFF 6 /* Transfer if dates or lengths different */ 101 | #define ZMPROT 7 /* Protect destination file */ 102 | /* Transport options, one of these in ZF2 */ 103 | #define ZTLZW 1 /* Lempel-Ziv compression */ 104 | #define ZTCRYPT 2 /* Encryption */ 105 | #define ZTRLE 3 /* Run Length encoding */ 106 | /* Extended options for ZF3, bit encoded */ 107 | #define ZXSPARS 64 /* Encoding for sparse file operations */ 108 | 109 | /* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ 110 | #define ZCACK1 1 /* Acknowledge, then do command */ 111 | 112 | //#ifdef NOTDEF 113 | // Pete (El Supremo) - fix up extern int 114 | /* Globals used by ZMODEM functions */ 115 | extern uint8_t Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ 116 | extern uint8_t Rxtype; /* Type of header received */ 117 | extern int Rxcount; /* Count of data bytes received */ 118 | //extern int Zrwindow; /* RX window size (controls garbage count) */ 119 | extern int Rxtimeout; /* Tenths of seconds to wait for something */ 120 | extern char Rxhdr[4]; /* Received header */ 121 | extern char Txhdr[4]; /* Transmitted header */ 122 | extern long Rxpos; /* Received file position */ 123 | extern long Txpos; /* Transmitted file position */ 124 | extern int8_t Txfcs32; /* TURE means send binary frames with 32 bit FCS */ 125 | extern int8_t Crc32t; /* Display flag indicating 32 bit CRC being sent */ 126 | extern int8_t Crc32; /* Display flag indicating 32 bit CRC being received */ 127 | //extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ 128 | extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ 129 | //#endif 130 | 131 | /* crctab.c */ 132 | _PROTOTYPE(long UPDC32 , (int b , long c )); 133 | 134 | /* rbsb.c */ 135 | #ifndef ARDUINO 136 | _PROTOTYPE(void from_cu , (void)); 137 | _PROTOTYPE(void cucheck , (void)); 138 | _PROTOTYPE(int rdchk , (int f )); 139 | _PROTOTYPE(int rdchk , (int f )); 140 | _PROTOTYPE(void sendbrk , (void)); 141 | #endif 142 | /* zm.c */ 143 | 144 | _PROTOTYPE(void zsbhdr , (int type , char *hdr )); 145 | _PROTOTYPE(void zshhdr , (int type , char *hdr )); 146 | _PROTOTYPE(void zsdata , (char *buf , int length , int frameend )); 147 | _PROTOTYPE(int zrdata , (char *buf , int length )); 148 | _PROTOTYPE(int zgethdr , (char *hdr , int eflag )); 149 | _PROTOTYPE(int zrbhdr , (char *hdr )); 150 | _PROTOTYPE(int zrbhdr32 , (char *hdr )); 151 | _PROTOTYPE(int zrhhdr , (char *hdr )); 152 | _PROTOTYPE(void zputhex , (int c )); 153 | _PROTOTYPE(int zsendline2 , (int c )); 154 | _PROTOTYPE(int zgethex , (void)); 155 | _PROTOTYPE(int zgeth1 , (void)); 156 | //_PROTOTYPE(int zdlread , (void)); 157 | _PROTOTYPE(int noxrd7 , (void)); 158 | _PROTOTYPE(void stohdr , (long pos )); 159 | _PROTOTYPE(long rclhdr , (char *hdr )); 160 | 161 | /* rz.c sz.c */ 162 | #ifndef ARDUINO 163 | void vfile(); 164 | #else 165 | #define vfile(a, ... ) 166 | #endif 167 | 168 | _PROTOTYPE(void bibi , (int n )); 169 | _PROTOTYPE(int wcs , (const char *oname)); 170 | _PROTOTYPE(void saybibi, (void)); 171 | 172 | int wctxpn(char *name,SdFile *file); 173 | int wcrx(); 174 | 175 | /* Ward Christensen / CP/M parameters - Don't change these! */ 176 | #define ENQ 005 177 | #define CAN ('X'&037) 178 | #define XOFF ('s'&037) 179 | #define XON ('q'&037) 180 | #define SOH 1 181 | #define STX 2 182 | #define EOT 4 183 | #define ACK 6 184 | #define NAK 025 185 | #define CPMEOF 032 186 | #define WANTCRC 0103 /* send C not NAK to get crc not checksum */ 187 | #define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */ 188 | #define TIMEOUT (-2) 189 | #define RCDO (-3) 190 | #define Tx_RETRYMAX 10 191 | #define Rx_RETRYMAX 5 192 | 193 | #endif 194 | 195 | /* End of ZMODEM.H */ 196 | 197 | -------------------------------------------------------------------------------- /zmodem/zmodem.ino: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include 3 | 4 | #include 5 | 6 | // Arghhh. These three links have disappeared! 7 | // See this page for the original code: 8 | // http://www.raspberryginger.com/jbailey/minix/html/dir_acf1a49c3b8ff2cb9205e4a19757c0d6.html 9 | // From: http://www.raspberryginger.com/jbailey/minix/html/zm_8c-source.html 10 | // docs at: http://www.raspberryginger.com/jbailey/minix/html/zm_8c.html 11 | // The minix files here might be the same thing: 12 | // http://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/commands/zmodem/ 13 | 14 | #include "zmodem_config.h" 15 | 16 | #include "zmodem.h" 17 | #include "zmodem_zm.h" 18 | 19 | // This works with Tera Term Pro Web Version 3.1.3 (2002/10/08) 20 | // (www.ayera.com) but TeraTerm only works on COM1, 2, 3 or 4. 21 | 22 | // It DOES NOT handle interruptions of the Tx or Rx lines so it 23 | // will NOT work in a hostile environment. 24 | 25 | /* 26 | Originally was an example by fat16lib of reading a directory 27 | and listing its files by directory entry number. 28 | See: http://forum.arduino.cc/index.php?topic=173562.0 29 | 30 | Heavily modified by Pete (El Supremo) to recursively list the files 31 | starting at a specified point in the directory structure and then 32 | use zmodem to transmit them to the PC via the ZSERIAL port 33 | 34 | Further heavy modifications by Dylan (monte_carlo_ecm, bitflipper, etc.) 35 | to create a user driven "file manager" of sorts. 36 | Many thanks to Pete (El Supremo) who got this started. Much work remained 37 | to get receive (rz) working, mostly due to the need for speed because of the 38 | very small (64 bytes) Serial buffer in the Arduino. 39 | 40 | I have tested this with an Arduino Mega 2560 R3 interfacing with Windows 10 41 | using Hyperterminal, Syncterm and TeraTerm. All of them seem to work, though 42 | their crash recovery (partial file transfer restart) behaviours vary. 43 | Syncterm kicks out a couple of non-fatal errors at the beginning of sending 44 | a file to the Arduino, but appears to always recover and complete the transfer. 45 | 46 | This sketch should work on any board with at least 30K of flash and 2K of RAM. 47 | Go to zmodem_config.h and disable some of the ARDUINO_SMALL_MEMORY_* macros 48 | for maximum peace of mind and stability if you don't need all the features 49 | (send, receive and file management). 50 | 51 | V2.1 52 | 2015-03-06 53 | - Large scale code clean-up, reduction of variable sizes where they were 54 | unnecessarily large, sharing variables previously unshared between sz and 55 | rz, and creative use of the send/receive buffer allowed this sketch to 56 | BARELY fit and run with all features enabled on a board with 30K flash and 57 | 2K of RAM. Uno & Nano users - enjoy. 58 | - Some boards were unstable at baud rates above 9600. I tracked this back 59 | to overrunning the SERIAL_TX_BUFFER_SIZE to my surprise. Added a check 60 | if a flush() is required both in the help and directory listings, as well 61 | as the sendline() macro. 62 | 63 | V2.0 64 | 2015-02-23 65 | - Taken over by Dylan (monte_carlo_ecm, bitflipper, etc.) 66 | - Added Serial based user interface 67 | - Added support for SparkFun MP3 shield based SDCard (see zmodem_config.h) 68 | - Moved CRC tables to PROGMEM to lighten footprint on dynamic memory (zmodem_crc16.cpp) 69 | - Added ZRQINIT at start of sz. All terminal applications I tested didn't strictly need it, but it's 70 | super handy for getting the terminal application to auto start the download 71 | - Completed adaptation of rz to Arduino 72 | - Removed directory recursion for sz in favour of single file or entire current directory ("*") for sz 73 | - Optimized zdlread, readline, zsendline and sendline 74 | into macros for rz speed - still only up to 57600 baud 75 | - Enabled "crash recovery" for both sz and rz. Various terminal applications may respond differently 76 | to restarting partially completed transfers; experiment with yours to see how it behaves. This 77 | feature could be particularly useful if you have an ever growing log file and you just need to 78 | download the entries since your last download from your Arduino to your computer. 79 | 80 | V1.03 81 | 140913 82 | - remove extraneous code such as the entire main() function 83 | in sz and rz and anything dependent on the vax, etc. 84 | - moved purgeline, sendline, readline and bttyout from rz to zm 85 | so that the the zmodem_rz.cpp file is not required when compiling 86 | sz 87 | 88 | V1.02 89 | 140912 90 | - yup, sz transfer still works. 91 | 10 files -- 2853852 bytes 92 | Time = 265 secs 93 | 94 | V1.01 95 | 140912 96 | This was originally working on a T++2 and now works on T3 97 | - This works on a T3 using the RTC/GPS/uSD breadboard 98 | It sent multiple files - see info.h 99 | - both rz and sz sources compile together here but have not 100 | yet ensured that transmit still works. 101 | 102 | V1.00 103 | 130630 104 | - it compiles. It even times out. But it doesn't send anything 105 | to the PC - the TTYUSB LEDs don't blink at all 106 | - ARGHH. It does help to open the Serial1 port!! 107 | - but now it sends something to TTerm but TTerm must be answering 108 | with a NAK because they just repeat the same thing over 109 | and over again. 110 | 111 | V2.00 112 | 130702 113 | - IT SENT A FILE!!!! 114 | It should have sent two, but I'll take it! 115 | - tried sending 2012/09 at 115200 - it sent the first file (138kB!) 116 | but hangs when it starts on the second one. The file is created 117 | but is zero length. 118 | 119 | - THIS VERSION SENDS MULTIPLE FILES 120 | 3.00 121 | 240222 122 | - Updated for Arduino IDE 2.3.1 and SdFat 2.2.2 123 | - This version has all features enabled by default. If you have a smaller 124 | board and want to disable features to attempt to get it to fit on your 125 | board, edit zmodem_config.h accordingly 126 | - I cannot guarantee this thing still fits on the really tiny boards as 127 | the new SdFat library is by its nature more memory hungry 128 | */ 129 | 130 | #include 131 | //#include 132 | 133 | SdFs sd; 134 | 135 | #ifdef SFMP3_SHIELD 136 | #include 137 | #include 138 | #include 139 | 140 | SFEMP3Shield mp3; 141 | #endif 142 | 143 | #define error(s) sd.errorHalt(s) 144 | 145 | extern int Filesleft; 146 | extern long Totalleft; 147 | 148 | extern SdFile fout; 149 | 150 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - This function was added because I found 151 | // that SERIAL_TX_BUFFER_SIZE was getting overrun at higher baud rates. This modified 152 | // Serial.print() function ensures we are not overrunning the buffer by flushing if 153 | // it gets more than half full. 154 | 155 | size_t DSERIALprint(const __FlashStringHelper *ifsh) 156 | { 157 | PGM_P p = reinterpret_cast(ifsh); 158 | size_t n = 0; 159 | while (1) { 160 | unsigned char c = pgm_read_byte(p++); 161 | if (c == 0) break; 162 | if (DSERIAL.availableForWrite() > SERIAL_TX_BUFFER_SIZE / 2) DSERIAL.flush(); 163 | if (DSERIAL.write(c)) n++; 164 | else break; 165 | } 166 | return n; 167 | } 168 | 169 | #define DSERIALprintln(_p) ({ DSERIALprint(_p); DSERIAL.write("\r\n"); }) 170 | 171 | void help(void) 172 | { 173 | DSERIALprint(Progname); 174 | DSERIALprint(F(" - Transfer rate: ")); 175 | DSERIAL.flush(); DSERIAL.println(ZMODEM_SPEED); DSERIAL.flush(); 176 | DSERIALprintln(F("Available Commands:")); DSERIAL.flush(); 177 | DSERIALprintln(F("HELP - Print this list of commands")); DSERIAL.flush(); 178 | DSERIALprintln(F("DIR - List files in current working directory - alternate LS")); DSERIAL.flush(); 179 | DSERIALprintln(F("PWD - Print current working directory")); DSERIAL.flush(); 180 | DSERIALprintln(F("CD - Change current working directory")); DSERIAL.flush(); 181 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_FILE_MGR 182 | DSERIALprintln(F("DEL file - Delete file - alternate RM")); DSERIAL.flush(); 183 | DSERIALprintln(F("MD dir - Create dir - alternate MKDIR")); DSERIAL.flush(); 184 | DSERIALprintln(F("RD dir - Delete dir - alternate RMDIR")); DSERIAL.flush(); 185 | #endif 186 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_SZ 187 | DSERIALprintln(F("SZ file - Send file from Arduino to terminal (* = all files)")); DSERIAL.flush(); 188 | #endif 189 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_RZ 190 | DSERIALprintln(F("RZ - Receive a file from terminal to Arduino (Hyperterminal sends this")); DSERIAL.flush(); 191 | DSERIALprintln(F(" automatically when you select Transfer->Send File...)")); DSERIAL.flush(); 192 | #endif 193 | } 194 | 195 | SdFile fout; 196 | //dir_t *dir ; 197 | 198 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - The way I made this sketch in any way operate on 199 | // a board with only 2K of RAM is to borrow the SZ/RZ buffer for the buffers needed by the main 200 | // loop(), in particular the file name parameter and the SdFat directory entry. This is very 201 | // unorthodox, but now it works on an Uno. Please see notes in zmodem_config.h for limitations 202 | 203 | #define name (&oneKbuf[512]) 204 | #define dir ((FsFile *)&oneKbuf[256]) 205 | #define file ((FsFile*)&oneKbuf[768]) 206 | 207 | void setup() 208 | { 209 | 210 | // NOTE: The following line needs to be uncommented if DSERIAL and ZSERIAL are decoupled again for debugging 211 | // DSERIAL.begin(115200); 212 | 213 | ZSERIAL.begin(ZMODEM_SPEED); 214 | ZSERIAL.setTimeout(TYPICAL_SERIAL_TIMEOUT); 215 | 216 | // DSERIALprintln(Progname); 217 | 218 | // DSERIALprint(F("Transfer rate: ")); 219 | // DSERIALprintln(ZMODEM_SPEED); 220 | 221 | #ifdef SFMP3_SHIELD 222 | DSERIAL.println(F("SparkFun MP3!\n")); 223 | #else 224 | DSERIAL.println(F("Regular SD Card\n")); 225 | #endif 226 | 227 | //Initialize the SdCard. 228 | //DSERIALprintln(F("About to initialize SdCard")); 229 | if(!sd.begin(SD_SEL, SPI_FULL_SPEED)) sd.initErrorHalt(&DSERIAL); 230 | // depending upon your SdCard environment, SPI_HALF_SPEED may work better. 231 | //DSERIALprintln(F("About to change directory")); 232 | if(!sd.chdir((const char *)("/"))) sd.errorHalt(F("sd.chdir")); 233 | //DSERIALprintln(F("SdCard setup complete")); 234 | 235 | #ifdef SFMP3_SHIELD 236 | mp3.begin(); 237 | #endif 238 | 239 | help(); 240 | 241 | } 242 | 243 | int count_files(int *file_count, long *byte_count) 244 | { 245 | *file_count = 0; 246 | *byte_count = 0; 247 | 248 | dir->openCwd(); 249 | dir->rewindDirectory(); 250 | 251 | while (file->openNext(dir)) { 252 | // read next directory entry in current working directory 253 | 254 | if (!file->isDir()) { 255 | *file_count = *file_count + 1; 256 | *byte_count = *byte_count + file->fileSize(); 257 | } 258 | 259 | file->close(); 260 | } 261 | dir->close(); 262 | return 0; 263 | } 264 | 265 | void loop(void) 266 | { 267 | char *cmd = oneKbuf; 268 | char *param; 269 | 270 | *cmd = 0; 271 | while (DSERIAL.available()) DSERIAL.read(); 272 | 273 | char c = 0; 274 | while(1) { 275 | if (DSERIAL.available() > 0) { 276 | c = DSERIAL.read(); 277 | if ((c == 8 or c == 127) && strlen(cmd) > 0) cmd[strlen(cmd)-1] = 0; 278 | if (c == '\n' || c == '\r') break; 279 | DSERIAL.write(c); 280 | if (c != 8 && c != 127) strncat(cmd, &c, 1); 281 | } else { 282 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - 283 | // This delay is required because I found that if I hard loop with DSERIAL.available, 284 | // in certain circumstances the Arduino never sees a new character. Various forum posts 285 | // seem to confirm that a short delay is required when using this style of reading 286 | // from Serial 287 | delay(20); 288 | } 289 | } 290 | 291 | param = strchr(cmd, 32); 292 | if (param > 0) { 293 | *param = 0; 294 | param = param + 1; 295 | } else { 296 | param = &cmd[strlen(cmd)]; 297 | } 298 | 299 | strupr(cmd); 300 | DSERIAL.println(); 301 | // DSERIALprintln(command); 302 | // DSERIALprintln(parameter); 303 | 304 | if (!strcmp_P(cmd, PSTR("HELP"))) { 305 | 306 | help(); 307 | 308 | } else if (!strcmp_P(cmd, PSTR("DIR")) || !strcmp_P(cmd, PSTR("LS"))) { 309 | DSERIALprintln(F("Directory Listing:")); 310 | 311 | dir->openCwd(); 312 | dir->rewindDirectory(); 313 | 314 | while (file->openNext(dir)) { 315 | // read next directory entry in current working directory 316 | 317 | // format file name 318 | file->getName(name, 64); 319 | 320 | DSERIAL.flush(); DSERIAL.print(name); DSERIAL.flush(); 321 | for (uint8_t i = 0; i < 64 - strlen(name); ++i) DSERIALprint(F(" ")); 322 | if (!(file->isDir())) { 323 | ultoa(file->fileSize(), name, 10); 324 | DSERIAL.flush(); DSERIAL.println(name); DSERIAL.flush(); 325 | } else { 326 | DSERIALprintln(F("DIR")); 327 | } 328 | DSERIAL.flush(); 329 | file->close(); 330 | } 331 | DSERIALprintln(F("End of Directory")); 332 | 333 | } else if (!strcmp_P(cmd, PSTR("PWD"))) { 334 | dir->openCwd(); 335 | dir->getName(name, 256); 336 | dir->close(); 337 | DSERIALprint(F("Current working directory is ")); 338 | DSERIAL.flush(); DSERIAL.println(name); DSERIAL.flush(); 339 | 340 | } else if (!strcmp_P(cmd, PSTR("CD"))) { 341 | if(!sd.chdir(param)) { 342 | DSERIALprint(F("Directory ")); 343 | DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush(); 344 | DSERIALprintln(F(" not found")); 345 | } else { 346 | DSERIALprint(F("Current directory changed to ")); 347 | DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush(); 348 | } 349 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_FILE_MGR 350 | } else if (!strcmp_P(cmd, PSTR("DEL")) || !strcmp_P(cmd, PSTR("RM"))) { 351 | if (!sd.remove(param)) { 352 | DSERIALprint(F("Failed to delete file ")); 353 | DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush(); 354 | } else { 355 | DSERIALprint(F("File ")); 356 | DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush(); 357 | DSERIALprintln(F(" deleted")); 358 | } 359 | } else if (!strcmp_P(cmd, PSTR("MD")) || !strcmp_P(cmd, PSTR("MKDIR"))) { 360 | if (!sd.mkdir(param, true)) { 361 | DSERIALprint(F("Failed to create directory ")); 362 | DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush(); 363 | } else { 364 | DSERIALprint(F("Directory ")); 365 | DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush(); 366 | DSERIALprintln(F(" created")); 367 | } 368 | } else if (!strcmp_P(cmd, PSTR("RD")) || !strcmp_P(cmd, PSTR("RMDIR"))) { 369 | if (!sd.rmdir(param)) { 370 | DSERIALprint(F("Failed to remove directory ")); 371 | DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush(); 372 | } else { 373 | DSERIALprint(F("Directory ")); 374 | DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush(); 375 | DSERIALprintln(F(" removed")); 376 | } 377 | #endif 378 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_SZ 379 | } else if (!strcmp_P(cmd, PSTR("SZ"))) { 380 | // Filcnt = 0; 381 | if (!strcmp_P(param, PSTR("*"))) { 382 | count_files(&Filesleft, &Totalleft); 383 | 384 | if (Filesleft > 0) { 385 | ZSERIAL.print(F("rz\n")); 386 | ZSERIAL.flush(); 387 | 388 | sendzrqinit(); 389 | delay(200); 390 | 391 | // Cannot use the "shared 1K memory" block with the latest SDFat because the file transfer will corrupt the directory object. 392 | FsFile dirsz; 393 | 394 | dirsz.openCwd(); 395 | dirsz.rewindDirectory(); 396 | 397 | while (fout.openNext(&dirsz)) { 398 | // read next directory entry in current working directory 399 | 400 | // open file 401 | fout.getName(name, 256); 402 | //if (!fout.open(name, O_READ)) error(F("file.open failed")); 403 | 404 | //else 405 | if (!fout.isDir()) { 406 | 407 | if (wcs(name) == ERROR) { 408 | delay(500); 409 | fout.close(); 410 | break; 411 | } 412 | else delay(500); 413 | } 414 | fout.close(); 415 | 416 | } 417 | 418 | dirsz.close(); 419 | 420 | saybibi(); 421 | } else { 422 | DSERIALprintln(F("No files found to send")); 423 | } 424 | } else if (!fout.open(param, O_READ)) { 425 | DSERIALprintln(F("file.open failed")); 426 | } else { 427 | // Start the ZMODEM transfer 428 | Filesleft = 1; 429 | Totalleft = fout.fileSize(); 430 | ZSERIAL.print(F("rz\n")); 431 | ZSERIAL.flush(); 432 | sendzrqinit(); 433 | delay(200); 434 | wcs(param); 435 | saybibi(); 436 | fout.close(); 437 | } 438 | #endif 439 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_RZ 440 | } else if (!strcmp_P(cmd, PSTR("RZ"))) { 441 | // DSERIALprintln(F("Receiving file...")); 442 | if (wcreceive(0, 0)) { 443 | DSERIALprintln(F("zmodem transfer failed")); 444 | } else { 445 | DSERIALprintln(F("zmodem transfer successful")); 446 | } 447 | //fout.flush(); 448 | fout.sync(); 449 | fout.close(); 450 | #endif 451 | } 452 | } 453 | 454 | 455 | 456 | -------------------------------------------------------------------------------- /zmodem/zmodem_config.h: -------------------------------------------------------------------------------- 1 | #ifndef ZMODEM_CONFIG_H 2 | #define ZMODEM_CONFIG_H 3 | 4 | #define Progname F("Arduino ZModem V3.0") 5 | 6 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - The SparkFun MP3 shield (which contains an SDCard) 7 | // doesn't operate properly with the SDFat library (SPI related?) unless the MP3 library is 8 | // initialized as well. If you are using a SparkFun MP3 shield as your SDCard interface, 9 | // the following macro must be defined. Otherwise, comment it out. 10 | 11 | //#define SFMP3_SHIELD 12 | 13 | #ifndef SFMP3_SHIELD 14 | // Make sure you set this correctly to define the pin where you have connected your SDCard's 15 | // CS pin! 16 | #define SD_SEL 9 17 | #endif 18 | 19 | // Serial output for debugging info 20 | #define DSERIAL Serial 21 | 22 | // The Serial port for the Zmodem connection 23 | // must not be the same as DSERIAL unless all 24 | // debugging output to DSERIAL is removed 25 | //#define ZSERIAL Serial3 26 | #define ZSERIAL Serial 27 | 28 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Adjust the baud rate to suit your board and needs 29 | #define ZMODEM_SPEED 57600 30 | 31 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - For smaller boards (32K flash, 2K RAM) it may only 32 | // be possible to have only one or some of the following 3 features enabled at a time: 1) File manager 33 | // commands (DEL, MD, RD, etc.), 2) SZ (Send ZModem) or 3) RZ (Receive ZModem). Large boards 34 | // like the Arduino Mega can handle all 3 features in a single sketch easily, but for smaller boards like 35 | // Uno or Nano, it's very tight. It seems to work okay, but if you don't need the file manager commands, 36 | // or one of send or receive, comment out the associated macro and it'll slim the sketch down some. 37 | 38 | // Uncomment the following macro to build a version with file manipulation commands. 39 | 40 | #define ARDUINO_SMALL_MEMORY_INCLUDE_FILE_MGR 41 | 42 | // Uncomment the following macro to build a version with SZ enabled. 43 | 44 | #define ARDUINO_SMALL_MEMORY_INCLUDE_SZ 45 | 46 | // Uncomment the following macro to build a version with RZ enabled 47 | 48 | #define ARDUINO_SMALL_MEMORY_INCLUDE_RZ 49 | 50 | 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /zmodem/zmodem_crc16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | /* 5 | * Crc calculation stuff 6 | */ 7 | #ifndef ZMODEM_CRC16_CPP 8 | #define ZMODEM_CRC16_CPP 9 | /* crctab calculated by Mark G. Mendel, Network Systems Corporation */ 10 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Moved to PROGMEM 11 | PROGMEM static const unsigned short crctab[256] = { 12 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 13 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 14 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 15 | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 16 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 17 | 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 18 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 19 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 20 | 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 21 | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 22 | 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 23 | 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 24 | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 25 | 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 26 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 27 | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 28 | 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 29 | 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 30 | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 31 | 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 32 | 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 33 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 34 | 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 35 | 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 36 | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 37 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 38 | 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 39 | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 40 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 41 | 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 42 | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 43 | 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 44 | }; 45 | 46 | /* 47 | * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. 48 | * NOTE: First argument must be in range 0 to 255. 49 | * Second argument is referenced twice. 50 | * 51 | * Programmers may incorporate any or all code into their programs, 52 | * giving proper credit within the source. Publication of the 53 | * source routines is permitted so long as proper credit is given 54 | * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, 55 | * Omen Technology. 56 | */ 57 | // Pete (El Supremo) Can't parenthesize this in a way that gets rid of a compiler 58 | // warning on line 283 of zmodem_zm.cpp 59 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - No warning in Arduino IDE 1.6.5 60 | 61 | #ifdef ARDUINO 62 | #define updcrc(cp, crc) ( ( (pgm_read_word(crctab + ((crc >> 8) & 255)) ^ (crc << 8) ) ^ cp)) 63 | #else 64 | #define updcrc(cp, crc) ( ( (crctab[((crc >> 8) & 255)] ^ (crc << 8) ) ^ cp)) 65 | #endif 66 | 67 | /* 68 | * Copyright (C) 1986 Gary S. Brown. You may use this program, or 69 | * code or tables extracted from it, as desired without restriction. 70 | */ 71 | 72 | /* First, the polynomial itself and its table of feedback terms. The */ 73 | /* polynomial is */ 74 | /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ 75 | /* Note that we take it "backwards" and put the highest-order term in */ 76 | /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ 77 | /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ 78 | /* the MSB being 1. */ 79 | 80 | /* Note that the usual hardware shift register implementation, which */ 81 | /* is what we're using (we're merely optimizing it by doing eight-bit */ 82 | /* chunks at a time) shifts bits into the lowest-order term. In our */ 83 | /* implementation, that means shifting towards the right. Why do we */ 84 | /* do it this way? Because the calculated CRC must be transmitted in */ 85 | /* order from highest-order term to lowest-order term. UARTs transmit */ 86 | /* characters in order from LSB to MSB. By storing the CRC this way, */ 87 | /* we hand it to the UART in the order low-byte to high-byte; the UART */ 88 | /* sends each low-bit to hight-bit; and the result is transmission bit */ 89 | /* by bit from highest- to lowest-order term without requiring any bit */ 90 | /* shuffling on our part. Reception works similarly. */ 91 | 92 | /* The feedback terms table consists of 256, 32-bit entries. Notes: */ 93 | /* */ 94 | /* The table can be generated at runtime if desired; code to do so */ 95 | /* is shown later. It might not be obvious, but the feedback */ 96 | /* terms simply represent the results of eight shift/xor opera- */ 97 | /* tions for all combinations of data and CRC register values. */ 98 | /* */ 99 | /* The values must be right-shifted by eight bits by the "updcrc" */ 100 | /* logic; the shift must be unsigned (bring in zeroes). On some */ 101 | /* hardware you could probably optimize the shift in assembler by */ 102 | /* using byte-swap instructions. */ 103 | 104 | // Pete (El_Supremo) add 'unsigned' 105 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Moved to PROGMEM 106 | PROGMEM static const unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */ 107 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 108 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 109 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 110 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 111 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 112 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 113 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 114 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 115 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 116 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 117 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 118 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 119 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 120 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 121 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 122 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 123 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 124 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 125 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 126 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 127 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 128 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 129 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 130 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 131 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 132 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 133 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 134 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 135 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 136 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 137 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 138 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 139 | }; 140 | 141 | #ifdef NFGM 142 | long 143 | UPDC32(b, c) 144 | long c; 145 | { 146 | return (pgm_read_dword(cr3tab + (((int)c ^ b) & 0xff)) ^ ((c >> 8) & 0x00FFFFFF)); 147 | // return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)); 148 | } 149 | 150 | #else 151 | #ifdef ARDUINO 152 | #define UPDC32(b, c) (pgm_read_dword(cr3tab + (((int)c ^ b) & 0xff)) ^ ((c >> 8) & 0x00FFFFFF)) 153 | #else 154 | #define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) 155 | #endif 156 | 157 | #endif 158 | 159 | /* End of crctab.c */ 160 | #endif 161 | 162 | -------------------------------------------------------------------------------- /zmodem/zmodem_fixes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Keep everything for ANSI prototypes. 3 | From: http://stackoverflow.com/questions/2607853/why-prototype-is-used-header-files 4 | */ 5 | 6 | #ifndef ZMODEM_FIXES_H 7 | #define ZMODEM_FIXES_H 8 | 9 | 10 | //////////////////////////////////////////////////////// 11 | 12 | 13 | #define _PROTOTYPE(function, params) function params 14 | 15 | #include 16 | 17 | extern SdFat sd; 18 | 19 | #include 20 | 21 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - changed serial read/write to macros to try to squeeze 22 | // out higher speed 23 | 24 | #define READCHECK 25 | #define TYPICAL_SERIAL_TIMEOUT 1200 26 | 27 | #define readline(timeout) ({ byte _c; ZSERIAL.readBytes(&_c, 1) > 0 ? _c : TIMEOUT; }) 28 | int zdlread2(int); 29 | #define zdlread(void) ({ int _z; ((_z = readline(Rxtimeout)) & 0140) ? _z : zdlread2(_z); }) 30 | //#define sendline(_c) ZSERIAL.write(char(_c)) 31 | #define sendline(_c) ({ if (ZSERIAL.availableForWrite() > SERIAL_TX_BUFFER_SIZE / 2) ZSERIAL.flush(); ZSERIAL.write(char(_c)); }) 32 | #define zsendline(_z) ({ (_z & 0140 ) ? sendline(_z) : zsendline2(_z); }) 33 | 34 | void sendzrqinit(void); 35 | int wctxpn(const char *name); 36 | #define ARDUINO_RECV 37 | //int wcrx(void); 38 | int wcreceive(int argc, char **argp); 39 | 40 | extern int Filcnt; 41 | 42 | #define register int 43 | 44 | // If this is not defined the default is 1024. 45 | // It must be a power of 2 46 | 47 | #ifdef ARDUINO_SMALL_MEMORY 48 | #define TXBSIZE 1024 49 | #else 50 | #define TXBSIZE 1024 51 | #endif 52 | 53 | #define sleep(x) delay((x)*1000L) 54 | #define signal(x,y) 55 | 56 | // Handle the calls to exit - one has SS_NORMAL 57 | #define SS_NORMAL 0 58 | #define exit(n) 59 | 60 | // For now, evaluate it to zero so that it does not 61 | // enter the "if" statement's clause 62 | #define setjmp(...) 63 | 64 | #define printf(s, ... ) DSERIAL.println(s); 65 | #define fprintf(...) 66 | 67 | // fseek(in, Rxpos, 0) 68 | //#define fseek(fd, pos, rel) sdfile->seekSet(pos) 69 | //#define fclose(c) 70 | 71 | // ignore calls to mode() function in rbsb.cpp 72 | #define mode(a) 73 | 74 | #define sendbrk() 75 | 76 | //extern int Fromcu; 77 | void purgeline(void); 78 | 79 | #ifndef UNSL 80 | #define UNSL unsigned 81 | #endif 82 | 83 | void flushmo(void); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /zmodem/zmodem_rz.cpp: -------------------------------------------------------------------------------- 1 | /*% cc -compat -M2 -Ox -K -i -DMD -DOMEN % -o rz; size rz; 2 | <-xtx-*> cc386 -Ox -DMD -DOMEN -DSEGMENTS=8 rz.c -o $B/rz; size $B/rz 3 | * 4 | * rz.c By Chuck Forsberg 5 | * 6 | * cc -O rz.c -o rz USG (3.0) Unix 7 | * cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3 8 | * 9 | * ln rz rb; ln rz rx For either system 10 | * 11 | * ln rz /usr/bin/rzrmail For remote mail. Make this the 12 | * login shell. rzrmail then calls 13 | * rmail(1) to deliver mail. 14 | * 15 | * To compile on VMS: 16 | * 17 | * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB 18 | * cc rz.c 19 | * cc vvmodem.c 20 | * link rz,vvmodem 21 | * rz :== $disk:[username.subdir]rz.exe 22 | * 23 | * 24 | * Unix is a trademark of Western Electric Company 25 | * 26 | * A program for Unix to receive files and commands from computers running 27 | * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. 28 | * rz uses Unix buffered input to reduce wasted CPU time. 29 | * 30 | * Iff the program is invoked by rzCOMMAND, output is piped to 31 | * "COMMAND filename" (Unix only) 32 | * 33 | * Some systems (Venix, Coherent, Regulus) may not support tty raw mode 34 | * read(2) the same way as Unix. ONEREAD must be defined to force one 35 | * character reads for these systems. Added 7-01-84 CAF 36 | * 37 | * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 38 | * 39 | * BIX added 6-30-87 to support BIX(TM) upload protocol used by the 40 | * Byte Information Exchange. 41 | * 42 | * NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN] 43 | * doesn't work properly (even though it compiles without error!), 44 | * 45 | * SEGMENTS=n added 2-21-88 as a model for CP/M programs 46 | * for CP/M-80 systems that cannot overlap modem and disk I/O. 47 | * 48 | * VMS flavor hacks begin with rz version 2.00 49 | * 50 | * -DMD may be added to compiler command line to compile in 51 | * Directory-creating routines from Public Domain TAR by John Gilmore 52 | * 53 | * HOWMANY may be tuned for best performance 54 | * 55 | * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin 56 | */ 57 | 58 | #include "zmodem_config.h" 59 | #include "zmodem_fixes.h" 60 | 61 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_RZ 62 | 63 | #include 64 | 65 | #define xsendline(c) sendline(c) 66 | 67 | #include "zmodem.h" 68 | #include "zmodem_zm.h" 69 | #include "zmodem_crc16.cpp" 70 | 71 | _PROTOTYPE(long getfree , (void)); 72 | _PROTOTYPE(int wcreceive , (int argc , char **argp )); 73 | _PROTOTYPE(int wcrxpn , (char *rpn )); 74 | _PROTOTYPE(int wcrx , ()); 75 | _PROTOTYPE(int wcgetsec , (char *rxbuf , int maxtime )); 76 | //_PROTOTYPE(int readline , (int timeout )); 77 | _PROTOTYPE(void purgeline , (void)); 78 | _PROTOTYPE(int procheader , (char *name )); 79 | _PROTOTYPE(int putsec , (char *buf , int n )); 80 | //_PROTOTYPE(void sendline , (int c )); 81 | _PROTOTYPE(void flushmo , (void)); 82 | _PROTOTYPE(void uncaps , (char *s )); 83 | _PROTOTYPE(int IsAnyLower , (char *s )); 84 | 85 | // Pete (El Supremo) 86 | //void zperr(); 87 | 88 | 89 | _PROTOTYPE(void canit , (void)); 90 | _PROTOTYPE(void report , (int sct )); 91 | _PROTOTYPE(int checkpath , (char *name )); 92 | _PROTOTYPE(int tryz , (void)); 93 | _PROTOTYPE(int rzfiles , (void)); 94 | _PROTOTYPE(int rzfile , (void)); 95 | _PROTOTYPE(void zmputs , (char *s )); 96 | _PROTOTYPE(int closeit , (void)); 97 | _PROTOTYPE(void ackbibi , (void)); 98 | _PROTOTYPE(void bttyout , (int c )); 99 | //_PROTOTYPE(int sys2 , (char *s )); 100 | //_PROTOTYPE(void exec2 , (char *s )); 101 | 102 | /* 103 | * Max value for HOWMANY is 255. 104 | * A larger value reduces system overhead but may evoke kernel bugs. 105 | * 133 corresponds to an XMODEM/CRC sector 106 | */ 107 | #ifndef HOWMANY 108 | #define HOWMANY 133 109 | #endif 110 | 111 | 112 | 113 | #define WCEOT (-10) 114 | #ifdef ARDUINO_SMALL_MEMORY 115 | #define PATHLEN 12 116 | #else 117 | #define PATHLEN 256 /* ready for 4.2 bsd ? */ 118 | #endif 119 | #define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */ 120 | 121 | 122 | 123 | 124 | 125 | #ifndef ARDUINO 126 | #ifdef vax11c 127 | #include "vrzsz.c" /* most of the system dependent stuff here */ 128 | #else 129 | #include "rbsb.c" /* most of the system dependent stuff here */ 130 | #endif 131 | 132 | #include "crctab.c" 133 | #endif 134 | 135 | #ifndef ARDUINO 136 | FILE *fout; 137 | #else 138 | extern SdFile fout; 139 | #endif 140 | 141 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Moved this to a global variable to enable 142 | // crash recovery (continuation of partial file transfer) 143 | extern long rxbytes; 144 | 145 | /* 146 | * Routine to calculate the free bytes on the current file system 147 | * ~0 means many free bytes (unknown) 148 | */ 149 | long getfree(void) 150 | { 151 | return(~0L); /* many free bytes ... */ 152 | } 153 | 154 | 155 | 156 | 157 | 158 | //#ifdef ONEREAD 159 | /* Sorry, Regulus and some others don't work right in raw mode! */ 160 | //int Readnum = 1; /* Number of bytes to ask for in read() from modem */ 161 | //#else 162 | //int Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */ 163 | //#endif 164 | 165 | #define DEFBYTL 2000000000L /* default rx file size */ 166 | extern long Bytesleft; /* number of bytes of incoming file left */ 167 | //long Modtime; /* Unix style mod time for incoming file */ 168 | //int Filemode; /* Unix style mode for incoming file */ 169 | 170 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Once again, in order to save every precious byte I 171 | // could find, I borrow the tail end of the receive buffer for the incoming Pathname. By the time 172 | // the ZModem file transfer begins and actually uses bytes of the buffer up to this point (768), 173 | // the need for Pathname is past because the file is already open. Again, very unorthodox, I 174 | // don't like writing code like this, but it's either tricks like this or the sketch cannot work 175 | // at all on a board with 2K of RAM. 176 | 177 | //char Pathname[PATHLEN]; 178 | #define Pathname (&oneKbuf[768]) 179 | 180 | //char *Progname; /* the name by which we were called */ 181 | 182 | #define Batch 0 183 | #define Topipe 0 184 | #define MakeLCPathname TRUE /* make received pathname lower case */ 185 | 186 | 187 | //int Nflag = 0; /* Don't really transfer files */ 188 | #define Rxclob FALSE /* Clobber existing file */ 189 | #define Rxbinary FALSE /* receive all files in bin mode */ 190 | #define Rxascii FALSE /* receive files in ascii (translate) mode */ 191 | uint8_t Thisbinary; /* current file is to be received in bin mode */ 192 | extern int Blklen; /* record length of received packets */ 193 | 194 | #ifdef SEGMENTS 195 | int chinseg = 0; /* Number of characters received in this data seg */ 196 | char secbuf[1+(SEGMENTS+1)*1024]; 197 | #else 198 | #define secbuf oneKbuf 199 | #define SECBUF_LEN TXBSIZE 200 | #endif 201 | 202 | 203 | //char linbuf[HOWMANY]; 204 | uint8_t Lleft=0; /* number of characters in linbuf */ 205 | //time_t timep[2]; 206 | 207 | 208 | 209 | 210 | //PEL 211 | //jmp_buf tohere; /* For the interrupt on RX timeout */ 212 | 213 | 214 | 215 | uint8_t tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */ 216 | 217 | #ifdef ARDUINO_RECV 218 | 219 | #ifndef ARDUINO 220 | /* called by signal interrupt or terminate to clean things up */ 221 | void bibi(int n) 222 | { 223 | if (Zmodem) 224 | zmputs(Attn); 225 | canit(); 226 | mode(0); 227 | fprintf(stderr, "rz: caught signal %d; exiting\n", n); 228 | cucheck(); 229 | exit(128+n); 230 | } 231 | #endif 232 | 233 | 234 | /* 235 | * Debugging information output interface routine 236 | */ 237 | /* VARARGS1 */ 238 | /*void vfile(char *f, char *a, char *b, char *c) 239 | { 240 | if (Verbose > 2) { 241 | fprintf(stderr, f, a, b, c); 242 | fprintf(stderr, "\n"); 243 | } 244 | }*/ 245 | 246 | /* 247 | * Let's receive something already. 248 | */ 249 | 250 | #define rbmsg F("%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n") 251 | 252 | int wcreceive(int argc, char **argp) 253 | //int argc; 254 | //char **argp; 255 | { 256 | register c; 257 | 258 | if (Batch || argc==0) { 259 | Crcflg=1; 260 | if ( !Quiet) 261 | fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz"); 262 | if (c=tryz()) { 263 | if (c == ZCOMPL) { 264 | fout.close(); 265 | return OK; 266 | } 267 | if (c == ERROR) { 268 | //DSERIAL.println(F("fubar 1")); 269 | goto fubar; 270 | } 271 | c = rzfiles(); 272 | if (c) { 273 | //DSERIAL.println(F("fubar 2")); 274 | goto fubar; 275 | } 276 | } 277 | else { 278 | for (;;) { 279 | if (wcrxpn(secbuf)== ERROR) { 280 | //DSERIAL.println(F("fubar 3")); 281 | goto fubar; 282 | } 283 | if (secbuf[0]==0) 284 | return OK; 285 | if (procheader(secbuf) == ERROR) { 286 | //DSERIAL.println(F("fubar 4")); 287 | goto fubar; 288 | } 289 | if (wcrx()==ERROR) { 290 | //DSERIAL.println(F("fubar 5")); 291 | goto fubar; 292 | } 293 | } 294 | } 295 | } 296 | else { 297 | Bytesleft = DEFBYTL; 298 | //Filemode = 0; 299 | //Modtime = 0L; 300 | 301 | procheader(""); 302 | strcpy(Pathname, *argp); 303 | // if (checkpath(Pathname)) { 304 | // canit(); 305 | // return ERROR; 306 | // } 307 | //DSERIAL.print("rz: ready to receive "); 308 | //DSERIAL.println(Pathname); 309 | #ifndef ARDUINO 310 | if ((fout=fopen(Pathname, "w")) == NULL) 311 | #else 312 | if (!fout.open(Pathname, O_WRITE | O_CREAT | O_AT_END)) 313 | #endif 314 | return ERROR; 315 | rxbytes = fout.fileSize(); 316 | 317 | if (wcrx()==ERROR) { 318 | DSERIAL.println(F("fubar 6")); 319 | goto fubar; 320 | } 321 | } 322 | fout.close(); 323 | return OK; 324 | fubar: 325 | canit(); 326 | #ifndef ARDUINO 327 | #ifndef vax11c 328 | if (Topipe && fout) { 329 | pclose(fout); 330 | return ERROR; 331 | } 332 | #endif 333 | if (fout) 334 | fclose(fout); 335 | #ifndef vax11c 336 | if (Restricted) { 337 | unlink(Pathname); 338 | fprintf(stderr, F("\r\nrz: %s removed.\r\n"), Pathname); 339 | } 340 | #endif 341 | #else 342 | fout.sync(); 343 | fout.close(); 344 | #endif 345 | return ERROR; 346 | } 347 | 348 | int Firstsec; 349 | /* 350 | * Fetch a pathname from the other end as a C ctyle ASCIZ string. 351 | * Length is indeterminate as long as less than Blklen 352 | * A null string represents no more files (YMODEM) 353 | */ 354 | int wcrxpn(char *rpn) 355 | /* receive a pathname */ 356 | { 357 | register c; 358 | 359 | #ifdef NFGVMIN 360 | readline(1); 361 | #else 362 | purgeline(); 363 | #endif 364 | 365 | et_tu: 366 | Firstsec=TRUE; 367 | Eofseen=FALSE; 368 | sendline(Crcflg?WANTCRC:NAK); 369 | Lleft=0; /* Do read next time ... */ 370 | while ((c = wcgetsec(rpn, 100)) != 0) { 371 | if (c == WCEOT) { 372 | zperr( "Pathname fetch returned %d", c); 373 | sendline(ACK); 374 | Lleft=0; /* Do read next time ... */ 375 | readline(1); 376 | goto et_tu; 377 | } 378 | return ERROR; 379 | 380 | 381 | } 382 | sendline(ACK); 383 | return OK; 384 | } 385 | 386 | /* 387 | * Adapted from CMODEM13.C, written by 388 | * Jack M. Wierda and Roderick W. Hart 389 | */ 390 | 391 | int wcrx() 392 | { 393 | int sectnum, sectcurr; 394 | char sendchar; 395 | int cblklen; /* bytes to dump this block */ 396 | 397 | Firstsec=TRUE; 398 | sectnum=0; 399 | Eofseen=FALSE; 400 | sendchar=Crcflg?WANTCRC:NAK; 401 | 402 | for (;;) { 403 | sendline(sendchar); /* send it now, we're ready! */ 404 | Lleft=0; /* Do read next time ... */ 405 | sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130); 406 | report(sectcurr); 407 | if (sectcurr==((sectnum+1) &0377)) { 408 | sectnum++; 409 | cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; 410 | if (putsec(secbuf, cblklen)==ERROR) 411 | return ERROR; 412 | if ((Bytesleft-=cblklen) < 0) 413 | Bytesleft = 0; 414 | sendchar=ACK; 415 | } 416 | else if (sectcurr==(sectnum&0377)) { 417 | zperr( "Received dup Sector"); 418 | sendchar=ACK; 419 | } 420 | else if (sectcurr==WCEOT) { 421 | if (closeit()) 422 | return ERROR; 423 | sendline(ACK); 424 | Lleft=0; /* Do read next time ... */ 425 | return OK; 426 | } 427 | else if (sectcurr==ERROR) 428 | return ERROR; 429 | else { 430 | zperr( "Sync Error"); 431 | return ERROR; 432 | } 433 | } 434 | } 435 | 436 | /* 437 | * Wcgetsec fetches a Ward Christensen type sector. 438 | * Returns sector number encountered or ERROR if valid sector not received, 439 | * or CAN CAN received 440 | * or WCEOT if eot sector 441 | * time is timeout for first char, set to 4 seconds thereafter 442 | ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** 443 | * (Caller must do that when he is good and ready to get next sector) 444 | */ 445 | 446 | int wcgetsec(char *rxbuf,int maxtime) 447 | { 448 | int checksum, wcj, firstch; 449 | unsigned short oldcrc; 450 | char *p; 451 | int sectcurr; 452 | 453 | for (Lastrx=errors=0; errors=0; ) { 466 | if ((firstch=readline(1)) < 0) { 467 | //DSERIAL.println(F("bilge 1")); 468 | goto bilge; 469 | } 470 | oldcrc=updcrc(firstch, oldcrc); 471 | checksum += (*p++ = firstch); 472 | } 473 | if ((firstch=readline(1)) < 0) { 474 | //DSERIAL.println(F("bilge 2")); 475 | 476 | goto bilge; 477 | } 478 | if (Crcflg) { 479 | oldcrc=updcrc(firstch, oldcrc); 480 | if ((firstch=readline(1)) < 0) { 481 | //DSERIAL.println(F("bilge 3")); 482 | 483 | goto bilge; 484 | } 485 | oldcrc=updcrc(firstch, oldcrc); 486 | if (oldcrc & 0xFFFF) { 487 | zperr( "CRC"); 488 | } else { 489 | Firstsec=FALSE; 490 | return sectcurr; 491 | } 492 | } 493 | else if (((checksum-firstch)&0377)==0) { 494 | Firstsec=FALSE; 495 | return sectcurr; 496 | } 497 | else 498 | zperr( "Checksum"); 499 | } 500 | else 501 | zperr("Sector number garbled"); 502 | } 503 | /* make sure eot really is eot and not just mixmash */ 504 | #ifdef NFGVMIN 505 | else if (firstch==EOT && readline(1)==TIMEOUT) 506 | return WCEOT; 507 | #else 508 | else if (firstch==EOT && Lleft==0) 509 | return WCEOT; 510 | #endif 511 | else if (firstch==CAN) { 512 | if (Lastrx==CAN) { 513 | zperr( "Sender CANcelled"); 514 | return ERROR; 515 | } 516 | else { 517 | Lastrx=CAN; 518 | continue; 519 | } 520 | } 521 | else if (firstch==TIMEOUT) { 522 | if (Firstsec) 523 | goto humbug; 524 | bilge: 525 | zperr( "TIMEOUT"); 526 | } 527 | else 528 | zperr( "Got 0%o sector header", firstch); 529 | 530 | humbug: 531 | Lastrx=0; 532 | while(readline(1)!=TIMEOUT) 533 | ; 534 | if (Firstsec) { 535 | sendline(Crcflg?WANTCRC:NAK); 536 | Lleft=0; /* Do read next time ... */ 537 | } 538 | else { 539 | maxtime=40; 540 | sendline(NAK); 541 | Lleft=0; /* Do read next time ... */ 542 | } 543 | } 544 | /* try to stop the bubble machine. */ 545 | canit(); 546 | return ERROR; 547 | } 548 | #endif 549 | 550 | 551 | #ifndef NOTDEF 552 | 553 | /* 554 | * Process incoming file information header 555 | */ 556 | int procheader(char *name) 557 | { 558 | char *openmode, *p; 559 | 560 | /* set default parameters and overrides */ 561 | openmode = "w"; 562 | Thisbinary = (!Rxascii) || Rxbinary; 563 | if (Lzmanag) 564 | zmanag = Lzmanag; 565 | 566 | /* 567 | * Process ZMODEM remote file management requests 568 | */ 569 | if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */ 570 | Thisbinary = 0; 571 | if (zconv == ZCBIN) /* Remote Binary override */ 572 | Thisbinary = TRUE; 573 | else if (zmanag == ZMAPND) 574 | openmode = "a"; 575 | 576 | #ifndef BIX 577 | /* Check for existing file */ 578 | #ifndef ARDUINO 579 | if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) { 580 | fclose(fout); 581 | return ERROR; 582 | } 583 | #else 584 | // if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && sd.exists(name)) { 585 | // return ERROR; 586 | // } 587 | #endif 588 | #endif 589 | 590 | Bytesleft = DEFBYTL; 591 | //Filemode = 0; 592 | //Modtime = 0L; 593 | 594 | p = name + 1 + strlen(name); 595 | if (*p) { /* file coming from Unix or DOS system */ 596 | // sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode); 597 | Bytesleft = atol(p); 598 | 599 | #ifndef vax11c 600 | // if (Filemode & UNIXFILE) 601 | ++Thisbinary; 602 | #endif 603 | if (Verbose) { 604 | fprintf(stderr, "\nIncoming: %s %ld %lo %o\n", 605 | name, Bytesleft, Modtime, Filemode); 606 | } 607 | } 608 | 609 | #ifdef BIX 610 | if ((fout=fopen(F("scratchpad"), openmode)) == NULL) 611 | return ERROR; 612 | return OK; 613 | #else 614 | 615 | else { /* File coming from CP/M system */ 616 | for (p=name; *p; ++p) /* change / to _ */ 617 | if ( *p == '/') 618 | *p = '_'; 619 | 620 | if ( *--p == '.') /* zap trailing period */ 621 | *p = 0; 622 | } 623 | 624 | #ifndef vax11c 625 | /* if (!Zmodem && MakeLCPathname && !IsAnyLower(name) 626 | && !(Filemode&UNIXFILE)) 627 | uncaps(name); */ 628 | #endif 629 | 630 | strcpy(Pathname, name); 631 | if (Verbose) { 632 | fprintf(stderr, "Receiving %s %s %s\n", 633 | name, Thisbinary?"BIN":"ASCII", openmode); 634 | } 635 | // if (checkpath(name)) { 636 | // canit(); 637 | // return ERROR; 638 | // } 639 | // if (Nflag) 640 | // name = "/dev/null"; 641 | #ifndef vax11c 642 | #ifdef OMEN 643 | if (name[0] == '!' || name[0] == '|') { 644 | if ( !(fout = popen(name+1, "w"))) { 645 | return ERROR; 646 | } 647 | Topipe = -1; 648 | return(OK); 649 | } 650 | #endif 651 | #endif 652 | 653 | #ifndef ARDUINO 654 | fout = fopen(name, openmode); 655 | #else 656 | fout.open(name, O_WRITE | O_CREAT | O_AT_END); 657 | rxbytes = fout.fileSize(); 658 | 659 | #endif 660 | #ifndef ARDUINO 661 | if ( !fout) 662 | #else 663 | if (!fout.isOpen()) 664 | #endif 665 | return ERROR; 666 | // } 667 | return OK; 668 | #endif /* BIX */ 669 | } 670 | 671 | /* 672 | * Putsec writes the n characters of buf to receive file fout. 673 | * If not in binary mode, carriage returns, and all characters 674 | * starting with CPMEOF are discarded. 675 | */ 676 | int putsec(char *buf,int n) 677 | { 678 | if (n == 0) 679 | return OK; 680 | if (Thisbinary) { 681 | #ifndef ARDUINO 682 | for (char *p=buf; --n>=0; ) 683 | putc( *p++, fout); 684 | #else 685 | fout.write(buf, n); 686 | // for (p=buf; --n>=0; ) 687 | // fout.write(*p++); 688 | 689 | #endif 690 | } 691 | else { 692 | if (Eofseen) 693 | return OK; 694 | for (char *p=buf; --n>=0; ++p ) { 695 | if ( *p == '\r') 696 | continue; 697 | if (*p == CPMEOF) { 698 | Eofseen=TRUE; 699 | return OK; 700 | } 701 | #ifndef ARDUINO 702 | putc(*p ,fout); 703 | #else 704 | fout.write(*p); 705 | #endif 706 | } 707 | } 708 | return OK; 709 | } 710 | #endif 711 | 712 | 713 | /* make string s lower case */ 714 | /*void uncaps(char *s) 715 | { 716 | for ( ; *s; ++s) 717 | if (isupper(*s)) 718 | *s = tolower(*s); 719 | } */ 720 | /* 721 | * IsAnyLower returns TRUE if string s has lower case letters. 722 | */ 723 | int IsAnyLower(char *s) 724 | { 725 | for ( ; *s; ++s) 726 | if (islower(*s)) 727 | return TRUE; 728 | return FALSE; 729 | } 730 | 731 | 732 | void report(int sct) 733 | { 734 | if (Verbose>1) 735 | fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r'); 736 | } 737 | 738 | 739 | /* 740 | * Initialize for Zmodem receive attempt, try to activate Zmodem sender 741 | * Handles ZSINIT frame 742 | * Return ZFILE if Zmodem filename received, -1 on error, 743 | * ZCOMPL if transaction finished, else 0 744 | */ 745 | int tryz(void) 746 | { 747 | int c, n; 748 | int cmdzack1flg; 749 | 750 | //DSERIAL.println(F("Entering tryz")); 751 | 752 | if (Nozmodem) /* Check for "rb" program name */ 753 | return 0; 754 | 755 | tryzhdrtype=ZRINIT; 756 | 757 | for (n=Zmodem?15:5; --n>=0; ) { 758 | /* Set buffer length (0) and capability flags */ 759 | #ifdef SEGMENTS 760 | stohdr(SEGMENTS*1024L); 761 | #else 762 | #ifndef ARDUINO 763 | stohdr(0L); 764 | #else 765 | // This unfortunate piece is a limiting factor. This parameter is supposed to control 766 | // the maximum buffer size that the sender expects us to have. It seems most ZModem send implementations 767 | // ignore it, with Hyperterminal being the only exception I can find. Without setting this, even 768 | // Hyperterminal outstrips the Arduino's speed and buffer (64 bytes) at 57600 baud. 769 | stohdr(SECBUF_LEN); 770 | #endif 771 | 772 | #endif 773 | #ifdef CANBREAK 774 | Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; 775 | #else 776 | Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; 777 | #endif 778 | 779 | if (Zctlesc) 780 | Txhdr[ZF0] |= TESCCTL; 781 | zshhdr(tryzhdrtype, Txhdr); 782 | if (tryzhdrtype == ZSKIP) /* Don't skip too far */ 783 | tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ 784 | again: 785 | switch (zgethdr(Rxhdr, 0)) { 786 | case ZRQINIT: 787 | //DSERIAL.println(F("tryz got ZRQINIT")); 788 | continue; 789 | case ZEOF: 790 | //DSERIAL.println(F("tryz got ZEOF")); 791 | continue; 792 | case TIMEOUT: 793 | //DSERIAL.println(F("tryz got TIMEOUT")); 794 | continue; 795 | case ZFILE: 796 | //DSERIAL.println(F("tryz got ZFILE")); 797 | 798 | zconv = Rxhdr[ZF0]; 799 | zmanag = Rxhdr[ZF1]; 800 | ztrans = Rxhdr[ZF2]; 801 | tryzhdrtype = ZRINIT; 802 | c = zrdata(secbuf, SECBUF_LEN); 803 | mode(3); 804 | if (c == GOTCRCW) 805 | return ZFILE; 806 | zshhdr(ZNAK, Txhdr); 807 | goto again; 808 | case ZSINIT: 809 | //DSERIAL.println(F("tryz got ZSINIT")); 810 | 811 | Zctlesc = TESCCTL & Rxhdr[ZF0]; 812 | if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { 813 | stohdr(1L); 814 | zshhdr(ZACK, Txhdr); 815 | goto again; 816 | } 817 | zshhdr(ZNAK, Txhdr); 818 | goto again; 819 | case ZFREECNT: 820 | stohdr(getfree()); 821 | zshhdr(ZACK, Txhdr); 822 | goto again; 823 | case ZCOMMAND: 824 | #ifdef vax11c 825 | return ERROR; 826 | #else 827 | //DSERIAL.println(F("tryz got ZCOMMAND")); 828 | 829 | cmdzack1flg = Rxhdr[ZF0]; 830 | if (zrdata(secbuf, SECBUF_LEN) == GOTCRCW) { 831 | // if (cmdzack1flg & ZCACK1) 832 | stohdr(0L); 833 | // else 834 | // stohdr((long)sys2(secbuf)); 835 | purgeline(); /* dump impatient questions */ 836 | do { 837 | zshhdr(ZCOMPL, Txhdr); 838 | } 839 | while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN); 840 | ackbibi(); 841 | // if (cmdzack1flg & ZCACK1) 842 | // exec2(secbuf); 843 | return ZCOMPL; 844 | } 845 | zshhdr(ZNAK, Txhdr); 846 | goto again; 847 | #endif 848 | case ZCOMPL: 849 | //DSERIAL.println(F("tryz got ZCOMPL")); 850 | 851 | goto again; 852 | default: 853 | //DSERIAL.println(F("tryz got default")); 854 | 855 | continue; 856 | case ZFIN: 857 | //DSERIAL.println(F("tryz got ZFIN")); 858 | 859 | ackbibi(); 860 | return ZCOMPL; 861 | case ZCAN: 862 | //DSERIAL.println(F("tryz got ZCAN")); 863 | 864 | return ERROR; 865 | } 866 | } 867 | return 0; 868 | } 869 | 870 | /* 871 | * Receive 1 or more files with ZMODEM protocol 872 | */ 873 | int rzfiles(void) 874 | { 875 | int c; 876 | 877 | for (;;) { 878 | switch (c = rzfile()) { 879 | case ZEOF: 880 | case ZSKIP: 881 | switch (tryz()) { 882 | case ZCOMPL: 883 | return OK; 884 | default: 885 | return ERROR; 886 | case ZFILE: 887 | break; 888 | } 889 | continue; 890 | default: 891 | return c; 892 | case ERROR: 893 | return ERROR; 894 | } 895 | } 896 | } 897 | 898 | /* 899 | * Receive a file with ZMODEM protocol 900 | * Assumes file name frame is in secbuf 901 | */ 902 | int rzfile(void) 903 | { 904 | int c, n; 905 | // long rxbytes; 906 | 907 | Eofseen=FALSE; 908 | if (procheader(secbuf) == ERROR) { 909 | return (tryzhdrtype = ZSKIP); 910 | } 911 | 912 | n = 20; 913 | // rxbytes = 0l; 914 | 915 | for (;;) { 916 | #ifdef SEGMENTS 917 | chinseg = 0; 918 | #endif 919 | stohdr(rxbytes); 920 | zshhdr(ZRPOS, Txhdr); 921 | nxthdr: 922 | switch (c = zgethdr(Rxhdr, 0)) { 923 | default: 924 | vfile(F("rzfile: zgethdr returned %d"), c); 925 | return ERROR; 926 | case ZNAK: 927 | case TIMEOUT: 928 | #ifdef SEGMENTS 929 | putsec(secbuf, chinseg); 930 | chinseg = 0; 931 | #endif 932 | if ( --n < 0) { 933 | vfile(F("rzfile: zgethdr returned %d"), c); 934 | return ERROR; 935 | } 936 | case ZFILE: 937 | zrdata(secbuf, SECBUF_LEN); 938 | continue; 939 | case ZEOF: 940 | #ifdef SEGMENTS 941 | putsec(secbuf, chinseg); 942 | chinseg = 0; 943 | #endif 944 | if (rclhdr(Rxhdr) != rxbytes) { 945 | /* 946 | * Ignore eof if it's at wrong place - force 947 | * a timeout because the eof might have gone 948 | * out before we sent our zrpos. 949 | */ 950 | errors = 0; 951 | goto nxthdr; 952 | } 953 | if (closeit()) { 954 | tryzhdrtype = ZFERR; 955 | vfile(F("rzfile: closeit returned <> 0")); 956 | return ERROR; 957 | } 958 | vfile(F("rzfile: normal EOF")); 959 | return c; 960 | case ERROR: /* Too much garbage in header search error */ 961 | #ifdef SEGMENTS 962 | putsec(secbuf, chinseg); 963 | chinseg = 0; 964 | #endif 965 | if ( --n < 0) { 966 | vfile(F("rzfile: zgethdr returned %d"), c); 967 | return ERROR; 968 | } 969 | zmputs(Attn); 970 | continue; 971 | case ZSKIP: 972 | #ifdef SEGMENTS 973 | putsec(secbuf, chinseg); 974 | chinseg = 0; 975 | #endif 976 | closeit(); 977 | vfile(F("rzfile: Sender SKIPPED file")); 978 | return c; 979 | case ZDATA: 980 | if (rclhdr(Rxhdr) != rxbytes) { 981 | if ( --n < 0) { 982 | return ERROR; 983 | } 984 | #ifdef SEGMENTS 985 | putsec(secbuf, chinseg); 986 | chinseg = 0; 987 | #endif 988 | zmputs(Attn); 989 | continue; 990 | } 991 | moredata: 992 | if (Verbose>1) 993 | fprintf(stderr, "\r%7ld ZMODEM%s ", 994 | rxbytes, Crc32?" CRC-32":""); 995 | #ifdef SEGMENTS 996 | if (chinseg >= (1024 * SEGMENTS)) { 997 | putsec(secbuf, chinseg); 998 | chinseg = 0; 999 | } 1000 | switch (c = zrdata(secbuf+chinseg, 1024)) 1001 | #else 1002 | switch (c = zrdata(secbuf, SECBUF_LEN)) 1003 | #endif 1004 | { 1005 | case ZCAN: 1006 | #ifdef SEGMENTS 1007 | putsec(secbuf, chinseg); 1008 | chinseg = 0; 1009 | #endif 1010 | vfile(F("rzfile: zgethdr returned %d"), c); 1011 | return ERROR; 1012 | case ERROR: /* CRC error */ 1013 | #ifdef SEGMENTS 1014 | putsec(secbuf, chinseg); 1015 | chinseg = 0; 1016 | #endif 1017 | if ( --n < 0) { 1018 | vfile(F("rzfile: zgethdr returned %d"), c); 1019 | return ERROR; 1020 | } 1021 | zmputs(Attn); 1022 | continue; 1023 | case TIMEOUT: 1024 | #ifdef SEGMENTS 1025 | putsec(secbuf, chinseg); 1026 | chinseg = 0; 1027 | #endif 1028 | if ( --n < 0) { 1029 | vfile(F("rzfile: zgethdr returned %d"), c); 1030 | return ERROR; 1031 | } 1032 | continue; 1033 | case GOTCRCW: 1034 | n = 20; 1035 | #ifdef SEGMENTS 1036 | chinseg += Rxcount; 1037 | putsec(secbuf, chinseg); 1038 | chinseg = 0; 1039 | #else 1040 | putsec(secbuf, Rxcount); 1041 | #endif 1042 | rxbytes += Rxcount; 1043 | stohdr(rxbytes); 1044 | zshhdr(ZACK, Txhdr); 1045 | sendline(XON); 1046 | goto nxthdr; 1047 | case GOTCRCQ: 1048 | n = 20; 1049 | #ifdef SEGMENTS 1050 | chinseg += Rxcount; 1051 | #else 1052 | putsec(secbuf, Rxcount); 1053 | #endif 1054 | rxbytes += Rxcount; 1055 | stohdr(rxbytes); 1056 | zshhdr(ZACK, Txhdr); 1057 | goto moredata; 1058 | case GOTCRCG: 1059 | n = 20; 1060 | #ifdef SEGMENTS 1061 | chinseg += Rxcount; 1062 | #else 1063 | putsec(secbuf, Rxcount); 1064 | #endif 1065 | rxbytes += Rxcount; 1066 | goto moredata; 1067 | case GOTCRCE: 1068 | n = 20; 1069 | #ifdef SEGMENTS 1070 | chinseg += Rxcount; 1071 | #else 1072 | putsec(secbuf, Rxcount); 1073 | #endif 1074 | rxbytes += Rxcount; 1075 | goto nxthdr; 1076 | } 1077 | } 1078 | } 1079 | } 1080 | 1081 | /* 1082 | * Send a string to the modem, processing for \336 (sleep 1 sec) 1083 | * and \335 (break signal) 1084 | */ 1085 | void zmputs(char *s) 1086 | { 1087 | int c; 1088 | 1089 | while (*s) { 1090 | switch (c = *s++) { 1091 | case '\336': 1092 | #ifndef ARDUINO 1093 | sleep(1); 1094 | #else 1095 | delay(1000); 1096 | #endif 1097 | continue; 1098 | case '\335': 1099 | sendbrk(); 1100 | continue; 1101 | default: 1102 | sendline(c); 1103 | } 1104 | } 1105 | } 1106 | 1107 | /* 1108 | * Close the receive dataset, return OK or ERROR 1109 | */ 1110 | 1111 | int closeit(void) 1112 | { 1113 | fout.sync(); 1114 | fout.close(); 1115 | 1116 | return OK; 1117 | } 1118 | 1119 | /* 1120 | * Ack a ZFIN packet, let byegones be byegones 1121 | */ 1122 | void ackbibi(void) 1123 | { 1124 | int n; 1125 | 1126 | vfile(F("ackbibi:")); 1127 | //Readnum = 1; 1128 | stohdr(0L); 1129 | for (n=3; --n>=0; ) { 1130 | purgeline(); 1131 | zshhdr(ZFIN, Txhdr); 1132 | switch (readline(100)) { 1133 | case 'O': 1134 | readline(1); /* Discard 2nd 'O' */ 1135 | vfile(F("ackbibi complete")); 1136 | return; 1137 | case RCDO: 1138 | return; 1139 | case TIMEOUT: 1140 | default: 1141 | break; 1142 | } 1143 | } 1144 | } 1145 | 1146 | /* End of rz.c */ 1147 | 1148 | 1149 | 1150 | 1151 | #endif 1152 | -------------------------------------------------------------------------------- /zmodem/zmodem_sz.cpp: -------------------------------------------------------------------------------- 1 | /*% cc -compat -M2 -Ox -K -i -DTXBSIZE=16384 -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz 2 | 3 | Following is used for testing, might not be reasonable for production 4 | <-xtx-*> cc -Osal -DTXBSIZE=32768 -DSV sz.c -lx -o $B/sz; size $B/sz 5 | 6 | **************************************************************************** 7 | * 8 | * sz.c By Chuck Forsberg, Omen Technology INC 9 | * 10 | **************************************************************************** 11 | * 12 | * Typical Unix/Xenix/Clone compiles: 13 | * 14 | * cc -O sz.c -o sz USG (SYS III/V) Unix 15 | * cc -O -DSV sz.c -o sz Sys V Release 2 with non-blocking input 16 | * Define to allow reverse channel checking 17 | * cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD 18 | * 19 | * cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz Classic Xenix 20 | * 21 | * ln sz sb **** All versions **** 22 | * ln sz sx **** All versions **** 23 | * 24 | **************************************************************************** 25 | * 26 | * Typical VMS compile and install sequence: 27 | * 28 | * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB 29 | * cc sz.c 30 | * cc vvmodem.c 31 | * link sz,vvmodem 32 | * sz :== $disk$user2:[username.subdir]sz.exe 33 | * 34 | * If you feel adventureous, remove the #define BADSYNC line 35 | * immediately following the #ifdef vax11c line! Some VMS 36 | * systems know how to fseek, some don't. 37 | * 38 | **************************************************************************** 39 | * 40 | * 41 | * A program for Unix to send files and commands to computers running 42 | * Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM. 43 | * 44 | * Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM. 45 | * 46 | * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin 47 | * 48 | * 2.1x hacks to avoid VMS fseek() bogosity, allow input from pipe 49 | * -DBADSEEK -DTXBSIZE=32768 50 | * 2.x has mods for VMS flavor 51 | * 52 | * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS 53 | * in accordance with the 7-31-87 ZMODEM Protocol Description 54 | */ 55 | 56 | #include "zmodem_config.h" 57 | #include "zmodem_fixes.h" 58 | 59 | #ifdef ARDUINO_SMALL_MEMORY_INCLUDE_SZ 60 | 61 | #define xsendline(c) sendline(c) 62 | 63 | #include "zmodem.h" 64 | #include "zmodem_zm.h" 65 | #include "zmodem_crc16.cpp" 66 | 67 | #include 68 | 69 | #define PATHLEN 64 70 | 71 | #define HOWMANY 2 72 | 73 | #define Txwindow 0 /* Control the size of the transmitted window */ 74 | #define Txwspac 0 /* Spacing between zcrcq requests */ 75 | unsigned Txwcnt; /* Counter used to space ack requests */ 76 | #define Lrxpos rxbytes 77 | extern long Lrxpos; /* Receiver's last reported offset */ 78 | 79 | int Filesleft = 0; 80 | long Totalleft = 0L; 81 | 82 | /* 83 | * Attention string to be executed by receiver to interrupt streaming data 84 | * when an error is detected. A pause (0336) may be needed before the 85 | * ^C (03) or after it. 86 | */ 87 | #ifdef READCHECK 88 | char Myattn[] = { 89 | 0 }; 90 | #else 91 | #ifdef USG 92 | char Myattn[] = { 93 | 03, 0336, 0 }; 94 | #else 95 | char Myattn[] = { 96 | 0 }; 97 | #endif 98 | #endif 99 | 100 | //FILE *in; 101 | 102 | #ifdef BADSEEK 103 | #define Canseek 0 /* 1: Can seek 0: only rewind -1: neither (pipe) */ 104 | #ifndef TXBSIZE 105 | #define TXBSIZE 16384 /* Must be power of two, < MAXINT */ 106 | #endif 107 | #else 108 | #define Canseek 1 /* 1: Can seek 0: only rewind -1: neither (pipe) */ 109 | #endif 110 | 111 | #ifdef TXBSIZE 112 | #define TXBMASK (TXBSIZE-1) 113 | #define Txb oneKbuf /* Circular buffer for file reads */ 114 | #define txbuf Txb /* Pointer to current file segment */ 115 | // Force the user to specify a buffer size 116 | //#else 117 | //char txbuf[1024]; 118 | #endif 119 | 120 | //long vpos = 0; /* Number of bytes read from file */ 121 | 122 | #define Modem2 0 /* XMODEM Protocol - don't send pathnames */ 123 | 124 | #define Ascii 0 /* Add CR's for brain damaged programs */ 125 | #define Fullname 0 /* transmit full pathname */ 126 | #define Unlinkafter 0 /* Unlink file after it is sent */ 127 | #define Dottoslash 0 /* Change foo.bar.baz to foo/bar/baz */ 128 | 129 | int errcnt=0; /* number of files unreadable */ 130 | #define blklen Blklen 131 | extern int blklen; /* length of transmitted records */ 132 | #define Optiong 0 /* Let it rip no wait for sector ACK's */ 133 | 134 | int Totsecs; /* total number of sectors this file */ 135 | //int Filcnt=0; /* count of number of files opened */ 136 | uint8_t Lfseen=0; 137 | #define Rxbuflen 16384 /* Receiver's max buffer length */ 138 | int Tframlen = 0; /* Override for tx frame length */ 139 | #define blkopt 0 /* Override value for zmodem blklen */ 140 | //int Rxflags = 0; 141 | #define bytcnt Bytesleft 142 | extern long bytcnt; 143 | //int Wantfcs32 = TRUE; /* want to send 32 bit FCS */ 144 | #define Lzconv 0 /* Local ZMODEM file conversion request */ 145 | 146 | #define Lskipnocor 0 147 | #define Lztrans 0 148 | 149 | //int Command; /* Send a command, then exit. */ 150 | //char *Cmdstr; /* Pointer to the command string */ 151 | //int Cmdtries = 11; 152 | //int Cmdack1; /* Rx ACKs command, then do it */ 153 | //int Exitcode = 0; 154 | #define Test 0 /* 1= Force receiver to send Attn, etc with qbf. */ 155 | /* 2= Character transparency test */ 156 | 157 | //char qbf[] = "The quick brown fox jumped over the lazy dog's back 1234567890\r\n"; 158 | 159 | long Lastsync; /* Last offset to which we got a ZRPOS */ 160 | uint8_t Beenhereb4; /* How many times we've been ZRPOS'd same place */ 161 | 162 | // Pete (El Supremo) 163 | _PROTOTYPE(int wcs , (const char *oname )); 164 | _PROTOTYPE(int wctxpn , (const char *name)); 165 | 166 | _PROTOTYPE(int wctx , (long flen )); 167 | _PROTOTYPE(int wcputsec , (char *buf , int sectnum , int cseclen )); 168 | _PROTOTYPE(int filbuf , (char *buf , int count )); 169 | _PROTOTYPE(int zfilbuf , (void)); 170 | _PROTOTYPE(void flushmo , (void)); 171 | _PROTOTYPE(void purgeline , (void)); 172 | _PROTOTYPE(void canit , (void)); 173 | 174 | //void zperr(); 175 | #define zperr(a, ... ) 176 | 177 | _PROTOTYPE(int sendzsinit , (void)); 178 | _PROTOTYPE(int zsendfile , (char *buf , int blen )); 179 | _PROTOTYPE(int zsendfdata , (void)); 180 | _PROTOTYPE(int getinsync , (int flag )); 181 | _PROTOTYPE(void saybibi , (void)); 182 | //_PROTOTYPE(void bttyout , (int c )); 183 | _PROTOTYPE(int zsendcmd , (char *buf , int blen )); 184 | 185 | 186 | #ifndef ARDUINO 187 | FILE *fout; 188 | #else 189 | extern SdFile fout; 190 | #endif 191 | 192 | int wcs(const char *oname) 193 | { 194 | // char name[PATHLEN]; 195 | 196 | // strcpy(name, oname); 197 | 198 | Eofseen = 0; 199 | // vpos = 0; 200 | 201 | switch (wctxpn(oname)) { 202 | case ERROR: 203 | return ERROR; 204 | case ZSKIP: 205 | return OK; 206 | } 207 | 208 | // ++Filcnt; 209 | if(!Zmodem && wctx(fout.fileSize())==ERROR) 210 | return ERROR; 211 | return 0; 212 | } 213 | 214 | 215 | /* 216 | * generate and transmit pathname block consisting of 217 | * pathname (null terminated), 218 | * file length, mode time and file mode in octal 219 | * as provided by the Unix fstat call. 220 | * N.B.: modifies the passed name, may extend it! 221 | */ 222 | int wctxpn(const char *name) 223 | { 224 | 225 | char *p, *q; 226 | 227 | //DSERIAL.println("\nwctxpn"); 228 | 229 | strcpy(txbuf,name); 230 | p = q = txbuf + strlen(txbuf)+1; 231 | //Pete (El Supremo) fix bug - was 1024, should be TXBSIZE?? 232 | while (q < (txbuf + TXBSIZE)) 233 | *q++ = 0; 234 | // if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1) 235 | if (!Ascii) 236 | // I will have to figure out how to convert the uSD date/time format to a UNIX epoch 237 | // sprintf(p, "%lu %lo %o 0 %d %ld", fout.fileSize(), 0L,0600, Filesleft, Totalleft); 238 | // Avoid sprintf to save memory for small boards. This sketch doesn't know what time it is anyway 239 | ultoa(fout.fileSize(), p, 10); 240 | strcat_P(p, PSTR(" 0 0 0 ")); 241 | q = p + strlen(p); 242 | ultoa(Filesleft, q, 10); 243 | strcat_P(q, PSTR(" ")); 244 | q = q + strlen(q); 245 | ultoa(Totalleft, q, 10); 246 | 247 | Totalleft -= fout.fileSize(); 248 | //DSERIAL.print(F("wctxpn sf = ")); 249 | //DSERIAL.print(sf); 250 | //DSERIAL.print(F(" length = ")); 251 | //DSERIAL.println(Totalleft); 252 | if (--Filesleft <= 0) 253 | Totalleft = 0; 254 | if (Totalleft < 0) 255 | Totalleft = 0; 256 | 257 | /* force 1k blocks if name won't fit in 128 byte block */ 258 | //Pete (El Supremo) This can't be right??! 259 | if (txbuf[125]) 260 | // blklen=1024; 261 | blklen = TXBSIZE; 262 | else { /* A little goodie for IMP/KMD */ 263 | blklen = 128; 264 | txbuf[127] = (fout.fileSize() + 127) >>7; 265 | txbuf[126] = (fout.fileSize() + 127) >>15; 266 | } 267 | return zsendfile(txbuf, 1+strlen(p)+(p-txbuf)); 268 | } 269 | 270 | 271 | int wctx(long flen) 272 | { 273 | int thisblklen; 274 | int sectnum, attempts, firstch; 275 | long charssent; 276 | 277 | //DSERIAL.println("\nwctx"); 278 | 279 | charssent = 0; 280 | firstsec=TRUE; 281 | thisblklen = blklen; 282 | vfile(F("wctx:file length=%ld"), flen); 283 | 284 | while ((firstch=readline(Rxtimeout))!=NAK && firstch != WANTCRC 285 | && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN) 286 | ; 287 | if (firstch==CAN) { 288 | zperr("Receiver CANcelled"); 289 | return ERROR; 290 | } 291 | if (firstch==WANTCRC) 292 | Crcflg=TRUE; 293 | if (firstch==WANTG) 294 | Crcflg=TRUE; 295 | sectnum=0; 296 | for (;;) { 297 | if (flen <= (charssent + 896L)) 298 | thisblklen = 128; 299 | if ( !filbuf(txbuf, thisblklen)) 300 | break; 301 | if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR) 302 | return ERROR; 303 | charssent += thisblklen; 304 | } 305 | //fclose(in); 306 | fout.close(); 307 | attempts=0; 308 | do { 309 | purgeline(); 310 | sendline(EOT); 311 | //fflush(stdout); 312 | ++attempts; 313 | } 314 | while ((firstch=(readline(Rxtimeout)) != ACK) && attempts < Tx_RETRYMAX); 315 | if (attempts == Tx_RETRYMAX) { 316 | zperr("No ACK on EOT"); 317 | return ERROR; 318 | } 319 | else 320 | return OK; 321 | } 322 | 323 | 324 | 325 | int wcputsec(char *buf,int sectnum,int cseclen) 326 | { 327 | int checksum, wcj; 328 | char *cp; 329 | unsigned oldcrc; 330 | int firstch; 331 | uint8_t attempts; 332 | 333 | firstch=0; /* part of logic to detect CAN CAN */ 334 | 335 | if (Verbose>2) 336 | fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 ); 337 | else if (Verbose>1) 338 | fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 ); 339 | for (attempts=0; attempts <= Tx_RETRYMAX; attempts++) { 340 | Lastrx= firstch; 341 | sendline(cseclen==1024?STX:SOH); 342 | sendline(sectnum); 343 | sendline(-sectnum -1); 344 | oldcrc=checksum=0; 345 | for (wcj=cseclen,cp=buf; --wcj>=0; ) { 346 | sendline(*cp); 347 | oldcrc=updcrc((0377& *cp), oldcrc); 348 | checksum += *cp++; 349 | } 350 | if (Crcflg) { 351 | oldcrc=updcrc(0,updcrc(0,oldcrc)); 352 | sendline((int)oldcrc>>8); 353 | sendline((int)oldcrc); 354 | } 355 | else 356 | sendline(checksum); 357 | 358 | if (Optiong) { 359 | firstsec = FALSE; 360 | return OK; 361 | } 362 | firstch = readline(Rxtimeout); 363 | gotnak: 364 | switch (firstch) { 365 | case CAN: 366 | if(Lastrx == CAN) { 367 | cancan: 368 | zperr("Cancelled"); 369 | return ERROR; 370 | } 371 | break; 372 | case TIMEOUT: 373 | zperr("Timeout on sector ACK"); 374 | continue; 375 | case WANTCRC: 376 | if (firstsec) 377 | Crcflg = TRUE; 378 | case NAK: 379 | zperr("NAK on sector"); 380 | continue; 381 | case ACK: 382 | firstsec=FALSE; 383 | Totsecs += (cseclen>>7); 384 | return OK; 385 | case ERROR: 386 | zperr("Got burst for sector ACK"); 387 | break; 388 | default: 389 | zperr("Got %02x for sector ACK", firstch); 390 | break; 391 | } 392 | for (;;) { 393 | Lastrx = firstch; 394 | if ((firstch = readline(Rxtimeout)) == TIMEOUT) 395 | break; 396 | if (firstch == NAK || firstch == WANTCRC) 397 | goto gotnak; 398 | if (firstch == CAN && Lastrx == CAN) 399 | goto cancan; 400 | } 401 | } 402 | zperr("Retry Count Exceeded"); 403 | return ERROR; 404 | } 405 | 406 | 407 | 408 | /* fill buf with count chars padding with ^Z for CPM */ 409 | int filbuf(char *buf,int count) 410 | { 411 | int c, m; 412 | 413 | //DSERIAL.println("\nfilbuf"); 414 | 415 | if ( !Ascii) { 416 | // m = read(fileno(in), buf, count); 417 | m = fout.read(buf, count); 418 | //DSERIAL.println(F("filbuf: '")); 419 | //for(int i=0;i=0) 452 | *buf++ = CPMEOF; 453 | return count; 454 | } 455 | 456 | 457 | 458 | /* Fill buffer with blklen chars */ 459 | int zfilbuf(void) 460 | { 461 | int n; 462 | 463 | // This code works: 464 | // n = fread(txbuf, 1, blklen, in); 465 | n = fout.read(txbuf,blklen); 466 | 467 | if (n < blklen) 468 | Eofseen = 1; 469 | return n; 470 | } 471 | 472 | /* Send file name and related info */ 473 | int zsendfile(char *buf, int blen) 474 | { 475 | int c; 476 | UNSL long crc; 477 | 478 | //DSERIAL.println(F("\nzsendfile")); 479 | 480 | for (;;) { 481 | Txhdr[ZF0] = Lzconv; /* file conversion request */ 482 | Txhdr[ZF1] = Lzmanag; /* file management request */ 483 | if (Lskipnocor) 484 | Txhdr[ZF1] |= ZMSKNOLOC; 485 | Txhdr[ZF2] = Lztrans; /* file transport request */ 486 | Txhdr[ZF3] = 0; 487 | zsbhdr(ZFILE, Txhdr); 488 | zsdata(buf, blen, ZCRCW); 489 | again: 490 | c = zgethdr(Rxhdr, 1); 491 | switch (c) { 492 | case ZRINIT: 493 | while ((c = readline(50)) > 0) 494 | if (c == ZPAD) { 495 | goto again; 496 | } 497 | /* **** FALL THRU TO **** */ 498 | default: 499 | continue; 500 | case ZCAN: 501 | case TIMEOUT: 502 | case ZABORT: 503 | case ZFIN: 504 | //DSERIAL.println(F("\nzsendfile - ZFIN")); 505 | 506 | return ERROR; 507 | case ZCRC: 508 | crc = 0xFFFFFFFFL; 509 | if (Canseek >= 0) { 510 | fout.seekSet(0); 511 | while (((c = fout.read()) != -1)) // && --Rxpos) 512 | crc = UPDC32(c, crc); 513 | crc = ~crc; 514 | // clearerr(in); /* Clear EOF */ 515 | //>>> Need to implement the seek 516 | // fseek(in, 0L, 0); 517 | fout.seekSet(0); 518 | } 519 | stohdr(crc); 520 | zsbhdr(ZCRC, Txhdr); 521 | goto again; 522 | case ZSKIP: 523 | fout.close(); 524 | //fclose(in); 525 | //DSERIAL.println(F("\nzsendfile - ZSKIP")); 526 | return c; 527 | case ZRPOS: 528 | /* 529 | * Suppress zcrcw request otherwise triggered by 530 | * lastyunc==bytcnt 531 | */ 532 | //>>> Need to implement the seek 533 | // if (Rxpos && fseek(in, Rxpos, 0)) 534 | if(Rxpos && !fout.seekSet(Rxpos)) 535 | return ERROR; 536 | Lastsync = (bytcnt = Txpos = Rxpos) -1; 537 | int ret = zsendfdata(); 538 | //DSERIAL.print(F("\nzsendfile - exit - ")); 539 | //DSERIAL.println(ret); 540 | return(ret); 541 | } 542 | } 543 | } 544 | 545 | 546 | 547 | /* Send the data in the file */ 548 | int zsendfdata(void) 549 | { 550 | int c, n; 551 | uint8_t e; 552 | int newcnt; 553 | uint8_t junkcount; /* Counts garbage chars received by TX */ 554 | 555 | //DSERIAL.print(F("\nzsendfdata: ")); 556 | //DSERIAL.print(F("number = ")); 557 | //DSERIAL.print(Filesleft+1); 558 | //DSERIAL.print(F(" length = ")); 559 | //DSERIAL.println(Totalleft); 560 | Lrxpos = 0; 561 | junkcount = 0; 562 | Beenhereb4 = FALSE; 563 | somemore: 564 | //if (setjmp(intrjmp)) { 565 | if (0) { 566 | waitack: 567 | junkcount = 0; 568 | c = getinsync(0); 569 | gotack: 570 | switch (c) { 571 | default: 572 | case ZCAN: 573 | fout.close(); 574 | //fclose(in); 575 | //DSERIAL.println(F("zsendfdata - error - 1")); 576 | return ERROR; 577 | case ZSKIP: 578 | fout.close(); 579 | //fclose(in); 580 | return c; 581 | case ZACK: 582 | case ZRPOS: 583 | break; 584 | case ZRINIT: 585 | return OK; 586 | } 587 | #ifdef READCHECK 588 | /* 589 | * If the reverse channel can be tested for data, 590 | * this logic may be used to detect error packets 591 | * sent by the receiver, in place of setjmp/longjmp 592 | * rdchk(fdes) returns non 0 if a character is available 593 | */ 594 | while (ZSERIAL.available()) { 595 | #ifdef SV 596 | switch (checked) 597 | #else 598 | switch (readline(1)) 599 | #endif 600 | { 601 | case CAN: 602 | case ZPAD: 603 | c = getinsync(1); 604 | goto gotack; 605 | case XOFF: /* Wait a while for an XON */ 606 | case XOFF|0200: 607 | readline(100); 608 | } 609 | } 610 | #endif 611 | } 612 | 613 | //DSERIAL.println("zsendfdata - 1"); 614 | 615 | // if ( !Fromcu) 616 | // signal(SIGINT, onintr); 617 | newcnt = Rxbuflen; 618 | Txwcnt = 0; 619 | stohdr(Txpos); 620 | zsbhdr(ZDATA, Txhdr); 621 | 622 | //DSERIAL.println("zsendfdata - 2"); 623 | 624 | do { 625 | n = zfilbuf(); 626 | // AHA - it reads the 18 chars here 627 | //DSERIAL.println(n); 628 | if (Eofseen) 629 | e = ZCRCE; 630 | else if (junkcount > 3) 631 | e = ZCRCW; 632 | else if (bytcnt == Lastsync) 633 | e = ZCRCW; 634 | else if (Rxbuflen && (newcnt -= n) <= 0) 635 | e = ZCRCW; 636 | else if (Txwindow && (Txwcnt += n) >= Txwspac) { 637 | Txwcnt = 0; 638 | e = ZCRCQ; 639 | } 640 | else 641 | e = ZCRCG; 642 | if (Verbose>1) 643 | fprintf(stderr, "\r%7ld ZMODEM%s ",Txpos, Crc32t?" CRC-32":""); 644 | zsdata(txbuf, n, e); 645 | bytcnt = Txpos += n; 646 | if (e == ZCRCW) 647 | goto waitack; 648 | #ifdef READCHECK 649 | /* 650 | * If the reverse channel can be tested for data, 651 | * this logic may be used to detect error packets 652 | * sent by the receiver, in place of setjmp/longjmp 653 | * rdchk(fdes) returns non 0 if a character is available 654 | */ 655 | // fflush(stdout); 656 | while (ZSERIAL.available()) { 657 | #ifdef SV 658 | switch (checked) 659 | #else 660 | switch (readline(1)) 661 | #endif 662 | { 663 | case CAN: 664 | case ZPAD: 665 | c = getinsync(1); 666 | if (c == ZACK) 667 | break; 668 | #ifdef TCFLSH 669 | ioctl(iofd, TCFLSH, 1); 670 | #endif 671 | /* zcrce - dinna wanna starta ping-pong game */ 672 | zsdata(txbuf, 0, ZCRCE); 673 | goto gotack; 674 | case XOFF: /* Wait a while for an XON */ 675 | case XOFF|0200: 676 | readline(100); 677 | default: 678 | ++junkcount; 679 | } 680 | } 681 | #endif /* READCHECK */ 682 | 683 | } while (!Eofseen); 684 | 685 | //DSERIAL.println("zsendfdata - 4"); 686 | 687 | // if ( !Fromcu) 688 | // signal(SIGINT, SIG_IGN); 689 | 690 | for (;;) { 691 | stohdr(Txpos); 692 | zsbhdr(ZEOF, Txhdr); 693 | switch (getinsync(0)) { 694 | case ZACK: 695 | //DSERIAL.println(F("zsendfdata - ZAK")); 696 | continue; 697 | case ZRPOS: 698 | //DSERIAL.println(F("zsendfdata - ZRPOS")); 699 | goto somemore; 700 | case ZRINIT: 701 | //DSERIAL.println(F("zsendfdata - OK")); 702 | return OK; 703 | case ZSKIP: 704 | fout.close(); 705 | //fclose(in); 706 | //DSERIAL.println(F("zsendfdata - ZSKIP")); 707 | return c; 708 | default: 709 | fout.close(); 710 | //fclose(in); 711 | //DSERIAL.println(F("zsendfdata - error - 2")); 712 | return ERROR; 713 | } 714 | } 715 | } 716 | 717 | 718 | 719 | 720 | /* 721 | * Respond to receiver's complaint, get back in sync with receiver 722 | */ 723 | int getinsync(int flag) 724 | { 725 | int c; 726 | 727 | for (;;) { 728 | if (Test) { 729 | //DSERIAL.println(F("***** Signal Caught *****")); 730 | Rxpos = 0; 731 | c = ZRPOS; 732 | } 733 | else 734 | c = zgethdr(Rxhdr, 0); 735 | switch (c) { 736 | case ZCAN: 737 | case ZABORT: 738 | case ZFIN: 739 | case TIMEOUT: 740 | //DSERIAL.println(F("getinsync - timeout")); 741 | return ERROR; 742 | case ZRPOS: 743 | /* ************************************* */ 744 | /* If sending to a buffered modem, you */ 745 | /* might send a break at this point to */ 746 | /* dump the modem's buffer. */ 747 | // clearerr(in); /* In case file EOF seen */ 748 | // if (fseek(in, Rxpos, 0)) { 749 | // seekSet returns true on success 750 | if(!fout.seekSet(Rxpos)) { 751 | //DSERIAL.println(F("getinsync - fseek")); 752 | return ERROR; 753 | } 754 | Eofseen = 0; 755 | bytcnt = Lrxpos = Txpos = Rxpos; 756 | if (Lastsync == Rxpos) { 757 | if (++Beenhereb4 > 4) 758 | if (blklen > 32) 759 | blklen /= 2; 760 | } 761 | Lastsync = Rxpos; 762 | return c; 763 | case ZACK: 764 | Lrxpos = Rxpos; 765 | if (flag || Txpos == Rxpos) 766 | return ZACK; 767 | continue; 768 | case ZRINIT: 769 | case ZSKIP: 770 | fout.close(); 771 | //fclose(in); 772 | return c; 773 | case ERROR: 774 | default: 775 | zsbhdr(ZNAK, Txhdr); 776 | continue; 777 | } 778 | } 779 | } 780 | 781 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - I added this simple ZRQINIT string to trigger 782 | // terminal program's receive auto start feature. This was missing in the code as I found it. 783 | // All the terminal applications I tried would receive files anyway if I manually started 784 | // the download, but sending the ZRQINIT is the right way to initiate a ZMODEM transfer 785 | // according to the protocol documentation. 786 | 787 | #define ZRQINIT_STR F("\x2a\x2a\x18\x42" \ 788 | "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30" \ 789 | "\x0d\x0a\x11") 790 | 791 | void sendzrqinit(void) 792 | { 793 | ZSERIAL.print(ZRQINIT_STR); 794 | } 795 | 796 | /* Say "bibi" to the receiver, try to do it cleanly */ 797 | void saybibi(void) 798 | { 799 | for (;;) { 800 | stohdr(0L); /* CAF Was zsbhdr - minor change */ 801 | zshhdr(ZFIN, Txhdr); /* to make debugging easier */ 802 | switch (zgethdr(Rxhdr, 0)) { 803 | case ZFIN: 804 | sendline('O'); 805 | sendline('O'); 806 | flushmo(); 807 | case ZCAN: 808 | case TIMEOUT: 809 | return; 810 | } 811 | } 812 | } 813 | 814 | #endif 815 | 816 | /* End of sz.c */ 817 | -------------------------------------------------------------------------------- /zmodem/zmodem_zm.cpp: -------------------------------------------------------------------------------- 1 | // See this page for all code: http://www.raspberryginger.com/jbailey/minix/html/dir_acf1a49c3b8ff2cb9205e4a19757c0d6.html 2 | // From: http://www.raspberryginger.com/jbailey/minix/html/zm_8c-source.html 3 | // docs at: http://www.raspberryginger.com/jbailey/minix/html/zm_8c.html 4 | 5 | // Look at all the files: 6 | // http://www.raspberryginger.com/jbailey/minix/html/files.html 7 | 8 | #ifndef ZMODEM_ZM_CPP 9 | #define ZMODEM_ZM_CPP 10 | 11 | /* 12 | * Z M . C 13 | * ZMODEM protocol primitives 14 | * 05-09-88 Chuck Forsberg Omen Technology Inc 15 | * 16 | * Entry point Functions: 17 | * zsbhdr(type, hdr) send binary header 18 | * zshhdr(type, hdr) send hex header 19 | * zgethdr(hdr, eflag) receive header - binary or hex 20 | * zsdata(buf, len, frameend) send data 21 | * zrdata(buf, len) receive data 22 | * stohdr(pos) store position data in Txhdr 23 | * long rclhdr(hdr) recover position offset from header 24 | */ 25 | 26 | #ifdef ARDUINO 27 | #include "zmodem_fixes.h" 28 | #include "zmodem.h" 29 | #include "zmodem_crc16.cpp" 30 | #include "zmodem_zm.h" 31 | #else 32 | #ifndef CANFDX 33 | #include "zmodem.h" 34 | #endif 35 | #endif 36 | 37 | // Shared globals 38 | long Bytesleft; // from rz - Shared with sz bytcnt 39 | long rxbytes; // from rz - Shared with sz Lrxpos 40 | int Blklen; // from rz - Shared with sz blklen 41 | 42 | #define Rxtimeout 100 /* Tenths of seconds to wait for something */ 43 | #define Verbose 0 44 | 45 | // This buffer blends Txb (from sz) and secbuf (from rz) into a single buffer, saving 1K 46 | // of memory. 47 | char oneKbuf[1025]; 48 | 49 | /* Globals used by ZMODEM functions */ 50 | uint8_t Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ 51 | uint8_t Rxtype; /* Type of header received */ 52 | int Rxcount; /* Count of data bytes received */ 53 | char Rxhdr[4]; /* Received header */ 54 | char Txhdr[4]; /* Transmitted header */ 55 | long Rxpos; /* Received file position */ 56 | long Txpos; /* Transmitted file position */ 57 | int8_t Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ 58 | int8_t Crc32t; /* Display flag indicating 32 bit CRC being sent */ 59 | int8_t Crc32; /* Display flag indicating 32 bit CRC being received */ 60 | //int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ 61 | char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ 62 | 63 | char zconv; /* ZMODEM file conversion request */ 64 | char zmanag; /* ZMODEM file management request */ 65 | char ztrans; /* ZMODEM file transport request */ 66 | uint8_t Zctlesc; /* Encode control characters */ 67 | #define Zrwindow 1400 /* RX window size (controls garbage count) */ 68 | //int Nozmodem = 0; /* If invoked as "rb" */ 69 | int lastsent; /* Last char we sent */ 70 | uint8_t Not8bit; /* Seven bits seen on header */ 71 | //char Lzmanag; /* Local ZMODEM file management request */ 72 | //int Restricted = 0; /* restricted; no /.. or ../ in filenames */ 73 | //int Quiet=0; /* overrides logic that would otherwise set verbose */ 74 | uint8_t Eofseen; /* EOF seen on input set by zfilbuf */ 75 | 76 | 77 | uint8_t firstsec; 78 | char Lastrx; 79 | char Crcflg; 80 | uint8_t errors; 81 | 82 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Removing this for release to save 83 | // memory, only used for debugging 84 | /* 85 | char *frametypes[] = { 86 | (char *)"Carrier Lost", // -3 87 | (char *)"TIMEOUT", // -2 88 | (char *)"ERROR", // -1 89 | #define FTOFFSET 3 90 | (char *)"ZRQINIT", 91 | (char *)"ZRINIT", 92 | (char *)"ZSINIT", 93 | (char *)"ZACK", 94 | (char *)"ZFILE", 95 | (char *)"ZSKIP", 96 | (char *)"ZNAK", 97 | (char *)"ZABORT", 98 | (char *)"ZFIN", 99 | (char *)"ZRPOS", 100 | (char *)"ZDATA", 101 | (char *)"ZEOF", 102 | (char *)"ZFERR", 103 | (char *)"ZCRC", 104 | (char *)"ZCHALLENGE", 105 | (char *)"ZCOMPL", 106 | (char *)"ZCAN", 107 | (char *)"ZFREECNT", 108 | (char *)"ZCOMMAND", 109 | (char *)"ZSTDERR", 110 | (char *)"xxxxx" 111 | #define FRTYPES 22 // Total number of frame types in this array 112 | // not including psuedo negative entries 113 | }; 114 | */ 115 | #define badcrc F("Bad CRC"); 116 | 117 | 118 | 119 | 120 | 121 | /* Send ZMODEM binary header hdr of type type */ 122 | void zsbhdr(int type, char *hdr) 123 | { 124 | 125 | 126 | vfile(F("zsbhdr: %s %lx"), frametypes[type+FTOFFSET], rclhdr(hdr)); 127 | /* if (type == ZDATA) 128 | for (n = Znulls; --n >=0; ) 129 | xsendline(0); 130 | */ 131 | xsendline(ZPAD); 132 | xsendline(ZDLE); 133 | //Pete (El Supremo) This looks wrong but it is correct - the code fails if == is used 134 | if ((Crc32t = Txfcs32)) { 135 | int n; 136 | UNSL long crc; 137 | 138 | xsendline(ZBIN32); 139 | zsendline(type); 140 | crc = 0xFFFFFFFFL; 141 | crc = UPDC32(type, crc); 142 | 143 | for (n=4; --n >= 0; ++hdr) { 144 | crc = UPDC32((0377 & *hdr), crc); 145 | zsendline(*hdr); 146 | } 147 | crc = ~crc; 148 | for (n=4; --n >= 0;) { 149 | zsendline((int)crc); 150 | crc >>= 8; 151 | } 152 | } else { 153 | int n; 154 | unsigned short crc; 155 | 156 | xsendline(ZBIN); 157 | zsendline(type); 158 | crc = updcrc(type, 0); 159 | 160 | for (n=4; --n >= 0; ++hdr) { 161 | zsendline(*hdr); 162 | crc = updcrc((0377& *hdr), crc); 163 | } 164 | crc = updcrc(0,updcrc(0,crc)); 165 | zsendline(crc>>8); 166 | zsendline(crc); 167 | } 168 | if (type != ZDATA) 169 | flushmo(); 170 | } 171 | 172 | 173 | /* Send ZMODEM HEX header hdr of type type */ 174 | void zshhdr(int type,char *hdr) 175 | { 176 | int n; 177 | unsigned short crc; 178 | 179 | vfile(F("zshhdr: %s %lx"), frametypes[type+FTOFFSET], rclhdr(hdr)); 180 | sendline(ZPAD); 181 | sendline(ZPAD); 182 | sendline(ZDLE); 183 | sendline(ZHEX); 184 | zputhex(type); 185 | Crc32t = 0; 186 | 187 | crc = updcrc(type, 0); 188 | for (n=4; --n >= 0; ++hdr) { 189 | zputhex(*hdr); 190 | crc = updcrc((0377 & *hdr), crc); 191 | } 192 | crc = updcrc(0,updcrc(0,crc)); 193 | zputhex(crc>>8); 194 | zputhex(crc); 195 | 196 | /* Make it printable on remote machine */ 197 | sendline(015); 198 | sendline(0212); 199 | /* 200 | * Uncork the remote in case a fake XOFF has stopped data flow 201 | */ 202 | if (type != ZFIN && type != ZACK) 203 | sendline(021); 204 | flushmo(); 205 | } 206 | 207 | 208 | /* 209 | * Send binary array buf of length length, with ending ZDLE sequence frameend 210 | */ 211 | /* 212 | static char *Zendnames[] = { 213 | (char *)"ZCRCE", 214 | (char *)"ZCRCG", 215 | (char *)"ZCRCQ", 216 | (char *)"ZCRCW" 217 | }; 218 | */ 219 | 220 | void zsdata(char *buf,int length,int frameend) 221 | { 222 | 223 | vfile(F("zsdata: %d %s"), length, Zendnames[(frameend-ZCRCE)&3]); 224 | if (Crc32t) { 225 | int c; 226 | UNSL long crc; 227 | 228 | crc = 0xFFFFFFFFL; 229 | for (;--length >= 0; ++buf) { 230 | c = *buf & 0377; 231 | if (c & 0140) 232 | xsendline(lastsent = c); 233 | else 234 | zsendline(c); 235 | crc = UPDC32(c, crc); 236 | } 237 | xsendline(ZDLE); 238 | xsendline(frameend); 239 | crc = UPDC32(frameend, crc); 240 | 241 | crc = ~crc; 242 | for (length=4; --length >= 0;) { 243 | zsendline((int)crc); 244 | crc >>= 8; 245 | } 246 | } else { 247 | unsigned short crc; 248 | 249 | crc = 0; 250 | for (;--length >= 0; ++buf) { 251 | zsendline(*buf); 252 | crc = updcrc((0377 & *buf), crc); 253 | } 254 | xsendline(ZDLE); 255 | xsendline(frameend); 256 | crc = updcrc(frameend, crc); 257 | 258 | crc = updcrc(0,updcrc(0,crc)); 259 | zsendline(crc>>8); 260 | zsendline(crc); 261 | } 262 | if (frameend == ZCRCW) { 263 | xsendline(XON); 264 | flushmo(); 265 | } 266 | } 267 | 268 | /* 269 | * Receive array buf of max length with ending ZDLE sequence 270 | * and CRC. Returns the ending character or error code. 271 | * NB: On errors may store length+1 bytes! 272 | */ 273 | int zrdata(char *buf,int length) 274 | { 275 | int c; 276 | char *end; 277 | int d; 278 | 279 | if (Rxframeind == ZBIN32) { 280 | UNSL long crc; 281 | 282 | crc = 0xFFFFFFFFL; 283 | Rxcount = 0; 284 | end = buf + length; 285 | while (buf <= end) { 286 | if ((c = zdlread()) & ~0377) { 287 | crcfoo32: 288 | switch (c) { 289 | case GOTCRCE: 290 | case GOTCRCG: 291 | case GOTCRCQ: 292 | case GOTCRCW: 293 | d = c; 294 | c &= 0377; 295 | crc = UPDC32(c, crc); 296 | if ((c = zdlread()) & ~0377) 297 | goto crcfoo32; 298 | crc = UPDC32(c, crc); 299 | if ((c = zdlread()) & ~0377) 300 | goto crcfoo32; 301 | crc = UPDC32(c, crc); 302 | if ((c = zdlread()) & ~0377) 303 | goto crcfoo32; 304 | crc = UPDC32(c, crc); 305 | if ((c = zdlread()) & ~0377) 306 | goto crcfoo32; 307 | crc = UPDC32(c, crc); 308 | if (crc != 0xDEBB20E3) { 309 | zperr(badcrc); 310 | return ERROR; 311 | } 312 | Rxcount = length - (end - buf); 313 | vfile(F("zrdat32: %d %s"), Rxcount, 314 | Zendnames[(d-GOTCRCE)&3]); 315 | return d; 316 | case GOTCAN: 317 | zperr("Sender Canceled"); 318 | return ZCAN; 319 | case TIMEOUT: 320 | zperr("TIMEOUT"); 321 | return c; 322 | default: 323 | zperr("Bad data subpacket"); 324 | return c; 325 | } 326 | } 327 | *buf++ = c; 328 | crc = UPDC32(c, crc); 329 | } 330 | zperr("Data subpacket too long"); 331 | return ERROR; 332 | } else { 333 | unsigned short crc; 334 | 335 | crc = Rxcount = 0; 336 | end = buf + length; 337 | while (buf <= end) { 338 | if ((c = zdlread()) & ~0377) { 339 | crcfoo16: 340 | switch (c) { 341 | case GOTCRCE: 342 | case GOTCRCG: 343 | case GOTCRCQ: 344 | case GOTCRCW: 345 | crc = updcrc((d=c)&0377, crc); 346 | if ((c = zdlread()) & ~0377) 347 | goto crcfoo16; 348 | crc = updcrc(c, crc); 349 | if ((c = zdlread()) & ~0377) 350 | goto crcfoo16; 351 | crc = updcrc(c, crc); 352 | if (crc & 0xFFFF) { 353 | zperr(badcrc); 354 | return ERROR; 355 | } 356 | Rxcount = length - (end - buf); 357 | vfile(F("zrdata: %d %s"), Rxcount, 358 | Zendnames[(d-GOTCRCE)&3]); 359 | return d; 360 | case GOTCAN: 361 | zperr("Sender Canceled"); 362 | return ZCAN; 363 | case TIMEOUT: 364 | zperr("TIMEOUT"); 365 | return c; 366 | default: 367 | zperr("Bad data subpacket"); 368 | return c; 369 | } 370 | } 371 | *buf++ = c; 372 | crc = updcrc(c, crc); 373 | } 374 | zperr("Data subpacket too long"); 375 | return ERROR; 376 | } 377 | } 378 | 379 | /* 380 | * Read a ZMODEM header to hdr, either binary or hex. 381 | * eflag controls local display of non zmodem characters: 382 | * 0: no display 383 | * 1: display printing characters only 384 | * 2: display all non ZMODEM characters 385 | * On success, set Zmodem to 1, set Rxpos and return type of header. 386 | * Otherwise return negative on error. 387 | * Return ERROR instantly if ZCRCW sequence, for fast error recovery. 388 | */ 389 | int zgethdr(char *hdr,int eflag) 390 | { 391 | int c, n, cancount; 392 | 393 | n = Zrwindow; //+ Baudrate; /* Max bytes before start of frame */ 394 | Rxframeind = Rxtype = 0; 395 | 396 | startover: 397 | cancount = 5; 398 | again: 399 | /* Return immediate ERROR if ZCRCW sequence seen */ 400 | ZSERIAL.setTimeout(Rxtimeout * 100); 401 | c = readline(Rxtimeout); 402 | ZSERIAL.setTimeout(TYPICAL_SERIAL_TIMEOUT); 403 | 404 | switch (c) { 405 | case RCDO: 406 | case TIMEOUT: 407 | goto fifi; 408 | case CAN: 409 | gotcan: 410 | if (--cancount <= 0) { 411 | c = ZCAN; 412 | goto fifi; 413 | } 414 | switch (c = readline(1)) { 415 | case TIMEOUT: 416 | goto again; 417 | case ZCRCW: 418 | c = ERROR; 419 | /* **** FALL THRU TO **** */ 420 | case RCDO: 421 | goto fifi; 422 | default: 423 | break; 424 | case CAN: 425 | if (--cancount <= 0) { 426 | c = ZCAN; 427 | goto fifi; 428 | } 429 | goto again; 430 | } 431 | /* **** FALL THRU TO **** */ 432 | default: 433 | agn2: 434 | if ( --n == 0) { 435 | zperr("Garbage count exceeded"); 436 | return(ERROR); 437 | } 438 | if (eflag && ((c &= 0177) & 0140)) 439 | bttyout(c); 440 | else if (eflag > 1) 441 | bttyout(c); 442 | #ifdef UNIX 443 | fflush(stderr); 444 | #endif 445 | goto startover; 446 | case ZPAD|0200: /* This is what we want. */ 447 | Not8bit = c; 448 | case ZPAD: /* This is what we want. */ 449 | break; 450 | } 451 | cancount = 5; 452 | splat: 453 | switch (c = noxrd7()) { 454 | case ZPAD: 455 | goto splat; 456 | case RCDO: 457 | case TIMEOUT: 458 | goto fifi; 459 | default: 460 | goto agn2; 461 | case ZDLE: /* This is what we want. */ 462 | break; 463 | } 464 | 465 | switch (c = noxrd7()) { 466 | case RCDO: 467 | case TIMEOUT: 468 | goto fifi; 469 | case ZBIN: 470 | Rxframeind = ZBIN; 471 | Crc32 = FALSE; 472 | c = zrbhdr(hdr); 473 | break; 474 | case ZBIN32: 475 | Crc32 = Rxframeind = ZBIN32; 476 | c = zrbhdr32(hdr); 477 | break; 478 | case ZHEX: 479 | Rxframeind = ZHEX; 480 | Crc32 = FALSE; 481 | c = zrhhdr(hdr); 482 | break; 483 | case CAN: 484 | goto gotcan; 485 | default: 486 | goto agn2; 487 | } 488 | Rxpos = hdr[ZP3] & 0377; 489 | Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377); 490 | Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377); 491 | Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377); 492 | fifi: 493 | 494 | switch (c) { 495 | case GOTCAN: 496 | c = ZCAN; 497 | /* **** FALL THRU TO **** */ 498 | case ZNAK: 499 | case ZCAN: 500 | case ERROR: 501 | case TIMEOUT: 502 | case RCDO: 503 | // zperr("Got %s", frametypes[c+FTOFFSET]); 504 | /* **** FALL THRU TO **** */ 505 | // default: 506 | // if (c >= -3 && c <= FRTYPES) 507 | // vfile(F("zgethdr: %s %lx"), frametypes[c+FTOFFSET], Rxpos); 508 | // else 509 | // vfile(F("zgethdr: %d %lx"), c, Rxpos); 510 | break; 511 | } 512 | return c; 513 | } 514 | 515 | //#endif 516 | 517 | /* Receive a binary style header (type and position) */ 518 | int zrbhdr(char *hdr) 519 | { 520 | int c, n; 521 | unsigned short crc; 522 | 523 | if ((c = zdlread()) & ~0377) 524 | return c; 525 | Rxtype = c; 526 | crc = updcrc(c, 0); 527 | 528 | for (n=4; --n >= 0; ++hdr) { 529 | if ((c = zdlread()) & ~0377) 530 | return c; 531 | crc = updcrc(c, crc); 532 | *hdr = c; 533 | } 534 | if ((c = zdlread()) & ~0377) 535 | return c; 536 | crc = updcrc(c, crc); 537 | if ((c = zdlread()) & ~0377) 538 | return c; 539 | crc = updcrc(c, crc); 540 | if (crc & 0xFFFF) { 541 | zperr(badcrc); 542 | return ERROR; 543 | } 544 | #ifdef ZMODEM 545 | Protocol = ZMODEM; 546 | #endif 547 | // Zmodem = 1; 548 | return Rxtype; 549 | } 550 | 551 | 552 | 553 | /* Receive a binary style header (type and position) with 32 bit FCS */ 554 | int zrbhdr32(char *hdr) 555 | { 556 | int c, n; 557 | UNSL long crc; 558 | 559 | if ((c = zdlread()) & ~0377) 560 | return c; 561 | Rxtype = c; 562 | crc = 0xFFFFFFFFL; 563 | crc = UPDC32(c, crc); 564 | #ifdef DEBUGZ 565 | vfile(F("zrbhdr32 c=%X crc=%lX"), c, crc); 566 | #endif 567 | 568 | for (n=4; --n >= 0; ++hdr) { 569 | if ((c = zdlread()) & ~0377) 570 | return c; 571 | crc = UPDC32(c, crc); 572 | *hdr = c; 573 | #ifdef DEBUGZ 574 | vfile(F("zrbhdr32 c=%X crc=%lX"), c, crc); 575 | #endif 576 | } 577 | for (n=4; --n >= 0;) { 578 | if ((c = zdlread()) & ~0377) 579 | return c; 580 | crc = UPDC32(c, crc); 581 | #ifdef DEBUGZ 582 | vfile(F("zrbhdr32 c=%X crc=%lX"), c, crc); 583 | #endif 584 | } 585 | if (crc != 0xDEBB20E3) { 586 | zperr(badcrc); 587 | return ERROR; 588 | } 589 | #ifdef ZMODEM 590 | Protocol = ZMODEM; 591 | #endif 592 | // Zmodem = 1; 593 | return Rxtype; 594 | } 595 | 596 | 597 | 598 | 599 | /* Receive a hex style header (type and position) */ 600 | int zrhhdr(char *hdr) 601 | { 602 | int c; 603 | unsigned short crc; 604 | int n; 605 | 606 | if ((c = zgethex()) < 0) 607 | return c; 608 | Rxtype = c; 609 | crc = updcrc(c, 0); 610 | 611 | for (n=4; --n >= 0; ++hdr) { 612 | if ((c = zgethex()) < 0) 613 | return c; 614 | crc = updcrc(c, crc); 615 | *hdr = c; 616 | } 617 | if ((c = zgethex()) < 0) 618 | return c; 619 | crc = updcrc(c, crc); 620 | if ((c = zgethex()) < 0) 621 | return c; 622 | crc = updcrc(c, crc); 623 | if (crc & 0xFFFF) { 624 | zperr(badcrc); 625 | return ERROR; 626 | } 627 | switch ( c = readline(1)) { 628 | case 0215: 629 | Not8bit = c; 630 | /* **** FALL THRU TO **** */ 631 | case 015: 632 | /* Throw away possible cr/lf */ 633 | switch (c = readline(1)) { 634 | case 012: 635 | Not8bit |= c; 636 | } 637 | } 638 | #ifdef ZMODEM 639 | Protocol = ZMODEM; 640 | #endif 641 | // Zmodem = 1; 642 | return Rxtype; 643 | } 644 | 645 | /* Send a byte as two hex digits */ 646 | /*void zputhex(int c) 647 | { 648 | static char digits[] = "0123456789abcdef"; 649 | 650 | if (Verbose>8) 651 | vfile(F("zputhex: %02X"), c); 652 | sendline(digits[(c&0xF0)>>4]); 653 | sendline(digits[(c)&0xF]); 654 | } */ 655 | 656 | PROGMEM static const char digits[17] = "0123456789abcdef"; 657 | 658 | void zputhex(int c) 659 | { 660 | // static char digits[] = "0123456789abcdef"; 661 | 662 | if (Verbose>8) 663 | vfile(F("zputhex: %02X"), c); 664 | sendline(pgm_read_byte(digits+((c&0xF0)>>4))); 665 | sendline(pgm_read_byte(digits+((c)&0xF))); 666 | } 667 | 668 | /* 669 | * Send character c with ZMODEM escape sequence encoding. 670 | * Escape XON, XOFF. Escape CR following @ (Telenet net escape) 671 | */ 672 | int zsendline2(int c) 673 | { 674 | 675 | /* Quick check for non control characters */ 676 | if (c & 0140) 677 | xsendline(lastsent = c); 678 | else { 679 | switch (c &= 0377) { 680 | case ZDLE: 681 | xsendline(ZDLE); 682 | xsendline (lastsent = (c ^= 0100)); 683 | break; 684 | case 015: 685 | case 0215: 686 | if (!Zctlesc && (lastsent & 0177) != '@') 687 | goto sendit; 688 | /* **** FALL THRU TO **** */ 689 | case 020: 690 | case 021: 691 | case 023: 692 | case 0220: 693 | case 0221: 694 | case 0223: 695 | xsendline(ZDLE); 696 | c ^= 0100; 697 | sendit: 698 | xsendline(lastsent = c); 699 | break; 700 | default: 701 | if (Zctlesc && ! (c & 0140)) { 702 | xsendline(ZDLE); 703 | c ^= 0100; 704 | } 705 | xsendline(lastsent = c); 706 | } 707 | } 708 | } 709 | 710 | 711 | /* Decode two lower case hex digits into an 8 bit byte value */ 712 | 713 | int zgethex(void) 714 | { 715 | int c, n; 716 | 717 | if ((c = noxrd7()) < 0) 718 | return c; 719 | n = c - '0'; 720 | if (n > 9) 721 | n -= ('a' - ':'); 722 | if (n & ~0xF) 723 | return ERROR; 724 | if ((c = noxrd7()) < 0) 725 | return c; 726 | c -= '0'; 727 | if (c > 9) 728 | c -= ('a' - ':'); 729 | if (c & ~0xF) 730 | return ERROR; 731 | c += (n<<4); 732 | return c; 733 | } 734 | 735 | 736 | 737 | /* 738 | * Read a byte, checking for ZMODEM escape encoding 739 | * including CAN*5 which represents a quick abort 740 | */ 741 | /* 742 | int zdlread(void) 743 | { 744 | int c; 745 | 746 | again: 747 | // Quick check for non control characters 748 | if ((c = readline(Rxtimeout)) & 0140) 749 | return c; 750 | switch (c) { 751 | case ZDLE: 752 | break; 753 | case 023: 754 | case 0223: 755 | case 021: 756 | case 0221: 757 | goto again; 758 | default: 759 | if (Zctlesc && !(c & 0140)) { 760 | goto again; 761 | } 762 | return c; 763 | } 764 | again2: 765 | if ((c = readline(Rxtimeout)) < 0) 766 | return c; 767 | if (c == CAN && (c = readline(Rxtimeout)) < 0) 768 | return c; 769 | if (c == CAN && (c = readline(Rxtimeout)) < 0) 770 | return c; 771 | if (c == CAN && (c = readline(Rxtimeout)) < 0) 772 | return c; 773 | switch (c) { 774 | case CAN: 775 | return GOTCAN; 776 | case ZCRCE: 777 | case ZCRCG: 778 | case ZCRCQ: 779 | case ZCRCW: 780 | return (c | GOTOR); 781 | case ZRUB0: 782 | return 0177; 783 | case ZRUB1: 784 | return 0377; 785 | case 023: 786 | case 0223: 787 | case 021: 788 | case 0221: 789 | goto again2; 790 | default: 791 | if (Zctlesc && ! (c & 0140)) { 792 | goto again2; 793 | } 794 | if ((c & 0140) == 0100) 795 | return (c ^ 0100); 796 | break; 797 | } 798 | if (Verbose>1) 799 | zperr("Bad escape sequence %x", c); 800 | return ERROR; 801 | } 802 | */ 803 | int zdlread2(int c) 804 | { 805 | again: 806 | // Quick check for non control characters 807 | 808 | switch (c) { 809 | case ZDLE: 810 | break; 811 | case 023: 812 | case 0223: 813 | case 021: 814 | case 0221: 815 | if ((c = readline(Rxtimeout)) & 0140) 816 | return c; 817 | goto again; 818 | default: 819 | if (Zctlesc && !(c & 0140)) { 820 | if ((c = readline(Rxtimeout)) & 0140) 821 | return c; 822 | goto again; 823 | } 824 | return c; 825 | } 826 | again2: 827 | if ((c = readline(Rxtimeout)) < 0) 828 | return c; 829 | if (c == CAN && (c = readline(Rxtimeout)) < 0) 830 | return c; 831 | if (c == CAN && (c = readline(Rxtimeout)) < 0) 832 | return c; 833 | if (c == CAN && (c = readline(Rxtimeout)) < 0) 834 | return c; 835 | switch (c) { 836 | case CAN: 837 | return GOTCAN; 838 | case ZCRCE: 839 | case ZCRCG: 840 | case ZCRCQ: 841 | case ZCRCW: 842 | return (c | GOTOR); 843 | case ZRUB0: 844 | return 0177; 845 | case ZRUB1: 846 | return 0377; 847 | case 023: 848 | case 0223: 849 | case 021: 850 | case 0221: 851 | goto again2; 852 | default: 853 | if (Zctlesc && ! (c & 0140)) { 854 | goto again2; 855 | } 856 | if ((c & 0140) == 0100) 857 | return (c ^ 0100); 858 | break; 859 | } 860 | if (Verbose>1) 861 | zperr("Bad escape sequence %x", c); 862 | return ERROR; 863 | } 864 | 865 | /* 866 | * Read a character from the modem line with timeout. 867 | * Eat parity, XON and XOFF characters. 868 | */ 869 | int noxrd7(void) 870 | { 871 | int c; 872 | 873 | for (;;) { 874 | if ((c = readline(Rxtimeout)) < 0) 875 | return c; 876 | switch (c &= 0177) { 877 | case XON: 878 | case XOFF: 879 | continue; 880 | default: 881 | if (Zctlesc && !(c & 0140)) 882 | continue; 883 | case '\r': 884 | case '\n': 885 | case ZDLE: 886 | return c; 887 | } 888 | } 889 | } 890 | 891 | 892 | 893 | /* Store long integer pos in Txhdr */ 894 | void stohdr(long pos) 895 | { 896 | Txhdr[ZP0] = pos; 897 | Txhdr[ZP1] = pos>>8; 898 | Txhdr[ZP2] = pos>>16; 899 | Txhdr[ZP3] = pos>>24; 900 | } 901 | 902 | 903 | #ifndef NOTDEF 904 | /* Recover a long integer from a header */ 905 | long rclhdr(char *hdr) 906 | { 907 | long l; 908 | 909 | l = (hdr[ZP3] & 0377); 910 | l = (l << 8) | (hdr[ZP2] & 0377); 911 | l = (l << 8) | (hdr[ZP1] & 0377); 912 | l = (l << 8) | (hdr[ZP0] & 0377); 913 | return l; 914 | } 915 | #endif 916 | 917 | /* 918 | * Send a character to modem. Small is beautiful. 919 | */ 920 | // Why was this called sendline ?? 921 | //void sendline(int c) 922 | //{ 923 | // ZSERIAL.write(c & 0xFF); 924 | // ZSERIAL.write(char(c)); 925 | // ZSERIAL.flush(); 926 | 927 | //DSERIAL.print("SEND: "); 928 | //DSERIAL.print(c, HEX); 929 | //DSERIAL.println(); 930 | 931 | //} 932 | /* 933 | //>>> Needs to be fixed up - see the original in rz 934 | // like sendline, this does not read a line! 935 | int readline(int timeout) 936 | { 937 | long then; 938 | unsigned char c; 939 | 940 | then = millis(); 941 | while(ZSERIAL.available() < 1) { 942 | if(millis() - then > (unsigned int)timeout*100UL) { 943 | DSERIAL.println("readline - TIMEOUT"); 944 | return(TIMEOUT); 945 | } 946 | } 947 | c = ZSERIAL.read(); 948 | //DSERIAL.print("READ: "); 949 | //DSERIAL.print(c, HEX); 950 | //DSERIAL.println(); 951 | return(c); 952 | } 953 | */ 954 | 955 | /* 956 | * Purge the modem input queue of all characters 957 | */ 958 | void purgeline(void) 959 | { 960 | while(ZSERIAL.available())ZSERIAL.read(); 961 | } 962 | 963 | /* 964 | * Local console output simulation 965 | */ 966 | void bttyout(int c) 967 | { 968 | #ifndef ARDUINO 969 | if (Verbose || Fromcu) 970 | putc(c, stderr); 971 | #endif 972 | } 973 | 974 | void flushmo(void) 975 | { 976 | ZSERIAL.flush(); 977 | } 978 | 979 | 980 | 981 | /* send cancel string to get the other end to shut up */ 982 | void canit(void) 983 | { 984 | for (int i=0; i < 10; ++i) { 985 | ZSERIAL.write(24); 986 | } 987 | for (int i=0; i < 10; ++i) { 988 | ZSERIAL.write(8); 989 | } 990 | ZSERIAL.flush(); 991 | } 992 | 993 | /* End of zm.c */ 994 | #endif 995 | -------------------------------------------------------------------------------- /zmodem/zmodem_zm.h: -------------------------------------------------------------------------------- 1 | #ifndef ZMODEM_ZM_h 2 | #define ZMODEM_ZM_H 3 | 4 | #define VERSION Progname 5 | 6 | extern char oneKbuf[1025]; 7 | 8 | //extern int Rxtimeout; /* Tenths of seconds to wait for something */ 9 | 10 | /* Globals used by ZMODEM functions */ 11 | extern uint8_t Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ 12 | extern uint8_t Rxtype; /* Type of header received */ 13 | extern int Rxcount; /* Count of data bytes received */ 14 | extern char Rxhdr[4]; /* Received header */ 15 | extern char Txhdr[4]; /* Transmitted header */ 16 | extern long Rxpos; /* Received file position */ 17 | extern long Txpos; /* Transmitted file position */ 18 | extern int8_t Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ 19 | extern int8_t Crc32t; /* Display flag indicating 32 bit CRC being sent */ 20 | extern int8_t Crc32; /* Display flag indicating 32 bit CRC being received */ 21 | //extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ 22 | extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ 23 | 24 | extern int lastsent; /* Last char we sent */ 25 | extern uint8_t Not8bit; /* Seven bits seen on header */ 26 | 27 | //extern char *frametypes[]; 28 | 29 | extern uint32_t Baudrate; 30 | #define xsendline(c) sendline(c) 31 | //int readline(int timeout); 32 | 33 | #define OK 0 34 | #define FALSE 0 35 | #define TRUE 1 36 | #undef ERROR 37 | #define ERROR (-1) 38 | 39 | #ifndef ARDUINO 40 | #define zperr(a, ... ) 41 | #else 42 | /* 43 | #define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: " 44 | #define WHEREARG __FILE__,__func__,__LINE__ 45 | #define DEBUG(...) {char s[256]; sprintf(s, __VA_ARGS__); DSERIAL.println(s);} 46 | #define zperr(_fmt, ...) DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__) 47 | */ 48 | //#define zperr(...) {char s[256]; sprintf(s, __VA_ARGS__); DSERIAL.println(s);} 49 | #define zperr(...) 50 | #endif 51 | 52 | void bttyout(int c); 53 | 54 | #define Zmodem 1 /* ZMODEM protocol requested */ 55 | extern uint8_t Verbose; 56 | extern char zconv; /* ZMODEM file conversion request */ 57 | extern char zmanag; /* ZMODEM file management request */ 58 | extern char ztrans; /* ZMODEM file transport request */ 59 | extern uint8_t Zctlesc; /* Encode control characters */ 60 | //extern int Zrwindow; /* RX window size (controls garbage count) */ 61 | //extern int Nozmodem; 62 | #define Nozmodem 0 63 | #define Lzmanag 0 64 | //extern int Restricted; 65 | //extern int Quiet; 66 | #define Quiet 0 67 | extern uint8_t Eofseen; 68 | 69 | extern uint8_t firstsec; 70 | extern char Lastrx; 71 | extern char Crcflg; 72 | extern uint8_t errors; 73 | // This is declared in the main sketch .ino 74 | //extern char *Progname; 75 | #endif 76 | --------------------------------------------------------------------------------