Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
212 dhylands 1
/****************************************************************************
2
*
3
*     Copyright (c) 2003 Dave Hylands
4
*           All Rights Reserved
5
*
6
*   Permission is granted to any individual or institution to use, copy, or
7
*   redistribute this software so long as it is not sold for profit, and that
8
*   this copyright notice is retained.
9
*
10
****************************************************************************/
11
/**
12
*
13
*   @file   ConsoleComm.cpp
14
*
15
*   @brief  Implements the abstract communications device using a serial port.
16
*
17
****************************************************************************/
18
 
19
// ---- Include Files -------------------------------------------------------
20
 
21
#include "Error.h"
22
#include "LogMessage.h"
23
#include "ConsoleComm.h"
24
 
25
/**
26
 * @addtogroup ConsoleComm
27
 * @{
28
 */
29
 
30
#define USE_DBG 0
31
#if USE_DBG
32
#define DBG(x)    LOG_DEBUG(x)
33
#else
34
#define DBG(x)
35
#endif
36
 
37
// ---- Public Variables ----------------------------------------------------
38
// ---- Private Constants and Types -----------------------------------------
39
// ---- Private Variables ---------------------------------------------------
40
// ---- Private Function Prototypes -----------------------------------------
41
// ---- Functions -----------------------------------------------------------
42
 
43
//***************************************************************************
44
/**
45
*   Constructor
46
*/
47
 
48
ConsoleComm::ConsoleComm()
49
{
50
    m_stdin  = INVALID_HANDLE_VALUE;
51
    m_stdout = INVALID_HANDLE_VALUE;
52
 
53
    memset( &m_inputRec, 0, sizeof( m_inputRec ));
54
 
55
    m_abortEvent = NULL;
56
 
57
    m_name = "Console";
58
 
59
    m_quitDetected = false;
60
}
61
 
62
//***************************************************************************
63
/**
64
*   Destructor
65
*
66
* virtual
67
*/
68
 
69
ConsoleComm::~ConsoleComm()
70
{
71
    Close();
72
}
73
 
74
//***************************************************************************
75
/**
76
*   Aborts a read, if one is pending.
77
*
78
* virtual
79
*/
80
 
81
void ConsoleComm::AbortRead()
82
{
83
    DBG( "ConsoleComm: AbortRead called" );
84
 
85
    if ( m_abortEvent != NULL )
86
    {
87
        DBG( "ConsoleComm: AbortRead setting event" );
88
        SetEvent( m_abortEvent );
89
    }
90
 
91
} // AbortRead
92
 
93
//***************************************************************************
94
/**
95
*   Close a previsouly opened device.
96
*
97
* virtual
98
*/
99
 
100
void ConsoleComm::Close()
101
{
102
    // We didn't open the handles, so we don't close them either.
103
 
104
    if ( m_abortEvent != NULL )
105
    {
106
        CloseHandle( m_abortEvent );
107
        m_abortEvent = NULL;
108
    }
109
}
110
 
111
//***************************************************************************
112
/**
113
*   Enable line input/editing mode, if supported by the device.
114
*
115
* virtual
116
*/
117
 
118
void ConsoleComm::EnableLineMode( bool enable )
119
{
120
    DWORD   inMode;
121
    DWORD   outMode;
122
 
123
    GetConsoleMode( m_stdin, &inMode );
124
    GetConsoleMode( m_stdin, &outMode );
125
 
126
    DWORD inMask  = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT;
127
    DWORD outMask = ENABLE_PROCESSED_OUTPUT;
128
 
129
    if ( enable )
130
    {
131
        inMode |= inMask;
132
        outMode |= outMask;
133
    }
134
    else
135
    {
136
        inMode &= ~inMask;
137
        outMode &= ~outMask;
138
    }
139
 
140
    SetConsoleMode( m_stdin, inMode );
141
    SetConsoleMode( m_stdout, outMode );
142
 
143
} // EnableLineMode
144
 
145
//***************************************************************************
146
/**
147
*   Opens the console.
148
*
149
*   @returns    true if the port was opened successfully, false otherwise.
150
*
151
* virtual
152
*/
153
 
154
bool ConsoleComm::Open
155
(
156
    const char *openStr     ///< Not use for the Console
157
)
158
{
159
    m_stdin  = GetStdHandle( STD_INPUT_HANDLE );
160
    m_stdout = GetStdHandle( STD_OUTPUT_HANDLE );
161
 
162
    EnableLineMode( false );
163
 
164
    m_abortEvent = CreateEvent( NULL,   // lpEventAttributes
165
                                FALSE,  // bManualReset
166
                                FALSE,  // bInitialState
167
                                NULL ); // lpName
168
 
169
    return true;
170
}
171
 
172
//***************************************************************************
173
/**
174
*   Returns true if the device has detected a quit indication. This is
175
*   typically only implemented by a console device.
176
*
177
* virtual
178
*/
179
 
180
bool ConsoleComm::QuitDetected() const
181
{
182
    return m_quitDetected;
183
 
184
} // QuitDetected
185
 
186
//***************************************************************************
187
/**
188
*   Read data from the communication device.
189
*
190
*   @returns    true if the read was successful, flse otherwise.
191
*
192
* virtual
193
*/
194
 
195
bool ConsoleComm::Read
196
(
197
    void   *buf,        ///< (out) Place to store the read data.
198
    size_t  bufSize,    ///< (in)  Size of the data buffer.
199
    size_t *bytesRead   ///< (out) Number of bytes actually read.
200
)
201
{
202
        DWORD   err;
203
    char    errStr[ 200 ];
204
 
205
    *bytesRead = 0;
206
 
207
    size_t  bytesRemaining = bufSize;
208
 
209
    CHAR    *s = (CHAR *)buf;
210
 
211
    while ( true )
212
    {
213
        bool processEvent = false;
214
 
215
        if (( m_inputRec.EventType == KEY_EVENT )
216
        &&  ( m_inputRec.Event.KeyEvent.bKeyDown )
217
        &&  ( m_inputRec.Event.KeyEvent.wRepeatCount > 0 ))
218
        {
219
            if ( m_inputRec.Event.KeyEvent.uChar.AsciiChar != 0x00 )
220
            {
221
                processEvent = true;
222
            }
223
            else
224
            if (( m_inputRec.Event.KeyEvent.wVirtualKeyCode == '2' )
225
            &&  (( m_inputRec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ) != 0 )
226
            &&  (( m_inputRec.Event.KeyEvent.dwControlKeyState & ( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED )) != 0 )
227
            &&  (( m_inputRec.Event.KeyEvent.dwControlKeyState & ( LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED )) == 0 ))
228
            {
229
                // Special case for Control-@ which should generate a null character
230
 
231
                processEvent = true;
232
            }
233
            else
234
            if (( m_inputRec.Event.KeyEvent.wVirtualKeyCode == VK_F4 )
235
            &&  (( m_inputRec.Event.KeyEvent.dwControlKeyState & ( LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED )) != 0 ))
236
            {
237
                // Alt-F4 sends a quit event
238
 
239
                m_quitDetected = true;
240
                return false;
241
            }
242
        }
243
        if ( processEvent )
244
        {
245
            size_t  bytesToCopy;
246
 
247
            bytesToCopy = m_inputRec.Event.KeyEvent.wRepeatCount;
248
            if ( bytesToCopy > bytesRemaining )
249
            {
250
                bytesToCopy = bytesRemaining;
251
            }
252
 
253
            if ( bytesToCopy > 0 )
254
            {
255
                memset( s, m_inputRec.Event.KeyEvent.uChar.AsciiChar, bytesToCopy );
256
                m_inputRec.Event.KeyEvent.wRepeatCount -= bytesToCopy;
257
                *bytesRead += bytesToCopy;
258
                s += bytesToCopy;
259
            }
260
 
261
            if ( m_inputRec.Event.KeyEvent.wRepeatCount > 0 )
262
            {
263
                // This means that we filled the buffer
264
 
265
                break;
266
            }
267
        }
268
 
269
        // See how many events are in the queue
270
 
271
        DWORD   numEvents;
272
 
273
        if ( !GetNumberOfConsoleInputEvents( m_stdin, &numEvents ))
274
        {
275
            LOG_ERROR( "ConsoleComm::Read call to GetNumberOfConsoleInputEvents failed: "
276
                    << GetLastErrorStr( errStr, sizeof( errStr )));
277
            return false;
278
        }
279
 
280
        if (( *bytesRead > 0 ) && ( numEvents == 0 ))
281
        {
282
            // We've read some data, and there aren't any events in the queue.
283
 
284
            break;
285
        }
286
 
287
        if ( numEvents == 0 )
288
        {
289
            // Wait for an event to show up in the queue.
290
 
291
            HANDLE  waitHandle[ 2 ];
292
 
293
            waitHandle[ 0 ] = m_stdin;
294
            waitHandle[ 1 ] = m_abortEvent;
295
 
296
                        DBG( "ConsoleComm: Waiting for event" );
297
            DWORD rc = WaitForMultipleObjects( 2, waitHandle, FALSE, INFINITE );
298
 
299
            if ( rc == ( WAIT_OBJECT_0 + 1 ))
300
            {
301
                // We've been asked to quit. Cancel the I/O.
302
 
303
                                DBG( "ConsoleComm: quit event received" );
304
                return false;
305
            }
306
            if ( rc != WAIT_OBJECT_0 )
307
            {
308
                err = GetLastError();
309
 
310
                LOG_ERROR( "ConsoleComm::Read Wait failed: " << GetErrorStr( err, errStr, sizeof( errStr )));
311
                return false;
312
            }
313
        }
314
 
315
        // Read the event
316
 
317
                DWORD   numEventsRead;
318
 
319
                DBG( "ConsoleComm: Calling ReadConsoleInput" );
320
        if ( !ReadConsoleInput( m_stdin, &m_inputRec, 1, &numEventsRead ))
321
        {
322
            LOG_ERROR( "ConsoleComm::Read call to ReadConsoleInput failed: "
323
                    << GetLastErrorStr( errStr, sizeof( errStr )));
324
            return false;
325
        }
326
                DBG( "ConsoleComm: ReadConsoleInput finished" );
327
    }
328
 
329
        return true;
330
}
331
 
332
//***************************************************************************
333
/**
334
*   Write data to the communication device.
335
*
336
*   @returns    true if the write was successful, flse otherwise.
337
*
338
* virtual
339
*/
340
 
341
bool ConsoleComm::Write
342
(
343
    const void *buf,            ///< (in)  Buffer containing data to write
344
    size_t      bytesToWrite,   ///< (in)  Number of bytes of data to write
345
    size_t     *bytesWritten    ///< (out) Number of bytes actually written
346
)
347
{
348
        DWORD   bytesWrittenDword;
349
 
350
    if ( !WriteFile( m_stdout, buf, bytesToWrite, &bytesWrittenDword, NULL ))
351
        {
352
        DWORD   err = GetLastError();
353
        char    errStr[ 200 ];
354
 
355
        *bytesWritten = 0;
356
 
357
        LOG_ERROR( "ConsoleComm::Write failed: "
358
                << GetErrorStr( err, errStr, sizeof( errStr )));
359
                return false;
360
        }
361
 
362
        *bytesWritten = bytesWrittenDword;
363
 
364
        return true;
365
}
366
 
367
/** @} */
368