3b31de2518bedc000b3fa886238e3f142e8b9c75
[public/netxms.git] / src / libnetxms / serial.cpp
1 /* $Id$ */
2
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
27 #ifndef CRTSCTS
28 # ifdef CNEW_RTSCTS
29 # define CRTSCTS CNEW_RTSCTS
30 # else
31 # define CRTSCTS 0
32 # endif
33 #endif
34
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
50
51 //
52 // Constructor
53 //
54
55 Serial::Serial(void)
56 {
57 m_nTimeout = 0;
58 m_hPort = INVALID_HANDLE_VALUE;
59 m_pszPort = NULL;
60 #ifndef _WIN32
61 memset(&m_originalSettings, 0, sizeof(m_originalSettings));
62 #endif
63 }
64
65
66 //
67 // Destructor
68 //
69
70 Serial::~Serial(void)
71 {
72 Close();
73 }
74
75
76 //
77 // Open serial device
78 //
79
80 bool Serial::Open(const TCHAR *pszPort)
81 {
82 bool bRet = false;
83
84 Close(); // In case if port already open
85 safe_free(m_pszPort);
86 m_pszPort = _tcsdup(pszPort);
87
88 #ifdef _WIN32
89 m_hPort = CreateFile(pszPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
90 OPEN_EXISTING, 0, NULL);
91 if (m_hPort != INVALID_HANDLE_VALUE)
92 {
93 #else // UNIX
94 m_hPort = _topen(pszPort, O_RDWR | O_NOCTTY | O_NDELAY);
95 if (m_hPort != -1)
96 {
97 tcgetattr(m_hPort, &m_originalSettings);
98 #endif
99 Set(38400, 8, NOPARITY, ONESTOPBIT, FLOW_NONE);
100 bRet = true;
101 }
102 return bRet;
103 }
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)
115 {
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;
134 dcb.fDtrControl = DTR_CONTROL_ENABLE;
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;
142 dcb.fRtsControl = RTS_CONTROL_ENABLE;
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 {
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;
186 }
187 #ifdef _NETWARE
188 cfsetispeed(&newTio, (speed_t)baud);
189 cfsetospeed(&newTio, (speed_t)baud);
190 #else
191 cfsetispeed(&newTio, baud);
192 cfsetospeed(&newTio, baud);
193 #endif
194
195 newTio.c_cflag &= ~(CSIZE);
196 switch(nDataBits)
197 {
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;
211 }
212
213 newTio.c_cflag &= ~(PARODD | PARENB);
214 switch(nParity)
215 {
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;
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 {
240 case FLOW_HARDWARE:
241 newTio.c_cflag |= CRTSCTS;
242 break;
243 case FLOW_SOFTWARE:
244 newTio.c_iflag |= IXON | IXOFF;
245 break;
246 default:
247 break;
248 }
249
250 tcsetattr(m_hPort, TCSANOW, &newTio);
251
252 #endif // _WIN32
253 return bRet;
254 }
255
256
257 //
258 // Close serial port
259 //
260
261 void Serial::Close(void)
262 {
263 if (m_hPort != INVALID_HANDLE_VALUE)
264 {
265 #ifdef _WIN32
266 //PurgeComm(m_hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
267 CloseHandle(m_hPort);
268 #else // UNIX
269 tcsetattr(m_hPort, TCSANOW, &m_originalSettings);
270 close(m_hPort);
271 #endif // _WIN32s
272 m_hPort = INVALID_HANDLE_VALUE;
273 safe_free(m_pszPort);
274 m_pszPort = NULL;
275 }
276 }
277
278
279 //
280 // Set receive timeout (in milliseconds)
281 //
282
283 void Serial::SetTimeout(int nTimeout)
284 {
285 #ifdef _WIN32
286 COMMTIMEOUTS ct;
287
288 m_nTimeout = nTimeout;
289 memset(&ct, 0, sizeof(COMMTIMEOUTS));
290 ct.ReadTotalTimeoutConstant = m_nTimeout;
291 ct.WriteTotalTimeoutConstant = m_nTimeout;
292
293 SetCommTimeouts(m_hPort, &ct);
294 #else
295 struct termios tio;
296
297 tcgetattr(m_hPort, &tio);
298
299 m_nTimeout = nTimeout / 100; // convert to deciseconds (VTIME in 1/10sec)
300 tio.c_cc[VTIME] = m_nTimeout;
301
302 tcsetattr(m_hPort, TCSANOW, &tio);
303 #endif // WIN32
304 }
305
306
307 //
308 // Restart port
309 //
310
311 bool Serial::Restart(void)
312 {
313 Close();
314 ThreadSleepMs(500);
315 if (Open(m_pszPort))
316 if (Set(m_nSpeed, m_nDataBits, m_nParity, m_nStopBits, m_nFlowControl))
317 return true;
318 return false;
319 }
320
321
322 //
323 // Read character(s) from port
324 //
325
326 int Serial::Read(char *pBuff, int nSize)
327 {
328 int nRet;
329
330 memset(pBuff, 0, nSize);
331 if (m_hPort == INVALID_HANDLE_VALUE)
332 return -1;
333
334 #ifdef _WIN32
335 DWORD nDone;
336
337 if (ReadFile(m_hPort, pBuff, nSize, &nDone, NULL) != 0)
338 {
339 nRet = (int)nDone;
340 }
341 else
342 {
343 nRet = -1;
344 }
345
346 #else // UNIX
347 fd_set rdfs;
348 struct timeval tv;
349
350 FD_ZERO(&rdfs);
351 FD_SET(m_hPort, &rdfs);
352 tv.tv_sec = m_nTimeout / 10;
353 tv.tv_usec = 0;
354 nRet = select(m_hPort + 1, &rdfs, NULL, NULL, &tv);
355 if (nRet > 0)
356 nRet = read(m_hPort, pBuff, nSize);
357 else
358 nRet = -1; // Timeout is an error
359
360 #endif // _WIN32
361
362 //if (nRet == -1)
363 // Restart();
364
365 return nRet;
366 }
367
368 //
369 // Read character(s) from port
370 //
371
372 int Serial::ReadAll(char *pBuff, int nSize)
373 {
374 int nRet;
375
376 memset(pBuff, 0, nSize);
377 if (m_hPort == INVALID_HANDLE_VALUE)
378 return -1;
379
380 #ifdef _WIN32
381 DWORD dwBytes;
382
383 if (ReadFile(m_hPort, pBuff, nSize, &dwBytes, NULL))
384 {
385 nRet = (int)dwBytes;
386 }
387 else
388 {
389 nRet = -1;
390 }
391
392 #else // UNIX
393 fd_set rdfs;
394 struct timeval tv;
395 int got, offset;
396
397 offset = 0;
398
399 while (offset < nSize)
400 {
401 FD_ZERO(&rdfs);
402 FD_SET(m_hPort, &rdfs);
403 tv.tv_sec = m_nTimeout / 10;
404 tv.tv_usec = 0;
405 nRet = select(m_hPort + 1, &rdfs, NULL, NULL, &tv);
406 if (nRet > 0)
407 {
408 got = read(m_hPort, pBuff + offset, nSize - offset);
409 if (got >= 0)
410 {
411 offset += got;
412 nRet = offset;
413 }
414 else
415 {
416 nRet = -1;
417 break;
418 }
419 }
420 else
421 {
422 if (offset == 0) // got no data
423 {
424 nRet = -1;
425 }
426 break;
427 }
428 }
429
430 #endif // _WIN32
431
432 //if (nRet == -1)
433 // Restart();
434
435 return nRet;
436 }
437
438 //
439 // Write character(s) to port
440 //
441
442 bool Serial::Write(const char *pBuff, int nSize)
443 {
444 bool bRet = false;
445
446 if (m_hPort == INVALID_HANDLE_VALUE)
447 return false;
448
449 #ifdef _WIN32
450
451 Sleep(100);
452
453 DWORD nDone;
454 if (WriteFile(m_hPort, pBuff, nSize, &nDone, NULL) != 0)
455 {
456 if (nDone == (DWORD)nSize)
457 {
458 bRet = true;
459 }
460 }
461 else
462 {
463 Restart();
464 }
465
466 #else // UNIX
467 usleep(100);
468
469 if (write(m_hPort, (char *)pBuff, nSize) == nSize)
470 {
471 bRet = true;
472 }
473 else
474 {
475 Restart();
476 }
477
478 #endif // _WIN32
479
480 return bRet;
481 }
482
483
484 //
485 // Flush buffer
486 //
487
488 void Serial::Flush(void)
489 {
490 #ifdef _WIN32
491
492 FlushFileBuffers(m_hPort);
493
494 #else // UNIX
495
496 #ifndef _NETWARE
497 tcflush(m_hPort, TCIOFLUSH);
498 #endif
499
500 #endif // _WIN32
501 }
502
503 ///////////////////////////////////////////////////////////////////////////////
504 /*
505
506 $Log: not supported by cvs2svn $
507 Revision 1.19 2007/01/24 21:34:55 victor
508 - Fixed Serial::ReadAll() under Windows
509 - Added isSystem object's attribute
510
511 Revision 1.18 2007/01/24 00:54:17 alk
512 Serial::ReadAll() implementation
513
514 Revision 1.17 2006/11/21 22:06:19 alk
515 DTR/RTS issues fixed (req. for nokia gsm modem on serial port)
516
517 Revision 1.16 2006/11/21 22:04:07 alk
518 code reformatted (mix of tab/space replaced with tabs)
519
520 Revision 1.15 2006/10/20 10:15:56 victor
521 - libnxcscp merged into libnetxms
522 - Fixed NetWare compilation issues
523
524 Revision 1.14 2006/09/10 06:59:37 victor
525 Fixed problmes with Win32 build
526
527 Revision 1.13 2006/09/07 22:02:06 alk
528 UNIX version of Serial rewritten
529 termio removed from configure (depricated in favour of termio_s_?)
530
531 */