2 #include "../../gsmstate.h"
4 #ifdef GSM_ENABLE_SERIALDEVICE
13 #include "../../gsmcomon.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
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
);
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");
43 static GSM_Error
serial_open (GSM_StateMachine
*s
)
45 GSM_Device_SerialData
*d
= &s
->Device
.Data
.Serial
;
47 unsigned char DeviceName
[80];
49 #ifdef GSM_ENABLE_FBUS2DKU5
54 strcpy(DeviceName
,s
->CurrentConfig
->Device
);
56 #ifdef GSM_ENABLE_FBUS2DKU5
57 if (s
->ConnectionType
== GCT_FBUS2DKU5
) {
59 RegOpenKeyEx(HKEY_LOCAL_MACHINE
, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE
, &hKey
);
60 RegQueryValueEx(hKey
, "\\Device\\AtmelVirtualPort000", NULL
, NULL
, (LPBYTE
) DeviceName
, &DeviceNameLen
);
62 if (strlen(DeviceName
) == 0) return GE_DEVICENOTWORK
;
63 smprintf(s
,"DKU5 device is \"%s\"\n",DeviceName
);
68 d
->hPhone
= CreateFile( DeviceName
,
69 GENERIC_READ
| GENERIC_WRITE
,
70 0, /* exclusive access */
71 NULL
, /* no security attrs */
73 FILE_ATTRIBUTE_NORMAL
|
74 FILE_FLAG_OVERLAPPED
, /* overlapped I/O */
77 if (d
->hPhone
== INVALID_HANDLE_VALUE
) {
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
));
107 dcb
.Parity
= NOPARITY
;
108 dcb
.StopBits
= ONESTOPBIT
;
110 /* No Xon/Xof flow control */
111 // dcb.fOutX = 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
;
128 static GSM_Error
serial_setparity (GSM_StateMachine
*s
, bool parity
)
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
;
150 /* Set the DTR and RTS bit of the serial device. */
151 static GSM_Error
serial_setdtrrts(GSM_StateMachine
*s
, bool dtr
, bool rts
)
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;
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
;
204 /* Change the speed of the serial device.
207 static GSM_Error
serial_setspeed(GSM_StateMachine
*s
, int speed
)
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
;
228 /* Read from serial device. */
229 static int serial_read(GSM_StateMachine
*s
, void *buf
, size_t nbytes
)
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
);
242 fReadStat
= ReadFile(d
->hPhone
, buf
, dwLength
, &dwLength
, &d
->osRead
);
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 */
258 GSM_OSErrorInfo(s
, "serial_read");
259 /* an error occurred, try to recover */
260 ClearCommError(d
->hPhone
, &dwErrorFlags
, &ComStat
);
265 GSM_OSErrorInfo(s
, "serial_read");
266 /* some other error occurred */
268 ClearCommError(d
->hPhone
, &dwErrorFlags
, &ComStat
);
276 /* Write to serial device. */
277 static int serial_write(GSM_StateMachine
*s
, void *buf
, size_t nbytes
)
280 DWORD dwBytesWritten
;
283 DWORD dwBytesSent
= 0;
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
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
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
;
318 GSM_OSErrorInfo(s
, "serial_write");
319 /* an error occurred, try to recover */
320 ClearCommError(d
->hPhone
, &dwErrorFlags
, &ComStat
);
324 dwBytesSent
+= dwBytesWritten
;
326 GSM_OSErrorInfo(s
, "serial_write");
327 /* some other error occurred */
328 ClearCommError(d
->hPhone
, &dwErrorFlags
, &ComStat
);
336 GSM_Device_Functions SerialDevice
= {
349 /* How should editor hadle tabs in this file? Add editor commands here.
350 * vim: noexpandtab sw=8 ts=8 sts=8: