Imported gammu 0.90.7
[gammu.git] / common / device / serial / ser_w32.c
blobc837981c18d795647d4d0b8f2d0354d9a5ef88df
2 #include "../../gsmstate.h"
4 #ifdef GSM_ENABLE_SERIALDEVICE
5 #ifdef WIN32
7 #include <windows.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <io.h>
11 #include <memory.h>
13 #include "../../gsmcomon.h"
14 #include "ser_w32.h"
16 /* Close the serial port and restore old settings. */
17 static GSM_Error serial_close(GSM_StateMachine *s)
19 GSM_Device_SerialData *d = &s->Device.Data.Serial;
21 /* disable event notification and wait for thread
22 to halt */
23 SetCommMask(d->hPhone, 0);
25 /* purge any outstanding reads/writes and close device handle */
26 PurgeComm(d->hPhone, PURGE_TXABORT | PURGE_RXABORT |
27 PURGE_TXCLEAR | PURGE_RXCLEAR);
29 /* drop DTR */
30 EscapeCommFunction(d->hPhone, CLRDTR);
32 if (SetCommState(d->hPhone, &d->backup_dcb)==0) {
33 GSM_OSErrorInfo(s, "SetCommState in serial_close");
36 if (CloseHandle(d->hPhone)==0) {
37 GSM_OSErrorInfo(s, "CloseHandle in serial_close");
40 return GE_NONE;
43 static GSM_Error serial_open (GSM_StateMachine *s)
45 GSM_Device_SerialData *d = &s->Device.Data.Serial;
46 DCB dcb;
47 unsigned char DeviceName[80];
48 int i;
49 #ifdef GSM_ENABLE_FBUS2DKU5
50 HKEY hKey;
51 DWORD DeviceNameLen;
52 #endif
54 strcpy(DeviceName,s->CurrentConfig->Device);
56 #ifdef GSM_ENABLE_FBUS2DKU5
57 if (s->ConnectionType == GCT_FBUS2DKU5) {
58 DeviceName[0] = 0;
59 RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey);
60 RegQueryValueEx(hKey, "\\Device\\AtmelVirtualPort000", NULL, NULL, (LPBYTE) DeviceName, &DeviceNameLen);
61 RegCloseKey(hKey);
62 if (strlen(DeviceName) == 0) return GE_DEVICENOTWORK;
63 smprintf(s,"DKU5 device is \"%s\"\n",DeviceName);
64 //nodriver
66 #endif
68 d->hPhone = CreateFile( DeviceName,
69 GENERIC_READ | GENERIC_WRITE,
70 0, /* exclusive access */
71 NULL, /* no security attrs */
72 OPEN_EXISTING,
73 FILE_ATTRIBUTE_NORMAL |
74 FILE_FLAG_OVERLAPPED, /* overlapped I/O */
75 NULL);
77 if (d->hPhone == INVALID_HANDLE_VALUE) {
78 i = GetLastError();
79 GSM_OSErrorInfo(s, "CreateFile in serial_open");
80 if (i == 2) return GE_DEVICENOTWORK; //can't find specified file
81 if (i == 5) return GE_DEVICEBUSY; //access denied
82 if (i == 31) return GE_DEVICENOTWORK; //attached device not working
83 if (i == 123) return GE_DEVICENOTEXIST;
84 return GE_DEVICEOPENERROR;
87 d->backup_dcb.DCBlength = sizeof(DCB);
88 if (GetCommState(d->hPhone, &d->backup_dcb)==0) {
89 GSM_OSErrorInfo(s, "ReadDevice in serial_open");
90 return GE_DEVICEREADERROR;
93 /* get any early notifications */
94 SetCommMask(d->hPhone, EV_RXCHAR);
96 /* setup device buffers */
97 SetupComm(d->hPhone, 4096, 4096);
99 /* purge any information in the buffer */
100 PurgeComm(d->hPhone, PURGE_TXABORT | PURGE_RXABORT |
101 PURGE_TXCLEAR | PURGE_RXCLEAR);
103 /* Initialise the port settings */
104 memcpy(&dcb, &d->backup_dcb, sizeof(DCB));
106 dcb.ByteSize = 8;
107 dcb.Parity = NOPARITY;
108 dcb.StopBits = ONESTOPBIT;
110 /* No Xon/Xof flow control */
111 // dcb.fOutX = false;
112 // dcb.fInX = false;
114 /* Hardware flow control */
115 // dcb.fOutxDsrFlow = true;
116 // dcb.fOutxCtsFlow = true;
117 // dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
118 // dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
120 if (SetCommState(d->hPhone, &dcb)==0) {
121 GSM_OSErrorInfo(s, "WriteDevice in serial_open");
122 return GE_DEVICEOPENERROR;
125 return GE_NONE;
128 static GSM_Error serial_setparity (GSM_StateMachine *s, bool parity)
130 DCB dcb;
131 GSM_Device_SerialData *d = &s->Device.Data.Serial;
133 dcb.DCBlength = sizeof(DCB);
134 if (GetCommState(d->hPhone, &dcb)==0) {
135 GSM_OSErrorInfo(s, "ReadDevice in serial_setparity");
136 return GE_DEVICEREADERROR;
139 if (parity) dcb.Parity = ODDPARITY;
140 else dcb.Parity = NOPARITY;
142 if (SetCommState(d->hPhone, &dcb)==0) {
143 GSM_OSErrorInfo(s, "WriteDevice in serial_setparity");
144 return GE_DEVICEPARITYERROR;
147 return GE_NONE;
150 /* Set the DTR and RTS bit of the serial device. */
151 static GSM_Error serial_setdtrrts(GSM_StateMachine *s, bool dtr, bool rts)
153 DCB dcb;
154 GSM_Device_SerialData *d = &s->Device.Data.Serial;
156 dcb.DCBlength = sizeof(DCB);
157 if (GetCommState(d->hPhone, &dcb)==0) {
158 GSM_OSErrorInfo(s, "ReadDevice in serial_setdtrrts");
159 return GE_DEVICEREADERROR;
162 dcb.fOutxDsrFlow = 0;
163 if (dtr) dcb.fDtrControl = DTR_CONTROL_ENABLE;
164 else dcb.fDtrControl = DTR_CONTROL_DISABLE;
166 dcb.fOutxCtsFlow = 0;
167 if (rts) dcb.fRtsControl = RTS_CONTROL_ENABLE;
168 else dcb.fRtsControl = RTS_CONTROL_DISABLE;
170 /* no software (Xon/Xof) flow control */
171 dcb.fInX = dcb.fOutX = 0;
173 if (SetCommState(d->hPhone, &dcb)==0) {
174 GSM_OSErrorInfo(s, "WriteDevice in serial_setdtrrts");
175 return GE_DEVICEDTRRTSERROR;
178 dcb.DCBlength = sizeof(DCB);
179 GetCommState(d->hPhone, &dcb);
181 dbgprintf("Serial device:");
182 dbgprintf(" DTR is ");
183 switch (dcb.fDtrControl) {
184 case DTR_CONTROL_ENABLE : dbgprintf("up"); break;
185 case DTR_CONTROL_DISABLE : dbgprintf("down"); break;
186 case DTR_CONTROL_HANDSHAKE : dbgprintf("handshake"); break;
188 dbgprintf(", RTS is ");
189 switch (dcb.fRtsControl) {
190 case RTS_CONTROL_ENABLE : dbgprintf("up"); break;
191 case RTS_CONTROL_DISABLE : dbgprintf("down"); break;
192 case RTS_CONTROL_HANDSHAKE : dbgprintf("handshake"); break;
193 case RTS_CONTROL_TOGGLE : dbgprintf("toggle"); break;
195 dbgprintf("\n");
196 if ( dtr && dcb.fDtrControl != DTR_CONTROL_ENABLE ) return GE_DEVICEDTRRTSERROR;
197 if (!dtr && dcb.fDtrControl != DTR_CONTROL_DISABLE) return GE_DEVICEDTRRTSERROR;
198 if ( rts && dcb.fRtsControl != RTS_CONTROL_ENABLE ) return GE_DEVICEDTRRTSERROR;
199 if (!rts && dcb.fRtsControl != RTS_CONTROL_DISABLE) return GE_DEVICEDTRRTSERROR;
201 return GE_NONE;
204 /* Change the speed of the serial device.
205 * RETURNS: Success
207 static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed)
209 DCB dcb;
210 GSM_Device_SerialData *d = &s->Device.Data.Serial;
212 dcb.DCBlength = sizeof(DCB);
213 if (GetCommState(d->hPhone, &dcb)==0) {
214 GSM_OSErrorInfo(s, "ReadDevice in serial_setspeed");
215 return GE_DEVICEREADERROR;
218 dcb.BaudRate = speed;
220 if (SetCommState(d->hPhone, &dcb)==0) {
221 GSM_OSErrorInfo(s, "WriteDevice in serial_setspeed");
222 return GE_DEVICECHANGESPEEDERROR;
225 return GE_NONE;
228 /* Read from serial device. */
229 static int serial_read(GSM_StateMachine *s, void *buf, size_t nbytes)
231 BOOL fReadStat;
232 COMSTAT ComStat;
233 DWORD dwErrorFlags;
234 DWORD dwLength=0;
235 DWORD dwError;
236 GSM_Device_SerialData *d = &s->Device.Data.Serial;
238 /* only try to read number of bytes in queue */
239 ClearCommError(d->hPhone, &dwErrorFlags, &ComStat);
240 dwLength = min((DWORD) nbytes, ComStat.cbInQue);
241 if (dwLength > 0) {
242 fReadStat = ReadFile(d->hPhone, buf, dwLength, &dwLength, &d->osRead);
243 if (!fReadStat) {
244 if (GetLastError() == ERROR_IO_PENDING) {
245 // dbgprintf("IO Pending\n");
246 /* We have to wait for read to complete.
247 * This function will timeout according to the
248 * CommTimeOuts.ReadTotalTimeoutConstant variable
249 * Every time it times out, check for port errors
251 while(!GetOverlappedResult(d->hPhone,
252 &d->osRead, &dwLength, TRUE)) {
253 dwError = GetLastError();
254 if (dwError == ERROR_IO_INCOMPLETE)
255 /* normal result if not finished */
256 continue;
257 else {
258 GSM_OSErrorInfo(s, "serial_read");
259 /* an error occurred, try to recover */
260 ClearCommError(d->hPhone, &dwErrorFlags, &ComStat);
261 break;
264 } else {
265 GSM_OSErrorInfo(s, "serial_read");
266 /* some other error occurred */
267 dwLength = 0;
268 ClearCommError(d->hPhone, &dwErrorFlags, &ComStat);
273 return (dwLength);
276 /* Write to serial device. */
277 static int serial_write(GSM_StateMachine *s, void *buf, size_t nbytes)
279 BOOL fWriteStat;
280 DWORD dwBytesWritten;
281 DWORD dwErrorFlags;
282 DWORD dwError;
283 DWORD dwBytesSent = 0;
284 COMSTAT ComStat;
285 GSM_Device_SerialData *d = &s->Device.Data.Serial;
287 fWriteStat = WriteFile(d->hPhone, buf, nbytes, &dwBytesSent, &d->osWrite);
289 /* Note that normally the code will not execute the following
290 * because the driver caches write operations. Small I/O requests
291 * (up to several thousand bytes) will normally be accepted
292 * immediately and WriteFile will return true even though an
293 * overlapped operation was specified
295 if (!fWriteStat) {
296 if(GetLastError() == ERROR_IO_PENDING) {
297 /* We should wait for the completion of the write operation
298 * so we know if it worked or not
300 * This is only one way to do this. It might be beneficial to
301 * place the write operation in a separate thread
302 * so that blocking on completion will not negatively
303 * affect the responsiveness of the UI
305 * If the write takes too long to complete, this
306 * function will timeout according to the
307 * CommTimeOuts.WriteTotalTimeoutMultiplier variable.
308 * This code logs the timeout but does not retry
309 * the write.
311 while(!GetOverlappedResult(d->hPhone, &d->osWrite, &dwBytesWritten, TRUE)) {
312 dwError = GetLastError();
313 if(dwError == ERROR_IO_INCOMPLETE) {
314 /* normal result if not finished */
315 dwBytesSent += dwBytesWritten;
316 continue;
317 } else {
318 GSM_OSErrorInfo(s, "serial_write");
319 /* an error occurred, try to recover */
320 ClearCommError(d->hPhone, &dwErrorFlags, &ComStat);
321 break;
324 dwBytesSent += dwBytesWritten;
325 } else {
326 GSM_OSErrorInfo(s, "serial_write");
327 /* some other error occurred */
328 ClearCommError(d->hPhone, &dwErrorFlags, &ComStat);
329 return dwBytesSent;
333 return dwBytesSent;
336 GSM_Device_Functions SerialDevice = {
337 serial_open,
338 serial_close,
339 serial_setparity,
340 serial_setdtrrts,
341 serial_setspeed,
342 serial_read,
343 serial_write
346 #endif
347 #endif
349 /* How should editor hadle tabs in this file? Add editor commands here.
350 * vim: noexpandtab sw=8 ts=8 sts=8: