#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;
}
}
}