// Comm.lib - Windows routines for accessing (open, read, write, etc...) // the COMM ports (serial ports, printer ports). You may want // to #include this file in your Cmm source, or just copy out // the parts that you want. // //---- OpenComm(): Open COMM device and get handle to it ------------------- // SYNTAX: int OpenComm(string CommName[,int ReadQueueSize,int WriteQueueSize]) // WHERE: CommName: String name for the device, such as "COM1", "COM2", "LPT1", etc... // ReadQueueSize, WriteQueueSize: Optional buffer sizes to prepare area // for data to reside while it is being received or sent. These // values are ignored by Windows for LPT ports. If these // are not supplied then they default to the following #define DEFAULT_COMM_QUEUE_SIZE 500 // RETURN: Returns a handle to the now-open communications device for subsequent // calls to ReadComm(), WriteComm(), etc. If error, then returns a // negatvie value, which may be one of the following: #define IE_BADID (-1) // Invalid or unsupported ID #define IE_BAUDRATE (-12) // Unsupported baud rate #define IE_BYTESIZE (-11) // Invalid byte size #define IE_DEFAULT (-5) // Error in default parameters #define IE_HARDWARE (-10) // Hardware Not Present #define IE_MEMORY (-4) // Unable to allocate queues #define IE_NOPEN (-3) // Device not open #define IE_OPEN (-2) // Device already open // NOTES: Call CloseComm before terminating your program. You may want to set // up an atexit() function to ensure this. // //---- CloseComm(): Close COMM device opened with OpenComm ------------------ // SYNTAX: int CloseComm(int CommHandle) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // RETURN: Returns 0 for success, else a negative error. This call is expected // to success and so most programmers don't test the return code. // NOTES: All characters in the output queue are sent before the device is closed. // //---- ReadComm(): Read characters from open COMM device --------------------- // SYNTAX: int ReadComm(int CommHandle,byte[] DestBuffer,int bufferLen[,int CommError]) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // DestBuffer: Data will be read into this buffer, will be created as a // buffer if it is not already // bufferLen: Maximum number of bytes to read into buffer // CommError: If there is a communications error during read, then this will // be set to the error, else 0 for no error. See CommError // values below. // RETURN: Returns number of bytes read, which is 0 up to bufferLen // NOTES: GetCommError() will always be called, whether or not the optional // CommError is supplied in this function, to clear port errors. If // return value is bufferLen, then there may be more characters // available. // //---- GetCommError(): Get COMM port error, and clear error ----------------- // SYNTAX: int GetCommError(CommHandle,[struct CommStatus]) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // CommStatus: an optional structure that will be set with the // following elements // bool fCtsHold Transmit is on CTS hold // bool fDsrHold Transmit is on DSR hold // bool fRlsdHold Transmit is on RLSD hold // bool fXoffHold Received handshake // bool fXoffSent Issued handshake // bool fEof End of file character found // bool fTxim Character being transmitted // int cbInQue count of characters in Rx Queue // int cbOutQue count of characters in Tx Queue // RETURN: Return 0 for no error, else an error that may be an OR combination // of the following: #define CE_RXOVER 0x0001 // Receive Queue overflow #define CE_OVERRUN 0x0002 // Receive Overrun Error #define CE_RXPARITY 0x0004 // Receive Parity Error #define CE_FRAME 0x0008 // Receive Framing error #define CE_BREAK 0x0010 // Break Detected #define CE_CTSTO 0x0020 // CTS Timeout #define CE_DSRTO 0x0040 // DSR Timeout #define CE_RLSDTO 0x0080 // RLSD Timeout #define CE_TXFULL 0x0100 // TX Queue is full #define CE_PTO 0x0200 // LPTx Timeout #define CE_IOE 0x0400 // LPTx I/O Error #define CE_DNS 0x0800 // LPTx Device not selected #define CE_OOP 0x1000 // LPTx Out-Of-Paper #define CE_MODE 0x8000 // Requested mode unsupported // NOTES: Many of the previous function call this function with no CommStatus // just to clear any potential errors // //---- WriteComm: Write characters to open COMM device -------------------- // SYNTAX: int WriteComm(int CommHandle,byte[] SrcBuffer,int bufferLen[,int CommError]) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // SrcBuffer: Data will be written from this buffer // bufferLen: Number of bytes to written from this buffer // CommError: If there is a communications error during write, then this will // be set to the error, else 0 for no error. See CommError // values below. // RETURN: Returns number of bytes written, which is 0 up to bufferLen. If less // than bufferLen then there was certainly an error. // NOTES: GetCommError() will always be called, whether or not the optional // CommError is supplied in this function, to clear port errors. If there // is not enough room in the output queue then some characters will be // lost, and so if you're not sure there's enough room you may want to // call GetCommError() to see how much room is available. // // //---- UngetCommChar: Place one character back into the receive queue ------- // SYNTAX: int UngetCommChar(int CommHandle,byte Character) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // Character: Single character to place back in read queue // RETURN: Zero if successful, else negative error code // NOTES: You can only place one character back in the queue. That character // must be read out of the queue before placing another // // //---- TransmitCommChar: Place character at head of tranmsit queue --------- // SYNTAX: int TransmitCommChar(int CommHandle,byte Character) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // Character: Single character for immediate transmission // RETURN: Zero if successful, else negative error code. Error if previous // TransmitCommChar() has not been transmitted yet. // // //---- FlushComm: Flush all characters out of receive or transmit queue ----- // SYNTAX: int FlushComm(int CommHandle,int WhichQueue) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // WhichQueue: 0 to flush transmit queue, else 1 to flush receive queue // RETURN: Zero if successful, else negative error code for invalid // CommHandle or invalid WhichQueue. // // //---- SetCommBreak: Suspend transmission and fo to break state ------------- // SYNTAX: int SetCommBreak(int CommHandle) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // RETURN: Return 0 for success, else negative if CommHandle is invalid // NOTES: Suspends transmission and places the line in the break state until // ClearCommBreak() is called. // // //---- ClearCommBreak: Restore transmission and set to non-break state ------ // SYNTAX: int ClearCommBreak(int CommHandle) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // RETURN: Return 0 for success, else negative if CommHandle is invalid // // //---- EscapeCommFunction: Perform an extended function --------------------- // SYNTAX: int EscapeCommFunction(int CommHandle,int ExtendedFunction) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // ExtendedFunction: One of the following values #define CLRDTR 6 // Set DTR low #define CLRRTS 4 // Set RTS low #define RESETDEV 7 // Reset device if possible #define SETDTR 5 // Set DTR high #define SETRTS 3 // Set RTS high #define SETXOFF 1 // Simulate XOFF received #define SETXON 2 // Simulate XON received // RETURN: Return 0 for success, else negative if CommHandle or // ExtendedFunction is invalid // // //---- SetCommEventMask: Retrieve and set events ---------------------- // SYNTAX: int SetCommEventMask(int CommHandle,int EventMask) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // EventMask: Mask of bits for events to be enabled #define EV_RXCHAR 0x0001 // Any Character received #define EV_RXFLAG 0x0002 // Received certain character #define EV_TXEMPTY 0x0004 // Transmitt Queue Empty #define EV_CTS 0x0008 // CTS changed state #define EV_DSR 0x0010 // DSR changed state #define EV_RLSD 0x0020 // RLSD changed state #define EV_BREAK 0x0040 // BREAK received #define EV_ERR 0x0080 // Line status error occurred #define EV_RING 0x0100 // Ring signal detected #define EV_PERR 0x0200 // Printer error occured // RETURN: Return integer event mask where each bit is set if that event has occured. // // //---- GetCommEventMask: Retrieve event mask and clear the mask --------- // SYNTAX: int GetCommEventMask(int CommHandle,int EventMask) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // EventMask: Mask of bits for events to be enabled, see SetCommEventMask() // RETURN: Return integer event mask where each bit is set if that event has occured. // // //---- GetCommState: Get port parameters for comm device ---------------- // SYNTAX: int GetCommState(int CommHandle,struct dcb) // WHERE: CommHandle: value returned from previous successful call to OpenComm() // dcb: Device control block to be set with the following members: // int Id // Internal Device ID // int BaudRate // Baud rate at which runing // int ByteSize // Number of bits/byte, 4-8 // int Parity // 0-4=None,Odd,Even,Mark,Space #define NOPARITY 0 #define ODDPARITY 1 #define EVENPARITY 2 #define MARKPARITY 3 #define SPACEPARITY 4 // int StopBits // 0,1,2 = 1, 1.5, 2 #define ONESTOPBIT 0 #define ONE5STOPBITS 1 #define TWOSTOPBITS 2 // int RlsTimeout // Timeout for RLSD to be set // int CtsTimeout // Timeout for CTS to be set // int DsrTimeout // Timeout for DSR to be set // bool Binary // Binary Mode (skip EOF check // bool RtsDisable // Don't assert RTS at init time // bool Parity // Enable parity checking // bool OutxCtsFlow // CTS handshaking on output // bool OutxDsrFlow // DSR handshaking on output // bool DtrDisable // Don't assert DTR at init time // bool OutX // Enable output X-ON/X-OFF // bool InX // Enable input X-ON/X-OFF // bool PeChar // Enable Parity Err Replacement // bool NullStrip // Enable Null stripping // bool ChEvt // Enable Rx character event. // bool Dtrflow // DTR handshake on input // bool Rtsflow // RTS handshake on input // int XonChar // Tx and Rx X-ON character // int XoffChar // Tx and Rx X-OFF character // int XonLim // Transmit X-ON threshold // int XoffLim // Transmit X-OFF threshold // int PeChar // Parity error replacement char // int EofChar // End of Input character // int EvtChar // Received Event character // int TxDelay // Amount of time between chars // RETURN: Return 0 for success, else negative error value // // //---- SetCommState: Set communication port parameters -------------------- // SYNTAX: int SetCommState(struct dcb) // WHERE: dcb: Device control block to be set, with the same fields as described // above in GetCommState() // RETURN: Return 0 for success, else negative error value // NOTES: ALL of the dcb fields must be define, and so it is recommended that // have previously set the structure with a call to GetCommState() or // BuildCommDCB. // // //---- BuildCommDCB: Translate definition string to device control block -- // SYNTAX: int BuildCommDCB(string DeviceInfo,struct dcb) // WHERE: DeviceInfo: string for setting device information; this string // uses the same format as the DOS MODE command // dcb: structure filled after translating DeviceInfo. This is same // structure as described in GetCommState() // RETURN: Return 0 for success, else negative error value // NOTES: This only fills dcb; call SetCommState fo set device. By default, // Xon/Xoff flow control will be disabled // // /***************************************************************** ********* END OF DESCRIPTION FOR COMM.LIB ********* *****************************************************************/ OpenComm(CommName,ReadQueueSize,WriteQueueSize) { // Get Queue sizes in case they weren't supplied _ocReadQSize = ( 1 == va_arg() ) ? DEFAULT_COMM_QUEUE_SIZE : ReadQueueSize; _ocWriteQSize = ( 1 == va_arg() ) ? DEFAULT_COMM_QUEUE_SIZE : WriteQueueSize; // Pass this call on to the Windows OpenComm routine return DynamicLink("USER","OPENCOMM",SWORD16,PASCAL, CommName,_ocReadQSize,_ocWriteQSize); } CloseComm(CommHandle) { return DynamicLink("USER","CLOSECOMM",SWORD16,PASCAL,CommHandle); } ReadComm(CommHandle,DestBuffer,bufferLen,CommError) { // make sure DestBuffer is big enough DestBuffer[bufferLen-1] = '\0'; // Get value from Windows ReadComm function _rcCount = DynamicLink("USER","READCOMM",SWORD16,PASCAL, CommHandle,DestBuffer,bufferLen); // If less then 1 byte read then take absolute, and might be error if ( _rcCount < 1 ) { _rcCount = abs(_rcCount); // get absolute bytes read _rcCommError = GetCommError(CommHandle); // get error and clear it } else _rcCommError = 0; // If CommError was supplied then set it if ( 3 < va_arg() ) CommError = _rcCommError; return _rcCount; } WriteComm(CommHandle,DestBuffer,bufferLen,CommError) { // Get value from Windows ReadComm function _wcCount = DynamicLink("USER","WRITECOMM",SWORD16,PASCAL, CommHandle,DestBuffer,bufferLen); // If less then 1 byte written then take absolute, and might be error if ( _wcCount < 1 ) { _wcCount = abs(_wcCount); // get absolute bytes read _wcCommError = GetCommError(CommHandle); // get error and clear it } else _wcCommError = 0; // If CommError was supplied then set it if ( 3 < va_arg() ) CommError = _wcCommError; return _wcCount; } GetCommError(CommHandle,CommStatus) { if ( 1 == va_arg() ) { // simple version, only return error code _commError = DynamicLink("USER","GETCOMMERROR",SWORD16,PASCAL, CommHandle,0,0); } else { // CommStatus has been supplied, so must fill in the structure BLObSize(_csBuf,5); _commError = DynamicLink("USER","GETCOMMERROR",SWORD16,PASCAL, CommHandle,_csBuf); _csBits = BLObGet(_csBuf,0,UWORD8); CommStatus.fCtsHold = (_csBits & 0x01) ? TRUE : FALSE ; CommStatus.fDsrHold = (_csBits & 0x02) ? TRUE : FALSE ; CommStatus.fRlsdHold = (_csBits & 0x04) ? TRUE : FALSE ; CommStatus.fXoffHold = (_csBits & 0x08) ? TRUE : FALSE ; CommStatus.fXoffSent = (_csBits & 0x10) ? TRUE : FALSE ; CommStatus.fEof = (_csBits & 0x20) ? TRUE : FALSE ; CommStatus.fTxim = (_csBits & 0x40) ? TRUE : FALSE ; CommStatus.cbInQue = BLObGet(_csBuf,1,SWORD16); CommStatus.cbOutQue = BLObGet(_csBuf,3,SWORD16); } return _commError; } UngetCommChar(CommHandle,Character) { return DynamicLink("USER","UNGETCOMMCHAR",SWORD16,PASCAL,CommHandle,Character); } TransmitCommChar(CommHandle,Character) { return DynamicLink("USER","TRANSMITCOMMCHAR",SWORD16,PASCAL,CommHandle,Character); } FlushComm(CommHandle,WhichQueue) { return DynamicLink("USER","FLUSHCOMM",SWORD16,PASCAL,CommHandle,WhichQueue); } SetCommBreak(CommHandle) { return DynamicLink("USER","SETCOMMBREAK",SWORD16,PASCAL,CommHandle); } ClearCommBreak(CommHandle) { return DynamicLink("USER","CLEARCOMMBREAK",SWORD16,PASCAL,CommHandle); } EscapeCommFunction(CommHandle,ExtendedFunction) { return DynamicLink("USER","ESCAPECOMMFUNCTION",SWORD16,PASCAL, CommHandle,ExtendedFunction); } SetCommEventMask(CommHandle,EventMask) { _EMaskPtr = DynamicLink("USER","SETCOMMEVENTMASK",UWORD32,PASCAL,CommHandle,EventMask); return peek(_EMaskPtr,UWORD16); } GetCommEventMask(CommHandle,EventMask) { return DynamicLink("USER","GETCOMMEVENTMASK",UWORD16,PASCAL,CommHandle,EventMask); } ConvertDCBblobTOstruct(b,s) { s.Id = BLObGet(b,0,UWORD8); s.BaudRate = BLObGet(b,1,UWORD16); s.ByteSize = BLObGet(b,3,UWORD8); s.Parity = BLObGet(b,4,UWORD8); s.StopBits = BLObGet(b,5,UWORD8); s.RlsTimeout = BLObGet(b,6,UWORD16); s.CtsTimeout = BLObGet(b,8,UWORD16); s.DsrTimeout = BLObGet(b,10,UWORD16); _flags = BLObGet(b,12,UWORD8); s.Binary = _flags & 0x01; s.RtsDisable = _flags & 0x02; s.Parity = _flags & 0x04; s.OutxCtsFlow = _flags & 0x08; s.OutxDsrFlow = _flags & 0x10; s.DtrDisable = _flags & 0x80; _flags = BLObGet(b,13,UWORD8); s.OutX = _flags & 0x01; s.InX = _flags & 0x02; s.PeChar = _flags & 0x04; s.NullStrip = _flags & 0x08; s.ChEvt = _flags & 0x10; s.Dtrflow = _flags & 0x20; s.Rtsflow = _flags & 0x40; s.XonChar = BLObGet(b,14,UWORD8); s.XoffChar = BLObGet(b,15,UWORD8); s.XonLim = BLObGet(b,16,UWORD16); s.XoffLim = BLObGet(b,18,UWORD16); s.PeChar = BLObGet(b,20,UWORD8); s.EofChar = BLObGet(b,21,UWORD8); s.EvtChar = BLObGet(b,22,UWORD8); s.TxDelay = BLObGet(b,23,UWORD16); } GetCommState(CommHandle,dcb) { BLObSize(_dcb,25); _ret = DynamicLink("USER","GETCOMMSTATE",SWORD16,PASCAL,CommHandle,_dcb); ConvertDCBblobTOstruct(_dcb,dcb); return _ret; } BuildCommDCB(DeviceInfo,dcb) { BLObSize(_dcb,25); _ret = DynamicLink("USER","BUILDCOMMDCB",SWORD16,PASCAL,DeviceInfo,_dcb); ConvertDCBblobTOstruct(_dcb,dcb); return _ret; } SetCommState(dcb) { BLObPut(_dcb,0,dcb.Id,UWORD8); BLObPut(_dcb,1,dcb.BaudRate,UWORD16); BLObPut(_dcb,3,dcb.ByteSize,UWORD8); BLObPut(_dcb,4,dcb.Parity,UWORD8); BLObPut(_dcb,5,dcb.StopBits,UWORD8); BLObPut(_dcb,6,dcb.RlsTimeout,UWORD16); BLObPut(_dcb,8,dcb.CtsTimeout,UWORD16); BLObPut(_dcb,10,dcb.DsrTimeout,UWORD16); _flags = 0; if ( dcb.Binary ) _flags |= 0x01; if ( dcb.RtsDisable) _flags |= 0x02; if ( dcb.Parity ) _flags |= 0x04; if ( dcb.OutxCtsFlow ) _flags |= 0x08; if ( dcb.OutxDsrFlow ) _flags |= 0x10; if ( dcb.DtrDisable ) _flags |= 0x80; BLObPut(_dcb,12,_flags,UWORD8); _flags = 0; if ( dcb.OutX ) _flags |= 0x01; if ( dcb.InX ) _flags |= 0x02; if ( dcb.PeChar ) _flags |= 0x04; if ( dcb.NullStrip ) _flags |= 0x08; if ( dcb.ChEvt ) _flags |= 0x10; if ( dcb.Dtrflow ) _flags |= 0x20; if ( dcb.Rtsflow ) _flags |= 0x40; BLObPut(_dcb,13,_flags,UWORD8); BLObPut(_dcb,14,dcb.XonChar,UWORD8); BLObPut(_dcb,15,dcb.XoffChar,UWORD8); BLObPut(_dcb,16,dcb.XonLim,UWORD16); BLObPut(_dcb,18,dcb.XoffLim,UWORD16); BLObPut(_dcb,20,dcb.PeChar,UWORD8); BLObPut(_dcb,21,dcb.EofChar,UWORD8); BLObPut(_dcb,22,dcb.EvtChar,UWORD8); BLObPut(_dcb,23,dcb.TxDelay,UWORD16); return DynamicLink("USER","SETCOMMSTATE",SWORD16,PASCAL,_dcb); }