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