Last active
October 27, 2023 01:48
-
-
Save nuft/d625fae77d43974a48e07c39441b370b to your computer and use it in GitHub Desktop.
Serialport C++ example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
MIT License | |
Copyright (c) 2018, Michael Spieler | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
*/ | |
#include <stdio.h> | |
#include <fcntl.h> | |
#include <termios.h> | |
#include <unistd.h> | |
#include <sys/ioctl.h> | |
#include "serialport.h" | |
int connect(const char *port, unsigned baudRate, unsigned stopBits, | |
bool canonical_mode, struct termios *originalTTYAttrs) | |
{ | |
struct termios options; | |
int fileDesc = -1; | |
fileDesc = open(port, O_RDWR | O_NONBLOCK | O_NOCTTY); | |
// Exclusive file open | |
if (ioctl(fileDesc, TIOCEXCL) == -1) { | |
goto error; | |
} | |
// allow communications to block | |
if (fcntl(fileDesc, F_SETFL, 0) == -1) { | |
goto error; | |
} | |
// Save current TTY settings | |
if (tcgetattr(fileDesc, originalTTYAttrs) == -1) { | |
goto error; | |
} | |
// Setup the terminal for ordinary I/O | |
// e.g. as an ordinary modem or serial port printer. | |
// | |
// Default config: hangup on close. | |
// if the HUPCL bit set, closing the port will hang up | |
// the modem. (i.e. will lower the modem control lines) | |
// | |
// Default config: | |
// 8 bits, no parity | |
options = *originalTTYAttrs; | |
options.c_cflag = CREAD | CS8 | HUPCL | CLOCAL; | |
// Send 2 stop bits, default: 1 | |
if (stopBits == 2) { | |
options.c_cflag |= CSTOPB; | |
} | |
speed_t speed; | |
switch (baudRate) { | |
case 230400: | |
speed = B230400; | |
break; | |
case 115200: | |
speed = B115200; | |
break; | |
case 57600: | |
speed = B57600; | |
break; | |
case 38400: | |
speed = B38400; | |
break; | |
case 19200: | |
speed = B19200; | |
break; | |
case 9600: | |
speed = B9600; | |
break; | |
case 4800: | |
speed = B4800; | |
break; | |
case 2400: | |
speed = B2400; | |
break; | |
case 1800: | |
speed = B1800; | |
break; | |
case 1200: | |
speed = B1200; | |
break; | |
case 600: | |
speed = B600; | |
break; | |
case 300: | |
speed = B300; | |
break; | |
default: | |
goto error; | |
} | |
cfsetspeed(&options, speed); | |
// disable canonical processing | |
if (canonical_mode) { | |
options.c_lflag |= ICANON; | |
} else { | |
options.c_lflag &= ~ICANON; | |
} | |
// disable echoing of input | |
options.c_lflag &= ~ECHO; | |
// disable all special control characters | |
options.c_cc[VEOF] = _POSIX_VDISABLE; | |
options.c_cc[VEOL] = _POSIX_VDISABLE; | |
options.c_cc[VEOL2] = _POSIX_VDISABLE; | |
options.c_cc[VERASE] = _POSIX_VDISABLE; | |
options.c_cc[VWERASE] = _POSIX_VDISABLE; | |
options.c_cc[VKILL] = _POSIX_VDISABLE; | |
options.c_cc[VREPRINT] = _POSIX_VDISABLE; | |
options.c_cc[VINTR] = _POSIX_VDISABLE; | |
options.c_cc[VQUIT] = _POSIX_VDISABLE; | |
options.c_cc[VSUSP] = _POSIX_VDISABLE; | |
options.c_cc[VDSUSP] = _POSIX_VDISABLE; | |
options.c_cc[VSTART] = _POSIX_VDISABLE; | |
options.c_cc[VSTOP] = _POSIX_VDISABLE; | |
options.c_cc[VLNEXT] = _POSIX_VDISABLE; | |
options.c_cc[VDISCARD] = _POSIX_VDISABLE; | |
options.c_cc[VSTATUS] = _POSIX_VDISABLE; | |
// more info on VMIN and VTIME here: | |
// http://unixwiz.net/techtips/termios-vmin-vtime.html | |
options.c_cc[VMIN] = 0; // min bytes in input queue | |
options.c_cc[VTIME] = 1; // timeout in 0.1 sec | |
// write options | |
if (tcsetattr(fileDesc, TCSANOW, &options) == -1) { | |
goto error; | |
} | |
// flush any unwritten, unread data | |
if (tcflush(fileDesc, TCIOFLUSH) == -1) { | |
goto error; | |
} | |
return fileDesc; | |
error: | |
if (fileDesc != -1) { | |
close(fileDesc); | |
} | |
return -1; | |
} | |
SerialPort::SerialPort(const char *port, unsigned baudRate, unsigned stopBits, | |
bool canonical_mode) | |
{ | |
mFileDesc = connect(port, baudRate, stopBits, canonical_mode, &mOriginalTTYAttrs); | |
if (mFileDesc == -1) { | |
throw; | |
} | |
} | |
SerialPort::~SerialPort() | |
{ | |
if (mFileDesc == -1) { | |
return; | |
} | |
tcflush(mFileDesc, TCIOFLUSH); | |
close(mFileDesc); | |
} | |
int SerialPort::write(const char *buf, size_t nBytes) | |
{ | |
if (nBytes == 0) { | |
return 0; | |
} | |
return ::write(mFileDesc, buf, nBytes); | |
} | |
int SerialPort::write(const std::string& string) | |
{ | |
size_t len = string.length(); | |
if (len == 0) { | |
return 0; | |
} | |
return ::write(mFileDesc, string.c_str(), len); | |
} | |
int SerialPort::read(char *buf, size_t nBytes) | |
{ | |
int n = 0; | |
while (n < nBytes) { | |
int ret = ::read(mFileDesc, &buf[n], nBytes - n); | |
if (ret < 0) { | |
return ret; | |
} | |
} | |
return n; | |
} | |
int SerialPort::readLine(char *line, size_t nmax) | |
{ | |
if (nmax == 0) { | |
return 0; | |
} | |
int n = 0; | |
while (n < nmax - 1) { | |
char c; | |
int ret = ::read(mFileDesc, &c, 1); | |
if (ret > 0) { | |
if (c == '\n' || c == '\r') { | |
break; | |
} | |
line[n] = c; | |
n++; | |
} else if (ret < 0) { | |
return ret; | |
} | |
} | |
line[n] = '\0'; | |
return n; | |
} | |
int SerialPort::readLine(std::string &line) | |
{ | |
int n = 0; | |
while (true) { | |
char c; | |
int ret = ::read(mFileDesc, &c, 1); | |
if (ret > 0) { | |
if (c == '\n' || c == '\r') { | |
break; | |
} | |
line.push_back(c); | |
n++; | |
} else if (ret < 0) { | |
return ret; | |
} | |
} | |
return n; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
MIT License | |
Copyright (c) 2018, Michael Spieler | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
*/ | |
#ifndef _SERIALPORT_H | |
#define _SERIALPORT_H | |
#include <string> | |
#include <termios.h> | |
/** Class to interface serialport under Linux and macOS */ | |
class SerialPort | |
{ | |
public: | |
/** SerialPort | |
* @param[in] port Path to the serialport. | |
* @param[in] baudRate Serial baud rate configuration. | |
* @param[in] stopBits Number of stop bits (1 or 2). | |
*/ | |
SerialPort(const char *port, unsigned baudRate = 57600, unsigned stopBits = 1, | |
bool canonical_mode = false); | |
~SerialPort(); | |
/** Write a buffer. | |
* @param[in] buf Output buffer. | |
* @param[in] nBytes Number of bytes to be written. | |
* @return Number of bytes read, negative on error. | |
*/ | |
int write(const char *buf, size_t nBytes); | |
/** Wrire a std::string. | |
* @param[in] string String to be written. | |
* @return Number of bytes written, negative on error. | |
*/ | |
int write(const std::string& string); | |
/** Read nBytes into a buffer. | |
* @param[out] buf Buffer read. | |
* @return Number of bytes read, negative on error. | |
*/ | |
int read(char *buf, size_t nBytes); | |
/** Read a line terminated by a newline character (CR or LF). | |
* @param[out] line Line read, NULL-terminated. | |
* @param[in] nmax Capacity of line buffer inclusive NULL-termination. | |
* @return Number of bytes read (without NULL-termination), negative on error. | |
*/ | |
int readLine(char *line, size_t nmax); | |
/** Read a line terminated by a newline character (CR or LF). | |
* @param[out] line Line read as a std::string. | |
* @return Number of bytes read, negative on error. | |
*/ | |
int readLine(std::string &line); | |
protected: | |
int mFileDesc; /**< File descriptor */ | |
private: | |
struct termios mOriginalTTYAttrs; /**< Original termios options */ | |
}; | |
#endif /* _SERIALPORT_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment