|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 //////////////////////////////////////////////////////////////////////////////////////// |
|
22 // STATSerial.cpp |
|
23 // Implementation of the serial comms transport |
|
24 //////////////////////////////////////////////////////////////////////////////////////// |
|
25 #include "stdafx.h" |
|
26 #include "statserial.h" |
|
27 #include "assert.h" |
|
28 #include "../../../../Common/inc/SerialPacketSize.h" |
|
29 |
|
30 #define SP_COMMANDSIZE 4 |
|
31 #define SP_LENGTHSIZE 4 |
|
32 |
|
33 //////////////////////////////////////////////////////////////////////////////////////// |
|
34 // Constructor |
|
35 CSTATSerial::CSTATSerial(STATCONNECTTYPE eConnect) |
|
36 : hComPort((HANDLE)0), pBuffer(NULL), iBufferLength(0), iMaxPacketSize(0) |
|
37 { |
|
38 switch(eConnect) |
|
39 { |
|
40 case SymbianSerial: |
|
41 case SymbianInfrared: |
|
42 iMaxPacketSize = KMaxPacketSize; |
|
43 break; |
|
44 case SymbianBluetooth: |
|
45 iMaxPacketSize = KMaxBluetoothPacketSize; |
|
46 break; |
|
47 default: |
|
48 assert(0); |
|
49 break; |
|
50 }; |
|
51 |
|
52 assert(0 != iMaxPacketSize); |
|
53 } |
|
54 |
|
55 |
|
56 //////////////////////////////////////////////////////////////////////////////////////// |
|
57 // Destructor |
|
58 CSTATSerial::~CSTATSerial() |
|
59 { |
|
60 Disconnect(); |
|
61 Release(); |
|
62 } |
|
63 |
|
64 |
|
65 //////////////////////////////////////////////////////////////////////////////////////// |
|
66 // Initialisation stuff |
|
67 int CSTATSerial::Initialise(void) |
|
68 { |
|
69 return ITS_OK; |
|
70 } |
|
71 |
|
72 |
|
73 //////////////////////////////////////////////////////////////////////////////////////// |
|
74 // Open a connection |
|
75 int CSTATSerial::Connect(const char *pAddress) |
|
76 { |
|
77 // already connected |
|
78 if (hComPort) |
|
79 return ITS_OK; |
|
80 |
|
81 if (OpenComPort(pAddress)) |
|
82 { |
|
83 SetError("Connected to port %s Speed %d Bytes %d Parity %d Stop %d", |
|
84 pAddress, STAT_BAUDRATE, STAT_BYTESIZE, STAT_PARITY, STAT_STOPBITS); |
|
85 return ITS_OK; |
|
86 } |
|
87 |
|
88 return E_CONNECTIONFAILED; |
|
89 } |
|
90 |
|
91 |
|
92 //////////////////////////////////////////////////////////////////////////////////////// |
|
93 // Send a command and associated data |
|
94 //////////////////////////////////////////////////////////////////////////////////////// |
|
95 int CSTATSerial::Send(const char cIdentifier, const char *pCommand, const unsigned long ulLength) |
|
96 { |
|
97 DWORD dwBytes = 0; |
|
98 int ret = E_WRITEFAILED; |
|
99 |
|
100 // prepare command |
|
101 STATCOMMAND STATSendCommand; |
|
102 memset(&STATSendCommand, 0, sizeof(STATCOMMAND)); |
|
103 STATSendCommand.cIdentifier = cIdentifier; |
|
104 STATSendCommand.ulLength = ulLength; |
|
105 |
|
106 int result = 0; |
|
107 if (result = WriteFile(hComPort, (LPVOID)&STATSendCommand, sizeof(STATCOMMAND), &dwBytes, NULL)) |
|
108 { |
|
109 if (dwBytes == sizeof(STATCOMMAND)) |
|
110 { |
|
111 // only send data if it will fit into our buffer |
|
112 if (pCommand && STATSendCommand.ulLength && STATSendCommand.ulLength <= iMaxPacketSize) |
|
113 { |
|
114 if (WriteFile(hComPort, (LPVOID)pCommand, STATSendCommand.ulLength, &dwBytes, NULL)) |
|
115 { |
|
116 if (dwBytes == STATSendCommand.ulLength) |
|
117 { |
|
118 SetError("Sent successfully %ld bytes", STATSendCommand.ulLength); |
|
119 ret = ITS_OK; |
|
120 } |
|
121 else |
|
122 { |
|
123 SetError("Incorrect number of bytes written - expected %ld sent %ld", STATSendCommand.ulLength, dwBytes); |
|
124 ret = E_BADNUMBERBYTES; |
|
125 } |
|
126 } |
|
127 else |
|
128 SetError("Write data to port failed"); |
|
129 } |
|
130 else |
|
131 { |
|
132 SetError("Sent successfully"); |
|
133 ret = ITS_OK; |
|
134 } |
|
135 } |
|
136 else |
|
137 { |
|
138 int err = ::GetLastError(); |
|
139 SetError("Incorrect number of bytes written - expected %ld sent %ld", sizeof(STATCOMMAND), dwBytes); |
|
140 ret = E_BADNUMBERBYTES; |
|
141 } |
|
142 } |
|
143 else |
|
144 SetError("Write command to port failed"); |
|
145 |
|
146 return ret; |
|
147 } |
|
148 |
|
149 |
|
150 //////////////////////////////////////////////////////////////////////////////////////// |
|
151 // Receive a command and associated data |
|
152 // |
|
153 // Tries to read a STATCOMMAND structure from the port. If successful, the length |
|
154 // of any data following will be specified in the structure. If extra data, try to |
|
155 // read this. If all successful, set the pointers to point to it |
|
156 // |
|
157 //////////////////////////////////////////////////////////////////////////////////////// |
|
158 int CSTATSerial::ReceiveBytes( char *buff, unsigned long size ) |
|
159 { |
|
160 int ret; |
|
161 int err; |
|
162 unsigned long bytes_read = 0; |
|
163 unsigned long bytes_read_this_iteration = 0; |
|
164 |
|
165 // make sure size > 0 otherwise the following semantics fail |
|
166 assert( size > 0 ); |
|
167 |
|
168 // loop until either all bytes have been received or an error occurs |
|
169 for( bytes_read = 0; bytes_read < size; bytes_read += bytes_read_this_iteration ) { |
|
170 ret = ReadFile( hComPort, &(buff[bytes_read]), (size - bytes_read), &bytes_read_this_iteration, NULL ); |
|
171 if( bytes_read_this_iteration == 0 ) { |
|
172 return NO_DATA_AT_PORT; |
|
173 } |
|
174 if( ret == 0 ) { |
|
175 err = ::GetLastError(); |
|
176 SetError( "Error while receiving command - %ld", err ); |
|
177 return err; |
|
178 } |
|
179 } |
|
180 |
|
181 // everything is OK |
|
182 return 0; |
|
183 } |
|
184 |
|
185 int CSTATSerial::Receive( char *cIdentifier, char **ppData, unsigned long *pLength ) |
|
186 { |
|
187 int ret; |
|
188 unsigned long command; |
|
189 unsigned long data_length; |
|
190 |
|
191 // initialise parameters |
|
192 *cIdentifier = 0; |
|
193 *ppData = NULL; |
|
194 *pLength = 0; |
|
195 |
|
196 // get command |
|
197 ret = ReceiveBytes( (char*)&command, SP_COMMANDSIZE ); |
|
198 if( ret != 0 ) { |
|
199 return ret; |
|
200 } |
|
201 |
|
202 static const int MAX_COMMAND = 127; |
|
203 if( command > MAX_COMMAND ){ |
|
204 return INVALID_COMMAND_FORMAT; |
|
205 } |
|
206 |
|
207 // get length |
|
208 ret = ReceiveBytes( (char*)&data_length, SP_LENGTHSIZE ); |
|
209 if( ret != 0 ) { |
|
210 return ret; |
|
211 } |
|
212 |
|
213 // put these values into the return slots |
|
214 *cIdentifier = (char)command; |
|
215 *pLength = data_length; |
|
216 |
|
217 // if the length is zero then there is no more to do |
|
218 if( data_length == 0 ) { |
|
219 return ITS_OK; |
|
220 } |
|
221 |
|
222 // if the length is greater than the buffer size then this is a header packet and we are not |
|
223 // supposed to actually read any data from it. |
|
224 // if( data_length > SP_BUFFERSIZE ) { |
|
225 if( data_length > iMaxPacketSize ) { |
|
226 SetError( "Received command ID: %c successfully length %d", (*cIdentifier), (*pLength) ); |
|
227 return ITS_OK; |
|
228 } |
|
229 |
|
230 // Otherwise we are about to read some data. We first have to setup the memory management |
|
231 // which is done in a pretty ugly way IMAO. |
|
232 if( data_length > iBufferLength ) |
|
233 { |
|
234 if( pBuffer ) { |
|
235 delete [] pBuffer; |
|
236 pBuffer = NULL; |
|
237 iBufferLength = 0; |
|
238 } |
|
239 pBuffer = new char [data_length]; |
|
240 if( pBuffer == NULL ) { |
|
241 SetError( "Unable to allocate %ld bytes of memory to hold data", data_length ); |
|
242 return E_OUTOFMEM; |
|
243 } |
|
244 iBufferLength = data_length; |
|
245 } |
|
246 |
|
247 // now read the data |
|
248 ret = ReceiveBytes( pBuffer, data_length ); |
|
249 if( ret != 0 ) { |
|
250 return ret; |
|
251 } |
|
252 *ppData = pBuffer; |
|
253 |
|
254 return ITS_OK; |
|
255 } |
|
256 |
|
257 |
|
258 //////////////////////////////////////////////////////////////////////////////////////// |
|
259 // Disconnect from the port |
|
260 int CSTATSerial::Disconnect(void) |
|
261 { |
|
262 // release previous resources |
|
263 if (pBuffer) |
|
264 { |
|
265 delete [] pBuffer; |
|
266 pBuffer = NULL; |
|
267 iBufferLength = 0; |
|
268 } |
|
269 |
|
270 // disconnect |
|
271 if (hComPort) |
|
272 { |
|
273 CloseHandle(hComPort); |
|
274 hComPort = (HANDLE)0; |
|
275 } |
|
276 |
|
277 SetError("Disconnected successfully"); |
|
278 return ITS_OK; |
|
279 } |
|
280 |
|
281 |
|
282 //////////////////////////////////////////////////////////////////////////////////////// |
|
283 // Release resources |
|
284 int CSTATSerial::Release(void) |
|
285 { |
|
286 Disconnect(); |
|
287 return ITS_OK; |
|
288 } |
|
289 |
|
290 |
|
291 //////////////////////////////////////////////////////////////////////////////////////// |
|
292 // PRIVATE FUNCTIONS |
|
293 //////////////////////////////////////////////////////////////////////////////////////// |
|
294 |
|
295 //////////////////////////////////////////////////////////////////////////////////////// |
|
296 // |
|
297 bool CSTATSerial::OpenComPort(const char *pAddress) |
|
298 { |
|
299 TCHAR szAddress[256] = {0}; |
|
300 |
|
301 #ifdef UNICODE |
|
302 szAddress[0] = (TCHAR)0; |
|
303 |
|
304 // Convert to UNICODE. |
|
305 MultiByteToWideChar(CP_ACP, // conversion type |
|
306 0, // flags |
|
307 pAddress, // source |
|
308 -1, // length |
|
309 szAddress, // dest |
|
310 256); // length |
|
311 #else |
|
312 strcpy(szAddress, pAddress); |
|
313 #endif |
|
314 |
|
315 // Use device naming for COM port. |
|
316 CString port; |
|
317 CString address(pAddress); // Local variable to cope with |
|
318 // wide UNICODE characters. |
|
319 port.Format(_T("\\\\.\\%s"), address.operator LPCTSTR()); |
|
320 |
|
321 if (INVALID_HANDLE_VALUE == (hComPort = CreateFile(port, |
|
322 GENERIC_READ | GENERIC_WRITE, |
|
323 0, |
|
324 NULL, |
|
325 OPEN_EXISTING, |
|
326 FILE_FLAG_WRITE_THROUGH, |
|
327 NULL))) |
|
328 { |
|
329 SetError("Port [%s] could not be opened", pAddress); |
|
330 int err = ::GetLastError(); |
|
331 hComPort = (HANDLE)0; |
|
332 return false; |
|
333 } |
|
334 |
|
335 COMMTIMEOUTS CommTimeOuts; |
|
336 CommTimeOuts.WriteTotalTimeoutMultiplier = STAT_WRITETOTALTIMEOUTMULTIPLIER; |
|
337 CommTimeOuts.WriteTotalTimeoutConstant = STAT_WRITETOTALTIMEOUTCONSTANT; |
|
338 CommTimeOuts.ReadIntervalTimeout = STAT_READINTERVALTIMEOUT; |
|
339 CommTimeOuts.ReadTotalTimeoutMultiplier = STAT_READTOTALTIMEOUTMULTIPLIER; |
|
340 CommTimeOuts.ReadTotalTimeoutConstant = STAT_READTOTALTIMEOUTCONSTANT; |
|
341 |
|
342 if (!SetCommTimeouts(hComPort, &CommTimeOuts)) |
|
343 { |
|
344 SetError("Comm port timeouts could not be set"); |
|
345 CloseHandle(hComPort); |
|
346 hComPort = (HANDLE)0; |
|
347 return false; |
|
348 } |
|
349 |
|
350 // Configure the COM port |
|
351 DCB dcb; |
|
352 GetCommState(hComPort, &dcb); |
|
353 dcb.DCBlength = sizeof(dcb); |
|
354 dcb.BaudRate = STAT_BAUDRATE; |
|
355 dcb.fBinary = TRUE; |
|
356 dcb.fParity = STAT_PARITY; |
|
357 dcb.fOutxCtsFlow = TRUE; |
|
358 dcb.fOutxDsrFlow = FALSE; |
|
359 dcb.fDtrControl = DTR_CONTROL_ENABLE; |
|
360 dcb.fDsrSensitivity = FALSE; |
|
361 dcb.fTXContinueOnXoff = TRUE; |
|
362 dcb.fOutX = FALSE; |
|
363 dcb.fInX = FALSE; |
|
364 dcb.fErrorChar = FALSE; |
|
365 dcb.fNull = FALSE; |
|
366 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; |
|
367 dcb.fAbortOnError = TRUE; |
|
368 dcb.XonLim = 4096; |
|
369 dcb.XoffLim = 1024; |
|
370 dcb.ByteSize = STAT_BYTESIZE; |
|
371 dcb.Parity = STAT_PARITY; |
|
372 dcb.StopBits = STAT_STOPBITS; |
|
373 dcb.XonChar = 17; |
|
374 dcb.XoffChar = 19; |
|
375 |
|
376 // dcb.fRtsControl = RTS_CONTROL_ENABLE; |
|
377 // dcb.BaudRate = STAT_BAUDRATE; |
|
378 // dcb.fOutxCtsFlow = FALSE; |
|
379 // dcb.XonLim = STAT_XONLIMIT; |
|
380 // dcb.XoffLim = STAT_XOFFLIMIT; |
|
381 |
|
382 if (!SetCommState(hComPort, &dcb)) |
|
383 { |
|
384 SetError("Comm port state could not be set"); |
|
385 CloseHandle(hComPort); |
|
386 hComPort = (HANDLE)0; |
|
387 return false; |
|
388 } |
|
389 |
|
390 return true; |
|
391 } |