license headers in libnetxms changed to LGPL
[public/netxms.git] / src / libnetxms / serial.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2005, 2006 Alex Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published
7 ** by the Free Software Foundation; either version 3 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: serial.cpp
20 **
21 **/
22
23 #include "libnetxms.h"
24
25 #ifndef CRTSCTS
26 # ifdef CNEW_RTSCTS
27 # define CRTSCTS CNEW_RTSCTS
28 # else
29 # define CRTSCTS 0
30 # endif
31 #endif
32
33 #ifdef _NETWARE
34 #ifndef ECHOKE
35 #define ECHOKE 0
36 #endif
37 #ifndef ECHOCTL
38 #define ECHOCTL 0
39 #endif
40 #ifndef OPOST
41 #define OPOST 0
42 #endif
43 #ifndef ONLCR
44 #define ONLCR 0
45 #endif
46 #endif
47
48
49 //
50 // Constructor
51 //
52
53 Serial::Serial(void)
54 {
55 m_nTimeout = 0;
56 m_hPort = INVALID_HANDLE_VALUE;
57 m_pszPort = NULL;
58 #ifndef _WIN32
59 memset(&m_originalSettings, 0, sizeof(m_originalSettings));
60 #endif
61 }
62
63
64 //
65 // Destructor
66 //
67
68 Serial::~Serial(void)
69 {
70 Close();
71 }
72
73
74 //
75 // Open serial device
76 //
77
78 bool Serial::Open(const TCHAR *pszPort)
79 {
80 bool bRet = false;
81
82 Close(); // In case if port already open
83 safe_free(m_pszPort);
84 m_pszPort = _tcsdup(pszPort);
85
86 #ifdef _WIN32
87 m_hPort = CreateFile(pszPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
88 OPEN_EXISTING, 0, NULL);
89 if (m_hPort != INVALID_HANDLE_VALUE)
90 {
91 #else // UNIX
92 m_hPort = _topen(pszPort, O_RDWR | O_NOCTTY | O_NDELAY);
93 if (m_hPort != -1)
94 {
95 tcgetattr(m_hPort, &m_originalSettings);
96 #endif
97 Set(38400, 8, NOPARITY, ONESTOPBIT, FLOW_NONE);
98 bRet = true;
99 }
100 return bRet;
101 }
102
103
104 //
105 // Set communication parameters
106 //
107 bool Serial::Set(int nSpeed, int nDataBits, int nParity, int nStopBits)
108 {
109 return Set(nSpeed, nDataBits, nParity, nStopBits, FLOW_NONE);
110 }
111
112 bool Serial::Set(int nSpeed, int nDataBits, int nParity, int nStopBits, int nFlowControl)
113 {
114 bool bRet = false;
115
116 m_nDataBits = nDataBits;
117 m_nSpeed = nSpeed;
118 m_nParity = nParity;
119 m_nStopBits = nStopBits;
120 m_nFlowControl = nFlowControl;
121
122 #ifdef _WIN32
123 DCB dcb;
124
125 dcb.DCBlength = sizeof(DCB);
126 if (GetCommState(m_hPort, &dcb))
127 {
128 dcb.BaudRate = nSpeed;
129 dcb.ByteSize = nDataBits;
130 dcb.Parity = nParity;
131 dcb.StopBits = nStopBits;
132 dcb.fDtrControl = DTR_CONTROL_ENABLE;
133 dcb.fBinary = TRUE;
134 dcb.fParity = FALSE;
135 dcb.fOutxCtsFlow = FALSE;
136 dcb.fOutxDsrFlow = FALSE;
137 dcb.fDsrSensitivity = FALSE;
138 dcb.fOutX = FALSE;
139 dcb.fInX = FALSE;
140 dcb.fRtsControl = RTS_CONTROL_ENABLE;
141 dcb.fAbortOnError = FALSE;
142
143 if (SetCommState(m_hPort, &dcb))
144 {
145 COMMTIMEOUTS ct;
146
147 memset(&ct, 0, sizeof(COMMTIMEOUTS));
148 ct.ReadTotalTimeoutConstant = m_nTimeout;
149 ct.WriteTotalTimeoutConstant = m_nTimeout;
150 SetCommTimeouts(m_hPort, &ct);
151 bRet = true;
152 }
153 }
154
155 #else /* UNIX */
156 struct termios newTio;
157
158 tcgetattr(m_hPort, &newTio);
159
160 newTio.c_cc[VMIN] = 1;
161 newTio.c_cc[VTIME] = m_nTimeout;
162
163 newTio.c_cflag |= CLOCAL | CREAD;
164
165 int baud;
166 switch(nSpeed)
167 {
168 case 50: baud = B50; break;
169 case 75: baud = B75; break;
170 case 110: baud = B110; break;
171 case 134: baud = B134; break;
172 case 150: baud = B150; break;
173 case 200: baud = B200; break;
174 case 300: baud = B300; break;
175 case 600: baud = B600; break;
176 case 1200: baud = B1200; break;
177 case 1800: baud = B1800; break;
178 case 2400: baud = B2400; break;
179 case 4800: baud = B4800; break;
180 case 9600: baud = B9600; break;
181 case 19200: baud = B19200; break;
182 case 38400: baud = B38400; break;
183 default: baud = B38400; break;
184 }
185 #ifdef _NETWARE
186 cfsetispeed(&newTio, (speed_t)baud);
187 cfsetospeed(&newTio, (speed_t)baud);
188 #else
189 cfsetispeed(&newTio, baud);
190 cfsetospeed(&newTio, baud);
191 #endif
192
193 newTio.c_cflag &= ~(CSIZE);
194 switch(nDataBits)
195 {
196 case 5:
197 newTio.c_cflag |= CS5;
198 break;
199 case 6:
200 newTio.c_cflag |= CS6;
201 break;
202 case 7:
203 newTio.c_cflag |= CS7;
204 break;
205 case 8:
206 default:
207 newTio.c_cflag |= CS8;
208 break;
209 }
210
211 newTio.c_cflag &= ~(PARODD | PARENB);
212 switch(nParity)
213 {
214 case ODDPARITY:
215 newTio.c_cflag |= PARODD | PARENB;
216 break;
217 case EVENPARITY:
218 newTio.c_cflag |= PARENB;
219 break;
220 default:
221 break;
222 }
223
224 newTio.c_cflag &= ~(CSTOPB);
225 if (nStopBits != ONESTOPBIT)
226 {
227 newTio.c_cflag |= CSTOPB;
228 }
229
230 //newTio.c_cflag &= ~(CRTSCTS | IXON | IXOFF);
231 newTio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL | ISIG | IEXTEN);
232 newTio.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL);
233 newTio.c_iflag |= IGNBRK;
234 newTio.c_oflag &= ~(OPOST | ONLCR);
235
236 switch(nFlowControl)
237 {
238 case FLOW_HARDWARE:
239 newTio.c_cflag |= CRTSCTS;
240 break;
241 case FLOW_SOFTWARE:
242 newTio.c_iflag |= IXON | IXOFF;
243 break;
244 default:
245 break;
246 }
247
248 tcsetattr(m_hPort, TCSANOW, &newTio);
249
250 #endif // _WIN32
251 return bRet;
252 }
253
254
255 //
256 // Close serial port
257 //
258
259 void Serial::Close(void)
260 {
261 if (m_hPort != INVALID_HANDLE_VALUE)
262 {
263 #ifdef _WIN32
264 //PurgeComm(m_hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
265 CloseHandle(m_hPort);
266 #else // UNIX
267 tcsetattr(m_hPort, TCSANOW, &m_originalSettings);
268 close(m_hPort);
269 #endif // _WIN32s
270 m_hPort = INVALID_HANDLE_VALUE;
271 safe_free(m_pszPort);
272 m_pszPort = NULL;
273 }
274 }
275
276
277 //
278 // Set receive timeout (in milliseconds)
279 //
280
281 void Serial::SetTimeout(int nTimeout)
282 {
283 #ifdef _WIN32
284 COMMTIMEOUTS ct;
285
286 m_nTimeout = nTimeout;
287 memset(&ct, 0, sizeof(COMMTIMEOUTS));
288 ct.ReadTotalTimeoutConstant = m_nTimeout;
289 ct.WriteTotalTimeoutConstant = m_nTimeout;
290
291 SetCommTimeouts(m_hPort, &ct);
292 #else
293 struct termios tio;
294
295 tcgetattr(m_hPort, &tio);
296
297 m_nTimeout = nTimeout / 100; // convert to deciseconds (VTIME in 1/10sec)
298 tio.c_cc[VTIME] = m_nTimeout;
299
300 tcsetattr(m_hPort, TCSANOW, &tio);
301 #endif // WIN32
302 }
303
304
305 //
306 // Restart port
307 //
308
309 bool Serial::Restart(void)
310 {
311 Close();
312 ThreadSleepMs(500);
313 if (Open(m_pszPort))
314 if (Set(m_nSpeed, m_nDataBits, m_nParity, m_nStopBits, m_nFlowControl))
315 return true;
316 return false;
317 }
318
319
320 //
321 // Read character(s) from port
322 //
323
324 int Serial::Read(char *pBuff, int nSize)
325 {
326 int nRet;
327
328 memset(pBuff, 0, nSize);
329 if (m_hPort == INVALID_HANDLE_VALUE)
330 return -1;
331
332 #ifdef _WIN32
333 DWORD nDone;
334
335 if (ReadFile(m_hPort, pBuff, nSize, &nDone, NULL) != 0)
336 {
337 nRet = (int)nDone;
338 }
339 else
340 {
341 nRet = -1;
342 }
343
344 #else // UNIX
345 fd_set rdfs;
346 struct timeval tv;
347
348 FD_ZERO(&rdfs);
349 FD_SET(m_hPort, &rdfs);
350 tv.tv_sec = m_nTimeout / 10;
351 tv.tv_usec = 0;
352 nRet = select(m_hPort + 1, &rdfs, NULL, NULL, &tv);
353 if (nRet > 0)
354 nRet = read(m_hPort, pBuff, nSize);
355 else
356 nRet = -1; // Timeout is an error
357
358 #endif // _WIN32
359
360 //if (nRet == -1)
361 // Restart();
362
363 return nRet;
364 }
365
366 //
367 // Read character(s) from port
368 //
369
370 int Serial::ReadAll(char *pBuff, int nSize)
371 {
372 int nRet;
373
374 memset(pBuff, 0, nSize);
375 if (m_hPort == INVALID_HANDLE_VALUE)
376 return -1;
377
378 #ifdef _WIN32
379 DWORD dwBytes;
380
381 if (ReadFile(m_hPort, pBuff, nSize, &dwBytes, NULL))
382 {
383 nRet = (int)dwBytes;
384 }
385 else
386 {
387 nRet = -1;
388 }
389
390 #else // UNIX
391 fd_set rdfs;
392 struct timeval tv;
393 int got, offset;
394
395 offset = 0;
396
397 while (offset < nSize)
398 {
399 FD_ZERO(&rdfs);
400 FD_SET(m_hPort, &rdfs);
401 tv.tv_sec = m_nTimeout / 10;
402 tv.tv_usec = 0;
403 nRet = select(m_hPort + 1, &rdfs, NULL, NULL, &tv);
404 if (nRet > 0)
405 {
406 got = read(m_hPort, pBuff + offset, nSize - offset);
407 if (got >= 0)
408 {
409 offset += got;
410 nRet = offset;
411 }
412 else
413 {
414 nRet = -1;
415 break;
416 }
417 }
418 else
419 {
420 if (offset == 0) // got no data
421 {
422 nRet = -1;
423 }
424 break;
425 }
426 }
427
428 #endif // _WIN32
429
430 //if (nRet == -1)
431 // Restart();
432
433 return nRet;
434 }
435
436 //
437 // Write character(s) to port
438 //
439
440 bool Serial::Write(const char *pBuff, int nSize)
441 {
442 bool bRet = false;
443
444 if (m_hPort == INVALID_HANDLE_VALUE)
445 return false;
446
447 #ifdef _WIN32
448
449 Sleep(100);
450
451 DWORD nDone;
452 if (WriteFile(m_hPort, pBuff, nSize, &nDone, NULL) != 0)
453 {
454 if (nDone == (DWORD)nSize)
455 {
456 bRet = true;
457 }
458 }
459 else
460 {
461 Restart();
462 }
463
464 #else // UNIX
465 usleep(100);
466
467 if (write(m_hPort, (char *)pBuff, nSize) == nSize)
468 {
469 bRet = true;
470 }
471 else
472 {
473 Restart();
474 }
475
476 #endif // _WIN32
477
478 return bRet;
479 }
480
481
482 //
483 // Flush buffer
484 //
485
486 void Serial::Flush(void)
487 {
488 #ifdef _WIN32
489
490 FlushFileBuffers(m_hPort);
491
492 #else // UNIX
493
494 #ifndef _NETWARE
495 tcflush(m_hPort, TCIOFLUSH);
496 #endif
497
498 #endif // _WIN32
499 }
500
501 ///////////////////////////////////////////////////////////////////////////////
502 /*
503
504 $Log: not supported by cvs2svn $
505 Revision 1.19 2007/01/24 21:34:55 victor
506 - Fixed Serial::ReadAll() under Windows
507 - Added isSystem object's attribute
508
509 Revision 1.18 2007/01/24 00:54:17 alk
510 Serial::ReadAll() implementation
511
512 Revision 1.17 2006/11/21 22:06:19 alk
513 DTR/RTS issues fixed (req. for nokia gsm modem on serial port)
514
515 Revision 1.16 2006/11/21 22:04:07 alk
516 code reformatted (mix of tab/space replaced with tabs)
517
518 Revision 1.15 2006/10/20 10:15:56 victor
519 - libnxcscp merged into libnetxms
520 - Fixed NetWare compilation issues
521
522 Revision 1.14 2006/09/10 06:59:37 victor
523 Fixed problmes with Win32 build
524
525 Revision 1.13 2006/09/07 22:02:06 alk
526 UNIX version of Serial rewritten
527 termio removed from configure (depricated in favour of termio_s_?)
528
529 */