Search code examples
cwinapiserial-portposixporting

Porting Win32 serial (RS232) comms to POSIX


Currently I'm porting a Win32 application to POSIX. The software itself is a couple decades old and used to update proprietary machines.

While most of the functions were relatively easy to replace with simple macros and some smaller functions calling POSIX functions, the RS232 comms-related functions are proving difficult.

The application uses these functions to communicate via RS232:

BOOL GetCommState(HANDLE comPort, DCB* dataControlBlock);

BOOL SetCommState(HANDLE comPort, DCB* dataControlBlock);

BOOL GetCommTimeouts(HANDLE comPort, LPCOMMTIMEOUTS comTimeouts);

BOOL SetCommTimeouts(HANDLE comPort, LPCOMMTIMEOUTS comTimeouts);

BOOL SetCommMask(HANDLE comPort, DWORD eventMask);

BOOL GetCommMask(HANDLE comPort, LPDWORD eventMask);

BOOL WaitCommEvent(HANDLE comPort, LPDWORD eventMask, LPOVERLAPPED overlapped);

Along with the following structs:

typedef struct _DCB { /*...*/ } DCB, *LPDCB;

typedef struct _COMMTIMEOUTS { /*...*/ } COMMTIMEOUTS, *LPCOMMTIMEOUTS;

While searching, I came across this link, which mentions termios.h and sys/select.h but the structure of these headers is far too different for my liking. Other answers mentioned using Wine, which simply isn't an option because of the hardware the application is being ported to.

If possible, I'd like to implement a simpler solution and preserve the structs currently being used by the application - in an attempt to keep everything cross-compatible.

Is there a way to achieve this?
Or am I stuck with re-writing gross portions of the application?


Solution

  • Depending on how complicated your application is, I see two possible solutions:

    1. Replace the Win32 calls with the equivalent POSIX call, as P__J__ mentioned in the comments. If you do that, the equivalent calls would probably be along the lines of the following:

    GetCommState : tcgetattr

    SetCommState : tcsetattr

    Get/SetCommTimeouts : You would still set this using tcsetattr, modify the c_cc[VTIME] entry in of a struct termios

    Set/GetCommMask : Unfortunately, the POSIX API does not have an equivalent of this function. If you need to care about the control signals(CTS,DSR,RING), you need to read the line status in a loop. If you only care about reading bytes that come back, you don't need to worry about this.

    WaitCommEvent : The equivalent on POSIX would be either select(old style) or poll(more modern). Similar to the CommMask as above though, select/poll will return when there is data to be read, not when the control lines change.

    1. If you don't want to try and figure out the cross-platform problems on your own, there are several libraries(in C) that are cross-platform capable. Here's a quick list:

    ..and that's it for everything that I know of. All of the other libraries that I am aware of are for C++.