Subversion Repositories HomeAutomation

Rev

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
}