Commit 18eb90734c8bc37df1c2640c3a1e14657c53b207

Authored by Geoffrey Hunter
1 parent 46234190

Re-enabled all UNIX baud rates. Improved README.md documentation.

.gitignore
@@ -4,4 +4,7 @@ cmake-build-debug/ @@ -4,4 +4,7 @@ cmake-build-debug/
4 .vscode/ 4 .vscode/
5 5
6 # Sphinx build dir 6 # Sphinx build dir
7 -docs/_build/  
8 \ No newline at end of file 7 \ No newline at end of file
  8 +docs/_build/
  9 +
  10 +# Build artifacts
  11 +a.out
9 \ No newline at end of file 12 \ No newline at end of file
CHANGELOG.md
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
7 7
8 ## [Unreleased] 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 ## [v2.0.3] - 2020-10-13 21 ## [v2.0.3] - 2020-10-13
11 22
12 ### Added 23 ### Added
README.md
1 # CppLinuxSerial 1 # CppLinuxSerial
2 2
3 -Serial port library written in C++ 3 +Linux serial port library written in C++.
4 4
5 [![Build Status](https://travis-ci.org/gbmhunter/CppLinuxSerial.svg?branch=master)](https://travis-ci.org/gbmhunter/CppLinuxSerial) 5 [![Build Status](https://travis-ci.org/gbmhunter/CppLinuxSerial.svg?branch=master)](https://travis-ci.org/gbmhunter/CppLinuxSerial)
6 6
@@ -8,7 +8,9 @@ Serial port library written in C++ @@ -8,7 +8,9 @@ Serial port library written in C++
8 8
9 Library for communicating with COM ports on a Linux system. 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 ## Installation 15 ## Installation
14 16
@@ -67,13 +69,14 @@ using namespace mn::CppLinuxSerial; @@ -67,13 +69,14 @@ using namespace mn::CppLinuxSerial;
67 int main() { 69 int main() {
68 // Create serial port object and open serial port 70 // Create serial port object and open serial port
69 SerialPort serialPort("/dev/ttyUSB0", BaudRate::B_57600); 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 serialPort.SetTimeout(-1); // Block when reading until any data is received 73 serialPort.SetTimeout(-1); // Block when reading until any data is received
71 serialPort.Open(); 74 serialPort.Open();
72 75
73 // Write some ASCII datae 76 // Write some ASCII datae
74 serialPort.Write("Hello"); 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 std::string readData; 80 std::string readData;
78 serialPort.Read(readData); 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,34 +91,7 @@ If the above code was in a file called `main.cpp` and you had installed `CppLinu
88 g++ main.cpp -lCppLinuxSerial 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 ## Issues 96 ## Issues
121 97
@@ -123,7 +99,7 @@ See GitHub Issues. @@ -123,7 +99,7 @@ See GitHub Issues.
123 99
124 ## FAQ 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 ## Changelog 104 ## Changelog
129 105
include/CppLinuxSerial/SerialPort.hpp
@@ -24,22 +24,11 @@ @@ -24,22 +24,11 @@
24 // User headers 24 // User headers
25 #include "Exception.hpp" 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 namespace mn { 27 namespace mn {
41 namespace CppLinuxSerial { 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 enum class BaudRateType { 32 enum class BaudRateType {
44 STANDARD, 33 STANDARD,
45 CUSTOM, 34 CUSTOM,
@@ -72,6 +61,7 @@ namespace mn { @@ -72,6 +61,7 @@ namespace mn {
72 B_CUSTOM, // Placeholder 61 B_CUSTOM, // Placeholder
73 }; 62 };
74 63
  64 + /// \brief Represents the state of the serial port.
75 enum class State { 65 enum class State {
76 CLOSED, 66 CLOSED,
77 OPEN, 67 OPEN,
@@ -90,13 +80,14 @@ namespace mn { @@ -90,13 +80,14 @@ namespace mn {
90 /// \brief Constructor that sets up serial port with the basic (required) parameters. 80 /// \brief Constructor that sets up serial port with the basic (required) parameters.
91 SerialPort(const std::string &device, speed_t baudRate); 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 virtual ~SerialPort(); 84 virtual ~SerialPort();
95 85
96 /// \brief Sets the device to use for serial port communications. 86 /// \brief Sets the device to use for serial port communications.
97 /// \details Method can be called when serial port is in any state. 87 /// \details Method can be called when serial port is in any state.
98 void SetDevice(const std::string &device); 88 void SetDevice(const std::string &device);
99 89
  90 + /// \brief Allows the user to set a standard baud rate.
100 void SetBaudRate(BaudRate baudRate); 91 void SetBaudRate(BaudRate baudRate);
101 92
102 /// \brief Allows the user to set a custom baud rate. 93 /// \brief Allows the user to set a custom baud rate.
@@ -139,15 +130,16 @@ namespace mn { @@ -139,15 +130,16 @@ namespace mn {
139 /// \brief Returns a populated termios structure for the passed in file descriptor. 130 /// \brief Returns a populated termios structure for the passed in file descriptor.
140 // termios GetTermios(); 131 // termios GetTermios();
141 132
142 -  
143 -  
144 /// \brief Configures the tty device as a serial port. 133 /// \brief Configures the tty device as a serial port.
145 /// \warning Device must be open (valid file descriptor) when this is called. 134 /// \warning Device must be open (valid file descriptor) when this is called.
146 void ConfigureTermios(); 135 void ConfigureTermios();
147 136
148 // void SetTermios(termios myTermios); 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 termios2 GetTermios2(); 140 termios2 GetTermios2();
  141 +
  142 + /// \brief Assigns the provided tty settings to the serial port pointed to by the file descriptor.
151 void SetTermios2(termios2 tty); 143 void SetTermios2(termios2 tty);
152 144
153 /// \brief Keeps track of the serial port's state. 145 /// \brief Keeps track of the serial port's state.
src/SerialPort.cpp
@@ -140,103 +140,140 @@ namespace CppLinuxSerial { @@ -140,103 +140,140 @@ namespace CppLinuxSerial {
140 140
141 //===================== BAUD RATE =================// 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 if (baudRateType_ == BaudRateType::STANDARD) { 147 if (baudRateType_ == BaudRateType::STANDARD) {
  148 + tty.c_cflag &= ~CBAUD;
  149 + tty.c_cflag |= CBAUDEX;
146 switch(baudRateStandard_) { 150 switch(baudRateStandard_) {
147 - // case BaudRate::B_0: 151 + case BaudRate::B_0:
148 // cfsetispeed(&tty, B0); 152 // cfsetispeed(&tty, B0);
149 // cfsetospeed(&tty, B0); 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 // cfsetispeed(&tty, B50); 158 // cfsetispeed(&tty, B50);
155 // cfsetospeed(&tty, B50); 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 // cfsetispeed(&tty, B9600); 230 // cfsetispeed(&tty, B9600);
205 // cfsetospeed(&tty, B9600); 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 default: 271 default:
237 throw std::runtime_error(std::string() + "baudRate passed to " + __PRETTY_FUNCTION__ + " unrecognized."); 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 else if (baudRateType_ == BaudRateType::CUSTOM) 277 else if (baudRateType_ == BaudRateType::CUSTOM)
241 { 278 {
242 tty.c_cflag &= ~CBAUD; 279 tty.c_cflag &= ~CBAUD;
@@ -300,14 +337,11 @@ namespace CppLinuxSerial { @@ -300,14 +337,11 @@ namespace CppLinuxSerial {
300 tty.c_cc[VMIN] = 0; 337 tty.c_cc[VMIN] = 0;
301 } 338 }
302 339
303 -  
304 //======================== (.c_iflag) ====================// 340 //======================== (.c_iflag) ====================//
305 341
306 tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl 342 tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
307 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); 343 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
308 344
309 -  
310 -  
311 //=========================== LOCAL MODES (c_lflag) =======================// 345 //=========================== LOCAL MODES (c_lflag) =======================//
312 346
313 // Canonical input is when read waits for EOL or EOF characters before returning. In non-canonical mode, the rate at which 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,7 +353,6 @@ namespace CppLinuxSerial {
319 tty.c_lflag &= ~ISIG; // Disables recognition of INTR (interrupt), QUIT and SUSP (suspend) characters 353 tty.c_lflag &= ~ISIG; // Disables recognition of INTR (interrupt), QUIT and SUSP (suspend) characters
320 354
321 355
322 -  
323 // Try and use raw function call 356 // Try and use raw function call
324 //cfmakeraw(&tty); 357 //cfmakeraw(&tty);
325 358
test/arduino/Basic/Basic.ino
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 // the setup routine runs once when you press reset: 13 // the setup routine runs once when you press reset:
14 void setup() { 14 void setup() {
15 // initialize serial communication at 9600 bits per second: 15 // initialize serial communication at 9600 bits per second:
16 - Serial.begin(13000); 16 + Serial.begin(9600);
17 // Serial.begin(81234); // Used to test custom baud rates 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,8 +4,8 @@ using namespace mn::CppLinuxSerial;
4 4
5 int main() { 5 int main() {
6 // Create serial port object and open serial port 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 serialPort.SetTimeout(-1); // Block when reading until any data is received 9 serialPort.SetTimeout(-1); // Block when reading until any data is received
10 serialPort.Open(); 10 serialPort.Open();
11 11