From 18eb90734c8bc37df1c2640c3a1e14657c53b207 Mon Sep 17 00:00:00 2001 From: Geoffrey Hunter Date: Sat, 7 Nov 2020 23:31:47 -0800 Subject: [PATCH] Re-enabled all UNIX baud rates. Improved README.md documentation. --- .gitignore | 5 ++++- CHANGELOG.md | 11 +++++++++++ README.md | 40 ++++++++-------------------------------- include/CppLinuxSerial/SerialPort.hpp | 24 ++++++++---------------- src/SerialPort.cpp | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------- test/arduino/Basic/Basic.ino | 2 +- test/arduino/main.cpp | 4 ++-- 7 files changed, 156 insertions(+), 141 deletions(-) diff --git a/.gitignore b/.gitignore index 1fc2c47..a749124 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ cmake-build-debug/ .vscode/ # Sphinx build dir -docs/_build/ \ No newline at end of file +docs/_build/ + +# Build artifacts +a.out \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b85fa4..8902279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [v2.1.0] - 2020-11-08 + +### Added +- Support for custom baud rates. +- Support for all standard UNIX baud rates. +- Improved Doxygen documentation. +- Improved README.md documentation. + +### Removed +- Dependencies from the README, they weren't that useful and were not accurate anyway. + ## [v2.0.3] - 2020-10-13 ### Added diff --git a/README.md b/README.md index 1a4582c..caea473 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CppLinuxSerial -Serial port library written in C++ +Linux serial port library written in C++. [![Build Status](https://travis-ci.org/gbmhunter/CppLinuxSerial.svg?branch=master)](https://travis-ci.org/gbmhunter/CppLinuxSerial) @@ -8,7 +8,9 @@ Serial port library written in C++ Library for communicating with COM ports on a Linux system. -Uses fstream to the file I/O. +* Simple API +* Supports custom baud rates +* cmake based build system ## Installation @@ -67,13 +69,14 @@ using namespace mn::CppLinuxSerial; int main() { // Create serial port object and open serial port SerialPort serialPort("/dev/ttyUSB0", BaudRate::B_57600); + // Use SerialPort serialPort("/dev/ttyACM0", 13000); instead if you want to provide a custom baud rate serialPort.SetTimeout(-1); // Block when reading until any data is received serialPort.Open(); // Write some ASCII datae serialPort.Write("Hello"); - // Read some data back + // Read some data back (will block until at least 1 byte is received due to the SetTimeout(-1) call above) std::string readData; serialPort.Read(readData); @@ -88,34 +91,7 @@ If the above code was in a file called `main.cpp` and you had installed `CppLinu g++ main.cpp -lCppLinuxSerial ``` -For more examples, see the `.cpp` files in `test/unit/`. - -## Dependencies - -The following table lists all of the libraries dependencies. - - - - - - - - - - - - - - - - - - - - - - -
DependencyComments
C++14C++14 used for strongly typed enums, `std::chrono` and literals.
stdio.hsnprintf()
sttyUsed in unit tests to verify the serial port is configured correctly.
+For more examples, see the files in `test/`. ## Issues @@ -123,7 +99,7 @@ See GitHub Issues. ## FAQ -1. My code stalls when calling functions like `SerialPort::Read()`. This is probably because the library is set up to do a blocking read, and not enough characters have been received to allow `SerialPort::Read()` to return. Use `SerialPort::SetNumCharsToWait()` to determine how many characters to wait for before returning (set to 0 for non-blocking mode). +1. My code stalls when calling functions like `SerialPort::Read()`. This is probably because the library is set up to do a blocking read, and not enough characters have been received to allow `SerialPort::Read()` to return. Call `SerialPort::SetTimeout(0)` before the serial port is open to set a non-blocking mode. ## Changelog diff --git a/include/CppLinuxSerial/SerialPort.hpp b/include/CppLinuxSerial/SerialPort.hpp index afc6d38..6739e7a 100644 --- a/include/CppLinuxSerial/SerialPort.hpp +++ b/include/CppLinuxSerial/SerialPort.hpp @@ -24,22 +24,11 @@ // User headers #include "Exception.hpp" - - typedef unsigned int speed_t; -// typedef struct termios2 { -// tcflag_t c_iflag; /* input mode flags */ -// tcflag_t c_oflag; /* output mode flags */ -// tcflag_t c_cflag; /* control mode flags */ -// tcflag_t c_lflag; /* local mode flags */ -// cc_t c_line; /* line discipline */ -// cc_t c_cc[NCCS]; /* control characters */ -// speed_t c_ispeed; /* input speed */ -// speed_t c_ospeed; /* output speed */ -// } termios2_t; - namespace mn { namespace CppLinuxSerial { + /// \brief Represents the baud rate "types" that can be used with the serial port. STANDARD represents all + /// the standard baud rates as provided by UNIX, CUSTOM represents a baud rate defined by an arbitray integer. enum class BaudRateType { STANDARD, CUSTOM, @@ -72,6 +61,7 @@ namespace mn { B_CUSTOM, // Placeholder }; + /// \brief Represents the state of the serial port. enum class State { CLOSED, OPEN, @@ -90,13 +80,14 @@ namespace mn { /// \brief Constructor that sets up serial port with the basic (required) parameters. SerialPort(const std::string &device, speed_t baudRate); - //! @brief Destructor. Closes serial port if still open. + /// \brief Destructor. Closes serial port if still open. virtual ~SerialPort(); /// \brief Sets the device to use for serial port communications. /// \details Method can be called when serial port is in any state. void SetDevice(const std::string &device); + /// \brief Allows the user to set a standard baud rate. void SetBaudRate(BaudRate baudRate); /// \brief Allows the user to set a custom baud rate. @@ -139,15 +130,16 @@ namespace mn { /// \brief Returns a populated termios structure for the passed in file descriptor. // termios GetTermios(); - - /// \brief Configures the tty device as a serial port. /// \warning Device must be open (valid file descriptor) when this is called. void ConfigureTermios(); // void SetTermios(termios myTermios); + /// \brief Returns a populated termios2 structure for the serial port pointed to by the file descriptor. termios2 GetTermios2(); + + /// \brief Assigns the provided tty settings to the serial port pointed to by the file descriptor. void SetTermios2(termios2 tty); /// \brief Keeps track of the serial port's state. diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index 72feedd..d3f09fa 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -140,103 +140,140 @@ namespace CppLinuxSerial { //===================== BAUD RATE =================// - // We used to use cfsetispeed() cand cfsetospeed(), but this didn't allow - // us to set custom baud rates + // We used to use cfsetispeed() and cfsetospeed() with the B... macros, but this didn't allow + // us to set custom baud rates. So now to support both standard and custom baud rates lets + // just make everything "custom". This giant switch statement could be replaced with a map/lookup + // in the future if (baudRateType_ == BaudRateType::STANDARD) { + tty.c_cflag &= ~CBAUD; + tty.c_cflag |= CBAUDEX; switch(baudRateStandard_) { - // case BaudRate::B_0: + case BaudRate::B_0: // cfsetispeed(&tty, B0); // cfsetospeed(&tty, B0); - // tty.c_ispeed = 0; - // tty.c_ospeed = 0; - // break; - // case BaudRate::B_50: + tty.c_ispeed = 0; + tty.c_ospeed = 0; + break; + case BaudRate::B_50: // cfsetispeed(&tty, B50); // cfsetospeed(&tty, B50); - // tty.c_ispeed = 50; - // tty.c_ospeed = 50; - // break; - // case BaudRate::B_75: - // cfsetispeed(&tty, B75); - // cfsetospeed(&tty, B75); - // break; - // case BaudRate::B_110: - // cfsetispeed(&tty, B110); - // cfsetospeed(&tty, B110); - // break; - // case BaudRate::B_134: - // cfsetispeed(&tty, B134); - // cfsetospeed(&tty, B134); - // break; - // case BaudRate::B_150: - // cfsetispeed(&tty, B150); - // cfsetospeed(&tty, B150); - // break; - // case BaudRate::B_200: - // cfsetispeed(&tty, B200); - // cfsetospeed(&tty, B200); - // break; - // case BaudRate::B_300: - // cfsetispeed(&tty, B300); - // cfsetospeed(&tty, B300); - // break; - // case BaudRate::B_600: - // cfsetispeed(&tty, B600); - // cfsetospeed(&tty, B600); - // break; - // case BaudRate::B_1200: - // cfsetispeed(&tty, B1200); - // cfsetospeed(&tty, B1200); - // break; - // case BaudRate::B_1800: - // cfsetispeed(&tty, B1800); - // cfsetospeed(&tty, B1800); - // break; - // case BaudRate::B_2400: - // cfsetispeed(&tty, B2400); - // cfsetospeed(&tty, B2400); - // break; - // case BaudRate::B_4800: - // cfsetispeed(&tty, B4800); - // cfsetospeed(&tty, B4800); - // break; - // case BaudRate::B_9600: + tty.c_ispeed = 50; + tty.c_ospeed = 50; + break; + case BaudRate::B_75: + // cfsetispeed(&tty, B75); + // cfsetospeed(&tty, B75); + tty.c_ispeed = 75; + tty.c_ospeed = 75; + break; + case BaudRate::B_110: + // cfsetispeed(&tty, B110); + // cfsetospeed(&tty, B110); + tty.c_ispeed = 110; + tty.c_ospeed = 110; + break; + case BaudRate::B_134: + // cfsetispeed(&tty, B134); + // cfsetospeed(&tty, B134); + tty.c_ispeed = 134; + tty.c_ospeed = 134; + break; + case BaudRate::B_150: + // cfsetispeed(&tty, B150); + // cfsetospeed(&tty, B150); + tty.c_ispeed = 150; + tty.c_ospeed = 150; + break; + case BaudRate::B_200: + // cfsetispeed(&tty, B200); + // cfsetospeed(&tty, B200); + tty.c_ispeed = 200; + tty.c_ospeed = 200; + break; + case BaudRate::B_300: + // cfsetispeed(&tty, B300); + // cfsetospeed(&tty, B300); + tty.c_ispeed = 300; + tty.c_ospeed = 300; + break; + case BaudRate::B_600: + // cfsetispeed(&tty, B600); + // cfsetospeed(&tty, B600); + tty.c_ispeed = 600; + tty.c_ospeed = 600; + break; + case BaudRate::B_1200: + // cfsetispeed(&tty, B1200); + // cfsetospeed(&tty, B1200); + tty.c_ispeed = 1200; + tty.c_ospeed = 1200; + break; + case BaudRate::B_1800: + // cfsetispeed(&tty, B1800); + // cfsetospeed(&tty, B1800); + tty.c_ispeed = 1800; + tty.c_ospeed = 1800; + break; + case BaudRate::B_2400: + // cfsetispeed(&tty, B2400); + // cfsetospeed(&tty, B2400); + tty.c_ispeed = 2400; + tty.c_ospeed = 2400; + break; + case BaudRate::B_4800: + // cfsetispeed(&tty, B4800); + // cfsetospeed(&tty, B4800); + tty.c_ispeed = 4800; + tty.c_ospeed = 4800; + break; + case BaudRate::B_9600: // cfsetispeed(&tty, B9600); // cfsetospeed(&tty, B9600); - // tty.c_ispeed = 9600; - // tty.c_ospeed = 9600; - // break; - // case BaudRate::B_19200: - // cfsetispeed(&tty, B19200); - // cfsetospeed(&tty, B19200); - // break; - // case BaudRate::B_38400: - // cfsetispeed(&tty, B38400); - // cfsetospeed(&tty, B38400); - // break; - // case BaudRate::B_57600: - // cfsetispeed(&tty, B57600); - // cfsetospeed(&tty, B57600); - // break; - // case BaudRate::B_115200: - // cfsetispeed(&tty, B115200); - // cfsetospeed(&tty, B115200); - // break; - // case BaudRate::B_230400: - // cfsetispeed(&tty, B230400); - // cfsetospeed(&tty, B230400); - // break; - // case BaudRate::B_460800: - // cfsetispeed(&tty, B460800); - // cfsetospeed(&tty, B460800); - // break; - // case BaudRate::CUSTOM: - // // See https://gist.github.com/kennethryerson/f7d1abcf2633b7c03cf0 - // throw std::runtime_error("Custom baud rate not yet supported."); + tty.c_ispeed = 9600; + tty.c_ospeed = 9600; + break; + case BaudRate::B_19200: + // cfsetispeed(&tty, B19200); + // cfsetospeed(&tty, B19200); + tty.c_ispeed = 19200; + tty.c_ospeed = 19200; + break; + case BaudRate::B_38400: + // cfsetispeed(&tty, B38400); + // cfsetospeed(&tty, B38400); + tty.c_ispeed = 38400; + tty.c_ospeed = 38400; + break; + case BaudRate::B_57600: + // cfsetispeed(&tty, B57600); + // cfsetospeed(&tty, B57600); + tty.c_ispeed = 57600; + tty.c_ospeed = 57600; + break; + case BaudRate::B_115200: + // cfsetispeed(&tty, B115200); + // cfsetospeed(&tty, B115200); + tty.c_ispeed = 115200; + tty.c_ospeed = 115200; + break; + case BaudRate::B_230400: + // cfsetispeed(&tty, B230400); + // cfsetospeed(&tty, B230400); + tty.c_ispeed = 230400; + tty.c_ospeed = 230400; + break; + case BaudRate::B_460800: + // cfsetispeed(&tty, B460800); + // cfsetospeed(&tty, B460800); + tty.c_ispeed = 460800; + tty.c_ospeed = 460800; + break; default: throw std::runtime_error(std::string() + "baudRate passed to " + __PRETTY_FUNCTION__ + " unrecognized."); } } + // This does no different than STANDARD atm, but let's keep + // them separate for now.... else if (baudRateType_ == BaudRateType::CUSTOM) { tty.c_cflag &= ~CBAUD; @@ -300,14 +337,11 @@ namespace CppLinuxSerial { tty.c_cc[VMIN] = 0; } - //======================== (.c_iflag) ====================// tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); - - //=========================== LOCAL MODES (c_lflag) =======================// // Canonical input is when read waits for EOL or EOF characters before returning. In non-canonical mode, the rate at which @@ -319,7 +353,6 @@ namespace CppLinuxSerial { tty.c_lflag &= ~ISIG; // Disables recognition of INTR (interrupt), QUIT and SUSP (suspend) characters - // Try and use raw function call //cfmakeraw(&tty); diff --git a/test/arduino/Basic/Basic.ino b/test/arduino/Basic/Basic.ino index d9a4a20..10fa637 100644 --- a/test/arduino/Basic/Basic.ino +++ b/test/arduino/Basic/Basic.ino @@ -13,7 +13,7 @@ // the setup routine runs once when you press reset: void setup() { // initialize serial communication at 9600 bits per second: - Serial.begin(13000); + Serial.begin(9600); // Serial.begin(81234); // Used to test custom baud rates } diff --git a/test/arduino/main.cpp b/test/arduino/main.cpp index 935d756..0cf1248 100644 --- a/test/arduino/main.cpp +++ b/test/arduino/main.cpp @@ -4,8 +4,8 @@ using namespace mn::CppLinuxSerial; int main() { // Create serial port object and open serial port - // SerialPort serialPort("/dev/ttyACM0", BaudRate::B_9600); - SerialPort serialPort("/dev/ttyACM0", 13000); + SerialPort serialPort("/dev/ttyACM0", BaudRate::B_9600); + // SerialPort serialPort("/dev/ttyACM0", 13000); serialPort.SetTimeout(-1); // Block when reading until any data is received serialPort.Open(); -- libgit2 0.21.4