FreeBASIC  0.91.0
io_serial.c
Go to the documentation of this file.
1 /* serial port access for Windows */
2 
3 #include "../fb.h"
4 #include <windows.h>
5 
6 #define GET_MSEC_TIME() ((DWORD) (fb_Timer() * 1000.0))
7 
8 typedef struct _W32_SERIAL_INFO {
10  int iPort;
13 
14 static int fb_hSerialWaitSignal( HANDLE hDevice, DWORD dwMask, DWORD dwResult, DWORD dwTimeout )
15 {
16  DWORD dwStartTime = GET_MSEC_TIME();
17  DWORD dwModemStatus = 0;
18 
19  if( !GetCommModemStatus( hDevice, &dwModemStatus ) )
20  return FALSE;
21 
22  while ( ((GET_MSEC_TIME() - dwStartTime) <= dwTimeout)
23  && ((dwModemStatus & dwMask)!=dwResult) )
24  {
25  if( !GetCommModemStatus( hDevice, &dwModemStatus ) )
26  return FALSE;
27  }
28  return ((dwModemStatus & dwMask)==dwResult);
29 }
30 
31 static
33 {
34  DBG_ASSERT( pOptions!=NULL );
35  if( pOptions->DurationCD!=0 ) {
36  if( !fb_hSerialWaitSignal( hDevice,
37  MS_RLSD_ON, MS_RLSD_ON,
38  pOptions->DurationCD ) )
39  return FALSE;
40  }
41 
42  if( pOptions->DurationDSR!=0 ) {
43  if( !fb_hSerialWaitSignal( hDevice,
44  MS_DSR_ON, MS_DSR_ON,
45  pOptions->DurationDSR ) )
46  return FALSE;
47  }
48  return TRUE;
49 }
50 
52  int iPort, FB_SERIAL_OPTIONS *options,
53  const char *pszDevice, void **ppvHandle )
54 {
55  DWORD dwDefaultTxBufferSize = 16384;
56  DWORD dwDefaultRxBufferSize = 16384;
57  DWORD dwDesiredAccess = 0;
58  DWORD dwShareMode = 0;
59  char *pszDev, *p;
60  HANDLE hDevice;
61  int res;
62 
63  /* The IRQ stuff is not supported on Windows ... */
64  if( options->IRQNumber!=0 )
66 
68 
69  switch( handle->access ) {
71  dwDesiredAccess = GENERIC_READ;
72  break;
74  dwDesiredAccess = GENERIC_WRITE;
75  break;
77  case FB_FILE_ACCESS_ANY:
78  dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
79  break;
80  }
81 
82  switch( handle->lock ) {
84  dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
85  break;
86  case FB_FILE_LOCK_READ:
87  dwShareMode = FILE_SHARE_WRITE;
88  break;
89  case FB_FILE_LOCK_WRITE:
90  dwShareMode = FILE_SHARE_READ;
91  break;
93  break;
94  }
95 
96  /* Get device name without ":" */
97  pszDev = calloc(strlen( pszDevice ) + 5, 1);
98  if( iPort == 0 )
99  {
100  iPort = 1;
101  strcpy( pszDev, "COM1:" );
102  }
103  else
104  {
105  if( iPort > 9 )
106  strcpy(pszDev, "\\\\.\\");
107  else
108  *pszDev = '\0';
109 
110  strcat(pszDev, pszDevice);
111  p = strchr( pszDev, ':');
112  if( p )
113  *p = '\0';
114  }
115 
116 #if 0
117  /* FIXME: Use default COM properties by default */
118  COMMCONFIG cc;
119  if( !GetDefaultCommConfig( pszDev, &cc, &dwSizeCC ) ) {
120  }
121 #endif
122 
123  /* Open device */
124  hDevice =
125  CreateFileA( pszDev,
126  dwDesiredAccess,
127  dwShareMode,
128  NULL,
129  OPEN_EXISTING,
130  0,
131  NULL );
132 
133  free( pszDev );
134 
135  if( hDevice==INVALID_HANDLE_VALUE )
137 
138  /* Set rx/tx buffer sizes */
139  if( res==FB_RTERROR_OK ) {
140  COMMPROP prop;
141  if( !GetCommProperties( hDevice, &prop ) ) {
143  } else {
144  if( prop.dwCurrentTxQueue ) {
145  dwDefaultTxBufferSize = prop.dwCurrentTxQueue;
146  } else if( prop.dwMaxTxQueue ) {
147  dwDefaultTxBufferSize = prop.dwMaxTxQueue;
148  }
149 
150  if( prop.dwCurrentRxQueue ) {
151  dwDefaultRxBufferSize = prop.dwCurrentRxQueue;
152  } else if( prop.dwMaxRxQueue ) {
153  dwDefaultRxBufferSize = prop.dwMaxRxQueue;
154  }
155 
156  if( options->TransmitBuffer )
157  dwDefaultTxBufferSize = options->TransmitBuffer;
158 
159  if( options->ReceiveBuffer )
160  dwDefaultRxBufferSize = options->ReceiveBuffer;
161 
162 
163  if( !SetupComm( hDevice,
164  dwDefaultRxBufferSize,
165  dwDefaultTxBufferSize ) )
166  {
168  }
169  }
170  }
171 
172  /* set timeouts */
173  if( res==FB_RTERROR_OK ) {
174  COMMTIMEOUTS timeouts;
175  if( !GetCommTimeouts( hDevice, &timeouts ) ) {
177  } else {
178  if( options->DurationCTS!=0 ) {
179  timeouts.ReadIntervalTimeout = options->DurationCTS;
180  timeouts.ReadTotalTimeoutMultiplier =
181  timeouts.ReadTotalTimeoutConstant = 0;
182  }
183  if( !SetCommTimeouts( hDevice, &timeouts ) ) {
185  }
186  }
187  }
188 
189  /* setup generic COM port configuration */
190  if( res==FB_RTERROR_OK ) {
191  DCB dcb;
192  if( !GetCommState( hDevice, &dcb ) ) {
194  } else {
195  dcb.BaudRate = options->uiSpeed;
196  dcb.fBinary = !options->AddLF; /* FIXME: Windows only supports binary mode */
197  dcb.fParity = options->CheckParity;
198  dcb.fOutxCtsFlow = options->DurationCTS!=0;
199  dcb.fDtrControl = ( (options->KeepDTREnabled) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE );
200 
201  /* Not sure about this one ... */
202  dcb.fDsrSensitivity = options->DurationDSR!=0;
203  dcb.fOutxDsrFlow = FALSE;
204 
205  /* No XON/XOFF */
206  dcb.fOutX = FALSE;
207  dcb.fInX = FALSE;
208  dcb.fNull = FALSE;
209 
210  /* Not sure about this one ... */
211  dcb.fRtsControl = ( ( options->SuppressRTS ) ? RTS_CONTROL_DISABLE : RTS_CONTROL_HANDSHAKE );
212 
213  dcb.fAbortOnError = FALSE;
214  dcb.ByteSize = (BYTE) options->uiDataBits;
215 
216  switch ( options->Parity ) {
218  dcb.Parity = NOPARITY;
219  break;
221  dcb.Parity = EVENPARITY;
222  break;
224  dcb.Parity = ODDPARITY;
225  break;
227  dcb.Parity = SPACEPARITY;
228  break;
230  dcb.Parity = MARKPARITY;
231  break;
232  }
233 
234  switch ( options->StopBits ) {
236  dcb.StopBits = ONESTOPBIT;
237  break;
239  dcb.StopBits = ONE5STOPBITS;
240  break;
242  dcb.StopBits = TWOSTOPBITS;
243  break;
244  }
245 
246  if( !SetCommState( hDevice, &dcb ) ) {
248  } else {
249  EscapeCommFunction( hDevice, SETDTR );
250  }
251  }
252  }
253 
254  if( !fb_hSerialCheckLines( hDevice, options ) ) {
256  }
257 
258  if( res!=FB_RTERROR_OK ) {
259  CloseHandle( hDevice );
260  } else {
261  W32_SERIAL_INFO *pInfo = calloc( 1, sizeof(W32_SERIAL_INFO) );
262  DBG_ASSERT( ppvHandle!=NULL );
263  *ppvHandle = pInfo;
264  pInfo->hDevice = hDevice;
265  pInfo->iPort = iPort;
266  pInfo->pOptions = options;
267  }
268 
269  return res;
270 }
271 
273  void *pvHandle, fb_off_t *pLength )
274 {
275  W32_SERIAL_INFO *pInfo = (W32_SERIAL_INFO*) pvHandle;
276  DWORD dwErrors;
277  COMSTAT Status;
278  if( !ClearCommError( pInfo->hDevice, &dwErrors, &Status ) )
280  if( pLength )
281  *pLength = (long) Status.cbInQue;
282  return fb_ErrorSetNum( FB_RTERROR_OK );
283 }
284 
286  void *pvHandle, const void *data, size_t length )
287 {
288  W32_SERIAL_INFO *pInfo = (W32_SERIAL_INFO*) pvHandle;
289  DWORD dwWriteCount;
290 
291  if( !fb_hSerialCheckLines( pInfo->hDevice, pInfo->pOptions ) ) {
293  }
294 
295  if( !WriteFile( pInfo->hDevice,
296  data,
297  length,
298  &dwWriteCount,
299  NULL ) )
301 
302  if( length != (size_t) dwWriteCount )
304 
305  return fb_ErrorSetNum( FB_RTERROR_OK );
306 }
307 
309  void *pvHandle, void *data, size_t *pLength )
310 {
311  W32_SERIAL_INFO *pInfo = (W32_SERIAL_INFO*) pvHandle;
312  DWORD dwReadCount;
313  DBG_ASSERT( pLength!=NULL );
314 
315  if( !fb_hSerialCheckLines( pInfo->hDevice, pInfo->pOptions ) ) {
317  }
318 
319  if( !ReadFile( pInfo->hDevice,
320  data,
321  *pLength,
322  &dwReadCount,
323  NULL ) )
325 
326  *pLength = (size_t) dwReadCount;
327 
328  return fb_ErrorSetNum( FB_RTERROR_OK );
329 }
330 
331 int fb_SerialClose( FB_FILE *handle, void *pvHandle )
332 {
333  W32_SERIAL_INFO *pInfo = (W32_SERIAL_INFO*) pvHandle;
334  CloseHandle( pInfo->hDevice );
335  free(pInfo);
336  return fb_ErrorSetNum( FB_RTERROR_OK );
337 }