Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
213 | dhylands | 1 | /**************************************************************************** |
2 | * |
||
3 | * Copyright (c) 2009 Dave Hylands <dhylands@gmail.com> |
||
4 | * |
||
5 | * This program is free software; you can redistribute it and/or modify |
||
6 | * it under the terms of the GNU General Public License version 2 as |
||
7 | * published by the Free Software Foundation. |
||
8 | * |
||
9 | * Alternatively, this software may be distributed under the terms of BSD |
||
10 | * license. |
||
11 | * |
||
12 | * See README and COPYING for more details. |
||
13 | * |
||
14 | ****************************************************************************/ |
||
15 | /** |
||
16 | * |
||
17 | * @file SerialPort.cpp |
||
18 | * |
||
19 | * @brief This file implements the SerialPort class using the posix |
||
20 | * API, which is supported by cygwin and linux. |
||
21 | * |
||
22 | ****************************************************************************/ |
||
23 | |||
24 | // ---- Include Files ------------------------------------------------------- |
||
25 | |||
26 | #include "Log.h" |
||
27 | #include "SerialPort.h" |
||
28 | #include "Str.h" |
||
29 | |||
30 | #include <stdio.h> |
||
31 | #include <stdlib.h> |
||
32 | #include <termios.h> |
||
33 | #include <errno.h> |
||
34 | #include <fcntl.h> |
||
35 | #include <sys/unistd.h> |
||
36 | #include <string.h> |
||
37 | #include <sys/ioctl.h> |
||
38 | |||
39 | // ---- Public Variables ---------------------------------------------------- |
||
40 | |||
41 | // ---- Private Constants and Types ----------------------------------------- |
||
42 | // ---- Private Variables --------------------------------------------------- |
||
43 | |||
44 | static struct |
||
45 | { |
||
46 | speed_t speed; |
||
47 | unsigned baudRate; |
||
48 | } gBaudTable[] = |
||
49 | { |
||
50 | { B50, 50 }, |
||
51 | { B75, 75 }, |
||
52 | { B110, 110 }, |
||
53 | { B134, 134 }, |
||
54 | { B150, 150 }, |
||
55 | { B200, 200 }, |
||
56 | { B300, 300 }, |
||
57 | { B600, 600 }, |
||
58 | { B1200, 1200 }, |
||
59 | { B1800, 1800 }, |
||
60 | { B2400, 2400 }, |
||
61 | { B4800, 4800 }, |
||
62 | { B9600, 9600 }, |
||
63 | { B19200, 19200 }, |
||
64 | { B38400, 38400 }, |
||
65 | { B57600, 57600 }, |
||
66 | { B115200, 115200 }, |
||
67 | { B230400, 230400 }, |
||
68 | { B1000000,1000000 } |
||
69 | }; |
||
70 | |||
71 | #define ARRAY_LEN(x) ( sizeof( x ) / sizeof( x[ 0 ])) |
||
72 | |||
73 | // ---- Private Function Prototypes ----------------------------------------- |
||
74 | // ---- Functions ----------------------------------------------------------- |
||
75 | |||
76 | /** |
||
77 | * @addtogroup SerialPort |
||
78 | * @{ |
||
79 | */ |
||
80 | |||
81 | //*************************************************************************** |
||
82 | /** |
||
83 | * Constructor |
||
84 | */ |
||
85 | |||
86 | SerialPort::SerialPort() |
||
87 | : m_fd( -1 ) |
||
88 | { |
||
89 | } |
||
90 | |||
91 | //*************************************************************************** |
||
92 | /** |
||
93 | * Destructor |
||
94 | */ |
||
95 | |||
96 | SerialPort::~SerialPort() |
||
97 | { |
||
98 | Close(); |
||
99 | } |
||
100 | |||
101 | //*************************************************************************** |
||
102 | /** |
||
103 | * Closes a previously opened serial port |
||
104 | */ |
||
105 | |||
106 | void SerialPort::Close() |
||
107 | { |
||
108 | if ( m_fd >= 0 ) |
||
109 | { |
||
110 | close( m_fd ); |
||
111 | |||
112 | m_fd = -1; |
||
113 | } |
||
114 | |||
115 | } // Close |
||
116 | |||
117 | //*************************************************************************** |
||
118 | /** |
||
119 | * Opens a serial port. |
||
120 | */ |
||
121 | |||
122 | bool SerialPort::Open( const char *inDevName, const char *param ) |
||
123 | { |
||
124 | char devName[ 40 ]; |
||
125 | unsigned baudRate; |
||
126 | |||
127 | devName[ 0 ] = '\0'; |
||
128 | |||
129 | #if 1 |
||
130 | if ( inDevName[ 0 ] != '/' ) |
||
131 | { |
||
132 | StrMaxCpy( devName, "/dev/", sizeof( devName )); |
||
133 | } |
||
134 | #endif |
||
135 | StrMaxCat( devName, inDevName, sizeof( devName )); |
||
136 | |||
137 | // Translate the params, if any |
||
138 | |||
139 | speed_t speed = B0; |
||
140 | if ( param == NULL ) |
||
141 | { |
||
142 | speed = B38400; |
||
143 | baudRate = 38400; |
||
144 | } |
||
145 | else |
||
146 | { |
||
147 | baudRate = atoi( param ); |
||
148 | |||
149 | for ( unsigned i = 0; i < ARRAY_LEN( gBaudTable ); i++ ) |
||
150 | { |
||
151 | if ( gBaudTable[ i ].baudRate == baudRate ) |
||
152 | { |
||
153 | speed = gBaudTable[ i ].speed; |
||
154 | break; |
||
155 | } |
||
156 | } |
||
157 | |||
158 | if ( speed == B0 ) |
||
159 | { |
||
160 | LogError( "Unrecognized baud rate: '%s'\n", param ); |
||
161 | return false; |
||
162 | } |
||
163 | } |
||
164 | |||
165 | LogVerbose( "Port: '%s' Baud: %d\n", devName, baudRate ); |
||
166 | |||
167 | if (( m_fd = open( devName, O_RDWR | O_EXCL )) < 0 ) |
||
168 | { |
||
169 | LogError( "Unable to open serial port '%s': %s\n", devName, strerror( errno )); |
||
170 | return false; |
||
171 | } |
||
172 | |||
173 | // Setup the serial port |
||
174 | |||
175 | struct termios attr; |
||
176 | |||
177 | if ( tcgetattr( m_fd, &attr ) < 0 ) |
||
178 | { |
||
179 | LogError( "A: Call to tcgetattr failed: %s\n", strerror( errno )); |
||
180 | return false; |
||
181 | } |
||
182 | |||
183 | attr.c_iflag = 0; |
||
184 | attr.c_oflag = 0; |
||
185 | attr.c_cflag = CLOCAL | CREAD | CS8; |
||
186 | attr.c_lflag = 0; |
||
187 | attr.c_cc[ VTIME ] = 0; // timeout in tenths of a second |
||
188 | attr.c_cc[ VMIN ] = 1; |
||
189 | |||
190 | cfsetispeed( &attr, speed ); |
||
191 | cfsetospeed( &attr, speed ); |
||
192 | |||
193 | if ( tcsetattr( m_fd, TCSAFLUSH, &attr ) < 0 ) |
||
194 | { |
||
195 | LogError( "Call to tcsetattr failed: %s\n", strerror( errno )); |
||
196 | return false; |
||
197 | } |
||
198 | |||
199 | return true; |
||
200 | |||
201 | } // Open |
||
202 | |||
203 | //*************************************************************************** |
||
204 | /** |
||
205 | * Reads data from the serial port. |
||
206 | */ |
||
207 | |||
208 | size_t SerialPort::Read( void *buf, size_t bufSize ) |
||
209 | { |
||
210 | int bytesRead; |
||
211 | |||
212 | if ( m_fd < 0 ) |
||
213 | { |
||
214 | return 0; |
||
215 | } |
||
216 | |||
217 | bytesRead = read( m_fd, buf, bufSize ); |
||
218 | if ( bytesRead < 0 ) |
||
219 | { |
||
220 | if ( errno != EBADF ) |
||
221 | { |
||
222 | // We get EBADF returned if the serial port is closed on |
||
223 | // us. |
||
224 | |||
225 | LogError( "read failed: %d\n", errno ); |
||
226 | } |
||
227 | return 0; |
||
228 | } |
||
229 | |||
230 | return bytesRead; |
||
231 | |||
232 | } // Read |
||
233 | |||
234 | //*************************************************************************** |
||
235 | /** |
||
236 | * Sets the timeout to use when waiting for data. 0 = infinite |
||
237 | * The timeout is specified in 1/10ths of a second. |
||
238 | */ |
||
239 | bool SerialPort::SetTimeout( uint8_t timeout ) |
||
240 | { |
||
241 | struct termios attr; |
||
242 | |||
243 | if ( tcgetattr( m_fd, &attr ) < 0 ) |
||
244 | { |
||
245 | LogError( "B: Call to tcgetattr failed: %s\n", strerror( errno )); |
||
246 | return false; |
||
247 | } |
||
248 | |||
249 | if ( timeout == 0 ) |
||
250 | { |
||
251 | attr.c_cc[ VTIME ] = 0; |
||
252 | attr.c_cc[ VMIN ] = 1; |
||
253 | } |
||
254 | else |
||
255 | { |
||
256 | attr.c_cc[ VTIME ] = timeout; // timeout in tenths of a second |
||
257 | attr.c_cc[ VMIN ] = 0; |
||
258 | } |
||
259 | |||
260 | if ( tcsetattr( m_fd, TCSAFLUSH, &attr ) < 0 ) |
||
261 | { |
||
262 | LogError( "Call to tcsetattr failed: %s\n", strerror( errno )); |
||
263 | return false; |
||
264 | } |
||
265 | |||
266 | return true; |
||
267 | |||
268 | } // SetTimeout |
||
269 | |||
270 | //*************************************************************************** |
||
271 | /** |
||
272 | * Writes data to the serial port. |
||
273 | */ |
||
274 | |||
275 | size_t SerialPort::Write( const void *buf, size_t bytesToWrite ) |
||
276 | { |
||
277 | int bytesWritten; |
||
278 | |||
279 | bytesWritten = write( m_fd, buf, bytesToWrite ); |
||
280 | if ( bytesWritten < 0 ) |
||
281 | { |
||
282 | LogError( "write failed: %d\n", errno ); |
||
283 | bytesWritten = 0; |
||
284 | } |
||
285 | |||
286 | return bytesWritten; |
||
287 | |||
288 | } // Write |
||
289 | |||
290 | //*************************************************************************** |
||
291 | /** |
||
292 | * Resets the target |
||
293 | */ |
||
294 | |||
295 | void SerialPort::StrobeRTS( int strobeWidthInMsec ) |
||
296 | { |
||
297 | int bits = TIOCM_RTS; |
||
298 | |||
299 | // On my computer downstairs, settinging the RTS line makes it low. |
||
300 | |||
301 | ioctl( m_fd, TIOCMBIS, &bits ); |
||
302 | |||
303 | // Sleep for 10 msec to allow the reset to take effect. |
||
304 | |||
305 | usleep( strobeWidthInMsec * 1000 ); |
||
306 | |||
307 | // On my computer downstairs, clearing the RTS line makes it high. |
||
308 | |||
309 | ioctl( m_fd, TIOCMBIC, &bits ); |
||
310 | |||
311 | } // StrobeRTS |
||
312 | |||
313 | /** @} */ |
||
314 |