Commit 18eb90734c8bc37df1c2640c3a1e14657c53b207
1 parent
46234190
Re-enabled all UNIX baud rates. Improved README.md documentation.
Showing
7 changed files
with
156 additions
and
141 deletions
.gitignore
CHANGELOG.md
| ... | ... | @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. |
| 7 | 7 | |
| 8 | 8 | ## [Unreleased] |
| 9 | 9 | |
| 10 | +## [v2.1.0] - 2020-11-08 | |
| 11 | + | |
| 12 | +### Added | |
| 13 | +- Support for custom baud rates. | |
| 14 | +- Support for all standard UNIX baud rates. | |
| 15 | +- Improved Doxygen documentation. | |
| 16 | +- Improved README.md documentation. | |
| 17 | + | |
| 18 | +### Removed | |
| 19 | +- Dependencies from the README, they weren't that useful and were not accurate anyway. | |
| 20 | + | |
| 10 | 21 | ## [v2.0.3] - 2020-10-13 |
| 11 | 22 | |
| 12 | 23 | ### Added | ... | ... |
README.md
| 1 | 1 | # CppLinuxSerial |
| 2 | 2 | |
| 3 | -Serial port library written in C++ | |
| 3 | +Linux serial port library written in C++. | |
| 4 | 4 | |
| 5 | 5 | [](https://travis-ci.org/gbmhunter/CppLinuxSerial) |
| 6 | 6 | |
| ... | ... | @@ -8,7 +8,9 @@ Serial port library written in C++ |
| 8 | 8 | |
| 9 | 9 | Library for communicating with COM ports on a Linux system. |
| 10 | 10 | |
| 11 | -Uses fstream to the file I/O. | |
| 11 | +* Simple API | |
| 12 | +* Supports custom baud rates | |
| 13 | +* cmake based build system | |
| 12 | 14 | |
| 13 | 15 | ## Installation |
| 14 | 16 | |
| ... | ... | @@ -67,13 +69,14 @@ using namespace mn::CppLinuxSerial; |
| 67 | 69 | int main() { |
| 68 | 70 | // Create serial port object and open serial port |
| 69 | 71 | SerialPort serialPort("/dev/ttyUSB0", BaudRate::B_57600); |
| 72 | + // Use SerialPort serialPort("/dev/ttyACM0", 13000); instead if you want to provide a custom baud rate | |
| 70 | 73 | serialPort.SetTimeout(-1); // Block when reading until any data is received |
| 71 | 74 | serialPort.Open(); |
| 72 | 75 | |
| 73 | 76 | // Write some ASCII datae |
| 74 | 77 | serialPort.Write("Hello"); |
| 75 | 78 | |
| 76 | - // Read some data back | |
| 79 | + // Read some data back (will block until at least 1 byte is received due to the SetTimeout(-1) call above) | |
| 77 | 80 | std::string readData; |
| 78 | 81 | serialPort.Read(readData); |
| 79 | 82 | |
| ... | ... | @@ -88,34 +91,7 @@ If the above code was in a file called `main.cpp` and you had installed `CppLinu |
| 88 | 91 | g++ main.cpp -lCppLinuxSerial |
| 89 | 92 | ``` |
| 90 | 93 | |
| 91 | -For more examples, see the `.cpp` files in `test/unit/`. | |
| 92 | - | |
| 93 | -## Dependencies | |
| 94 | - | |
| 95 | -The following table lists all of the libraries dependencies. | |
| 96 | - | |
| 97 | -<table> | |
| 98 | - <thead> | |
| 99 | - <tr> | |
| 100 | - <td>Dependency</td> | |
| 101 | - <td>Comments</td> | |
| 102 | - </tr> | |
| 103 | - </thead> | |
| 104 | - <tbody> | |
| 105 | - <tr> | |
| 106 | - <td>C++14</td> | |
| 107 | - <td>C++14 used for strongly typed enums, `std::chrono` and literals.</td> | |
| 108 | - </tr> | |
| 109 | - <tr> | |
| 110 | - <td>stdio.h</td> | |
| 111 | - <td>snprintf()</td> | |
| 112 | - </tr> | |
| 113 | - <tr> | |
| 114 | - <td>stty</td> | |
| 115 | - <td>Used in unit tests to verify the serial port is configured correctly.</td> | |
| 116 | - </tr> | |
| 117 | - </tbody> | |
| 118 | -</table> | |
| 94 | +For more examples, see the files in `test/`. | |
| 119 | 95 | |
| 120 | 96 | ## Issues |
| 121 | 97 | |
| ... | ... | @@ -123,7 +99,7 @@ See GitHub Issues. |
| 123 | 99 | |
| 124 | 100 | ## FAQ |
| 125 | 101 | |
| 126 | -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). | |
| 102 | +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. | |
| 127 | 103 | |
| 128 | 104 | ## Changelog |
| 129 | 105 | ... | ... |
include/CppLinuxSerial/SerialPort.hpp
| ... | ... | @@ -24,22 +24,11 @@ |
| 24 | 24 | // User headers |
| 25 | 25 | #include "Exception.hpp" |
| 26 | 26 | |
| 27 | - | |
| 28 | - typedef unsigned int speed_t; | |
| 29 | -// typedef struct termios2 { | |
| 30 | -// tcflag_t c_iflag; /* input mode flags */ | |
| 31 | -// tcflag_t c_oflag; /* output mode flags */ | |
| 32 | -// tcflag_t c_cflag; /* control mode flags */ | |
| 33 | -// tcflag_t c_lflag; /* local mode flags */ | |
| 34 | -// cc_t c_line; /* line discipline */ | |
| 35 | -// cc_t c_cc[NCCS]; /* control characters */ | |
| 36 | -// speed_t c_ispeed; /* input speed */ | |
| 37 | -// speed_t c_ospeed; /* output speed */ | |
| 38 | -// } termios2_t; | |
| 39 | - | |
| 40 | 27 | namespace mn { |
| 41 | 28 | namespace CppLinuxSerial { |
| 42 | 29 | |
| 30 | + /// \brief Represents the baud rate "types" that can be used with the serial port. STANDARD represents all | |
| 31 | + /// the standard baud rates as provided by UNIX, CUSTOM represents a baud rate defined by an arbitray integer. | |
| 43 | 32 | enum class BaudRateType { |
| 44 | 33 | STANDARD, |
| 45 | 34 | CUSTOM, |
| ... | ... | @@ -72,6 +61,7 @@ namespace mn { |
| 72 | 61 | B_CUSTOM, // Placeholder |
| 73 | 62 | }; |
| 74 | 63 | |
| 64 | + /// \brief Represents the state of the serial port. | |
| 75 | 65 | enum class State { |
| 76 | 66 | CLOSED, |
| 77 | 67 | OPEN, |
| ... | ... | @@ -90,13 +80,14 @@ namespace mn { |
| 90 | 80 | /// \brief Constructor that sets up serial port with the basic (required) parameters. |
| 91 | 81 | SerialPort(const std::string &device, speed_t baudRate); |
| 92 | 82 | |
| 93 | - //! @brief Destructor. Closes serial port if still open. | |
| 83 | + /// \brief Destructor. Closes serial port if still open. | |
| 94 | 84 | virtual ~SerialPort(); |
| 95 | 85 | |
| 96 | 86 | /// \brief Sets the device to use for serial port communications. |
| 97 | 87 | /// \details Method can be called when serial port is in any state. |
| 98 | 88 | void SetDevice(const std::string &device); |
| 99 | 89 | |
| 90 | + /// \brief Allows the user to set a standard baud rate. | |
| 100 | 91 | void SetBaudRate(BaudRate baudRate); |
| 101 | 92 | |
| 102 | 93 | /// \brief Allows the user to set a custom baud rate. |
| ... | ... | @@ -139,15 +130,16 @@ namespace mn { |
| 139 | 130 | /// \brief Returns a populated termios structure for the passed in file descriptor. |
| 140 | 131 | // termios GetTermios(); |
| 141 | 132 | |
| 142 | - | |
| 143 | - | |
| 144 | 133 | /// \brief Configures the tty device as a serial port. |
| 145 | 134 | /// \warning Device must be open (valid file descriptor) when this is called. |
| 146 | 135 | void ConfigureTermios(); |
| 147 | 136 | |
| 148 | 137 | // void SetTermios(termios myTermios); |
| 149 | 138 | |
| 139 | + /// \brief Returns a populated termios2 structure for the serial port pointed to by the file descriptor. | |
| 150 | 140 | termios2 GetTermios2(); |
| 141 | + | |
| 142 | + /// \brief Assigns the provided tty settings to the serial port pointed to by the file descriptor. | |
| 151 | 143 | void SetTermios2(termios2 tty); |
| 152 | 144 | |
| 153 | 145 | /// \brief Keeps track of the serial port's state. | ... | ... |
src/SerialPort.cpp
| ... | ... | @@ -140,103 +140,140 @@ namespace CppLinuxSerial { |
| 140 | 140 | |
| 141 | 141 | //===================== BAUD RATE =================// |
| 142 | 142 | |
| 143 | - // We used to use cfsetispeed() cand cfsetospeed(), but this didn't allow | |
| 144 | - // us to set custom baud rates | |
| 143 | + // We used to use cfsetispeed() and cfsetospeed() with the B... macros, but this didn't allow | |
| 144 | + // us to set custom baud rates. So now to support both standard and custom baud rates lets | |
| 145 | + // just make everything "custom". This giant switch statement could be replaced with a map/lookup | |
| 146 | + // in the future | |
| 145 | 147 | if (baudRateType_ == BaudRateType::STANDARD) { |
| 148 | + tty.c_cflag &= ~CBAUD; | |
| 149 | + tty.c_cflag |= CBAUDEX; | |
| 146 | 150 | switch(baudRateStandard_) { |
| 147 | - // case BaudRate::B_0: | |
| 151 | + case BaudRate::B_0: | |
| 148 | 152 | // cfsetispeed(&tty, B0); |
| 149 | 153 | // cfsetospeed(&tty, B0); |
| 150 | - // tty.c_ispeed = 0; | |
| 151 | - // tty.c_ospeed = 0; | |
| 152 | - // break; | |
| 153 | - // case BaudRate::B_50: | |
| 154 | + tty.c_ispeed = 0; | |
| 155 | + tty.c_ospeed = 0; | |
| 156 | + break; | |
| 157 | + case BaudRate::B_50: | |
| 154 | 158 | // cfsetispeed(&tty, B50); |
| 155 | 159 | // cfsetospeed(&tty, B50); |
| 156 | - // tty.c_ispeed = 50; | |
| 157 | - // tty.c_ospeed = 50; | |
| 158 | - // break; | |
| 159 | - // case BaudRate::B_75: | |
| 160 | - // cfsetispeed(&tty, B75); | |
| 161 | - // cfsetospeed(&tty, B75); | |
| 162 | - // break; | |
| 163 | - // case BaudRate::B_110: | |
| 164 | - // cfsetispeed(&tty, B110); | |
| 165 | - // cfsetospeed(&tty, B110); | |
| 166 | - // break; | |
| 167 | - // case BaudRate::B_134: | |
| 168 | - // cfsetispeed(&tty, B134); | |
| 169 | - // cfsetospeed(&tty, B134); | |
| 170 | - // break; | |
| 171 | - // case BaudRate::B_150: | |
| 172 | - // cfsetispeed(&tty, B150); | |
| 173 | - // cfsetospeed(&tty, B150); | |
| 174 | - // break; | |
| 175 | - // case BaudRate::B_200: | |
| 176 | - // cfsetispeed(&tty, B200); | |
| 177 | - // cfsetospeed(&tty, B200); | |
| 178 | - // break; | |
| 179 | - // case BaudRate::B_300: | |
| 180 | - // cfsetispeed(&tty, B300); | |
| 181 | - // cfsetospeed(&tty, B300); | |
| 182 | - // break; | |
| 183 | - // case BaudRate::B_600: | |
| 184 | - // cfsetispeed(&tty, B600); | |
| 185 | - // cfsetospeed(&tty, B600); | |
| 186 | - // break; | |
| 187 | - // case BaudRate::B_1200: | |
| 188 | - // cfsetispeed(&tty, B1200); | |
| 189 | - // cfsetospeed(&tty, B1200); | |
| 190 | - // break; | |
| 191 | - // case BaudRate::B_1800: | |
| 192 | - // cfsetispeed(&tty, B1800); | |
| 193 | - // cfsetospeed(&tty, B1800); | |
| 194 | - // break; | |
| 195 | - // case BaudRate::B_2400: | |
| 196 | - // cfsetispeed(&tty, B2400); | |
| 197 | - // cfsetospeed(&tty, B2400); | |
| 198 | - // break; | |
| 199 | - // case BaudRate::B_4800: | |
| 200 | - // cfsetispeed(&tty, B4800); | |
| 201 | - // cfsetospeed(&tty, B4800); | |
| 202 | - // break; | |
| 203 | - // case BaudRate::B_9600: | |
| 160 | + tty.c_ispeed = 50; | |
| 161 | + tty.c_ospeed = 50; | |
| 162 | + break; | |
| 163 | + case BaudRate::B_75: | |
| 164 | + // cfsetispeed(&tty, B75); | |
| 165 | + // cfsetospeed(&tty, B75); | |
| 166 | + tty.c_ispeed = 75; | |
| 167 | + tty.c_ospeed = 75; | |
| 168 | + break; | |
| 169 | + case BaudRate::B_110: | |
| 170 | + // cfsetispeed(&tty, B110); | |
| 171 | + // cfsetospeed(&tty, B110); | |
| 172 | + tty.c_ispeed = 110; | |
| 173 | + tty.c_ospeed = 110; | |
| 174 | + break; | |
| 175 | + case BaudRate::B_134: | |
| 176 | + // cfsetispeed(&tty, B134); | |
| 177 | + // cfsetospeed(&tty, B134); | |
| 178 | + tty.c_ispeed = 134; | |
| 179 | + tty.c_ospeed = 134; | |
| 180 | + break; | |
| 181 | + case BaudRate::B_150: | |
| 182 | + // cfsetispeed(&tty, B150); | |
| 183 | + // cfsetospeed(&tty, B150); | |
| 184 | + tty.c_ispeed = 150; | |
| 185 | + tty.c_ospeed = 150; | |
| 186 | + break; | |
| 187 | + case BaudRate::B_200: | |
| 188 | + // cfsetispeed(&tty, B200); | |
| 189 | + // cfsetospeed(&tty, B200); | |
| 190 | + tty.c_ispeed = 200; | |
| 191 | + tty.c_ospeed = 200; | |
| 192 | + break; | |
| 193 | + case BaudRate::B_300: | |
| 194 | + // cfsetispeed(&tty, B300); | |
| 195 | + // cfsetospeed(&tty, B300); | |
| 196 | + tty.c_ispeed = 300; | |
| 197 | + tty.c_ospeed = 300; | |
| 198 | + break; | |
| 199 | + case BaudRate::B_600: | |
| 200 | + // cfsetispeed(&tty, B600); | |
| 201 | + // cfsetospeed(&tty, B600); | |
| 202 | + tty.c_ispeed = 600; | |
| 203 | + tty.c_ospeed = 600; | |
| 204 | + break; | |
| 205 | + case BaudRate::B_1200: | |
| 206 | + // cfsetispeed(&tty, B1200); | |
| 207 | + // cfsetospeed(&tty, B1200); | |
| 208 | + tty.c_ispeed = 1200; | |
| 209 | + tty.c_ospeed = 1200; | |
| 210 | + break; | |
| 211 | + case BaudRate::B_1800: | |
| 212 | + // cfsetispeed(&tty, B1800); | |
| 213 | + // cfsetospeed(&tty, B1800); | |
| 214 | + tty.c_ispeed = 1800; | |
| 215 | + tty.c_ospeed = 1800; | |
| 216 | + break; | |
| 217 | + case BaudRate::B_2400: | |
| 218 | + // cfsetispeed(&tty, B2400); | |
| 219 | + // cfsetospeed(&tty, B2400); | |
| 220 | + tty.c_ispeed = 2400; | |
| 221 | + tty.c_ospeed = 2400; | |
| 222 | + break; | |
| 223 | + case BaudRate::B_4800: | |
| 224 | + // cfsetispeed(&tty, B4800); | |
| 225 | + // cfsetospeed(&tty, B4800); | |
| 226 | + tty.c_ispeed = 4800; | |
| 227 | + tty.c_ospeed = 4800; | |
| 228 | + break; | |
| 229 | + case BaudRate::B_9600: | |
| 204 | 230 | // cfsetispeed(&tty, B9600); |
| 205 | 231 | // cfsetospeed(&tty, B9600); |
| 206 | - // tty.c_ispeed = 9600; | |
| 207 | - // tty.c_ospeed = 9600; | |
| 208 | - // break; | |
| 209 | - // case BaudRate::B_19200: | |
| 210 | - // cfsetispeed(&tty, B19200); | |
| 211 | - // cfsetospeed(&tty, B19200); | |
| 212 | - // break; | |
| 213 | - // case BaudRate::B_38400: | |
| 214 | - // cfsetispeed(&tty, B38400); | |
| 215 | - // cfsetospeed(&tty, B38400); | |
| 216 | - // break; | |
| 217 | - // case BaudRate::B_57600: | |
| 218 | - // cfsetispeed(&tty, B57600); | |
| 219 | - // cfsetospeed(&tty, B57600); | |
| 220 | - // break; | |
| 221 | - // case BaudRate::B_115200: | |
| 222 | - // cfsetispeed(&tty, B115200); | |
| 223 | - // cfsetospeed(&tty, B115200); | |
| 224 | - // break; | |
| 225 | - // case BaudRate::B_230400: | |
| 226 | - // cfsetispeed(&tty, B230400); | |
| 227 | - // cfsetospeed(&tty, B230400); | |
| 228 | - // break; | |
| 229 | - // case BaudRate::B_460800: | |
| 230 | - // cfsetispeed(&tty, B460800); | |
| 231 | - // cfsetospeed(&tty, B460800); | |
| 232 | - // break; | |
| 233 | - // case BaudRate::CUSTOM: | |
| 234 | - // // See https://gist.github.com/kennethryerson/f7d1abcf2633b7c03cf0 | |
| 235 | - // throw std::runtime_error("Custom baud rate not yet supported."); | |
| 232 | + tty.c_ispeed = 9600; | |
| 233 | + tty.c_ospeed = 9600; | |
| 234 | + break; | |
| 235 | + case BaudRate::B_19200: | |
| 236 | + // cfsetispeed(&tty, B19200); | |
| 237 | + // cfsetospeed(&tty, B19200); | |
| 238 | + tty.c_ispeed = 19200; | |
| 239 | + tty.c_ospeed = 19200; | |
| 240 | + break; | |
| 241 | + case BaudRate::B_38400: | |
| 242 | + // cfsetispeed(&tty, B38400); | |
| 243 | + // cfsetospeed(&tty, B38400); | |
| 244 | + tty.c_ispeed = 38400; | |
| 245 | + tty.c_ospeed = 38400; | |
| 246 | + break; | |
| 247 | + case BaudRate::B_57600: | |
| 248 | + // cfsetispeed(&tty, B57600); | |
| 249 | + // cfsetospeed(&tty, B57600); | |
| 250 | + tty.c_ispeed = 57600; | |
| 251 | + tty.c_ospeed = 57600; | |
| 252 | + break; | |
| 253 | + case BaudRate::B_115200: | |
| 254 | + // cfsetispeed(&tty, B115200); | |
| 255 | + // cfsetospeed(&tty, B115200); | |
| 256 | + tty.c_ispeed = 115200; | |
| 257 | + tty.c_ospeed = 115200; | |
| 258 | + break; | |
| 259 | + case BaudRate::B_230400: | |
| 260 | + // cfsetispeed(&tty, B230400); | |
| 261 | + // cfsetospeed(&tty, B230400); | |
| 262 | + tty.c_ispeed = 230400; | |
| 263 | + tty.c_ospeed = 230400; | |
| 264 | + break; | |
| 265 | + case BaudRate::B_460800: | |
| 266 | + // cfsetispeed(&tty, B460800); | |
| 267 | + // cfsetospeed(&tty, B460800); | |
| 268 | + tty.c_ispeed = 460800; | |
| 269 | + tty.c_ospeed = 460800; | |
| 270 | + break; | |
| 236 | 271 | default: |
| 237 | 272 | throw std::runtime_error(std::string() + "baudRate passed to " + __PRETTY_FUNCTION__ + " unrecognized."); |
| 238 | 273 | } |
| 239 | 274 | } |
| 275 | + // This does no different than STANDARD atm, but let's keep | |
| 276 | + // them separate for now.... | |
| 240 | 277 | else if (baudRateType_ == BaudRateType::CUSTOM) |
| 241 | 278 | { |
| 242 | 279 | tty.c_cflag &= ~CBAUD; |
| ... | ... | @@ -300,14 +337,11 @@ namespace CppLinuxSerial { |
| 300 | 337 | tty.c_cc[VMIN] = 0; |
| 301 | 338 | } |
| 302 | 339 | |
| 303 | - | |
| 304 | 340 | //======================== (.c_iflag) ====================// |
| 305 | 341 | |
| 306 | 342 | tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl |
| 307 | 343 | tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); |
| 308 | 344 | |
| 309 | - | |
| 310 | - | |
| 311 | 345 | //=========================== LOCAL MODES (c_lflag) =======================// |
| 312 | 346 | |
| 313 | 347 | // 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 { |
| 319 | 353 | tty.c_lflag &= ~ISIG; // Disables recognition of INTR (interrupt), QUIT and SUSP (suspend) characters |
| 320 | 354 | |
| 321 | 355 | |
| 322 | - | |
| 323 | 356 | // Try and use raw function call |
| 324 | 357 | //cfmakeraw(&tty); |
| 325 | 358 | ... | ... |
test/arduino/Basic/Basic.ino
| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | // the setup routine runs once when you press reset: |
| 14 | 14 | void setup() { |
| 15 | 15 | // initialize serial communication at 9600 bits per second: |
| 16 | - Serial.begin(13000); | |
| 16 | + Serial.begin(9600); | |
| 17 | 17 | // Serial.begin(81234); // Used to test custom baud rates |
| 18 | 18 | } |
| 19 | 19 | ... | ... |
test/arduino/main.cpp
| ... | ... | @@ -4,8 +4,8 @@ using namespace mn::CppLinuxSerial; |
| 4 | 4 | |
| 5 | 5 | int main() { |
| 6 | 6 | // Create serial port object and open serial port |
| 7 | - // SerialPort serialPort("/dev/ttyACM0", BaudRate::B_9600); | |
| 8 | - SerialPort serialPort("/dev/ttyACM0", 13000); | |
| 7 | + SerialPort serialPort("/dev/ttyACM0", BaudRate::B_9600); | |
| 8 | + // SerialPort serialPort("/dev/ttyACM0", 13000); | |
| 9 | 9 | serialPort.SetTimeout(-1); // Block when reading until any data is received |
| 10 | 10 | serialPort.Open(); |
| 11 | 11 | ... | ... |