termiWin: a termios porting for Windows
~ A termios porting for Windows ~
Current Version 1.2.1 (16/11/2020)
termiWin is a library which purpose is to allow you to use on a Windows system, the same code used in Linux to communicate with a device through a serial port. This is possible because termios’s functions have been rewritten to be compatible with Windows’s COM functions.
I'm no longer working on this project, so this should be considered as an abandoned project. Feel free to fork it, but please, consider that even forking this project should be considered wrong, and here's why:
First of all, I think this project is just wrong. I've implemented this in 2017, when I had just started my career as a dev, and many things have changed since then, even the way I see software. At the time I saw no issue with something like termiwin, but now, personally, I think termiwin is a huge mistake, I even feel ashamed for implementing it. It is so far from my idea of how software should work, that I just feel bad every time someone stars this project. Portings are a cool thing, but termiwin is not a porting. It's just a copy-paste of some linux headers and "pray it works and be thankful to the creator of the world if it runs on your machine".
why didn't you fix it to make it good, then?
Well, I tried at least, but it's just not possible. If there is not a porting of termios out there for windows, it's because there cannot be one. I/O on linux is so much different from how I/O is managed on Windows, that this thing cannot just work. I felt so smart when I implemented this like
I'm so cool yo, I'm the only one who wrote a porting of termios for Windows
Do you think MinGW devs are stupid? No, they're F not.
In addition to this, I have just no interest in this project:
TL;DR I won't work on this project anymore. Stop asking me to solve your issue, because I won't be able to. I hate Windows.
It's enough to include termios.h, termiWin.h and termiWin.c to build the project. You don't have to change anything else in your code
-D TERMIWIN_DONOTREDEFINE
to build (which means that open, close, select etc must be replaced with openSerial, closeSerial, ...), but works fine afterall and it's used on my travis configurationOnce you are in the project root, run:
cmake .. -G "MinGW Makefiles" -DTERMIWIN_DONOTREDEFINE=yes -DCMAKE_SH="CMAKE_SH-NOTFOUND"
mingw32-make
This is the main structure of the library and it’s often passed as argument to the functions, it has the following members:
tcflag_t c_iflag; /*input modes*/
tcflag_t c_oflag; /*output modes*/
tcflag_t c_cflag; /*control modes*/
tcflag_t c_lflag; /*local modes*/
cc_t c_cc[NCCS]; /* special character */
where tcflag_t is defined as an unsigned integer.
The members of termios structure are used to set and retrieve the serial port configuration parameters.
There five types of flags, sorted by mode; they are implemented in the same way as they are in termios, except for some, which are not used.
Since there’s no way to implement them in Windows, they have asbolutely no effect using termiWin, but you can keep the same you use in Linux for compatibilty.
Since there’s no way to implement them in Windows, they have absolutely no effect using termiWin, but you can keep the same you use in Linux for compatibilty.
int tcgetattr(int fd, struct termios *termios_p)
Sets in the internal DCB structures the current serial port parameters, it always has to be invoked before using tcsetattr.
Returns 0 if succeded, otherwise -1.
int tcsetattr(int fd, int optional_actions, struct termios *termios_p)
Reads the flags set in the termios structure and sets the properly parameters in the DCB structure and eventually it applies the parameters to the serial port.
Returns 0 if succeded, otherwise -1.
int tcsendbreak(int fd, int duration)
Sends a break character to the serial port; duration is not implemented.
Returns 0 if succeded, otherwise -1.
int tcdrain(int fd)
Waits until all output written to the serial port has been transmitted.
Returns 0 if succeded, otherwise -1.
int tcflush(int fd, int queue_selector)
Discards data on serial port. queue_selector can assume the following values:
Returns 0 if succeded, otherwise -1.
int tcflow(int fd, int action)
Suspends transmission or receptions of data on serial port based on action. Action can assume the following values:
Returns 0 if succeded, otherwise -1.
void cfmakeraw(struct termios *termios_p)
Sets but doesn’t commit the following options for the serial port:
Use tcsetattr to commit them.
speed_t cfgetispeed(const struct termios *termios_p)
Returns the input speed, speed can assume the same values of termios (B9600, B115200, …).
speed_t cfgetospeed(const struct termios *termios_p)
returns the output speed, speed can assume the same values of termios (B9600, B115200, …).
int cfsetispeed(struct termios *termios_p, speed_t speed)
Sets, but doesn’t commits the parameter of speed for the serial port (in Windows there’s no distinction between input/output /control), speed can assume the same values of termios (B9600, B115200, …).
Returns 0 if succeded, otherwise -1.
int cfsetospeed(struct termios *termios_p, speed_t speed)
Sets, but doesn’t commits the parameter of speed for the serial port (in Windows there’s no distinction between input/output /control), speed can assume the same values of termios (B9600, B115200, ...).
Returns 0 if succeded, otherwise -1.
int cfsetsspeed(struct termios \*termios_p, speed_t speed)
Sets, but doesn’t commits the parameter of speed for the serial port (in Windows there’s no distinction between input/output /control), speed can assume the same values of termios (B9600, B115200, ...).
Returns 0 if succeded, otherwise -1.
The supported speeds are the the following (not all speeds could be implemented since some of them can't be used in a Windows environment)
You can use open/close/write/read instead of these names by default. If it causes to you conflicts with another library you can deactivate these definitions defining in your project:
#define TERMIWIN_DONOTREDEFINE
int open_serial(const char* portname, int opt)
Open the serial port which name is portname with opt set for the port to be read only, write only or both read/write (O_RDONLY,
O_WRONLY, O_RDWR). Returns the file descriptor (fd is actually useless in Windows with serial ports, but is set for
compatibilty). The function can be called using open instead of openSerial (for termios compatibilty).
The portname must be in the format "COMnumber" (e.g. COM2, COM11).
int close_serial(int fd)
Closes the serial port. Returns 0 if succeded, otherwise -1. The function can be called using close instead of closeSerial. (for termios compatibilty).
ssize_t write_serial(int fd, const void* buffer, size_t count)
Writes to serial “count” characters contained in buffer. Returns the number of transmitted characters or -1 if transmission failed. The function can be called using write instead of writeToSerial (for termios compatibilty).
ssize_t read_serial(int fd, void* buffer, size_t count)
Reads “count” bytes from serial port and put them into buffer. Returns the number of read bytes or -1 if read failed. The function can be called using read instead of readFromSerial (for termios compatibilty).
int select_serial(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
It behaves as termios select. Returns the file descriptor ready for the chosen operation or -1 if failed. The function can be called using select instead of selectSerial (for termios compatibility).
HANDLE getHandle()
Returns the HANDLE from the COM structure.
At the moment is not possible to have more than one serial communication at the same time. I have never implemented this feature and probably I won't.
termiWin is just a simple library which executes termios functions using Windows libsock functions, because of that, any particular behaviour in the communication with the serial device, could not work properly. termiWin is intended just for simple communications.
When termiWin can be a good choice? ✅
When termiWin is NOT a good choice? ❌
Everybody can contribute to this project, indeed any improvement will be appreciated.
View CHANGELOG
termiWin is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
termiWin is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with termiWin.
If not, see http://www.gnu.org/licenses/.