API
 
Loading...
Searching...
No Matches
ttyIOUtils.cpp
Go to the documentation of this file.
1/** \file ttyIOUtils.cpp
2 * \brief Utilities for i/o on a file descriptor pointing to a tty device.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup tty_files
6 */
7
8#include "ttyIOUtils.hpp"
9
10#include <unistd.h>
11#include <fcntl.h>
12#include <poll.h>
13#include <termios.h>
14
15#include <mx/sys/timeUtils.hpp>
16
17#include "ttyErrors.hpp"
18
19
20
21namespace MagAOX
22{
23namespace tty
24{
25
26int telnetCRLF( std::string & telnetStr, // [out] the string with \\r an \\n converted to \\r\\n
27 const std::string & inputStr // [in] the string to be converted
28 )
29{
30 telnetStr.resize(inputStr.size());
31
32 size_t N = inputStr.size();
33 size_t j = 0;
34 for(size_t i=0;i<N; ++i)
35 {
36 if(inputStr[i] != '\r' && inputStr[i] != '\n')
37 {
38 telnetStr[j] = inputStr[i];
39 }
40 else if(inputStr[i] == '\r')
41 {
42 telnetStr[j] = '\r';
43
44 if(i < N-1)
45 {
46 if(inputStr[i+1] == '\n')
47 {
48 ++j;
49 telnetStr[j] = '\n';
50 ++i;
51 ++j; //i is incremented on continue, but j is not
52 continue;
53 }
54 }
55 telnetStr.push_back(' ');
56 ++j;
57 telnetStr[j] = '\n';
58 }
59 else if(inputStr[i] == '\n')
60 {
61 telnetStr[j] = '\r';
62 telnetStr.push_back(' ');
63 ++j;
64 telnetStr[j] = '\n';
65 }
66 ++j;
67 }
68
69 return 0;
70}
71
72int ttyOpenRaw( int & fileDescrip, // [out] the file descriptor. Set to 0 on an error.
73 std::string & deviceName, // [in] the device path name, e.g. /dev/ttyUSB0
74 speed_t speed // [in] indicates the baud rate (see http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html)
75 )
76{
77 errno = 0;
78
79 fileDescrip = ::open( deviceName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
80
81
82 struct termios termopt;
83 if( tcgetattr(fileDescrip, &termopt) < 0 )
84 {
85 close(fileDescrip);
86 fileDescrip = 0;
87 return TTY_E_TCGETATTR;
88 }
89
90 if( cfsetispeed(&termopt, speed) < 0 )
91 {
92 close(fileDescrip);
93 fileDescrip = 0;
94 return TTY_E_SETISPEED;
95 }
96
97 if( cfsetospeed(&termopt, speed) < 0 )
98 {
99 close(fileDescrip);
100 fileDescrip = 0;
101 return TTY_E_SETOSPEED;
102 }
103
104 cfmakeraw(&termopt);
105
106 if( tcsetattr(fileDescrip, TCSANOW, &termopt) < 0 )
107 {
108 close(fileDescrip);
109 fileDescrip = 0;
110 return TTY_E_TCSETATTR;
111 }
112
113 return TTY_E_NOERROR;
114}
115
116bool isEndOfTrans( const std::string & strRead, // [in] The read buffer to check
117 const std::string & eot // [in] The end-of-transmission string
118 )
119{
120 //If buffRead isn't long enough yet.
121 if(eot.size() > strRead.size()) return false;
122
123 //Now check from back, if any don't match it's false.
124 for(size_t i=0; i < eot.size(); ++i)
125 {
126 if( strRead[strRead.size()-1-i] != eot[eot.size()-1-i] ) return false;
127 }
128
129 return true;
130}
131
132int ttyWrite( const std::string & buffWrite, // [in] The characters to write to the tty.
133 int fd, // [in] The file descriptor of the open tty.
134 int timeoutWrite // [in] The timeout in milliseconds.
135 )
136{
137 double t0;
138 struct pollfd pfd;
139
140 errno = 0;
141 pfd.fd = fd;
142 pfd.events = POLLOUT;
143
144 t0 = mx::sys::get_curr_time();
145
146 size_t totWritten = 0;
147 while( totWritten < buffWrite.size())
148 {
149 int timeoutCurrent = timeoutWrite - (mx::sys::get_curr_time()-t0)*1000;
150 if(timeoutCurrent < 0) return TTY_E_TIMEOUTONWRITE;
151
152 int rv = poll( &pfd, 1, timeoutCurrent);
153 if( rv == 0 ) return TTY_E_TIMEOUTONWRITEPOLL;
154 else if( rv < 0 ) return TTY_E_ERRORONWRITEPOLL;
155
156 rv = write(fd, buffWrite.c_str()+totWritten, buffWrite.size()-totWritten);
157 if(rv < 0) return TTY_E_ERRORONWRITE;
158
159 //sleep(1);
160 #ifdef TTY_DEBUG
161 std::cerr << "Wrote " << rv << " chars of " << buffWrite.size() << "\n";
162 #endif
163
164 totWritten += rv;
165
166 if( ( mx::sys::get_curr_time()-t0)*1000 > timeoutWrite ) return TTY_E_TIMEOUTONWRITE;
167 }
168
169 return TTY_E_NOERROR;
170}
171
172int ttyReadRaw( std::vector<unsigned char> & vecRead, // [out] The buffer in which to store the output.
173 int & readBytes, // [out] The number of bytes read.
174 int fd, // [in] The file descriptor of the open tty.
175 int timeoutRead // [in] The timeout in milliseconds.
176 )
177{
178 int rv;
179
180 struct pollfd pfd;
181
182 errno = 0;
183
184 pfd.fd = fd;
185 pfd.events = POLLIN;
186
187
188 rv = poll( &pfd, 1, timeoutRead);
189 if( rv == 0 ) return TTY_E_TIMEOUTONREADPOLL;
190 if( rv < 0 ) return TTY_E_ERRORONREADPOLL;
191
192 readBytes = 0;
193
194 rv = read(fd, vecRead.data(), vecRead.size());
195 if( rv < 0 ) return TTY_E_ERRORONREAD;
196
197
198 readBytes = rv;
199
200
201 return TTY_E_NOERROR;
202
203
204}
205
206int ttyRead( std::string & strRead, // [out] The string in which to store the output.
207 int bytes, // [in] the number of bytes to read
208 int fd, // [in] The file descriptor of the open tty.
209 int timeoutRead // [in] The timeout in milliseconds.
210 )
211{
212 int rv;
213 int timeoutCurrent;
214 double t0;
215
216 struct pollfd pfd;
217
218 errno = 0;
219
220 pfd.fd = fd;
221 pfd.events = POLLIN;
222
223 strRead.clear();
224 char buffRead[TTY_BUFFSIZE];
225
226 //Start timeout clock for reading.
227 t0 = mx::sys::get_curr_time();
228 timeoutCurrent = timeoutRead;
229
230 //Now read the response up to the eot.
231 strRead.clear();
232
233 rv = poll( &pfd, 1, timeoutCurrent);
234 if( rv == 0 ) return TTY_E_TIMEOUTONREADPOLL;
235 if( rv < 0 ) return TTY_E_ERRORONREADPOLL;
236
237 rv = read(fd, buffRead, TTY_BUFFSIZE);
238 if( rv < 0 ) return TTY_E_ERRORONREAD;
239
240 strRead.append( buffRead, rv);
241
242 int totBytes = rv;
243
244 while( totBytes < bytes )
245 {
246 timeoutCurrent = timeoutRead - (mx::sys::get_curr_time()-t0)*1000;
247 if(timeoutCurrent < 0) return TTY_E_TIMEOUTONREAD;
248
249 rv = poll( &pfd, 1, timeoutCurrent);
250 if( rv == 0 ) return TTY_E_TIMEOUTONREADPOLL;
251 if( rv < 0 ) return TTY_E_ERRORONREADPOLL;
252
253 rv = read(fd, buffRead, TTY_BUFFSIZE);
254 if( rv < 0 ) return TTY_E_ERRORONREAD;
255 buffRead[rv] ='\0';
256
257 strRead.append( buffRead, rv);
258 totBytes += rv;
259
260 #ifdef TTY_DEBUG
261 std::cerr << "ttyRead: read " << rv << " bytes. buffRead=" << buffRead << "\n";
262 #endif
263 }
264
265
266 return TTY_E_NOERROR;
267
268
269}
270
271int ttyRead( std::string & strRead, // [out] The string in which to store the output.
272 const std::string & eot, // [in] A sequence of characters which indicates the end of transmission.
273 int fd, // [in] The file descriptor of the open tty.
274 int timeoutRead // [in] The timeout in milliseconds.
275 )
276{
277 int rv;
278 int timeoutCurrent;
279 double t0;
280
281 struct pollfd pfd;
282
283 errno = 0;
284
285 pfd.fd = fd;
286 pfd.events = POLLIN;
287
288 strRead.clear();
289 char buffRead[TTY_BUFFSIZE];
290
291 //Start timeout clock for reading.
292 t0 = mx::sys::get_curr_time();
293 timeoutCurrent = timeoutRead;
294
295 //Now read the response up to the eot.
296 strRead.clear();
297
298 rv = poll( &pfd, 1, timeoutCurrent);
299 if( rv == 0 ) return TTY_E_TIMEOUTONREADPOLL;
300 if( rv < 0 ) return TTY_E_ERRORONREADPOLL;
301
302 rv = read(fd, buffRead, TTY_BUFFSIZE);
303 if( rv < 0 ) return TTY_E_ERRORONREAD;
304
305 strRead.append( buffRead, rv);
306
307 while( !isEndOfTrans(strRead, eot) )
308 {
309 timeoutCurrent = timeoutRead - (mx::sys::get_curr_time()-t0)*1000;
310 if(timeoutCurrent < 0) return TTY_E_TIMEOUTONREAD;
311
312 rv = poll( &pfd, 1, timeoutCurrent);
313 if( rv == 0 ) return TTY_E_TIMEOUTONREADPOLL;
314 if( rv < 0 ) return TTY_E_ERRORONREADPOLL;
315
316 rv = read(fd, buffRead, TTY_BUFFSIZE);
317 if( rv < 0 ) return TTY_E_ERRORONREAD;
318 buffRead[rv] ='\0';
319
320 strRead.append( buffRead, rv);
321 #ifdef TTY_DEBUG
322 std::cerr << "ttyRead: read " << rv << " bytes. buffRead=" << buffRead << "\n";
323 #endif
324 }
325
326
327 return TTY_E_NOERROR;
328
329
330}
331
332int ttyWriteRead( std::string & strRead, // [out] The string in which to store the output.
333 const std::string & strWrite, // [in] The characters to write to the tty.
334 const std::string & eot, // [in] A sequence of characters which indicates the end of transmission.
335 bool swallowEcho, // [in] If true, strWrite.size() characters are read after the write
336 int fd, // [in] The file descriptor of the open tty.
337 int timeoutWrite, // [in] The write timeout in milliseconds.
338 int timeoutRead // [in] The read timeout in milliseconds.
339 )
340{
341 strRead.clear();
342
343 int rv;
344
345 //Write First
346 rv = ttyWrite( strWrite, fd, timeoutWrite);
347 if(rv != TTY_E_NOERROR) return rv;
348
349
350
351 //Now read response from console
352 int timeoutCurrent;
353 double t0;
354
355
356 //Start timeout clock for reading.
357 t0 = mx::sys::get_curr_time();;
358
359 if(swallowEcho)
360 {
361 struct pollfd pfd;
362 pfd.fd = fd;
363 pfd.events = POLLIN;
364
365 size_t totrv = 0;
366 char buffRead[TTY_BUFFSIZE];
367
368 //First swallow the echo.
369 while( totrv <= strWrite.size() )
370 {
371 timeoutCurrent = timeoutRead - (mx::sys::get_curr_time()-t0)*1000;
372 if(timeoutCurrent < 0) return TTY_E_TIMEOUTONREAD;
373
374 rv = poll( &pfd, 1, timeoutCurrent);
375 if( rv == 0 ) return TTY_E_TIMEOUTONREADPOLL;
376 if( rv < 0 ) return TTY_E_ERRORONREADPOLL;
377
378 rv = read(fd, buffRead, TTY_BUFFSIZE);
379 if( rv < 0 ) return TTY_E_ERRORONREAD;
380
381 totrv += rv;
382 }
383 }
384
385 timeoutCurrent = timeoutRead - (mx::sys::get_curr_time()-t0)*1000;
386 if(timeoutCurrent < 0) return TTY_E_TIMEOUTONREAD;
387
388 //Now read the response up to the eot.
389 return ttyRead(strRead, eot, fd, timeoutCurrent);
390}
391
392
393
394} //namespace tty
395} //namespace MagAOX
396
int ttyReadRaw(std::vector< unsigned char > &vecRead, int &readBytes, int fd, int timeoutRead)
Read from a tty console indicated by a file-descriptor, up to a given number of bytes.
int ttyWriteRead(std::string &strRead, const std::string &strWrite, const std::string &eot, bool swallowEcho, int fd, int timeoutWrite, int timeoutRead)
Write to a tty on an open file descriptor, then get the result.
int ttyWrite(const std::string &buffWrite, int fd, int timeoutWrite)
Write to the tty console indicated by a file descriptor.
int ttyRead(std::string &strRead, int bytes, int fd, int timeoutRead)
Read from a tty console indicated by a file-descriptor, until a given number of bytes are read.
int ttyOpenRaw(int &fileDescrip, std::string &deviceName, speed_t speed)
Open a file as a raw-mode tty device.
bool isEndOfTrans(const std::string &strRead, const std::string &eot)
Check if the end of the buffer contains the end-of-transmission string.
int telnetCRLF(std::string &telnetStr, const std::string &inputStr)
Replace lone \r and \n with \r\n for telnet-ness.
Definition dm.hpp:24
Error numbers for the tty utilities.
#define TTY_E_TCGETATTR
Definition ttyErrors.hpp:16
#define TTY_E_SETOSPEED
Definition ttyErrors.hpp:18
#define TTY_E_TIMEOUTONREAD
Definition ttyErrors.hpp:27
#define TTY_E_SETISPEED
Definition ttyErrors.hpp:17
#define TTY_E_TIMEOUTONREADPOLL
Definition ttyErrors.hpp:24
#define TTY_E_ERRORONWRITE
Definition ttyErrors.hpp:22
#define TTY_E_ERRORONWRITEPOLL
Definition ttyErrors.hpp:21
#define TTY_E_TCSETATTR
Definition ttyErrors.hpp:19
#define TTY_E_ERRORONREADPOLL
Definition ttyErrors.hpp:25
#define TTY_E_ERRORONREAD
Definition ttyErrors.hpp:26
#define TTY_E_TIMEOUTONWRITEPOLL
Definition ttyErrors.hpp:20
#define TTY_E_TIMEOUTONWRITE
Definition ttyErrors.hpp:23
#define TTY_E_NOERROR
Definition ttyErrors.hpp:15
Utilities for i/o on a file descriptor pointing to a tty device.
#define TTY_BUFFSIZE