Fixed a base class of serial communication under several bugs .NET
Using system;
Using system.runtime.interopservices; using system.threading; using system.io; using system.xml.serialization;
Namespace xst.xstcomm.base {////
/// Lowest Level COM Driver Handling All Win32 API Calls and Processing Send and received in Terms of /// Individual Bytes. Used as a base class for higher level drivers. ///
Public Abstract Class CommBase: IDisposable
{
PRIVATE INTPTR HPORT;
PRIVATE INTPTR PTRUWO = INTPTR.ZERO;
Private thread rxthread = null;
PRIVATE BOOL online = false;
PRIVATE BOOL Auto = FALSE;
Private bool checksends = true;
PRIVATE EXCETION RXEXCEPTION = NULL;
Private bool rxExceptionReported = false;
PRIVATE INT WRITECOUNT = 0;
Private manualReveTevent WriteEvent = New ManualReveTevent (false);
// JH 1.2: Added Below To Improve Robustness of Thread Start-Up.
Private manualReveTevent Startevent = New ManualReveTevent (false);
Private int staterts = 2;
Private int stat = 2;
Private Int Statebrk = 2;
// JH 1.3: Added to support The New Congestion Detection Scheme (FOLLOWING TWO "):
Private bool [] EMPTY = New bool [1];
PRIVATE BOOL DATAQUED = FALSE;
///
/// Parity Settings ////
Public Enum Parity
{
///
/// Characters Do Not Have a Parity Bit. ///
None = 0,
///
///Iff there 1s in the data bits, The Parity Bit IS 1. ///
ODD = 1,
///
/// if there is an evenu number of 1s in the data bits, the parity bit is ////
Even = 2,
///
/// The parity bit is always 1. ///
Mark = 3,
///
/// The parity bit is always 0. ////
Space = 4
}
///
/// stop bit settings ////
Public Enum Stopbits
{
///
/// line is asserted for 1 bit duration at end of each character /// one = 0,
///
/// line is asked for 1.5 bit duration at end of each character ////////
OnePointFive = 1,
///
/// line is asked for 2 bit duration at end of each character ///
TWO = 2
}
///
/// Uses for rts or dtr pins ////
Public Enum HSOUTPUT
{
///
/// pin is asserted when this station is able to remove data. ///
Handshake = 2,
///
/// pin is asserted when this station is transmitting data (rts on nt, 2000 or xp "///
Gate = 3,
///
/// pin is asserted when this station is open (port is open). ///
ONLINE = 1,
///
/// pin is never asserted. ///
None = 0
}
///
/// standard handshake methods ///
Public Enum Handshake
{
///
/// no Handshaking ///
None,
///
/// Software Handshaking Using XON / XOFF ///
Xonxoff,
///
/// Hardware Handshaking Using CTS / RTS /////
CTSRTS,
///
/// Hardware Handshaking Using DSR / DTR / / / /
DSRDTR
}
///
/// set the public fields to supply settings to commit. ///
Public class commbasesettings
{
///
/// port name (Default: "COM1:") ///
Public String Port = "COM1";
///
/// baud Rate (Default: 2400) Unsupported Rates Will Throw "Bad Settings" /////
Public int baudrate = 19200;
///
/// The Parity Checking Scheme (Default: none) ///
Public Parity Parity = Parity.none;
///
/// Number of DataBits 1..8 (Default: 8) Unsupported Values Will Throw "Bad Settings" ///
Public int DATABITS = 8;
///
/// Number of Stop Bits (Default: One) ///
Public stopbits stopbits = stopbits.one;
///
/// if true, transmission is halted unless cts is asserted by the remote station (default: false) /// public bool txflowcts = false
///
/// if true, transmission is halted unless dsr is asserted by The Remote Station (Default: false) ///
Public bool txflowdsr = false;
///
/// if true, transmission is halted when Xoff is recection and restarted WHEN XON IS Rece: false ///
Public bool txflowx = false;
///
/// if false, Transmission is suspended gen this station skill: true) /// set false if the remote station treats any character as an xon. ///
Public bool txwhenrxxoff = true;
///
/// if true, receivated characters area ignored unless dsr is asked by the remote station (default: false) ///
Public bool rxgatedsr = false;
///
/// if true, Xon and Xoff Characters Are Sent To Control The Data Flow from The Remote Station (Default: false) ///
Public bool rxflowx = false;
///
/// specifies the use to which the RTS Output is Put (Default: None) ///
Public hsideput utes = hsoutput.none;
///
/// Specidies the Use to which the DTR OUTPUT IS PUT (DEFAULT: NONE) ///
Public hsideput usedtr = hsoutput.none;
///
/// the character used to signal xon for x flow control (default: dc1) ////
Public ascii xonchar = asCII.NULL; // ascii.dc1;
///
/// The character used to signal Xoff for x flow control (default: DC3) /////
Public ascii xoffchar = ascii.null; // ascii.dc3;
// JH 1.2: Next Two defaults change to 0 to use new defaulting mechanism dependant on queue size.
///
//////////// (default: 0 = set to 1 / 10th of actual rxqueue size) /// public int rxhighwater = 0;
///
////////// (Default: 0 = set to 1 / 10th of actual rxqueue size) ///
Public int rXlowwater = 0;
///
/// Multiplier. Max Time for send in ms = (multiplier * characters) constant /// (Default: 0 = no timeout) ///
Public uint sendtimeoutmultiPlier = 0;
///
/// constant. Max time for send in ms = (multiplier * characters) Constant (default: 0) ///
Public uint sendtimeoutConstant = 0;
///
/// Requested Size for Receive Queue (Default: 0 = Use Operating System Default) ///
Public int rxqueue = 0;
///
/// Requested Size for Transmit Queue (Default: 0 = Use Operating System Default) ///
Public int TXQUE = 0;
///
/// if true, the port will automaticly re-open next sendness due /// to an error: false ////
Public Bool Autoreopen = False;
///
/// If true, subsequent Send commands wait for completion of earlier ones enabling the results /// to be checked. If false, errors, including timeouts, may not be detected, but performance /// may be better. ///
Public Bool Checkallsends = true;
///
/// pre-configures settings for MOST MODERN Devices: 8 Database, 1 Stop Bit, No Parity and /// One of the common handshake protocols. Change Individual Settings Later if Necessary. ///
///
The port to use (i.e. "COM1:")
///
The baud rate
///
The Handshake Protocol
Public Void SetStandard (String Port, Int Baud, Handshake HS)
{
Database = 8; stopbits = stopbits.one; PARITY = PARITY.NONE; port = port; baudrate = baud;
Switch (HS)
{
Case Handshake.none:
Txflowcts = false; txflowdsr = false; txflowx = false;
Rxflowx = false; useerts = hsoutput.online; usedtr = hsoutput.online;
TxwhenRxxoff = true; rxgatedsr = false;
Break;
Case Handshake.xonxoff:
Txflowcts = false; txflowdsr = false; txflowx = true;
Rxflowx = true; userts = hsoutput.online; usedtr = hsoutput.online;
TxwhenRxxoff = true; rxgatedsr = false;
Xonchar = ascii.dc1; xoffchar = ascii.dc3;
Break;
Case Handshake.cts:
Txflowcts = true; txflowdsr = false; txflowx = false;
Rxflowx = false; userts = hsoutput.handshake; usedtr = hsoutput.online;
TxwhenRxxoff = true; rxgatedsr = false;
Break;
Case Handshake.dsrdtr:
Txflowcts = false; txflowdsr = true; txflowx = false;
RxFlowx = false; userts = hsoutput.online; usedtr = hsoutput.handshake;
TxwhenRxxoff = true; rxgatedsr = false;
Break;
}
}
///
/// Save the Object in XML Format to a stream ///
///
Street to save the object to save
Public void saveasxml (stream s)
{
XMLSERIALIZER SR = New XmlSerializer (this.gettype ());
Sr.Serialize (s, this);
}
///
/// Create a new commbasesettings object initialised from xml data ////
///
Stream to loading the xml from
///
CommBasesettings Object
Public Static CommBasesettings LoadFromxml (Stream S)
{
Return LoadFromxml (S, TypeOf (CommBaseTings));
}
///
/// Create a new object loading members from the stream in XML format /// Derived class should call this from a static method ie:. /// return (ComDerivedSettings) LoadFromXML (s, typeof (ComDerivedSettings)); /// ///
Stream to loading the object from
///
Type of the derived object
///
Protected Static Commbasesettings LoadFromxml (Street S, Type T)
{
XMLSERIALIZER SR = New XMLSERIALIZER (T);
Try
{
Return (CommBasesettings) Sr.Deselialize (s);
}
Catch
{
Return NULL;
}
}
}
#Region "ASCII Defense" // JH 1.3: Corrected Sth -> StX (THANKS - Johan Thelin!) ///
/// Byte Type with Enumeration Constants for ASCII Control Codes. ///
Public Enum ascii: byte
{
///
/// null /////
NULL = 0x00,
///
/// SOH //////
SOH = 0x01,
///
/// stx /////
STX = 0x02,
///
/// etX /////
ETX = 0x03,
///
/// Eot ////
Eot = 0x04,
///
/// ////
ENQ = 0x05,
///
/// ////
ACK = 0x06,
///
/// ////
Bell = 0x07,
///
/// ////
BS = 0x08,
///
/// ////
HT = 0x09,
///
/// ////
LF = 0x0a,
///
/// ////
Vt = 0x0b,
///
/// ////
FF = 0x0c,
///
/// ////
Cr = 0x0d,
///
/// ////
SO = 0x0E,
///
/// ////
Si = 0x0f,
///
/// ////
DC1 = 0x11,
///
/// ////
DC2 = 0x12,
///
/// ////
DC3 = 0x13,
///
/// ////
DC4 = 0x14,
///
/// ////
NAK = 0x15,
///
/// ////
SYN = 0x16,
///
/// ////
ETB = 0x17,
///
/// ////
CAN = 0x18,
///
/// ////
EM = 0x19,
///
/// ////
Sub = 0x1a,
///
/// ////
ESC = 0x1b,
///
/// ////
FS = 0x1c,
///
/// ////
GS = 0x1d,
///
/// ////
RS = 0x1e,
///
/// ////
US = 0x1f,
////// ////
Sp = 0x20,
///
/// ////
Del = 0x7f
}
#ndregion
// jh 1.3: Added AltName Function, Portstatus Enum and isportavailable function.
///
/// Returns the alternative name of a com port i.e. ///com1 for com1: /// Some Systems Require this form number ost p p
///
Name in form com1 or com1:
///
Name in form
//./Com1
//./ " S;
}
///
/// Availability Status of a port /////
Public Enum Portstatus
{
///
/// port exissrs but is unavailable (may be open to noother program) ///
Unavailable = 0,
///
/// Available for USE /////
AVAILABLE = 1,
///
/// port does not exist ///
ABSENT = -1
}
///
/// Tests the availability of a named comm port. ///
///
Name of port
///
Availability of Port
Public portstatus isportavailable (String s)
{
INTPTR H;
h = Win32Com.CreateFile (s, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); if (== h (IntPtr) Win32Com.INVALID_HANDLE_VALUE) {if ( Marshal.GetLastWin32Error () == Win32Com.ERROR_ACCESS_DENIED) {return PortStatus.unavailable;} else {// JH 1.3: Automatically try AltName if supplied name fails: h = Win32Com.CreateFile (AltName (s), Win32Com.GENERIC_READ | win32Com. GENERIC_WRITE, 0, IntPtr.Zero, Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); if (== h (IntPtr) Win32Com.INVALID_HANDLE_VALUE) {if (Marshal.GetLastWin32Error () == Win32Com.ERROR_ACCESS_DENIED) {return PortStatus .unavailable;}}} win32com.closehandle (h); return portstatus.available;} ///
/// Opens the com port and configures it with the required settings //////
///
False if the port could not be opened
Public bool open ()
{
Win32com.dcb portdcb = new win32com.dcb ();
Win32com.commtimeouts Commtimeouts = New Win32com.commtimeouts ();
CommBasetdtings CS;
Win32com.Overlapped wo = new win32com.overlapped ();
Win32com.commprop CP;
IF (Online) Return False; CS = CommSttings ();
hPort = Win32Com.CreateFile (cs.port, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); if (hPort == (IntPtr) Win32Com.INVALID_HANDLE_VALUE) { if (Marshal.GetLastWin32Error () == Win32Com.ERROR_ACCESS_DENIED) {return false;} else {// JH 1.3: Try alternative name form if main one fails: hPort = Win32Com.CreateFile (AltName (cs.port), Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); if (hPort == (IntPtr) Win32Com.INVALID_HANDLE_VALUE) {if (Marshal.GetLastWin32Error () == Win32Com.ERROR_ACCESS_DENIED) {RETURN FALSE;} else {throw new commportException ("Port Open Failure");}}}} online = true;
//JH1.1: Changed from 0 to "magic number" to give instant return on ReadFile: CommTimeouts.ReadIntervalTimeout = Win32Com.MAXDWORD; CommTimeouts.ReadTotalTimeoutConstant = 0; CommTimeouts.ReadTotalTimeoutMultiplier = 0;
//JH1.2: 0 Does Not Seem To Mean Infinite on Non-NT Platforms, So Default It To 10 // Seconds Per Byte Which Should Be Enough for anyone. If (cs.sendtimeoutmultiplier == 0) {IF (System. Environment.OSVersion.Platform == System.PlatformID.Win32NT) {CommTimeouts.WriteTotalTimeoutMultiplier = 0;} else {CommTimeouts.WriteTotalTimeoutMultiplier = 10000;}} else {CommTimeouts.WriteTotalTimeoutMultiplier = cs.sendTimeoutMultiplier;} CommTimeouts.WriteTotalTimeoutConstant = cs.sendTimeoutConstant; Portdcb.init ((cs.parity == parity.od) || (cs.parity == parity.even)), cs.txflowcts, cs.txflowdsr, (int) cs.usedtr, cs.rxgatedsr,! Cs .txwhenrxxoff, cs.txflowx, cs.rxflowx, (int) cs.userts; portdcb.baudrate = cs.baudrate; portdcb.bytesize = (byte) cs.database; portdcb.parity = (byte) cs.parity; portdcb .Stopbits = (byte) cs.stopbits; portdcb.xoffchar = (byte) cs.xOffchar; portdcb.xonchar = (byte) cs.xonchar; if ((cs.rxqueue! = 0) || (CS) .txqueue! = 0))) IF (! Win32com.Setupcomm (hport, (uint) cs.rxqueue, (uint) cs.txqueue) throwexception ("Bad Queue Settings");
// JH 1.2:. Defaulting mechanism for handshake thresholds - prevents problems of setting specific // defaults which may violate the size of the actually granted queue If the user specifically sets // these values, it's their problem if ((cs.rxLowWater! == 0) || (cs.rxhighwater == 0)) {if (! Win32com.getCommproperties (HPORT, OUT CP)) cp.dwcurrentrxqueue = 0; if (cp.dwcurrentrxqueue> 0) {// if we can determine The Queue Size, Default To 1 / 10th, 8 / 10th, 1 / 10th. // Note That Highwater Is Measured from Top of Queue. Portdcb.xOfflim = Portdcb.xonlim = (Short) ((int) cp.dwcurrentrxqueue / 10 } Else {// if we do not know the queue size, set value low defaults for safety. Portdcb.xofflim = portdcb.xonlim = 8;}} else {portdcb.xofflim = (short) cs.RxHighwater; portdcb. Xonlim = (short) cs.rxlowwater;} if (! Win32com.setcommstate (HPORT, REF portdcb)) throwexception ("Bad CoM Settings"); if (! Win32com.setcommtimeout) (Hport, Ref Comm THROWEXCEPTION ("Bad Timeout Settings"); statebrk = 0; if (cs.usedtr == hsoutput.none) statedtr = 0; if (cs.usedtr == hsoutput.online) StatedTR = 1; IF (CS. Userts == hsoutput.none) staterts = 0; if (cs.userts == hsoutput.online) staterts = 1;
Checksends = cs.checkallsends; wo.offset = 0; wo.offsetHigh = 0; if (checksends) hevent = writeevent.handle; else wo.Hevent = INTPTR.ZERO;
Ptruwo = Marshal.allochglobal (Marshal.SizeOf (WO));
Marshal.StructureToPtr (wo, ptrUWO, true); writeCount = 0; //JH1.3: empty [0] = true; dataQueued = false; rxException = null; rxExceptionReported = false; rxThread = new Thread (new ThreadStart (this. ReceiveThread)); rxThread.Name = "CommBaseRx"; rxThread.Priority = ThreadPriority.AboveNormal; rxThread.Start (); // JH1.2:. More robust thread start-up wait startEvent.WaitOne (500, false);
Auto = false; if (afteropen ()) {auto = cs.autoreopen; return true;} else {close (); return false;}
}
///
/// Adder: SYMA Date: 2004-06-07 // Open the serial port /// according to the port and baud rate set
///
///
///
Public Bool Open (String Port, Int Baud)
{
Win32com.dcb portdcb = new win32com.dcb ();
Win32com.commtimeouts Commtimeouts = New Win32com.commtimeouts ();
CommBasetdtings CS;
Win32com.Overlapped wo = new win32com.overlapped ();
Win32com.commprop CP;
IF (Online) Return False; CS = CommSettings (); cs.port = port; cs.baudrate = baud;
hPort = Win32Com.CreateFile (cs.port, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); if (hPort == (IntPtr) Win32Com.INVALID_HANDLE_VALUE) { if (Marshal.GetLastWin32Error () == Win32Com.ERROR_ACCESS_DENIED) {return false;} else {// JH 1.3: Try alternative name form if main one fails: hPort = Win32Com.CreateFile (AltName (cs.port), Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); if (hPort == (IntPtr) Win32Com.INVALID_HANDLE_VALUE) {if (Marshal.GetLastWin32Error () == Win32Com.ERROR_ACCESS_DENIED) {RETURN FALSE;} else {throw new commportException ("Port Open Failure");}}}} online = true;
//JH1.1: Changed from 0 to "magic number" to give instant return on ReadFile: CommTimeouts.ReadIntervalTimeout = Win32Com.MAXDWORD; CommTimeouts.ReadTotalTimeoutConstant = 0; CommTimeouts.ReadTotalTimeoutMultiplier = 0;
//JH1.2: 0 Does Not Seem To Mean Infinite on Non-NT Platforms, So Default It To 10 // Seconds Per Byte Which Should Be Enough for anyone. If (cs.sendtimeoutmultiplier == 0) {IF (System. Environment.OSVersion.Platform == System.PlatformID.Win32NT) {CommTimeouts.WriteTotalTimeoutMultiplier = 0;} else {CommTimeouts.WriteTotalTimeoutMultiplier = 10000;}} else {CommTimeouts.WriteTotalTimeoutMultiplier = cs.sendTimeoutMultiplier;} CommTimeouts.WriteTotalTimeoutConstant = cs.sendTimeoutConstant; Portdcb.init ((cs.parity == parity.od) || (cs.parity == parity.even)), cs.txflowcts, cs.txflowdsr, (int) cs.usedtr, cs.rxgatedsr,! Cs .txwhenrxxoff, cs.txflowx, cs.rxflowx, (int) cs.userts; portdcb.baudrate = cs.baudrate; portdcb.bytesize = (byte) cs.database; portdcb.parity = (byte) cs.parity; portdcb .Stopbits = (byte) cs.stopbits; portdcb.xoffchar = (byte) cs.xOffchar; portdcb.xonchar = (byte) cs.xonchar; if ((cs.rxqueue! = 0) || (CS) .txqueue! = 0))) IF (! Win32com.Setupcomm (hport, (uint) cs.rxqueue, (uint) cs.txqueue) throwexception ("Bad Queue Settings");
// JH 1.2:. Defaulting mechanism for handshake thresholds - prevents problems of setting specific // defaults which may violate the size of the actually granted queue If the user specifically sets // these values, it's their problem if ((cs.rxLowWater! == 0) || (cs.rxhighwater == 0)) {if (! Win32com.getCommproperties (HPORT, OUT CP)) cp.dwcurrentrxqueue = 0; if (cp.dwcurrentrxqueue> 0) {// if we can determine The Queue Size, Default To 1 / 10th, 8 / 10th, 1 / 10th. // Note That Highwater Is Measured from Top of Queue. Portdcb.xOfflim = Portdcb.xonlim = (Short) ((int) cp.dwcurrentrxqueue / 10 } Else {// if we do not know the queue size, set value low defaults for safety. Portdcb.xofflim = portdcb.xonlim = 8;}} else {portdcb.xofflim = (short) cs.RxHighwater; portdcb. Xonlim = (short) cs.rxlowwater;} if (! Win32com.setcommstate (HPORT, REF portdcb)) throwexception ("Bad CoM Settings"); if (! Win32com.setcommtimeout) (Hport, Ref Comm THROWEXCEPTION ("Bad Timeout Settings"); statebrk = 0; if (cs.usedtr == hsoutput.none) statedtr = 0; if (cs.usedtr == hsoutput.online) StatedTR = 1; IF (CS. Userts == hsoutput.none) staterts = 0; if (cs.userts == hsoutput.online) staterts = 1;
Checksends = cs.checkallsends; wo.offset = 0; wo.offsetHigh = 0; if (checksends) hevent = writeevent.handle; else wo.Hevent = INTPTR.ZERO;
Ptruwo = Marshal.allochglobal (Marshal.SizeOf (WO));
Marshal.StructureToPtr (wo, ptrUWO, true); writeCount = 0; //JH1.3: empty [0] = true; dataQueued = false; rxException = null; rxExceptionReported = false; rxThread = new Thread (new ThreadStart (this. ReceiveThread)); rxThread.Name = "CommBaseRx"; rxThread.Priority = ThreadPriority.AboveNormal; rxThread.Start (); // JH1.2:. More robust thread start-up wait startEvent.WaitOne (500, false);
Auto = false; if (afteropen ()) {auto = cs.autoreopen; return true;} else {close (); return false;}
}
///
/// Closes the COM port. ///
Public void close ()
{
IF (Online)
{
Auto = FALSE;
BeforeClose (false);
INTERNALCLOSE ();
RxException = NULL;
}
}
Private void internalclose ()
{
Win32com.cancelio (HPORT);
IF (RXTHREAD! = NULL)
{
Rxthread.abort ();
// jh 1.3: Improve Robustness of Close In Case Were Followed by Open:
Rxthread.join (100);
Rxthread = NULL;
}
Win32com.closehandle (HPORT);
IF (Ptruwo! = INTPTR.ZERO) Marshal.Freehglobal (Ptruwo);
STATERTS = 2;
StateDTR = 2;
Statebrk = 2;
ONLINE = FALSE;
}
///
/// for idisposable ///
Public void dispose () {close ();
///
/// destructor (just in case) //////
~ Commbase () {close ();
///
/// true ife. ///
Public Bool Online {Get {if (! Online) Return False; else returnch checkonline ();}}
///
/// block unsil alltes in the queue have been transmitted. ///
Public void flush ()
{
Checkonline ();
CheckResult ();
}
///
/// Set the baud rate ///
///
Public Void ResetBaudrate (int BDR)
{
Win32com.dcb dcb = new xst.xstcomm.base.win32com.dcb ();
Win32com.getCommState (HPORT, REF DCB);
Dcb.baudrate = BDR;
Win32com.Setcommstate (HPORT, REF DCB); purgein ();
Purgeout ();
}
///
/// Remove the read buffer content ///
Private void purgein ()
{
//Win32com.purgecomm (Hport ,Win32com.purge_rxabort | Win32com.purge_rxclear);
CANCELREAD ();
Purgeread ();
}
///
/// Clear write buffer content ///
Private void purgeout ()
{
//Win32com.purgecomm (Hport ,win32com.purge_txabort | win32com.purge_txclear);
CANCELWRITE ();
Purgewrite ();
}
private bool PurgeRead () {return (Win32Com.PurgeComm (hPort, Win32Com.PURGE_RXCLEAR));} private bool PurgeWrite () {return (Win32Com.PurgeComm (hPort, Win32Com.PURGE_TXCLEAR));} private bool CancelRead () {return ( Win32com.purgecomm (hport, win32com.purge_rxabort);} private bool can Cancelwrite () {return (Win32com.purgecomm (hport, win32com.purge_txabort);}
///
/// Use this to throw exceptionins in derived classes. CORRECTLY HANDLES THREADING ISSUES /// and closs the port if neseary. ///
///
Description of fault
Protected void throwexception (String REASON)
{
IF (thread.currentthread == rxthread)
{
Throw new commportException (REASON);
}
Else
{
IF (Online)
{
BeforeClose (True);
INTERNALCLOSE ();
}
IF (rxException == null)
{
Throw new commportException (REASON);
}
Else
{
Throw new commitexception (rxexception);
}
}
}
///
/// Queues BYTES for Transmission. ///
///
Array of Bytes to Be Sent
protected void send (byte [] tosend)
{
Uint Sent = 0;
Checkonline ();
CheckResult ();
Writecount = tosend.getLength (0);
IF (Win32com.Writefile (Hport, Tosend, (UINT) WRITECUNT, OUT SENT, PTRUWO)
{
Writecount - = (int) SENT;
}
Else
{
IF (Marshal.getlastwin32error ()! = Win32com.ErroROR_IO_PENDING) ThrowException ("Send Failed");
//JH1.3:
Dataqueued = True;
}
}
///
/// queues a single byte for transmission. //////
Byte to be Sent
Protected Void Send (Byte Tosend)
{
Byte [] b = new byte [1];
B [0] = TOSEND;
Send (b);
}
Private void checkresult () {uint Sent = 0;
// JH 1.3:. Fixed a number of problems working with checkSends == false Byte counting was unreliable because // occasionally GetOverlappedResult would return true with a completion having missed one or more previous // completions The test for ERROR_IO_INCOMPLETE was incorrectly for ERROR_IO_PENDING. INSTEAD.
if (writeCount> 0) {if (Win32Com.GetOverlappedResult (hPort, ptrUWO, out sent, checkSends)) {if (checkSends) {writeCount - = (int) sent; if (writeCount = 0!) ThrowException ( "Send Timeout" ); Writecount = 0;}} else {if (Marshal.getlastwin32ERROR ()! = Win32com.error_io_incumplete) throwexception ("Write Error");}}}
///
/// sends a protocol byte immediely ahead of any queued bytes. ///
///
Byte To Send
Protected void sendimmediate (byte tosend)
{
Checkonline ();
IF (! Win32com.TransmitCommchar (HPORT, TOSEND)) ThrowException ("Transmission Failure);
}
///
/// DELAY processing. ///
///
Milliseconds to delay by
Protected Void Sleep (Int MilliseConds)
{
Thread.sleep (MilliseConds);
}
///
/// REPRESENTS The Status of the MODEM Control InputiGnals. ///
Public struct modemstatus
{
Private uint status;
INTERNAL MODEMSTATUS (UINT VAL) {status = val;}
///
/// Condition of the clear to send signal. ///
Public Bool CTS {Get {Return (status & win32com.ms_cts_on)! = 0);}}
///
/// Condition of the data set ready signal. ///
Public Bool DSR {Get {Return (status & win32com.ms_dsr_on)! = 0);}} ///
/// Condition of the receive line status detection signal. ///
Public Bool rlsd {get {return (status & win32com.ms_rlsd_on)! = 0);}}
///
/// Condition of the Ring Detection signal. ///
Public Bool Ring {Get {Return ((status & win32com.ms_ring_on)! = 0);}}
}
///
/// Gets The Status of the MODEM Control Input Signals. ///
///
Modem Status Object
Protected ModemStatus getModemStatus ()
{
UINT F;
Checkonline (); if (! Win32com.getCommodemStatus (HPORT, OUT F)) throwexception ("Unexpected Failure"); Return New ModemStatus (f);}
///
/// REPRESENTS The Current Condition of The Port Queues. ///
Public struct queuesttus
{
Private uint status;
PRIVATE UINT INQUEUE;
PRIVATE uint Outqueue;
Private uint inqueueSize;
PRIVATE UINT OUTQUEESIZE;
INTERNAL Queuesttus (uint stat, uint inq, uint outq, uint inqs, uint out {status = stat; inqueue = inq; outqueue = Outq; inQueueSize = inqs; outqueueesize = Outqs;} ///
/// output is blocked by CTS Handshaking. ///
Public bool ctshold {get {return (status & win32com.comstat.fctshold)! = 0);}}
///
/// output is blocked by DRS HANDSHAKING. ///
Public Bool DSRHOLD {Get {Return ((status & win32com.comstat.fdsrhold)! = 0);}}
///
/// output is blocked by rlsd haandshaking. ///
Public Bool rlsdhold {get {return ((status & win32com.comstat.frlsdhold)! = 0);}}
///
/// output is blocked Because Software Handshaking IS enabled and xoff Was received. ///
Public Bool Xoffhold {Get {Return ((Status & Win32com.comstat.fxoffhold)! = 0);}}
///
/// Output WAS Blocked Because Xoff WAS Sent and this station station station} (status & win32com.comstat.fxoffsent)! = 0);}}
///
//////////////////////////////////////////////////////////>
Public bool immediatewaiting {get {return ((status & win32com.comstat.ftxim)! = 0);}}
///
/// Number of bytes waiting in the input queue. ///
PUBLIC Long Inqueue {Get {Return (Long) Incueue;}}
///
/// Number of bytes waiting for transmission. ///
PUBLIC Long Outqueue {Get {Return (long) Outqueue;}}
///
/// Total Size of INPUT Queue (0 means information unavailable) ///
PUBLIC Long InqueueSize {Get {Return (long) inQueueSize;}}
///
/// Total Size of Output Queue (0 means Information unavailable) ///
Public long outqueesize {get {return (long) OutqueueSize;}}
///
/// ////
///
Public override string toString ()
{
StringBuilder M = New StringBuilder ("The Reception Queue IS", 60);
IF (InqueueSize == 0)
{
M.Append ("of unknown size and");
}
Else
{
M.Append (InqueueSize.toString () "BYTES long and");
}
IF (inqueue == 0)
{
M.APpend ("IS Empty.");
}
Else if (inqueue == 1)
{
M.apore ("Contains 1 Byte.");
}
Else
{
M.Append ("contains");
M.Append (Inqueue.toString ());
M.Append ("bytes.");
}
M.Append ("THE Transmission Queue IS";
IF (OutqueueSize == 0)
{
M.Append ("of unknown size and");
}
Else
{
M.Append (OutqueueSize.toString () "BYTES long and");
}
IF (Outqueue == 0)
{
M.Append ("is empty");
}
Else if (Outqueue == 1)
{
M.Append ("Contains 1 Byte. IT IS");
Else
{
M.Append ("contains");
M.Append (Outqueue.toString ());
M.Append ("Bytes. IT IS");
}
IF (Outqueue> 0)
{
IF (CTShold || DSRhold || rlsdhold || Xoffhold || Xoffsent)
{
M.Append ("Holding On");
IF (CTSHOLD) M.APpend ("CTS");
IF (DSRHOLD) M.APpend ("DSR");
IF (rlsdhold) M.Append ("rlsd");
IF (Xoffhold) M.Append ("RX XOFF");
IF (XOFFSENT) M.APpend ("TX Xoff");
}
Else
{
M.Append ("Pumping Data");
}
}
M.Append (". The immediate buffer is");
IF (immediatewaiting)
M.Append ("full.");
Else
M.APpend ("Empty.");
Return m.toString ();
}
}
///
/// Get the status of the queues ///
///
Queue Status Object
protected queuestatus getQueuesttatus ()
{
Win32com.comstat CS;
Win32com.commprop CP;
UINT ER;
CheckOnline (); if (Win32Com.ClearCommError (hPort, out er, out cs)!) ThrowException ( "Unexpected failure"); if (Win32Com.GetCommProperties (hPort, out cp)!) ThrowException ( "Unexpected failure"); return New queuesttus (cs.flags, cs.cbinque, cs.cboutque, cp.dwcurrentrxqueue, cp.dwcurrenttxqueue);}
// jh 1.3. Added for this version. ///
/// Test if the line is congested (data being queued for send faster than it is being dequeued) /// This detects if baud rate is too slow or if handshaking is not allowing enough transmission /// time. It should be called AT REASONABLY Long Fixed Intervals. If Data Has Been Sent During /// The Interval, Congest IS Reported If The Queue Was Never Empty During The Interval. ///
///
True if congsted
protected bool iscongested ()
{
BOOL E;
IF (! Dataqueue) Return False;
Lock (EMPTY) {E = Empty [0]; EMPTY [0] = false;} Dataqueueue
Return! E;
}
///
/// true if the rts pin is controllable via the rts printy ///
Protected Bool RTSAVAILABLE {Get {Return (Staterts <2);}}
///
/// set the state of the rts modem control output ///
Protected Bool RTS
{
set
{
IF (Staterts> 1) Return;
Checkonline ();
IF (Value)
{
IF (Win32com.escapecommfunction (hport, win32com.setrs)
STATERTS = 1;
Else
ThrowException ("Unexpected Failure";
}
Else
{
IF (Win32com.escapecommfunction))
// JH 1.3: WAS 1, Should BE 0:
STATERTS = 0;
Else
ThrowException ("Unexpected Failure";
}
}
get
{
Return (staterts == 1);
}
}
///
/// true if the dtr pin is controllable via the DTR Property ///
Protected Bool DTRAVAILABLE {Get {Return (StateDtr <2);}}
///
//////////////////
Protected Bool DTR
{
set
{
IF (StateDtr> 1) Return;
Checkonline ();
IF (Value)
{
IF (Win32com.escapecommfunction (hport, win32com.setdtr))
StateDtr = 1;
Else
ThrowException ("Unexpected Failure";
}
Else
{
IF (Win32com.escapecommfunction (hport, win32com.clrdtr))
StateDTR = 0;
Else
ThrowException ("Unexpected Failure";
}
}
get
{
Return (StateDtr == 1);
}
}
///
/// assert or remove a break condition from the transmission line ///
Protected Bool Break
{
set
{
IF (Statebrk> 1) Return;
Checkonline ();
IF (Value)
{
IF (Win32com.escapecommfunction) (HPORT, WIN32COM.SetBreak))
Statebrk = 0;
Else
ThrowException ("Unexpected Failure";
}
Else
{
IF (Win32com.escapecommfunction (HPORT, WIN32COM.CLRBREAK)
Statebrk = 0;
Else
ThrowException ("Unexpected Failure";
}
}
get
{
Return (statebrk == 1);
}
}
///
/// Override this to provide settings. (NB this is caled during open method) ///
///
Commbasesettings, or derived Object with required settings initialia
Protected Virtual CommBasesettings CommSettings () {Return New CommbaseSettings ();
///
/// Override this to provide processing after the port is openned (i.e. To configure recee /// device or just check presence). ///
///
False to close the port again
Protected Virtual Bool afterOpen () {Return True;}
///
/// Override this to provide processing prior to port closure. ///
///
True if closing due to an error
Protected Virtual Void BeforeClose (Bool Error) {}
///
/// Override this to process received Bytes. ///
///
The byte tria tas received
Protected Virtual Void OnRxchar (Byte Ch) {}
///
/// Override this to take action means (i.e. alltes have actual "/// been sample, not just queued). ///
Protected Virtual Void ONTXDODONE () {}
///
//////////////////////////>
Protected virtual void onbreak () {}
// jh 1.3: Deleted Onring () Which Was Never Called: Use onstatuschange INSTEAD (THANKS JIM FOSTER)
///
/////////////////////////////////>
///
The Status Inputs That Have Changed State
///
The State of The Status Inputs
Protected Virtual Void OnStatusChange (ModemStatus Mask, Modemstatus State) {}
///
/// Override this to take a the action thread closes due to an exception being thrown. ///
///
The Exception Which Was Thrown
Protected Virtual Void OnRxexception (Exception E) {}
private void ReceiveThread () {byte [] buf = new Byte [1]; uint gotbytes; bool starting; starting = true; AutoResetEvent sg = new AutoResetEvent (false); Win32Com.OVERLAPPED ov = new Win32Com.OVERLAPPED ();
INTPTR UNMANAGED; INTPTR umask; uint eventmask = 0; unmanagedov = Marshal.allochglobal (Marshal.SizeOf (OV)); umask = marshal.allochglobal (Marshal.Sizeof (eventmask);
Ov.offset = 0; ov.offsethiGH = 0; ov.hevent = sg.handle; Marshal.StructureToptr (OV, Unmanagedov, True);
try {while (true) {if (Win32Com.SetCommMask (hPort, Win32Com.EV_RXCHAR |! Win32Com.EV_TXEMPTY | Win32Com.EV_CTS | Win32Com.EV_DSR | Win32Com.EV_BREAK | Win32Com.EV_RLSD | Win32Com.EV_RING | Win32Com.EV_ERR)) { Throw new commitException ("IO Error [001]");} Marshal.writeInt32 (Umask, 0); // JH 1.2: Tells the main thread That Thread is Ready for action. If (starting) {Startevent.Set () ; starting = false;} if (! Win32Com.WaitCommEvent (hPort, uMask, unmanagedOv)) {if (Marshal.GetLastWin32Error () == Win32Com.ERROR_IO_PENDING) {sg.WaitOne ();} else {throw new CommPortException ( "IO Error [002] ");}} EventMask = (uint) Marshal.Readint32 (umask); if (EventMask & Win32com.ev_err)! = 0) {uint32 errs; if (Win32com.clearcommorror (Hport, Out Errs, INTPTR) . Zero) {// jh 1.2: Break condition Has An Error flag and and an Event flag. Not Sure IF Both // Are ALWAY s raised, so if CE_BREAK is only error flag ignore it and set the EV_BREAK // flag for normal handling. Also made more robust by handling case were no recognised // error was present in the flags. (Thanks to Fred Pittroff for finding this Problem!) int EC = 0; StringBuilder S = New StringBuilder ("UART Error:", 40); if ((Errs & Win32com.ce_frame)! = 0) {s = S.Append ("framing,"); EC } IF ((Errs & Win32com.ce_ioe)! = 0) {s = S.Append ("IO,"); EC ;} f ((Errs & Win32com.ce_Overrun)! = 0) {s = S.Append ("Overrun,"); EC ;} IF ((Errs &)
Win32com.ce_rxover)! = 0) {S = S.Append ("Receive Cverflow,"); EC ;} if ((Errs & Win32com.ce_RXPARITY)! = 0) {s = S.Append ("Parity,") ; EC ;} if ((errs & win32com.ce_txfull! = 0) {s = S.Append ("Transmit overflow,"); EC ;} if (EC> 0) {s.ley = S.LENGTH - 1 Throw new commportException (S.ToString ());} else {if (errs == win32com.ce_break) {eventmask | = Win32com.ev_break;} else {throw new commportException ("IO Error [003]);}} } Else {throw new commportException ("IO Error [003]");}}} f ((EventMask & Win32com.ev_rxchar)! = 0) {DO {gotbytes = 0; if (! Win32com.readfile (Hport, BUF, 1 Out gotbytes, unmanagedov) {// jh 1.1: removed error_IO_PENDING HANDLING As Comm Timeouts Have Now // Been Set So Readfile Returns Immediately, this Avoids Use of Cancelio // Which Was Caus ING LOSS of Data. Thanks To Daniel Moth for Suggesting this // Might Be a problem, and to many Others for Reporting That It was! int x = marshal.getlastwin32error ();
Throw new commportException ("IO Error [004]");} if (gotbytes == 1) OnRxChar (BUF [0]);} while (gotbytes> 0);} if ((EventMask & Win32com.ev_txempty)! = 0 ) {//JH1.3: Lock (EMPTY) EMPTY [0] = true; ONTXDONE ();} IF ((Eventmask & Win32com.ev_break)! = 0) Onbreak (); uint i = 0; if ((Eventmask) & Win32com.ev_cts)! = 0) I | = WIN32COM.MS_CTS_ON; IF ((EventMask & Win32com.ev_dsr)! = 0) i | = Win32com.ms_DSR_ON; IF ((Eventmask & Win32com.ev_rlsd)! = 0) i | = WIN32COM.MS_RLSD_ON; IF ((EventMask & Win32Com.ev_ring)! = 0) i | = Win32com.ms_ring_on; if (i! = 0) {uint f; if (! Win32com.getcommodemstatus (Hport, Out F)) throw new CommPortException ( "IO Error [005]"); OnStatusChange (new ModemStatus (i), new ModemStatus (f));}}} catch (Exception e) {// JH 1.3: Added for shutdown robustness (Thanks to Fred PitTroff, Mark Behner and Kevin Williamson!),. Win32com.cancelio (HPORT); IF (Umask ! = IntPtr.Zero) Marshal.FreeHGlobal (uMask); if (unmanagedOv = IntPtr.Zero) Marshal.FreeHGlobal (unmanagedOv);! If ((e is ThreadAbortException!)) {RxException = e; OnRxException (e);}} }
private bool CheckOnline () {if (!! (rxException = null) && (rxExceptionReported)) {rxExceptionReported = true; ThrowException ( "rx");} if (online) {// JH 1.1: Avoid use of GetHandleInformation for W98 compatability . if (hPort = (System.IntPtr) Win32Com.INVALID_HANDLE_VALUE!) return true; ThrowException ( "Offline"); return false;} else {if (auto) {if (Open ()) return true;} ThrowException ( "Offline "); Return false;}}}
///
/// Overlays CommBase to provide line or packet oriented communications to derived classes. Strings /// are sent and received and the Transact method is added which transmits a string and then blocks until /// a reply string has been received (subject to a timeout). ///
Public Abstract Class Comline: CommBase
{
Private byte [] rxbuffer;
Private uint rxbufferp = 0;
Private ASCII RXTERM;
PRIVATE ASCII [] TXTERM;
Private ascii [] rxfilter;
Private string rxstring = ""
Private manualReveTevent Transflag = New ManualReveTevent (TRUE);
PRIVATE UINT TRANSTIMEOUT;
///
/// Extends Commbasesettings to add the settings buy by circline. ////
Public Class CommLinesettings: commit.commbasesettings
{
///
/// Maximum size of review string (Default: 256) //////
Public int rxstringBuffersize = 256;
///
/// ASCII Code That Terminates A Received String (Default: CR) ///
Public ascii rxterminator = ascii.cr;
///
/// ASCII Codes That Will BE ignored in received string (Default: null) ///
Public ASCII [] RXFilter;
///
/// Maximum Time (MS) for the Transact Method to Complete (Default: 500) ///
Public int transacttimeout = 500;
///
/// ASCII Codes Transmitted After Each Send String /// Public ASCII [] TXTERMINATOR;
///
/// Get setting information from the XML file ///
///
///
Public Static New CommlineSettings LoadFromXML (stream s)
{
Return (CommLinesettings) LoadFromxml (S, TypeOf (CommLineSetting));
}
}
///
/// Queue the ascii representation of a string and then the set terminator bytes for sending. ///
///
String to bas.
Protected Void Send (String Tosend)
{
// jh 1.1: Use static encoder for effect. Thanks to PROF. Dr. Peter Jesorsky!
UINT L = (uint) Encoding.ascii.getbytecount (TOSEND);
IF (txterm! = null) L = (uint) TXTERM.GETLENGTH (0);
Byte [] b = new byte [l];
Byte [] s = encoding.ascii.getbytes (TOSEND);
INT I;
For (i = 0; (i <= s.getupperbound (0)); i ) b [i] = s [i];
IF (TXTERM! = NULL) for (int J = 0; (j <= txterm.getupperbound (0)); J , i ) B [i] = (byte) TXTERM [J];
Send (b);
}
///
/// transmits the ascii representation of a string followed by the set terminator bytes and life /// awaits a response string. ///
///
The string to be slow.
///
The response string.
Protected string transact (String Tosend)
{
Send (tosend);
Transflag.reset ();
IF (! Transflag.waitone ((int) TRANSTIMEOUT, FALSE)) ThrowException ("Timeout");
String S;
Lock (rxstring) {s = rxstring;}
Return S;
}
///
/// if a derived class overrides comsettings (), IT Must Call this prior to return the settings to ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Class Containing the appropriate settings.
Protected Void Setup (Commlinesettings S)
{
Rxbuffer = new byte [s.rxstringbuffersize];
RXTERM = S.Rxterminator;
Rxfilter = s.rxfilter;
TRANSTIMEOUT = (uint) S.TransActTimeout; TXTERM = S.TXTERMINATOR;
}
///
/// Override this to process unsolicited Input Lines (not a result of transact). ///
///
String containing the receivated ascii text.
Protected Virtual Void OnRxline (String s) {}
///
/// According to the byte acceptance data ///
///
Protected Override Void OnRxchar (Byte Ch)
{
ASCII CA = (ASCII) CH;
IF ((CA == RXTERM) || (RxBufferp> rxbuffer.getupperbound (0)))
{
// jh 1.1: Use static encoder for effect. Thanks to PROF. Dr. Peter Jesorsky!
Lock (rxstring) {rxstring = encoding.ascii.getstring (rxbuffer, 0, (int) rxbufferp);}
RxBufferp = 0;
IF (Transflag.Waitone (0, FALSE))
{
OnRxline (rxstring);
}
Else
{
Transflag.set ();
}
}
Else
{
BOOL WR = True;
IF (RxFilter! = NULL)
{
For (int i = 0; i <= rxfilter.getupperbound (0); i ) IF (RxFilter [i] == ca) WR = FALSE;
}
IF (WR)
{
RxBuffer [rxbufferp] = ch;
RxBufferp ;
}
}
}
}
///
/// Exception use for all errors. /////
Public Class CommPortext: ApplicationException
{
///
/// constructor for raising direct exceptions //////
///
Description of error
Public CommPortexception (String DESC): Base (DESC) {}
///
/// Constructor for Re-raising Exceptions from receive thread ///
///
Inner Exception Raised on Receive Thread
Public CommPortexception (Exception E): BASE ("Receive Thread Exception", E) {}
}
INTERNAL CLASS WIN32COM {
///
/// Opening Testing and Closing The port handle. ///
[DLLIMPORT ("kernel32.dll", setLastError = true)]
INTERNAL Static Extern INTPTR CREATEFILE (STRING LPFILENAME, UINT32 DWDESIREDACCESS, UINT32 DWSHAREMODE,
INTPTR LPSECurityAttributes, uint32 dwcreationdisposition, uint32 dwflagsandattributes, intptr htemplatefile;
// Constants for errors: internal const UInt32 ERROR_FILE_NOT_FOUND = 2; internal const UInt32 ERROR_INVALID_NAME = 123; internal const UInt32 ERROR_ACCESS_DENIED = 5; internal const UInt32 ERROR_IO_PENDING = 997; internal const UInt32 ERROR_IO_INCOMPLETE = 996;
// Constants for return value: INTERNAL const INT32 invalid_handle_value = -1;
// Constants for dwflagsandattributes: internal const uint32 file_flag_overlapped = 0x40000000;
// constants for dwcreationdisposition: internal const uint32 open_exiSTING = 3;
// constants for dwdesiredaccess: internal const uint32 generic_read = 0x80000000; INTERNAL const uint32 generic_write = 0x40000000;
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean CloseHandle (INTPTR HOBJECT);
///
/// manipulating the communications settings. ///
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean getcommstate (INTPTR HFILE, REF DCB LPDCB);
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean getcommtimeouts (INTPTR HFILE, OUT COMMTIMEOUTS LPCOMMTIMEOUTS);
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean BuildcommdcBandTimeouts (String LPDEF, REF DCB LPDCB, Ref Commtimeouts LPCommtimeout);
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean SetCommState (INTPTR HFILE, [IN] REF DCB LPDCB);
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean setcommtimeouts (INTPTR HFILE, [IN] Ref strtimeouts lpcommtimeout;
[DllImport ( "kernel32.dll")] internal static extern Boolean SetupComm (IntPtr hFile, UInt32 dwInQueue, UInt32 dwOutQueue); [StructLayout (LayoutKind.Sequential)] internal struct COMMTIMEOUTS {// JH 1.1: Changed Int32 to UInt32 to allow setting to MAXDWORD internal UInt32 ReadIntervalTimeout; internal UInt32 ReadTotalTimeoutMultiplier; internal UInt32 ReadTotalTimeoutConstant; internal UInt32 WriteTotalTimeoutMultiplier; internal UInt32 WriteTotalTimeoutConstant;} // JH 1.1: Added to enable use of "return immediately" timeout internal const UInt32 MAXDWORD = 0xffffffff;.
[StructLayout (LayoutKind.Sequential)] internal struct DCB {internal Int32 DCBlength; internal Int32 BaudRate; internal Int32 PackedValues; internal Int16 wReserved; internal Int16 XonLim; internal Int16 XoffLim; internal Byte ByteSize; internal Byte Parity; internal Byte StopBits; internal Byte INTERNAL BYTE ERRORCHAR; Internal Byte EOFCHAR; Internal Byte Evtchar; Internal INT16 WRESERVED1;
internal void init (bool parity, bool outCTS, bool outDSR, int dtr, bool inDSR, bool txc, bool xOut, bool xIn, int rts) {// JH 1.3:! Was 0x8001 ans so not setting fAbortOnError - Thanks Larry Delby DCBlength = 28; packedvalues = 0x4001; if (Parity) PackedValues | = 0x0002; if (outcts) packedValues | = 0x0004; if (outdsr) PackedValues | = 0x0008; PackedValues | = ((DTR & 0x0003) << 4); IF INDSR) PackedValues | = 0x0040; IF (TXC) PackedValues | = 0x0080; if (xout) PackedValues | = 0x0100; if (xin) PackedValues | = 0x0200; PackedValues | = ((RTS & 0x0003) << 12);
}
///
/// reading and Writing. ///
[DLLIMPORT ("kernel32.dll", setLastError = true)]
INTERNAL Static Extern Boolean Writefile (INTPTR FFILE, BYTE [] lpbuffer, uint32 nnumberofbytestowrite,
OUT uint32 lpnumberofbyteswritten, intptr lpoverlapped;
[StructLayout (LayoutKind.Sequential)] internal struct OVERLAPPED {internal UIntPtr Internal; internal UIntPtr InternalHigh; internal UInt32 Offset; internal UInt32 OffsetHigh; internal IntPtr hEvent;}
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean SetCommmask (INTPTR HFILE, UINT32 DWEVTMASK);
// Constants for dwEvtMask: internal const UInt32 EV_RXCHAR = 0x0001; internal const UInt32 EV_RXFLAG = 0x0002; internal const UInt32 EV_TXEMPTY = 0x0004; internal const UInt32 EV_CTS = 0x0008; internal const UInt32 EV_DSR = 0x0010; internal const UInt32 EV_RLSD = 0x0020; internal const UInt32 EV_BREAK = 0x0040; internal const UInt32 EV_ERR = 0x0080; internal const UInt32 EV_RING = 0x0100; internal const UInt32 EV_PERR = 0x0200; internal const UInt32 EV_RX80FULL = 0x0400; internal const UInt32 EV_EVENT1 = 0x0800; internal const UInt32 EV_EVENT2 = 0x1000;
[DLLIMPORT ("kernel32.dll", setlasterror = true)] INTERNAL Static Extern Boolean Waitcommmevent (INTPTR HFILE, INTPTR LPEVTMASK, INTPTR LPOVERLAPPED);
[DllImport ( "kernel32.dll")] internal static extern Boolean CancelIo (IntPtr hFile); [DllImport ( "kernel32.dll", SetLastError = true)] internal static extern Boolean ReadFile (IntPtr hFile, [Out] Byte [] lpBuffer , Uint32 nnumberofbytestoread, out uint32 nNumberofbytesRead, INTPTR LPOVERLAPPED;
[DLLIMPORT ("kernel32.dll")] INTERNAL Static Extern Boolean Transmitcommchar (INTPTR HFILE, BYTE CCHAR); ///
/// Control port functions. ///
[DLLIMPORT ("kernel32.dll")]]]]
INTERNAL Static Extern Boolean EscapeCommfunction (INTPTR HFILE, UINT32 DWFUNC);
// Constants for dwFunc: internal const UInt32 SETXOFF = 1; internal const UInt32 SETXON = 2; internal const UInt32 SETRTS = 3; internal const UInt32 CLRRTS = 4; internal const UInt32 SETDTR = 5; internal const UInt32 CLRDTR = 6; internal const UInt32 RESETDEV = 7; internal const UInt32 SETBREAK = 8; internal const UInt32 CLRBREAK = 9; [DllImport ( "kernel32.dll")] internal static extern Boolean GetCommModemStatus (IntPtr hFile, out UInt32 lpModemStat);
// constants for lpmodemstat: INTERNAL const uint32 ms_cts_on = 0x0010; INTERNAL const uint32 ms_dsr_on = 0x0020; INTERNAL const UINT32 ms_ring_on = 0x0040; Internal const uint32 ms_rlsd_on = 0x0080;
///
/// status functions. ///
[DLLIMPORT ("kernel32.dll", setLastError = true)]
INTERNAL Static Extern Boolean GetoverlappedResult (INTPTR HFILE, INTPTR LPOVERLAPPED,
Out uint32 nnumberofbytestransferred, boolean bwait;
[DLLIMPORT ("kernel32.dll", setlasterror = true)] INTERNAL Static Extern Boolean PurgeComm (INTPTR HFILE, UINT DWFLAGS);
internal const uint PURGE_TXABORT = 0x0001; // Kill the pending / current writes to the comm port internal const uint PURGE_RXABORT = 0x0002;. // Kill the pending / current reads to the comm port internal const uint PURGE_TXCLEAR = 0x0004;. // Kill INTERNAL CONST UINT PURGE_RXCLEAR = 0x0008; // Kill The Typeahead Buffer if There.
[DllImport ( "kernel32.dll")] internal static extern Boolean ClearCommError (IntPtr hFile, out UInt32 lpErrors, IntPtr lpStat); [DllImport ( "kernel32.dll")] internal static extern Boolean ClearCommError (IntPtr hFile, out UInt32 lpErrors, out COMSTAT cs); // Constants for lpErrors: internal const UInt32 CE_RXOVER = 0x0001; internal const UInt32 CE_OVERRUN = 0x0002; internal const UInt32 CE_RXPARITY = 0x0004; internal const UInt32 CE_FRAME = 0x0008; internal const UInt32 CE_BREAK = 0x0010; internal const UInt32 CE_TXFULL = 0x0100; internal const UInt32 CE_PTO = 0x0200; internal const UInt32 CE_IOE = 0x0400; internal const UInt32 CE_DNS = 0x0800; internal const UInt32 CE_OOP = 0x1000; internal const UInt32 CE_MODE = 0x8000;
[StructLayout (LayoutKind.Sequential)] internal struct COMSTAT {internal const uint fCtsHold = 0x1; internal const uint fDsrHold = 0x2; internal const uint fRlsdHold = 0x4; internal const uint fXoffHold = 0x8; internal const uint fXoffSent = 0x10; internal const uint fEof = 0x20; internal const uint fTxim = 0x40; internal UInt32 Flags; internal UInt32 cbInQue; internal UInt32 cbOutQue;} [DllImport ( "kernel32.dll")] internal static extern Boolean GetCommProperties (IntPtr hFile, out COMMPROP cp);
[StructLayout (LayoutKind.Sequential)] internal struct COMMPROP {internal UInt16 wPacketLength; internal UInt16 wPacketVersion; internal UInt32 dwServiceMask; internal UInt32 dwReserved1; internal UInt32 dwMaxTxQueue; internal UInt32 dwMaxRxQueue; internal UInt32 dwMaxBaud; internal UInt32 dwProvSubType; internal UInt32 dwProvCapabilities; internal UInt32 dwSettableParams; internal UInt32 dwSettableBaud; internal UInt16 wSettableData; internal UInt16 wSettableStopParity; internal UInt32 dwCurrentTxQueue; internal UInt32 dwCurrentRxQueue; internal UInt32 dwProvSpec1; internal UInt32 dwProvSpec2; internal Byte wcProvChar;}}}