Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
270 johboh 1
//	Serial.cpp - Implementation of the CSerial class
2
//
3
//	Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl)
4
//
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
9
// 
10
// This library 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 GNU
13
// Lesser General Public License for more details.
14
// 
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
19
 
20
//////////////////////////////////////////////////////////////////////
21
// Include the standard header files
22
 
23
#define STRICT
24
#include <crtdbg.h>
25
#include <tchar.h>
26
#include <windows.h>
27
#include "stdafx.h"
28
 
29
 
30
//////////////////////////////////////////////////////////////////////
31
// Include module headerfile
32
 
33
#include "Serial.h"
34
 
35
 
36
//////////////////////////////////////////////////////////////////////
37
// Disable warning C4127: conditional expression is constant, which
38
// is generated when using the _RPTF and _ASSERTE macros.
39
 
40
#pragma warning(disable: 4127)
41
 
42
 
43
//////////////////////////////////////////////////////////////////////
44
// Enable debug memory manager
45
 
46
#ifdef _DEBUG
47
 
48
#ifdef THIS_FILE
49
#undef THIS_FILE
50
#endif
51
 
52
static const char THIS_FILE[] = __FILE__;
53
#define new DEBUG_NEW
54
 
55
#endif
56
 
57
 
58
//////////////////////////////////////////////////////////////////////
59
// Helper methods
60
 
61
inline void CSerial::CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const
62
{
63
#ifdef SERIAL_NO_OVERLAPPED
64
 
65
	// Check if an overlapped structure has been specified
66
	if (lpOverlapped || (dwTimeout != INFINITE))
67
	{
68
		// Quit application
69
		::MessageBox(0,_T("Overlapped I/O and time-outs are not supported, when overlapped I/O is disabled."),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
70
		::DebugBreak();
71
		::ExitProcess(0xFFFFFFF);
72
	}
73
 
74
#endif
75
 
76
#ifdef SERIAL_NO_CANCELIO
77
 
78
	// Check if 0 or INFINITE time-out has been specified, because
79
	// the communication I/O cannot be cancelled.
80
	if ((dwTimeout != 0) && (dwTimeout != INFINITE))
81
	{
82
		// Quit application
83
		::MessageBox(0,_T("Timeouts are not supported, when SERIAL_NO_CANCELIO is defined"),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
84
		::DebugBreak();
85
		::ExitProcess(0xFFFFFFF);
86
	}
87
 
88
#endif	// SERIAL_NO_CANCELIO
89
 
90
	// Avoid warnings
91
	(void) dwTimeout;
92
	(void) lpOverlapped;
93
}
94
 
95
inline BOOL CSerial::CancelCommIo (void)
96
{
97
#ifdef SERIAL_NO_CANCELIO
98
	// CancelIo shouldn't have been called at this point
99
	::DebugBreak();
100
	return FALSE;
101
#else
102
 
103
	// Cancel the I/O request
104
	return ::CancelIo(m_hFile);
105
 
106
#endif	// SERIAL_NO_CANCELIO
107
}
108
 
109
 
110
//////////////////////////////////////////////////////////////////////
111
// Code
112
 
113
CSerial::CSerial ()
114
	: m_lLastError(ERROR_SUCCESS)
115
	, m_hFile(0)
116
	, m_eEvent(EEventNone)
117
	, m_dwEventMask(0)
118
#ifndef SERIAL_NO_OVERLAPPED
119
	, m_hevtOverlapped(0)
120
#endif
121
{
122
}
123
 
124
CSerial::~CSerial ()
125
{
126
	// If the device is already closed,
127
	// then we don't need to do anything.
128
	if (m_hFile)
129
	{
130
		// Display a warning
131
		_RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n");
132
 
133
		// Close implicitly
134
		Close();
135
	}
136
}
137
 
138
CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice)
139
{
140
	// Try to open the device
141
	HANDLE hFile = ::CreateFile(lpszDevice, 
142
						   GENERIC_READ|GENERIC_WRITE, 
143
						   0, 
144
						   0, 
145
						   OPEN_EXISTING, 
146
						   0,
147
						   0);
148
 
149
	// Check if we could open the device
150
	if (hFile == INVALID_HANDLE_VALUE)
151
	{
152
		// Display error
153
		switch (::GetLastError())
154
		{
155
		case ERROR_FILE_NOT_FOUND:
156
			// The specified COM-port does not exist
157
			return EPortNotAvailable;
158
 
159
		case ERROR_ACCESS_DENIED:
160
			// The specified COM-port is in use
161
			return EPortInUse;
162
 
163
		default:
164
			// Something else is wrong
165
			return EPortUnknownError;
166
		}
167
	}
168
 
169
	// Close handle
170
	::CloseHandle(hFile);
171
 
172
	// Port is available
173
	return EPortAvailable;
174
}
175
 
176
LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped)
177
{
178
	// Reset error state
179
	m_lLastError = ERROR_SUCCESS;
180
 
181
	// Check if the port isn't already opened
182
	if (m_hFile)
183
	{
184
		m_lLastError = ERROR_ALREADY_INITIALIZED;
185
		_RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n");
186
		return m_lLastError;
187
	}
188
 
189
	// Open the device
190
	m_hFile = ::CreateFile(lpszDevice,
191
						   GENERIC_READ|GENERIC_WRITE,
192
						   0,
193
						   0,
194
						   OPEN_EXISTING,
195
						   fOverlapped?FILE_FLAG_OVERLAPPED:0,
196
						   0);
197
	if (m_hFile == INVALID_HANDLE_VALUE)
198
	{
199
		// Reset file handle
200
		m_hFile = 0;
201
 
202
		// Display error
203
		m_lLastError = ::GetLastError();
204
		_RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
205
		return m_lLastError;
206
	}
207
 
208
#ifndef SERIAL_NO_OVERLAPPED
209
	// We cannot have an event handle yet
210
	_ASSERTE(m_hevtOverlapped == 0);
211
 
212
	// Create the event handle for internal overlapped operations (manual reset)
213
	if (fOverlapped)
214
	{
215
		m_hevtOverlapped = ::CreateEvent(0,true,false,0);
216
		if (m_hevtOverlapped == 0)
217
		{
218
			// Obtain the error information
219
			m_lLastError = ::GetLastError();
220
			_RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n");
221
 
222
			// Close the port
223
			::CloseHandle(m_hFile);
224
			m_hFile = 0;
225
 
226
			// Return the error
227
			return m_lLastError;
228
		}
229
	}
230
#else
231
 
232
	// Overlapped flag shouldn't be specified
233
	_ASSERTE(!fOverlapped);
234
 
235
#endif
236
 
237
	// Setup the COM-port
238
	if (dwInQueue || dwOutQueue)
239
	{
240
		// Make sure the queue-sizes are reasonable sized. Win9X systems crash
241
		// if the input queue-size is zero. Both queues need to be at least
242
		// 16 bytes large.
243
		_ASSERTE(dwInQueue >= 16);
244
		_ASSERTE(dwOutQueue >= 16);
245
 
246
		if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
247
		{
248
			// Display a warning
249
			long lLastError = ::GetLastError();
250
			_RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n");
251
 
252
			// Close the port
253
			Close();
254
 
255
			// Save last error from SetupComm
256
			m_lLastError = lLastError;
257
			return m_lLastError;	
258
		}
259
	}
260
 
261
	// Setup the default communication mask
262
	SetMask();
263
 
264
	// Non-blocking reads is default
265
	SetupReadTimeouts(EReadTimeoutNonblocking);
266
 
267
	// Setup the device for default settings
268
 	COMMCONFIG commConfig = {0};
269
	DWORD dwSize = sizeof(commConfig);
270
	commConfig.dwSize = dwSize;
271
	if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize))
272
	{
273
		// Set the default communication configuration
274
		if (!::SetCommConfig(m_hFile,&commConfig,dwSize))
275
		{
276
			// Display a warning
277
			_RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n");
278
		}
279
	}
280
	else
281
	{
282
		// Display a warning
283
		_RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n");
284
	}
285
 
286
	// Return successful
287
	return m_lLastError;
288
}
289
 
290
LONG CSerial::Close (void)
291
{
292
	// Reset error state
293
	m_lLastError = ERROR_SUCCESS;
294
 
295
	// If the device is already closed,
296
	// then we don't need to do anything.
297
	if (m_hFile == 0)
298
	{
299
		// Display a warning
300
		_RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n");
301
		return m_lLastError;
302
	}
303
 
304
#ifndef SERIAL_NO_OVERLAPPED
305
	// Free event handle
306
	if (m_hevtOverlapped)
307
	{
308
		::CloseHandle(m_hevtOverlapped);
309
		m_hevtOverlapped = 0;
310
	}
311
#endif
312
 
313
	// Close COM port
314
	::CloseHandle(m_hFile);
315
	m_hFile = 0;
316
 
317
	// Return successful
318
	return m_lLastError;
319
}
320
 
321
LONG CSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
322
{
323
	// Reset error state
324
	m_lLastError = ERROR_SUCCESS;
325
 
326
	// Check if the device is open
327
	if (m_hFile == 0)
328
	{
329
		// Set the internal error code
330
		m_lLastError = ERROR_INVALID_HANDLE;
331
 
332
		// Issue an error and quit
333
		_RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n");
334
		return m_lLastError;
335
	}
336
 
337
	// Obtain the DCB structure for the device
338
	CDCB dcb;
339
	if (!::GetCommState(m_hFile,&dcb))
340
	{
341
		// Obtain the error code
342
		m_lLastError = ::	GetLastError();
343
 
344
		// Display a warning
345
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
346
		return m_lLastError;
347
	}
348
 
349
	// Set the new data
350
	dcb.BaudRate = DWORD(eBaudrate);
351
	dcb.ByteSize = BYTE(eDataBits);
352
	dcb.Parity   = BYTE(eParity);
353
	dcb.StopBits = BYTE(eStopBits);
354
 
355
	// Determine if parity is used
356
	dcb.fParity  = (eParity != EParNone);
357
 
358
	// Set the new DCB structure
359
	if (!::SetCommState(m_hFile,&dcb))
360
	{
361
		// Obtain the error code
362
		m_lLastError = ::GetLastError();
363
 
364
		// Display a warning
365
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n");
366
		return m_lLastError;
367
	}
368
 
369
	// Return successful
370
	return m_lLastError;
371
}
372
 
373
LONG CSerial::SetEventChar (BYTE bEventChar, bool fAdjustMask)
374
{
375
	// Reset error state
376
	m_lLastError = ERROR_SUCCESS;
377
 
378
	// Check if the device is open
379
	if (m_hFile == 0)
380
	{
381
		// Set the internal error code
382
		m_lLastError = ERROR_INVALID_HANDLE;
383
 
384
		// Issue an error and quit
385
		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Device is not opened\n");
386
		return m_lLastError;
387
	}
388
 
389
	// Obtain the DCB structure for the device
390
	CDCB dcb;
391
	if (!::GetCommState(m_hFile,&dcb))
392
	{
393
		// Obtain the error code
394
		m_lLastError = ::GetLastError();
395
 
396
		// Display a warning
397
		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to obtain DCB information\n");
398
		return m_lLastError;
399
	}
400
 
401
	// Set the new event character
402
	dcb.EvtChar = char(bEventChar);
403
 
404
	// Adjust the event mask, to make sure the event will be received
405
	if (fAdjustMask)
406
	{
407
		// Enable 'receive event character' event.  Note that this
408
		// will generate an EEventNone if there is an asynchronous
409
		// WaitCommEvent pending.
410
		SetMask(GetEventMask() | EEventRcvEv);
411
	}
412
 
413
	// Set the new DCB structure
414
	if (!::SetCommState(m_hFile,&dcb))
415
	{
416
		// Obtain the error code
417
		m_lLastError = ::GetLastError();
418
 
419
		// Display a warning
420
		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to set DCB information\n");
421
		return m_lLastError;
422
	}
423
 
424
	// Return successful
425
	return m_lLastError;
426
}
427
 
428
LONG CSerial::SetMask (DWORD dwEventMask)
429
{
430
	// Reset error state
431
	m_lLastError = ERROR_SUCCESS;
432
 
433
	// Check if the device is open
434
	if (m_hFile == 0)
435
	{
436
		// Set the internal error code
437
		m_lLastError = ERROR_INVALID_HANDLE;
438
 
439
		// Issue an error and quit
440
		_RPTF0(_CRT_WARN,"CSerial::SetMask - Device is not opened\n");
441
		return m_lLastError;
442
	}
443
 
444
	// Set the new mask. Note that this will generate an EEventNone
445
	// if there is an asynchronous WaitCommEvent pending.
446
	if (!::SetCommMask(m_hFile,dwEventMask))
447
	{
448
		// Obtain the error code
449
		m_lLastError = ::GetLastError();
450
 
451
		// Display a warning
452
		_RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n");
453
		return m_lLastError;
454
	}
455
 
456
	// Save event mask and return successful
457
	m_dwEventMask = dwEventMask;
458
	return m_lLastError;
459
}
460
 
461
LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
462
{
463
	// Check if time-outs are supported
464
	CheckRequirements(lpOverlapped,dwTimeout);
465
 
466
	// Reset error state
467
	m_lLastError = ERROR_SUCCESS;
468
 
469
	// Check if the device is open
470
	if (m_hFile == 0)
471
	{
472
		// Set the internal error code
473
		m_lLastError = ERROR_INVALID_HANDLE;
474
 
475
		// Issue an error and quit
476
		_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n");
477
		return m_lLastError;
478
	}
479
 
480
#ifndef SERIAL_NO_OVERLAPPED
481
 
482
	// Check if an overlapped structure has been specified
483
	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
484
	{
485
		// Set the internal error code
486
		m_lLastError = ERROR_INVALID_FUNCTION;
487
 
488
		// Issue an error and quit
489
		_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Overlapped I/O is disabled, specified parameters are illegal.\n");
490
		return m_lLastError;
491
	}
492
 
493
	// Wait for the event to happen
494
	OVERLAPPED ovInternal;
495
	if (!lpOverlapped && m_hevtOverlapped)
496
	{
497
		// Setup our own overlapped structure
498
		memset(&ovInternal,0,sizeof(ovInternal));
499
		ovInternal.hEvent = m_hevtOverlapped;
500
 
501
		// Use our internal overlapped structure
502
		lpOverlapped = &ovInternal;
503
	}
504
 
505
	// Make sure the overlapped structure isn't busy
506
	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
507
 
508
	// Wait for the COM event
509
	if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped))
510
	{
511
		// Set the internal error code
512
		long lLastError = ::GetLastError();
513
 
514
		// Overlapped operation in progress is not an actual error
515
		if (lLastError != ERROR_IO_PENDING)
516
		{
517
			// Save the error
518
			m_lLastError = lLastError;
519
 
520
			// Issue an error and quit
521
			_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
522
			return m_lLastError;
523
		}
524
 
525
		// We need to block if the client didn't specify an overlapped structure
526
		if (lpOverlapped == &ovInternal)
527
		{
528
			// Wait for the overlapped operation to complete
529
			switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
530
			{
531
			case WAIT_OBJECT_0:
532
				// The overlapped operation has completed
533
				break;
534
 
535
			case WAIT_TIMEOUT:
536
				// Cancel the I/O operation
537
				CancelCommIo();
538
 
539
				// The operation timed out. Set the internal error code and quit
540
				m_lLastError = ERROR_TIMEOUT;
541
				return m_lLastError;
542
 
543
			default:
544
				// Set the internal error code
545
				m_lLastError = ::GetLastError();
546
 
547
				// Issue an error and quit
548
				_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait until COM event has arrived\n");
549
				return m_lLastError;
550
			}
551
		}
552
	}
553
	else
554
	{
555
		// The operation completed immediatly. Just to be sure
556
		// we'll set the overlapped structure's event handle.
557
		if (lpOverlapped)
558
			::SetEvent(lpOverlapped->hEvent);
559
	}
560
#else
561
 
562
	// Wait for the COM event
563
	if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),0))
564
	{
565
		// Set the internal error code
566
		m_lLastError = ::GetLastError();
567
 
568
		// Issue an error and quit
569
		_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
570
		return m_lLastError;
571
	}
572
 
573
#endif
574
 
575
	// Return successfully
576
	return m_lLastError;
577
}
578
 
579
 
580
LONG CSerial::SetupHandshaking (EHandshake eHandshake)
581
{
582
	// Reset error state
583
	m_lLastError = ERROR_SUCCESS;
584
 
585
	// Check if the device is open
586
	if (m_hFile == 0)
587
	{
588
		// Set the internal error code
589
		m_lLastError = ERROR_INVALID_HANDLE;
590
 
591
		// Issue an error and quit
592
		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Device is not opened\n");
593
		return m_lLastError;
594
	}
595
 
596
	// Obtain the DCB structure for the device
597
	CDCB dcb;
598
	if (!::GetCommState(m_hFile,&dcb))
599
	{
600
		// Obtain the error code
601
		m_lLastError = ::GetLastError();
602
 
603
		// Display a warning
604
		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to obtain DCB information\n");
605
		return m_lLastError;
606
	}
607
 
608
	// Set the handshaking flags
609
	switch (eHandshake)
610
	{
611
	case EHandshakeOff:
612
		dcb.fOutxCtsFlow = false;					// Disable CTS monitoring
613
		dcb.fOutxDsrFlow = false;					// Disable DSR monitoring
614
		dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR monitoring
615
		dcb.fOutX = false;							// Disable XON/XOFF for transmission
616
		dcb.fInX = false;							// Disable XON/XOFF for receiving
617
		dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
618
		break;
619
 
620
	case EHandshakeHardware:
621
		dcb.fOutxCtsFlow = true;					// Enable CTS monitoring
622
		dcb.fOutxDsrFlow = true;					// Enable DSR monitoring
623
		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;	// Enable DTR handshaking
624
		dcb.fOutX = false;							// Disable XON/XOFF for transmission
625
		dcb.fInX = false;							// Disable XON/XOFF for receiving
626
		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;	// Enable RTS handshaking
627
		break;
628
 
629
	case EHandshakeSoftware:
630
		dcb.fOutxCtsFlow = false;					// Disable CTS (Clear To Send)
631
		dcb.fOutxDsrFlow = false;					// Disable DSR (Data Set Ready)
632
		dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR (Data Terminal Ready)
633
		dcb.fOutX = true;							// Enable XON/XOFF for transmission
634
		dcb.fInX = true;							// Enable XON/XOFF for receiving
635
		dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
636
		break;
637
 
638
	default:
639
		// This shouldn't be possible
640
		_ASSERTE(false);
641
		m_lLastError = E_INVALIDARG;
642
		return m_lLastError;
643
	}
644
 
645
	// Set the new DCB structure
646
	if (!::SetCommState(m_hFile,&dcb))
647
	{
648
		// Obtain the error code
649
		m_lLastError = ::GetLastError();
650
 
651
		// Display a warning
652
		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to set DCB information\n");
653
		return m_lLastError;
654
	}
655
 
656
	// Return successful
657
	return m_lLastError;
658
}
659
 
660
LONG CSerial::SetupReadTimeouts (EReadTimeout eReadTimeout)
661
{
662
	// Reset error state
663
	m_lLastError = ERROR_SUCCESS;
664
 
665
	// Check if the device is open
666
	if (m_hFile == 0)
667
	{
668
		// Set the internal error code
669
		m_lLastError = ERROR_INVALID_HANDLE;
670
 
671
		// Issue an error and quit
672
		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Device is not opened\n");
673
		return m_lLastError;
674
	}
675
 
676
	// Determine the time-outs
677
	COMMTIMEOUTS cto;
678
	if (!::GetCommTimeouts(m_hFile,&cto))
679
	{
680
		// Obtain the error code
681
		m_lLastError = ::GetLastError();
682
 
683
		// Display a warning
684
		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to obtain timeout information\n");
685
		return m_lLastError;
686
	}
687
 
688
	// Set the new timeouts
689
	switch (eReadTimeout)
690
	{
691
	case EReadTimeoutBlocking:
692
		cto.ReadIntervalTimeout = 0;
693
		cto.ReadTotalTimeoutConstant = 0;
694
		cto.ReadTotalTimeoutMultiplier = 0;
695
		break;
696
	case EReadTimeoutNonblocking:
697
		cto.ReadIntervalTimeout = MAXDWORD;
698
		cto.ReadTotalTimeoutConstant = 0;
699
		cto.ReadTotalTimeoutMultiplier = 0;
700
		break;
701
	default:
702
		// This shouldn't be possible
703
		_ASSERTE(false);
704
		m_lLastError = E_INVALIDARG;
705
		return m_lLastError;
706
	}
707
 
708
	// Set the new DCB structure
709
	if (!::SetCommTimeouts(m_hFile,&cto))
710
	{
711
		// Obtain the error code
712
		m_lLastError = ::GetLastError();
713
 
714
		// Display a warning
715
		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to set timeout information\n");
716
		return m_lLastError;
717
	}
718
 
719
	// Return successful
720
	return m_lLastError;
721
}
722
 
723
CSerial::EBaudrate CSerial::GetBaudrate (void)
724
{
725
	// Reset error state
726
	m_lLastError = ERROR_SUCCESS;
727
 
728
	// Check if the device is open
729
	if (m_hFile == 0)
730
	{
731
		// Set the internal error code
732
		m_lLastError = ERROR_INVALID_HANDLE;
733
 
734
		// Issue an error and quit
735
		_RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Device is not opened\n");
736
		return EBaudUnknown;
737
	}
738
 
739
	// Obtain the DCB structure for the device
740
	CDCB dcb;
741
	if (!::GetCommState(m_hFile,&dcb))
742
	{
743
		// Obtain the error code
744
		m_lLastError = ::GetLastError();
745
 
746
		// Display a warning
747
		_RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Unable to obtain DCB information\n");
748
		return EBaudUnknown;
749
	}
750
 
751
	// Return the appropriate baudrate
752
	return EBaudrate(dcb.BaudRate);
753
}
754
 
755
CSerial::EDataBits CSerial::GetDataBits (void)
756
{
757
	// Reset error state
758
	m_lLastError = ERROR_SUCCESS;
759
 
760
	// Check if the device is open
761
	if (m_hFile == 0)
762
	{
763
		// Set the internal error code
764
		m_lLastError = ERROR_INVALID_HANDLE;
765
 
766
		// Issue an error and quit
767
		_RPTF0(_CRT_WARN,"CSerial::GetDataBits - Device is not opened\n");
768
		return EDataUnknown;
769
	}
770
 
771
	// Obtain the DCB structure for the device
772
	CDCB dcb;
773
	if (!::GetCommState(m_hFile,&dcb))
774
	{
775
		// Obtain the error code
776
		m_lLastError = ::GetLastError();
777
 
778
		// Display a warning
779
		_RPTF0(_CRT_WARN,"CSerial::GetDataBits - Unable to obtain DCB information\n");
780
		return EDataUnknown;
781
	}
782
 
783
	// Return the appropriate bytesize
784
	return EDataBits(dcb.ByteSize);
785
}
786
 
787
CSerial::EParity CSerial::GetParity (void)
788
{
789
	// Reset error state
790
	m_lLastError = ERROR_SUCCESS;
791
 
792
	// Check if the device is open
793
	if (m_hFile == 0)
794
	{
795
		// Set the internal error code
796
		m_lLastError = ERROR_INVALID_HANDLE;
797
 
798
		// Issue an error and quit
799
		_RPTF0(_CRT_WARN,"CSerial::GetParity - Device is not opened\n");
800
		return EParUnknown;
801
	}
802
 
803
	// Obtain the DCB structure for the device
804
	CDCB dcb;
805
	if (!::GetCommState(m_hFile,&dcb))
806
	{
807
		// Obtain the error code
808
		m_lLastError = ::GetLastError();
809
 
810
		// Display a warning
811
		_RPTF0(_CRT_WARN,"CSerial::GetParity - Unable to obtain DCB information\n");
812
		return EParUnknown;
813
	}
814
 
815
	// Check if parity is used
816
	if (!dcb.fParity)
817
	{
818
		// No parity
819
		return EParNone;
820
	}
821
 
822
	// Return the appropriate parity setting
823
	return EParity(dcb.Parity);
824
}
825
 
826
CSerial::EStopBits CSerial::GetStopBits (void)
827
{
828
	// Reset error state
829
	m_lLastError = ERROR_SUCCESS;
830
 
831
	// Check if the device is open
832
	if (m_hFile == 0)
833
	{
834
		// Set the internal error code
835
		m_lLastError = ERROR_INVALID_HANDLE;
836
 
837
		// Issue an error and quit
838
		_RPTF0(_CRT_WARN,"CSerial::GetStopBits - Device is not opened\n");
839
		return EStopUnknown;
840
	}
841
 
842
	// Obtain the DCB structure for the device
843
	CDCB dcb;
844
	if (!::GetCommState(m_hFile,&dcb))
845
	{
846
		// Obtain the error code
847
		m_lLastError = ::GetLastError();
848
 
849
		// Display a warning
850
		_RPTF0(_CRT_WARN,"CSerial::GetStopBits - Unable to obtain DCB information\n");
851
		return EStopUnknown;
852
	}
853
 
854
	// Return the appropriate stopbits
855
	return EStopBits(dcb.StopBits);
856
}
857
 
858
DWORD CSerial::GetEventMask (void)
859
{
860
	// Reset error state
861
	m_lLastError = ERROR_SUCCESS;
862
 
863
	// Check if the device is open
864
	if (m_hFile == 0)
865
	{
866
		// Set the internal error code
867
		m_lLastError = ERROR_INVALID_HANDLE;
868
 
869
		// Issue an error and quit
870
		_RPTF0(_CRT_WARN,"CSerial::GetEventMask - Device is not opened\n");
871
		return 0;
872
	}
873
 
874
	// Return the event mask
875
	return m_dwEventMask;
876
}
877
 
878
BYTE CSerial::GetEventChar (void)
879
{
880
	// Reset error state
881
	m_lLastError = ERROR_SUCCESS;
882
 
883
	// Check if the device is open
884
	if (m_hFile == 0)
885
	{
886
		// Set the internal error code
887
		m_lLastError = ERROR_INVALID_HANDLE;
888
 
889
		// Issue an error and quit
890
		_RPTF0(_CRT_WARN,"CSerial::GetEventChar - Device is not opened\n");
891
		return 0;
892
	}
893
 
894
	// Obtain the DCB structure for the device
895
	CDCB dcb;
896
	if (!::GetCommState(m_hFile,&dcb))
897
	{
898
		// Obtain the error code
899
		m_lLastError = ::GetLastError();
900
 
901
		// Display a warning
902
		_RPTF0(_CRT_WARN,"CSerial::GetEventChar - Unable to obtain DCB information\n");
903
		return 0;
904
	}
905
 
906
	// Set the new event character
907
	return BYTE(dcb.EvtChar);
908
}
909
 
910
CSerial::EHandshake CSerial::GetHandshaking (void)
911
{
912
	// Reset error state
913
	m_lLastError = ERROR_SUCCESS;
914
 
915
	// Check if the device is open
916
	if (m_hFile == 0)
917
	{
918
		// Set the internal error code
919
		m_lLastError = ERROR_INVALID_HANDLE;
920
 
921
		// Issue an error and quit
922
		_RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Device is not opened\n");
923
		return EHandshakeUnknown;
924
	}
925
 
926
	// Obtain the DCB structure for the device
927
	CDCB dcb;
928
	if (!::GetCommState(m_hFile,&dcb))
929
	{
930
		// Obtain the error code
931
		m_lLastError = ::GetLastError();
932
 
933
		// Display a warning
934
		_RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Unable to obtain DCB information\n");
935
		return EHandshakeUnknown;
936
	}
937
 
938
	// Check if hardware handshaking is being used
939
	if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE))
940
		return EHandshakeHardware;
941
 
942
	// Check if software handshaking is being used
943
	if (dcb.fOutX && dcb.fInX)
944
		return EHandshakeSoftware;
945
 
946
	// No handshaking is being used
947
	return EHandshakeOff;
948
}
949
 
950
LONG CSerial::Write (const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
951
{
952
	// Check if time-outs are supported
953
	CheckRequirements(lpOverlapped,dwTimeout);
954
 
955
	// Overlapped operation should specify the pdwWritten variable
956
	_ASSERTE(!lpOverlapped || pdwWritten);
957
 
958
	// Reset error state
959
	m_lLastError = ERROR_SUCCESS;
960
 
961
	// Use our own variable for read count
962
	DWORD dwWritten;
963
	if (pdwWritten == 0)
964
	{
965
		pdwWritten = &dwWritten;
966
	}
967
 
968
	// Reset the number of bytes written
969
	*pdwWritten = 0;
970
 
971
	// Check if the device is open
972
	if (m_hFile == 0)
973
	{
974
		// Set the internal error code
975
		m_lLastError = ERROR_INVALID_HANDLE;
976
 
977
		// Issue an error and quit
978
		_RPTF0(_CRT_WARN,"CSerial::Write - Device is not opened\n");
979
		return m_lLastError;
980
	}
981
 
982
#ifndef SERIAL_NO_OVERLAPPED
983
 
984
	// Check if an overlapped structure has been specified
985
	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
986
	{
987
		// Set the internal error code
988
		m_lLastError = ERROR_INVALID_FUNCTION;
989
 
990
		// Issue an error and quit
991
		_RPTF0(_CRT_WARN,"CSerial::Write - Overlapped I/O is disabled, specified parameters are illegal.\n");
992
		return m_lLastError;
993
	}
994
 
995
	// Wait for the event to happen
996
	OVERLAPPED ovInternal;
997
	if (!lpOverlapped && m_hevtOverlapped)
998
	{
999
		// Setup our own overlapped structure
1000
		memset(&ovInternal,0,sizeof(ovInternal));
1001
		ovInternal.hEvent = m_hevtOverlapped;
1002
 
1003
		// Use our internal overlapped structure
1004
		lpOverlapped = &ovInternal;
1005
	}
1006
 
1007
	// Make sure the overlapped structure isn't busy
1008
	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
1009
 
1010
	// Write the data
1011
	if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,lpOverlapped))
1012
	{
1013
		// Set the internal error code
1014
		long lLastError = ::GetLastError();
1015
 
1016
		// Overlapped operation in progress is not an actual error
1017
		if (lLastError != ERROR_IO_PENDING)
1018
		{
1019
			// Save the error
1020
			m_lLastError = lLastError;
1021
 
1022
			// Issue an error and quit
1023
			_RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
1024
			return m_lLastError;
1025
		}
1026
 
1027
		// We need to block if the client didn't specify an overlapped structure
1028
		if (lpOverlapped == &ovInternal)
1029
		{
1030
			// Wait for the overlapped operation to complete
1031
			switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
1032
			{
1033
			case WAIT_OBJECT_0:
1034
				// The overlapped operation has completed
1035
				if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwWritten,FALSE))
1036
				{
1037
					// Set the internal error code
1038
					m_lLastError = ::GetLastError();
1039
 
1040
					_RPTF0(_CRT_WARN,"CSerial::Write - Overlapped completed without result\n");
1041
					return m_lLastError;
1042
				}
1043
				break;
1044
 
1045
			case WAIT_TIMEOUT:
1046
				// Cancel the I/O operation
1047
				CancelCommIo();
1048
 
1049
				// The operation timed out. Set the internal error code and quit
1050
				m_lLastError = ERROR_TIMEOUT;
1051
				return m_lLastError;
1052
 
1053
			default:
1054
				// Set the internal error code
1055
				m_lLastError = ::GetLastError();
1056
 
1057
				// Issue an error and quit
1058
				_RPTF0(_CRT_WARN,"CSerial::Write - Unable to wait until data has been sent\n");
1059
				return m_lLastError;
1060
			}
1061
		}
1062
	}
1063
	else
1064
	{
1065
		// The operation completed immediatly. Just to be sure
1066
		// we'll set the overlapped structure's event handle.
1067
		if (lpOverlapped)
1068
			::SetEvent(lpOverlapped->hEvent);
1069
	}
1070
 
1071
#else
1072
 
1073
	// Write the data
1074
	if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,0))
1075
	{
1076
		// Set the internal error code
1077
		m_lLastError = ::GetLastError();
1078
 
1079
		// Issue an error and quit
1080
		_RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
1081
		return m_lLastError;
1082
	}
1083
 
1084
#endif
1085
 
1086
	// Return successfully
1087
	return m_lLastError;
1088
}
1089
 
1090
LONG CSerial::Write (LPCSTR pString, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
1091
{
1092
	// Check if time-outs are supported
1093
	CheckRequirements(lpOverlapped,dwTimeout);
1094
 
1095
	// Determine the length of the string
1096
	return Write(pString,strlen(pString),pdwWritten,lpOverlapped,dwTimeout);
1097
}
1098
 
1099
LONG CSerial::Read (void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
1100
{
1101
	// Check if time-outs are supported
1102
	CheckRequirements(lpOverlapped,dwTimeout);
1103
 
1104
	// Overlapped operation should specify the pdwRead variable
1105
	_ASSERTE(!lpOverlapped || pdwRead);
1106
 
1107
	// Reset error state
1108
	m_lLastError = ERROR_SUCCESS;
1109
 
1110
	// Use our own variable for read count
1111
	DWORD dwRead;
1112
	if (pdwRead == 0)
1113
	{
1114
		pdwRead = &dwRead;
1115
	}
1116
 
1117
	// Reset the number of bytes read
1118
	*pdwRead = 0;
1119
 
1120
	// Check if the device is open
1121
	if (m_hFile == 0)
1122
	{
1123
		// Set the internal error code
1124
		m_lLastError = ERROR_INVALID_HANDLE;
1125
 
1126
		// Issue an error and quit
1127
		_RPTF0(_CRT_WARN,"CSerial::Read - Device is not opened\n");
1128
		return m_lLastError;
1129
	}
1130
 
1131
#ifdef _DEBUG
1132
	// The debug version fills the entire data structure with
1133
	// 0xDC bytes, to catch buffer errors as soon as possible.
1134
	memset(pData,0xDC,iLen);
1135
#endif
1136
 
1137
#ifndef SERIAL_NO_OVERLAPPED
1138
 
1139
	// Check if an overlapped structure has been specified
1140
	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
1141
	{
1142
		// Set the internal error code
1143
		m_lLastError = ERROR_INVALID_FUNCTION;
1144
 
1145
		// Issue an error and quit
1146
		_RPTF0(_CRT_WARN,"CSerial::Read - Overlapped I/O is disabled, specified parameters are illegal.\n");
1147
		return m_lLastError;
1148
	}
1149
 
1150
	// Wait for the event to happen
1151
	OVERLAPPED ovInternal;
1152
	if (lpOverlapped == 0)
1153
	{
1154
		// Setup our own overlapped structure
1155
		memset(&ovInternal,0,sizeof(ovInternal));
1156
		ovInternal.hEvent = m_hevtOverlapped;
1157
 
1158
		// Use our internal overlapped structure
1159
		lpOverlapped = &ovInternal;
1160
	}
1161
 
1162
	// Make sure the overlapped structure isn't busy
1163
	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
1164
 
1165
	// Read the data
1166
	if (!::ReadFile(m_hFile,pData,iLen,pdwRead,lpOverlapped))
1167
	{
1168
		// Set the internal error code
1169
		long lLastError = ::GetLastError();
1170
 
1171
		// Overlapped operation in progress is not an actual error
1172
		if (lLastError != ERROR_IO_PENDING)
1173
		{
1174
			// Save the error
1175
			m_lLastError = lLastError;
1176
 
1177
			// Issue an error and quit
1178
			_RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n");
1179
			return m_lLastError;
1180
		}
1181
 
1182
		// We need to block if the client didn't specify an overlapped structure
1183
		if (lpOverlapped == &ovInternal)
1184
		{
1185
			// Wait for the overlapped operation to complete
1186
			switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
1187
			{
1188
			case WAIT_OBJECT_0:
1189
				// The overlapped operation has completed
1190
				if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwRead,FALSE))
1191
				{
1192
					// Set the internal error code
1193
					m_lLastError = ::GetLastError();
1194
 
1195
					_RPTF0(_CRT_WARN,"CSerial::Read - Overlapped completed without result\n");
1196
					return m_lLastError;
1197
				}
1198
				break;
1199
 
1200
			case WAIT_TIMEOUT:
1201
				// Cancel the I/O operation
1202
				CancelCommIo();
1203
 
1204
				// The operation timed out. Set the internal error code and quit
1205
				m_lLastError = ERROR_TIMEOUT;
1206
				return m_lLastError;
1207
 
1208
			default:
1209
				// Set the internal error code
1210
				m_lLastError = ::GetLastError();
1211
 
1212
				// Issue an error and quit
1213
				_RPTF0(_CRT_WARN,"CSerial::Read - Unable to wait until data has been read\n");
1214
				return m_lLastError;
1215
			}
1216
		}
1217
	}
1218
	else
1219
	{
1220
		// The operation completed immediatly. Just to be sure
1221
		// we'll set the overlapped structure's event handle.
1222
		if (lpOverlapped)
1223
			::SetEvent(lpOverlapped->hEvent);
1224
	}
1225
 
1226
#else
1227
 
1228
	// Read the data
1229
	if (!::ReadFile(m_hFile,pData,iLen,pdwRead,0))
1230
	{
1231
		// Set the internal error code
1232
		m_lLastError = ::GetLastError();
1233
 
1234
		// Issue an error and quit
1235
		_RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n");
1236
		return m_lLastError;
1237
	}
1238
 
1239
#endif
1240
 
1241
	// Return successfully
1242
	return m_lLastError;
1243
}
1244
 
1245
LONG CSerial::Purge()
1246
{
1247
	// Reset error state
1248
	m_lLastError = ERROR_SUCCESS;
1249
 
1250
	// Check if the device is open
1251
	if (m_hFile == 0)
1252
	{
1253
		// Set the internal error code
1254
		m_lLastError = ERROR_INVALID_HANDLE;
1255
 
1256
		// Issue an error and quit
1257
		_RPTF0(_CRT_WARN,"CSerial::Purge - Device is not opened\n");
1258
		return m_lLastError;
1259
	}
1260
 
1261
	if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR))
1262
	{
1263
		// Set the internal error code
1264
		m_lLastError = ::GetLastError();
1265
		_RPTF0(_CRT_WARN,"CSerial::Purge - Overlapped completed without result\n");
1266
	}
1267
 
1268
	// Return successfully
1269
	return m_lLastError;
1270
}
1271
 
1272
LONG CSerial::Break (void)
1273
{
1274
	// Reset error state
1275
	m_lLastError = ERROR_SUCCESS;
1276
 
1277
	// Check if the device is open
1278
	if (m_hFile == 0)
1279
	{
1280
		// Set the internal error code
1281
		m_lLastError = ERROR_INVALID_HANDLE;
1282
 
1283
		// Issue an error and quit
1284
		_RPTF0(_CRT_WARN,"CSerial::Break - Device is not opened\n");
1285
		return m_lLastError;
1286
	}
1287
 
1288
    // Set the RS-232 port in break mode for a little while
1289
    ::SetCommBreak(m_hFile);
1290
    ::Sleep(100);
1291
    ::ClearCommBreak(m_hFile);
1292
 
1293
	// Return successfully
1294
	return m_lLastError;
1295
}
1296
 
1297
CSerial::EEvent CSerial::GetEventType (void)
1298
{
1299
#ifdef _DEBUG
1300
	// Check if the event is within the mask
1301
	if ((m_eEvent & m_dwEventMask) == 0)
1302
		_RPTF2(_CRT_WARN,"CSerial::GetEventType - Event %08Xh not within mask %08Xh.\n", m_eEvent, m_dwEventMask);
1303
#endif
1304
 
1305
	// Obtain the event (mask unwanted events out)
1306
	EEvent eEvent = EEvent(m_eEvent & m_dwEventMask);
1307
 
1308
	// Reset internal event type
1309
	m_eEvent = EEventNone;
1310
 
1311
	// Return the current cause
1312
	return eEvent;
1313
}
1314
 
1315
CSerial::EError CSerial::GetError (void)
1316
{
1317
	// Reset error state
1318
	m_lLastError = ERROR_SUCCESS;
1319
 
1320
	// Check if the device is open
1321
	if (m_hFile == 0)
1322
	{
1323
		// Set the internal error code
1324
		m_lLastError = ERROR_INVALID_HANDLE;
1325
 
1326
		// Issue an error and quit
1327
		_RPTF0(_CRT_WARN,"CSerial::GetError - Device is not opened\n");
1328
		return EErrorUnknown;
1329
	}
1330
 
1331
	// Obtain COM status
1332
	DWORD dwErrors = 0;
1333
	if (!::ClearCommError(m_hFile,&dwErrors,0))
1334
	{
1335
		// Set the internal error code
1336
		m_lLastError = ::GetLastError();
1337
 
1338
		// Issue an error and quit
1339
		_RPTF0(_CRT_WARN,"CSerial::GetError - Unable to obtain COM status\n");
1340
		return EErrorUnknown;
1341
	}
1342
 
1343
	// Return the error
1344
	return EError(dwErrors);
1345
}
1346
 
1347
bool CSerial::GetCTS (void)
1348
{
1349
	// Reset error state
1350
	m_lLastError = ERROR_SUCCESS;
1351
 
1352
	// Obtain the modem status
1353
	DWORD dwModemStat = 0;
1354
	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
1355
	{
1356
		// Obtain the error code
1357
		m_lLastError = ::GetLastError();
1358
 
1359
		// Display a warning
1360
		_RPTF0(_CRT_WARN,"CSerial::GetCTS - Unable to obtain the modem status\n");
1361
		return false;
1362
	}
1363
 
1364
	// Determine if CTS is on
1365
	return (dwModemStat & MS_CTS_ON) != 0;
1366
}
1367
 
1368
bool CSerial::GetDSR (void)
1369
{
1370
	// Reset error state
1371
	m_lLastError = ERROR_SUCCESS;
1372
 
1373
	// Obtain the modem status
1374
	DWORD dwModemStat = 0;
1375
	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
1376
	{
1377
		// Obtain the error code
1378
		m_lLastError = ::GetLastError();
1379
 
1380
		// Display a warning
1381
		_RPTF0(_CRT_WARN,"CSerial::GetDSR - Unable to obtain the modem status\n");
1382
		return false;
1383
	}
1384
 
1385
	// Determine if DSR is on
1386
	return (dwModemStat & MS_DSR_ON) != 0;
1387
}
1388
 
1389
bool CSerial::GetRing (void)
1390
{
1391
	// Reset error state
1392
	m_lLastError = ERROR_SUCCESS;
1393
 
1394
	// Obtain the modem status
1395
	DWORD dwModemStat = 0;
1396
	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
1397
	{
1398
		// Obtain the error code
1399
		m_lLastError = ::GetLastError();
1400
 
1401
		// Display a warning
1402
		_RPTF0(_CRT_WARN,"CSerial::GetRing - Unable to obtain the modem status");
1403
		return false;
1404
	}
1405
 
1406
	// Determine if Ring is on
1407
	return (dwModemStat & MS_RING_ON) != 0;
1408
}
1409
 
1410
bool CSerial::GetRLSD (void)
1411
{
1412
	// Reset error state
1413
	m_lLastError = ERROR_SUCCESS;
1414
 
1415
	// Obtain the modem status
1416
	DWORD dwModemStat = 0;
1417
	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
1418
	{
1419
		// Obtain the error code
1420
		m_lLastError = ::GetLastError();
1421
 
1422
		// Display a warning
1423
		_RPTF0(_CRT_WARN,"CSerial::GetRLSD - Unable to obtain the modem status");
1424
		return false;
1425
	}
1426
 
1427
	// Determine if RLSD is on
1428
	return (dwModemStat & MS_RLSD_ON) != 0;
1429
}