// serial.c - Serial port abstraction layer // // Wraps Windows 3.1 comm API for use by the MSComm VBX control. // All functions operate on a comm ID returned by serialOpen(). #include #include #include "serial.h" // ----------------------------------------------------------------------- // Prototypes // ----------------------------------------------------------------------- int16_t serialClose(int16_t commId); int16_t serialConfigure(int16_t commId, int16_t port, const char FAR *settings); int16_t serialEnableNotify(int16_t commId, HWND hwnd, int16_t rxThreshold, int16_t txThreshold); int16_t serialEscape(int16_t commId, int16_t func); int16_t serialFlush(int16_t commId, int16_t queue); UINT serialGetEventMask(int16_t commId, UINT mask); int16_t serialGetStatus(int16_t commId, COMSTAT FAR *stat); int16_t serialOpen(int16_t port, int16_t inBufSize, int16_t outBufSize); int16_t serialRead(int16_t commId, char FAR *buf, int16_t len); int16_t serialSetHandshaking(int16_t commId, int16_t mode); int16_t serialSetOptions(int16_t commId, BOOL nullDiscard, const char FAR *parityReplace); int16_t serialWrite(int16_t commId, const char FAR *buf, int16_t len); // ----------------------------------------------------------------------- // serialClose - Close an open comm port // ----------------------------------------------------------------------- int16_t serialClose(int16_t commId) { // Drop DTR and RTS before closing EscapeCommFunction(commId, CLRDTR); EscapeCommFunction(commId, CLRRTS); return (int16_t)CloseComm(commId); } // ----------------------------------------------------------------------- // serialConfigure - Set baud, parity, data bits, stop bits // ----------------------------------------------------------------------- int16_t serialConfigure(int16_t commId, int16_t port, const char FAR *settings) { DCB dcb; char buf[64]; int rc; // Get current state to preserve existing settings rc = GetCommState(commId, &dcb); if (rc != 0) { return -1; } // Build DCB from "COMn:baud,parity,data,stop" string wsprintf(buf, "COM%d:%s", (int)port, (LPSTR)settings); rc = BuildCommDCB(buf, &dcb); if (rc != 0) { return -1; } // Ensure binary mode for reliable operation dcb.fBinary = 1; // Ensure comm ID matches our open port dcb.Id = (BYTE)commId; rc = SetCommState(&dcb); if (rc != 0) { return -1; } return 0; } // ----------------------------------------------------------------------- // serialEnableNotify - Enable WM_COMMNOTIFY messages // ----------------------------------------------------------------------- BOOL serialEnableNotify(int16_t commId, HWND hwnd, int16_t rxThreshold, int16_t txThreshold) { // Enable event mask for modem status line changes, errors, and breaks SetCommEventMask(commId, EV_CTS | EV_DSR | EV_RLSD | EV_RING | EV_ERR | EV_BREAK | EV_RXCHAR); return EnableCommNotification(commId, hwnd, rxThreshold, txThreshold); } // ----------------------------------------------------------------------- // serialEscape - Execute escape function (DTR, RTS, break control) // ----------------------------------------------------------------------- int16_t serialEscape(int16_t commId, int16_t func) { LONG rc; rc = EscapeCommFunction(commId, func); return (rc == 0) ? 0 : -1; } // ----------------------------------------------------------------------- // serialFlush - Flush receive or transmit buffer // ----------------------------------------------------------------------- int16_t serialFlush(int16_t commId, int16_t queue) { return (int16_t)FlushComm(commId, queue); } // ----------------------------------------------------------------------- // serialGetEventMask - Get and clear event mask bits // ----------------------------------------------------------------------- UINT serialGetEventMask(int16_t commId, UINT mask) { return GetCommEventMask(commId, mask); } // ----------------------------------------------------------------------- // serialGetStatus - Get error status and buffer counts // ----------------------------------------------------------------------- int16_t serialGetStatus(int16_t commId, COMSTAT FAR *stat) { return (int16_t)GetCommError(commId, stat); } // ----------------------------------------------------------------------- // serialOpen - Open a COM port with specified buffer sizes // ----------------------------------------------------------------------- int16_t serialOpen(int16_t port, int16_t inBufSize, int16_t outBufSize) { char name[8]; int commId; wsprintf(name, "COM%d", (int)port); commId = OpenComm(name, (UINT)inBufSize, (UINT)outBufSize); return (int16_t)commId; } // ----------------------------------------------------------------------- // serialRead - Read data from receive buffer // ----------------------------------------------------------------------- int16_t serialRead(int16_t commId, char FAR *buf, int16_t len) { return (int16_t)ReadComm(commId, (LPSTR)buf, len); } // ----------------------------------------------------------------------- // serialSetHandshaking - Apply handshaking mode // ----------------------------------------------------------------------- int16_t serialSetHandshaking(int16_t commId, int16_t mode) { DCB dcb; int rc; rc = GetCommState(commId, &dcb); if (rc != 0) { return -1; } // Clear all flow control settings dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fOutX = 0; dcb.fInX = 0; dcb.fRtsDisable = 0; dcb.fRtsflow = 0; switch (mode) { case HANDSHAKE_XONXOFF: dcb.fOutX = 1; dcb.fInX = 1; dcb.XonChar = 0x11; // Ctrl-Q dcb.XoffChar = 0x13; // Ctrl-S dcb.XonLim = 256; dcb.XoffLim = 256; break; case HANDSHAKE_RTSCTS: dcb.fOutxCtsFlow = 1; dcb.fRtsflow = 1; break; case HANDSHAKE_BOTH: dcb.fOutxCtsFlow = 1; dcb.fRtsflow = 1; dcb.fOutX = 1; dcb.fInX = 1; dcb.XonChar = 0x11; dcb.XoffChar = 0x13; dcb.XonLim = 256; dcb.XoffLim = 256; break; case HANDSHAKE_NONE: default: break; } dcb.Id = (BYTE)commId; rc = SetCommState(&dcb); if (rc != 0) { return -1; } return 0; } // ----------------------------------------------------------------------- // serialSetOptions - Apply null-discard and parity-replace settings // ----------------------------------------------------------------------- int16_t serialSetOptions(int16_t commId, BOOL nullDiscard, const char FAR *parityReplace) { DCB dcb; int rc; rc = GetCommState(commId, &dcb); if (rc != 0) { return -1; } dcb.fNull = nullDiscard ? 1 : 0; if (parityReplace != NULL && parityReplace[0] != '\0') { dcb.fParity = 1; dcb.PeChar = parityReplace[0]; } else { dcb.fParity = 0; dcb.PeChar = '\0'; } dcb.Id = (BYTE)commId; rc = SetCommState(&dcb); if (rc != 0) { return -1; } return 0; } // ----------------------------------------------------------------------- // serialWrite - Write data to transmit buffer // ----------------------------------------------------------------------- int16_t serialWrite(int16_t commId, const char FAR *buf, int16_t len) { return (int16_t)WriteComm(commId, (LPSTR)buf, len); }