#define DEBUG using System; using System.Diagnostics; using Microsoft.SPOT; using Microsoft.SPOT.IO; using System.IO; using System.IO.Ports; using System.Threading; //using Microsoft.SPOT namespace CPF.FileTransfer { public class Zmodem { //VERBOSITY private const bool Verbose = true; //Headers public const byte ZPAD = 0x2a; /* pad character; begins frames */ public const byte ZDLE = 0x18; /* ctrl-x zmodem escape */ public const byte ZDLEE = 0x58; /* escaped ZDLE */ public const byte ZBIN = 0x41; /* binary frame indicator (CRC16) */ public const byte ZHEX = 0x42; /* hex frame indicator */ public const byte ZBIN32 = 0x43; /* binary frame indicator (CRC32) */ public const byte ZBINR32 = 0x44; /* run length encoded binary frame (CRC32) */ public const byte ZVBIN = 0x61; /* binary frame indicator (CRC16) */ public const byte ZVHEX = 0x62; /* hex frame indicator */ public const byte ZVBIN32 = 0x63; /* binary frame indicator (CRC32) */ public const byte ZVBINR32 = 0x64; /* run length encoded binary frame (CRC32) */ public const byte ZRESC = 0x7e; /* run length encoding flag / escape character */ //Frame Types public const byte ZRQINIT = 0; /* Request receive init */ public const byte ZRINIT = 1; /* Receive init */ public const byte ZSINIT = 2; /* Send init sequence (optional) */ public const byte ZACK = 3; /* ACK to above */ public const byte ZFILE = 4; /* File name from sender */ public const byte ZSKIP = 5; /* To sender: skip this file */ public const byte ZNAK = 6; /* Last packet was garbled */ public const byte ZABORT = 7; /* Abort batch transfers */ public const byte ZFIN = 8; /* Finish session */ public const byte ZRPOS = 9; /* Resume data trans at this position */ public const byte ZDATA = 10; /* Data packet(s) follow */ public const byte ZEOF = 11; /* End of file */ public const byte ZFERR = 12; /* Fatal Read or Write error Detected */ public const byte ZCRC = 13; /* Request for file CRC and response */ public const byte ZCHALLENGE = 14; /* Receiver's Challenge */ public const byte ZCOMPL = 15; /* Request is complete */ public const byte ZCAN = 16; /* Other end canned session with CAN*5 */ public const byte ZFREECNT = 17; /* Request for free bytes on filesystem */ public const byte ZCOMMAND = 18; /* Command from sending program */ public const byte ZSTDERR = 19; /* Output to standard error, data follows */ /* ZDLE sequences */ public const byte ZCRCE = 0x68; /* CRC next, frame ends, header packet follows */ public const byte ZCRCG = 0x69; /* CRC next, frame continues nonstop */ public const byte ZCRCQ = 0x6A; /* CRC next, frame continues, ZACK expected */ public const byte ZCRCW = 0x6B; /* CRC next, ZACK expected, end of frame */ public const byte ZRUB0 = 0x6C; /* Translate to rubout 0177 */ public const byte ZRUB1 = 0x6D; /* Translate to rubout 0377 */ /* Byte positions within header array */ public const byte ZF0 = 3; /* First flags byte */ public const byte ZF1 = 2; public const byte ZF2 = 1; public const byte ZF3 = 0; public const byte ZP0 = 0; /* Low order 8 bits of position */ public const byte ZP1 = 1; public const byte ZP2 = 2; public const byte ZP3 = 3; /* High order 8 bits of file position */ /* Bit Masks for ZRINIT flags byte ZF0 */ public const byte CANFDX = 0x01; /* Rx can send and receive true FDX */ public const byte CANOVIO = 0x02; /* Rx can receive data during disk I/O */ public const byte CANBRK = 0x04; /* Rx can send a break signal */ public const byte CANCRY = 0x08; /* Receiver can decrypt */ public const byte CANLZW = 0x10; /* Receiver can uncompress */ public const byte CANFC32 = 0x20; /* Receiver can use 32 bit Frame Check */ public const byte ESCCTL = 0x40; /* Receiver expects ctl chars to be escaped */ public const byte ESC8 = 0x80; /* Receiver expects 8th bit to be escaped */ /* zdlread return values (internal) */ /* -1 is general error, -2 is timeout */ private const int GOTOR = 0x100; public const int GOTCRCE = (ZCRCE | GOTOR); /* ZDLE-ZCRCE received */ public const int GOTCRCG = (ZCRCG | GOTOR); /* ZDLE-ZCRCG received */ public const int GOTCRCQ = (ZCRCQ | GOTOR); /* ZDLE-ZCRCQ received */ public const int GOTCRCW = (ZCRCW | GOTOR); /* ZDLE-ZCRCW received */ private const int GOTCAN = (GOTOR | 0x18); /* CAN*5 seen */ /* Static Buffers for header generation and storage */ public static byte[] Rxhdr = new byte[4]; /* Received Header */ public static byte[] Txhdr = new byte[4]; /* Transmitted Header */ public static long Txpos; /* Transmitted File Position */ public static bool Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ public static int Crc32t; /* Display flag indicating 32 bit CRC being sent */ public static int Crc32; /* Display flag indicating 32 bit CRC being received */ public static int Znulls = 0; /* Number of nulls to send at beginning of ZDATA hdr */ public static int Rxtimeout = 100; /*Tenths of Seconds to wait for a reply */ public static int Rxframeind; public static int Zrwindow = 1400; /* RX window size (controls garbage count) */ /* Types for Connections */ /*public enum Modes { BIN16, HEX16, BIN32 };*/ /* Property Accessor */ //public static Modes Mode; public static bool turbo_escape = false; public static bool Zctlesc; /*Encode Control Characters*/ public static void Init(bool zctlesc) { //Mode = mode; turbo_escape = false; Zctlesc = false; Txfcs32 = true; zsendline_init(); } /* public static void Header(SerialPort sp, byte type, ref byte[] flags) { if (Mode == Modes.BIN16 | Mode == Modes.BIN32) { zsbhdr(sp, type, ref flags); } else if (Mode == Modes.HEX16) { zshhdr(sp, type, ref flags); } } */ private static byte lastsent; private static void AddByte(byte c, ref byte[] buff, ref int nbytes) { switch (zsendline_tab[(UInt16)(c & 0xFF)]) { case 0: /*don't need to escape*/ lastsent = c; buff[nbytes++] = c; break; case 1: /*needs escape*/ buff[nbytes++] = ZDLE; c ^= 0x40; lastsent = c; buff[nbytes++] = c; break; case 2: if ((lastsent & 0x7F) != 0x40) { lastsent = c; buff[nbytes++] = c; } else { buff[nbytes++] = ZDLE; c ^= 0x40; buff[nbytes++] = c; } break; } } public static void zsbhdr(SerialPort sp, byte type, ref byte[] flags) { //Debug.Print("Inserting Binary Header."); // Insert nulls int n = 0; ushort crc; if (type == ZDATA) { for (n = 0; n < Znulls; n++) xsendline(sp, 0); } // Binary header initial sequence xsendline(sp, ZPAD); xsendline(sp, ZDLE); Crc32t = Zmodem.Txfcs32 ? 1 : 0; if (Zmodem.Txfcs32) { UInt32 crc32; xsendline(sp, ZBIN32); zsendline(sp, type); crc32 = 0xFFFFFFFF; crc32 = CRC.UPDC32(type, crc32); for (n = 0; n < 4; n++) { zsendline(sp, flags[n]); crc32 = CRC.UPDC32(flags[n], crc32); } crc32 = ~crc32; for (n = 0; n < 4; n++) { zsendline(sp, (byte)(crc32 & 0xFF)); crc32 >>= 8; } } else { xsendline(sp, ZBIN); zsendline(sp, type); crc = CRC.updcrc(type, 0); for (n = 0; n < 4; n++) { zsendline(sp, flags[n]); crc = CRC.updcrc((byte)(0xFF & flags[n]), crc); } crc = CRC.updcrc(0, CRC.updcrc(0, crc)); zsendline(sp, (byte)((crc >> 8) & 0xFF)); zsendline(sp, (byte)(crc & 0xFF)); } } static byte[] hbuff = new byte[30]; public static void zshhdr(SerialPort sp, byte type, ref byte[] flags) { ushort crc; int nbytes = 0; hbuff[0] = ZPAD; hbuff[1] = ZPAD; hbuff[2] = ZDLE; hbuff[3] = ZHEX; zputhex(ref hbuff, 4, (byte)(type & 0x7F)); nbytes = 6; crc = CRC.updcrc((byte)(type & 0x7F), 0); Crc32t = 0; for (int n = 0; n < 4; n++) { nbytes += zputhex(ref hbuff, nbytes, flags[n]); crc = CRC.updcrc((byte)(0xFF & flags[n]), crc); } //add the crc crc = CRC.updcrc(0, CRC.updcrc(0, crc)); nbytes += zputhex(ref hbuff, nbytes, ((crc >> 8) & 0xFF)); nbytes += zputhex(ref hbuff, nbytes, ((crc) & 0xFF)); /* Make it printable on the remote machine */ hbuff[nbytes++] = 13; hbuff[nbytes++] = 10; /* * Uncork the remote in case a fake XOFF has stopped data flow */ if (type != ZFIN && type != ZACK) hbuff[nbytes++] = 17; sp.Write(hbuff, 0, nbytes); return; } public static void EncodeDataSubPacket16(ref byte[] data, int length, byte frameend, ref byte[] buff, out int nbytes) { ushort crc = 0; nbytes = 0; for (int n = 0; n < length; n++) { AddByte(data[n], ref buff, ref nbytes); crc = CRC.updcrc((byte)(data[n] & 0xFF), crc); } buff[nbytes++] = ZDLE; buff[nbytes++] = frameend; crc = CRC.updcrc(frameend, crc); crc = CRC.updcrc(0, CRC.updcrc(0, crc)); AddByte((byte)((crc >> 8) & 0xFF), ref buff, ref nbytes); AddByte((byte)(crc & 0xFF), ref buff, ref nbytes); if (frameend == ZCRCW) { buff[nbytes++] = XON; } } /* '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'*/ private static byte[] digits = new byte[16] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102 }; private static int zputhex(ref byte[] buff, int offset, int c) { #if DEBUG //TODO P2 Put a debug write here. #endif buff[0 + offset] = digits[((c & 0xF0) >> 4)]; buff[1 + offset] = digits[(c & 0x0F)]; return 2; } public static int readline(SerialPort sp, int timeoutInTenths) { TimeSpan tsStart = DateTime.Now.TimeOfDay; TimeSpan tsTimeLimit = new TimeSpan(0, 0, timeoutInTenths / 10); bool timedOut = false; int c = ERROR; while (!timedOut) { if (sp.BytesToRead == 0) { //check timer if (DateTime.Now.TimeOfDay - tsStart > tsTimeLimit) { timedOut = true; } continue; } try { c = sp.ReadByte(); } catch (Exception e) { Debug.Print("Caught Exception: "+ e.ToString()); c = ERROR; } break; } if (timedOut) c = TIMEOUT; //if (c >= 0) // Debug.Print("Got Char {0}", c); return c; } private static int noxrd7(SerialPort sp) { int c; for (; ; ) { if ((c = readline(sp, Rxtimeout)) < 0) return c; switch (c &= 0x7F) { case XON: case XOFF: continue; default: if (Zctlesc && ((c & 0x60) == 0)) { //not continue; } return c; case 0x0D: //'\r' case 0x0A: //'\n' case ZDLE: return c; } } } public static int zgeth1(SerialPort sp) { int n, c; //First Hex Character c = noxrd7(sp); if (c < 0) return c; n = c - 0x30; if (n > 9) n -= (0x061 - 0x3A); //'a'-':' if ((n & ~0xF) != 0) return ERROR; //Second Hex Char c = noxrd7(sp); if (c < 0) return c; c -= 0x30; if (c > 9) c -= (0x061 - 0x3a); //'a' - ':' if ((c & ~0xF) != 0) return ERROR; c += (n << 4); return c; } /// /// Decode two lower case hex digits into an 8 bit byte value /// /// Serialport to operate on /// int value communicated in two characters from the serial port buffer public static int zgethex(SerialPort sp) { int c; c = zgeth1(sp); //Debug.Print("zgethex: {0}", c); return c; } static byte[] xsc = new byte[1]; public static void xsendline(SerialPort sp, byte c) { xsc[0] = c; sp.Write(xsc, 0, 1); } public static void zsendline(SerialPort sp, byte c) { switch (zsendline_tab[c]) { case 0: xsendline(sp, lastsent = c); break; case 1: xsendline(sp, ZDLE); c ^= 0x40; xsendline(sp, lastsent = c); break; case 2: if ((lastsent & 0x7F) != 0x40)/*'@'*/ xsendline(sp, lastsent = c); else { xsendline(sp, ZDLE); c ^= 0x40; xsendline(sp, lastsent = c); } break; } } public static int zrhhdr(SerialPort sp, ref byte[] hdr) { int c; ushort crc; int n; int RxType; c = zgethex(sp); if (c < 0) return c; RxType = c; crc = CRC.updcrc((byte)c, 0); for (n = 0; n < 4; n++) { c = zgethex(sp); if (c < 0) return c; crc = CRC.updcrc((byte)c, crc); hdr[n] = (byte)c; } c = zgethex(sp); if (c < 0) return c; crc = CRC.updcrc((byte)c, crc); c = zgethex(sp); if (c < 0) return c; crc = CRC.updcrc((byte)c, crc); if ((crc & 0xFFFF) != 0) { //zperr(badcrc); Debug.Print("BAD CRC"); return ERROR; } c = readline(sp, 1); switch (c) { case 0x8D: case 0x0D: // throw away possible CR/LF readline(sp, 1); break; } //protocol = ZM_ZMODEM; //zmodem_requested = true; return RxType; } public static void stohdr(UInt32 pos) { UInt32 lpos = (UInt32)pos; Txhdr[ZP0] = (byte)(lpos & 0xFF); Txhdr[ZP1] = (byte)((lpos >> 8) & 0xFF); Txhdr[ZP2] = (byte)((lpos >> 16) & 0xFF); Txhdr[ZP3] = (byte)((lpos >> 24) & 0xFF); } public static int zgethdr(SerialPort sp, ref byte[] hdr, int eflag, ref UInt32 Rxpos) { int c, cancount; UInt16 max_garbage; max_garbage = (UInt16)(Zrwindow + sp.BaudRate); UInt32 rxpos = 0; startover: cancount = 5; /*Return immediately if ZCRCW sequence seen */ again: switch (c = readline(sp, Rxtimeout)) { case TIMEOUT: goto fifi; case CAN: goto gotcan; default: goto agn2; } gotcan: switch (c = readline(sp, 1)) { case TIMEOUT: goto again; case ZCRCW: Debug.Print("zgethdr():Got ZCRCW"); c = ERROR; goto fifi; case CAN: if (--cancount <= 0) { c = ZCAN; goto fifi; } goto again; } agn2: switch (c) { default: if (--max_garbage == 0) { Debug.Print("Garbage Count Exceeded"); sp.DiscardInBuffer(); return ERROR; } if (eflag == 1 && ((c &= 0x7F) & 0x60) != 0 && Verbose) Debug.Print("GotChar: " + c.ToString("X")); else if (eflag > 1) Debug.Print("GotChar: " + c.ToString("x")); goto startover; case ZPAD: /* This is what we want */ case (ZPAD | 0x80): break; } cancount = 5; splat: switch (c = noxrd7(sp)) { case ZPAD: goto splat; case TIMEOUT: goto fifi; default: goto agn2; case ZDLE: /* this is what we expect */ break; } switch (c = noxrd7(sp)) { case TIMEOUT: goto fifi; case ZBIN: Rxframeind = ZBIN; Crc32 = 0; c = zrbhdr(sp, ref hdr); break; case ZBIN32: Rxframeind = ZBIN32; Crc32 = ZBIN32; c = zrbhdr32(sp, ref hdr); break; case ZHEX: Rxframeind = ZHEX; Crc32 = 0; c = zrhhdr(sp, ref hdr); break; case CAN: goto gotcan; default: goto agn2; } rxpos = (UInt32)(hdr[ZP3] & 0xFF); rxpos = (UInt32)((rxpos << 8) + (hdr[ZP2] & 0xFF)); rxpos = (UInt32)((rxpos << 8) + (hdr[ZP1] & 0xFF)); rxpos = (UInt32)((rxpos << 8) + (hdr[ZP0] & 0xFF)); fifi: switch (c) { case GOTCAN: c = ZCAN; Debug.Print("GOT CAN"); break; case ZNAK: Debug.Print("GOT ZNAK"); break; case ZCAN: Debug.Print("GOT ZCAN"); break; case ERROR: Debug.Print("GOT ERROR"); break; case TIMEOUT: Debug.Print("GOT TIMEOUT"); break; } Rxpos = rxpos; return c; } /* Bit Masks for ZRINIT flags byze ZF1 */ public const byte ZF1_CANVHDR = 0x01; /* Variable headers OK, unused in lrzsz */ public const byte ZF1_TIMESYNC = 0x02; /* nonstandard, Receiver request timesync */ /* Parameters for ZSINIT frame */ public const byte ZATTNLEN = 32; /* Max length of attention string */ /* Bit Masks for ZSINIT flags byte ZF0 */ public const byte TESCCTL = 0x40; /* Transmitter expects ctl chars to be escaped */ public const byte TESC8 = 0x80; /* Transmitter expects 8th bit to be escaped */ /* Parameters for ZFILE frame */ /* Conversion options one of these in ZF0 */ public const byte ZCBIN = 1; /* Binary transfer - inhibit conversion */ public const byte ZCNL = 2; /* Convert NL to local end of line convention */ public const byte ZCRESUM = 3; /* Resume interrupted file transfer */ /* Management include options, one of these ored in ZF1 */ public const byte ZF1_ZMSKNOLOC = 0x80; /* Skip file if not present at rx */ /* Management options, one of these ored in ZF1 */ public const byte ZF1_ZMMASK = 0x1f; /* Mask for the choices below */ public const byte ZF1_ZMNEWL = 1; /* Transfer if source newer or longer */ public const byte ZF1_ZMCRC = 2; /* Transfer if different file CRC or length */ public const byte ZF1_ZMAPND = 3; /* Append contents to existing file (if any) */ public const byte ZF1_ZMCLOB = 4; /* Replace existing file */ public const byte ZF1_ZMNEW = 5; /* Transfer if source newer */ /* Number 5 is alive ... */ public const byte ZF1_ZMDIFF = 6; /* Transfer if dates or lengths different */ public const byte ZF1_ZMPROT = 7; /* Protect destination file */ public const byte ZF1_ZMCHNG = 8; /* Change filename if destination exists */ /* Transport options, one of these in ZF2 */ public const byte ZTLZW = 1; /* Lempel-Ziv compression */ public const byte ZTCRYPT = 2; /* Encryption */ public const byte ZTRLE = 3; /* Run Length encoding */ /* Extended options for ZF3, bit encoded */ public const byte ZXSPARS = 64; /* Encoding for sparse file operations */ /* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ public const byte ZCACK1 = 1; /* Acknowledge, then do command */ public const byte XOFF = 0x73 & 0x1F; /* ^s */ public const byte XON = 0x71 & 0x1F; /* ^q */ public const int ERROR = -1; public const int OK = 0; public const int TIMEOUT = -2; public const int RCDO = -3; public const byte CPMEOF = 0x1A; public const byte CAN = 0x58 & 0x1F; /* ^X */ public const uint UNIXFILE = 0xF000; internal static byte[] Attn = new byte[ZATTNLEN + 1]; private static byte[] zsendline_tab = new byte[256]; public static void zsendline_init() { for (int i = 0; i < 256; i++) { if ((i & 0x60) > 0) zsendline_tab[i] = 0; else { switch (i) { case ZDLE: case XOFF: /* ^Q */ case XON: /* ^S */ case (XOFF | 0x80): case (XON | 0x80): zsendline_tab[i] = 1; break; case 0x10: /* ^P */ case 0x90: if (turbo_escape) zsendline_tab[i] = 0; else zsendline_tab[i] = 1; break; case 0x0D: case 0x8D: if (Zctlesc) zsendline_tab[i] = 1; else if (!turbo_escape) zsendline_tab[i] = 2; else zsendline_tab[i] = 0; break; default: if (Zctlesc) zsendline_tab[i] = 1; else zsendline_tab[i] = 0; break; } } } } /* public static int zsdata(SerialPort sp, ref byte[] buff, UInt16 length, byte frameend) { ushort crc = 0; for (int n = 0; n < length; n++) { zsendline(sp, buff[n]); } while (true) ; xsendline(sp, ZDLE); xsendline(sp, frameend); crc = CRC.updcrc(frameend, crc); crc = CRC.updcrc(0, CRC.updcrc(0, crc)); zsendline(sp, (byte)((crc >> 8) & 0xFF)); zsendline(sp, (byte)(crc & 0xFF)); if (frameend == ZCRCW) { xsendline(sp, XON); } } */ internal static void zsdata(SerialPort sp, ref byte[] buff, UInt16 length, byte frameend) { ushort crc; Debug.Print("Zmodem.zsdata(): " + length.ToString() + " " + frameend.ToString()); crc = 0; for (int n = 0; n < length; n++) { zsendline(sp, buff[n]); crc = CRC.updcrc((byte)(0xFF & buff[n]), crc); } xsendline(sp, ZDLE); xsendline(sp, frameend); crc = CRC.updcrc(frameend, crc); crc = CRC.updcrc(0, CRC.updcrc(0, crc)); zsendline(sp, (byte)((crc >> 8) & 0xFF)); zsendline(sp, (byte)(crc & 0xFF)); if (frameend == ZCRCW) { xsendline(sp, XON); } } internal static void zsda32(SerialPort sp, ref byte[] buff, UInt16 length, byte frameend) { byte c; UInt32 crc; //Debug.Print("Zmodem.zsda32(): " + length.ToString() + " " + frameend.ToString()); crc = 0xFFFFFFFF; zsendline_s(sp, ref buff, length); for (int n = 0; n < length; n++) { c = (byte)(buff[n] & 0xFF); crc = CRC.UPDC32(c, crc); } xsendline(sp, ZDLE); xsendline(sp, frameend); crc = CRC.UPDC32(frameend, crc); crc = ~crc; for (int n = 0; n < 4; n++) { c = (byte)crc; if ((c & 0x60) != 0) xsendline(sp, lastsent = c); else zsendline(sp, c); crc >>= 8; } if (frameend == ZCRCW) { xsendline(sp, XON); } } private static void zsendline_s(SerialPort sp, ref byte[] buff, UInt16 length) { int last_esc = 0; int n, i; byte c; n = 0; while (n < length) { last_esc = 0; i = n; while (i < length) { last_esc = zsendline_tab[(UInt16)(buff[i] & 0xFF)]; if (last_esc > 0) break; i++; } if (i != n) { sp.Write(buff, n, i - n); n = i; } if (last_esc > 0) { c = buff[n]; switch (last_esc) { case 0: xsendline(sp, lastsent = c); break; case 1: xsendline(sp, ZDLE); c ^= 0x40; xsendline(sp, lastsent = c); break; case 2: if ((lastsent & 0x7F) != 0x40) { xsendline(sp, lastsent = c); } else { xsendline(sp, ZDLE); c ^= 0x40; xsendline(sp, lastsent = c); } break; } n++; } } } private static int zdlread(SerialPort sp) { int c; c = readline(sp, Rxtimeout); if ((c & 0x60) != 0) return c; return zdlread2(sp, c); } private static int zdlread2(SerialPort sp, int c) { goto jump_over; again: c = readline(sp, Rxtimeout); if ((c & 0x60) > 0) return c; jump_over: switch (c) { case ZDLE: break; case (XON): case (XON | 0x80): case XOFF: case (XOFF | 0x80): goto again; default: if (Zctlesc && ((c & 0x60) == 0)) goto again; return c; } again2: if ((c = readline(sp, Rxtimeout)) < 0) return c; if (c == CAN && (c = readline(sp, Rxtimeout)) < 0) return c; if (c == CAN && (c = readline(sp, Rxtimeout)) < 0) return c; if (c == CAN && (c = readline(sp, Rxtimeout)) < 0) return c; switch (c) { case CAN: return GOTCAN; case ZCRCE: case ZCRCG: case ZCRCQ: case ZCRCW: return (c | GOTOR); case ZRUB0: return 0x7F; case ZRUB1: return 0xFF; case XON: case (XON | 0x80): case XOFF: case (XOFF | 0x80): goto again2; default: if (Zctlesc && ((c & 0x60) == 0)) goto again2; if ((c & 0x60) == 0x40) return (c ^ 0x40); break; } Debug.Print("zdlread2(): Bad escape sequence."); return ERROR; } internal static int zrdata(SerialPort sp, ref byte[] buff, ref UInt16 nbytes) { ushort crc; int c, d; nbytes = 0; if (Rxframeind == ZBIN32) { return zrdat32(sp, ref buff, ref nbytes); } crc = 0; while (nbytes < buff.Length) { if (((c = zdlread(sp)) & ~0xFF) != 0) { crcfoo: switch (c) { case GOTCRCE: case GOTCRCG: case GOTCRCQ: case GOTCRCW: d = c; c &= 0xFF; crc = CRC.updcrc((byte)c, crc); if (((c = zdlread(sp)) & ~0xFF) != 0) goto crcfoo; crc = CRC.updcrc((byte)c, crc); if (((c = zdlread(sp)) & ~0xFF) != 0) goto crcfoo; crc = CRC.updcrc((byte)c, crc); if ((crc & 0xFFFF) > 0) return ERROR; return d; case GOTCAN: return ZCAN; case TIMEOUT: return c; default: Debug.Print("zrdata(): BAD Data Subpacket."); return c; } } buff[nbytes++] = (byte)c; crc = CRC.updcrc((byte)c, crc); } Debug.Print("zrdata(): Data subpacket too long."); return ERROR; } private static int zrdat32(SerialPort sp, ref byte[] buff, ref UInt16 nbytes) { int c; uint crc; int d; crc = 0xFFFFFFFF; while (nbytes < buff.Length) { if (((c = zdlread(sp)) & ~0xFF) != 0) { crcfoo: switch (c) { case GOTCRCE: case GOTCRCG: case GOTCRCQ: case GOTCRCW: d = c; Debug.Print("Got CRC*: " + c.ToString()); c &= 0xFF; crc = CRC.UPDC32((byte)c, crc); if (((c = zdlread(sp)) & ~0xFF) != 0) goto crcfoo; crc = CRC.UPDC32((byte)c, crc); if (((c = zdlread(sp)) & ~0xFF) != 0) goto crcfoo; crc = CRC.UPDC32((byte)c, crc); if (((c = zdlread(sp)) & ~0xFF) != 0) goto crcfoo; crc = CRC.UPDC32((byte)c, crc); if (((c = zdlread(sp)) & ~0xFF) != 0) goto crcfoo; crc = CRC.UPDC32((byte)c, crc); if (crc != 0xDEBB20E3) { sp.DiscardInBuffer(); Debug.Print("zrdat32(): Bad CRC on " + nbytes + " bytes. Bytes Remaining:"+sp.BytesToRead); return ERROR; } //Debug.Print("zrdat32(): CRC good on " + nbytes + " bytes."); return d; case GOTCAN: Debug.Print("Sender Canceled"); return ZCAN; case TIMEOUT: Debug.Print("TIMEOUT"); return c; default: Debug.Print("zrdat32(): Bad Data subpacket"); return c; } } buff[nbytes++] = (byte)c; crc = CRC.UPDC32((byte)c, crc); } Debug.Print("zrdat32(): Data Subpacket too long"); return ERROR; } private static int zrbhdr(SerialPort sp, ref byte[] hdr) { int c, n, Rxtype; ushort crc; if (((c = zdlread(sp)) & ~0xFF) != 0) return c; Rxtype = c; crc = CRC.updcrc((byte)c, 0); // Read in header bytes for (n = 0; n < 4; n++) { if (((c = zdlread(sp)) & ~0xFF) != 0) return c; crc = CRC.updcrc((byte)c, crc); hdr[n] = (byte)c; } if (((c = zdlread(sp)) & ~0xFF) != 0) return c; crc = CRC.updcrc((byte)c, crc); if (((c = zdlread(sp)) & ~0xFF) != 0) return c; crc = CRC.updcrc((byte)c, crc); if ((crc & 0xFFFF) != 0) { Debug.Print("Bad CRC"); } return Rxtype; } internal static int rclhdr(ref byte[] hdr) { Int32 l; l = (hdr[ZP3] & 0xFF); l = (l << 8) | (hdr[ZP2] & 0xFF); l = (l << 8) | (hdr[ZP1] & 0xFF); l = (l << 8) | (hdr[ZP0] & 0xFF); return l; } private static int zrbhdr32(SerialPort sp, ref byte[] hdr) { int c, n, Rxtype; UInt32 crc; if (((c = zdlread(sp)) & ~0xFF) != 0) return c; Rxtype = c; crc = 0xFFFFFFFF; crc = CRC.UPDC32((byte)c, crc); // Read in header bytes for (n = 0; n < 4; n++) { if (((c = zdlread(sp)) & ~0xFF) != 0) return c; crc = CRC.UPDC32((byte)c, crc); hdr[n] = (byte)c; } // Read in crc for (n = 0; n < 4; n++) { if (((c = zdlread(sp)) & ~0xFF) != 0) return c; crc = CRC.UPDC32((byte)c, crc); } if (crc != 0xDEBB20E3) { Debug.Print("BAD CRC"); return ERROR; } return Rxtype; } } }