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 .vscode/
5 5  
6 6 # Sphinx build dir
7   -docs/_build/
8 7 \ No newline at end of file
  8 +docs/_build/
  9 +
  10 +# Build artifacts
  11 +a.out
9 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 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 [![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 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  
... ...