FreeBASIC  0.91.0
dev_com.c
Go to the documentation of this file.
1 /* COMx device */
2 
3 #include "fb.h"
4 
5 typedef struct _DEV_COM_INFO {
6  void *hSerial; /* This memmber must be first */
7  char *pszDevice;
8  int iPort;
10 } DEV_COM_INFO;
11 
13 {
14  int res;
15  DEV_COM_INFO *pInfo;
16 
17  FB_LOCK();
18 
19  pInfo = (DEV_COM_INFO*) handle->opaque;
20  res = fb_SerialClose( handle, pInfo->hSerial );
21  if( res==FB_RTERROR_OK ) {
22  free(pInfo->pszDevice);
23  free(pInfo);
24  }
25 
26  FB_UNLOCK();
27 
28  return res;
29 }
30 
31 static int fb_DevComWrite( FB_FILE *handle, const void* value, size_t valuelen )
32 {
33  int res;
34  DEV_COM_INFO *pInfo;
35 
36  FB_LOCK();
37 
38  pInfo = (DEV_COM_INFO*) handle->opaque;
39  res = fb_SerialWrite( handle, pInfo->hSerial, value, valuelen );
40 
41  FB_UNLOCK();
42 
43  return res;
44 }
45 
46 static int fb_DevComWriteWstr( FB_FILE *handle, const FB_WCHAR* value, size_t valuelen )
47 {
48  return fb_DevComWrite( handle, (void*)value, valuelen * sizeof( FB_WCHAR ) );
49 }
50 
51 static int fb_DevComRead( FB_FILE *handle, void* value, size_t *pValuelen )
52 {
53  int res;
54  DEV_COM_INFO *pInfo;
55 
56  FB_LOCK();
57 
58  pInfo = (DEV_COM_INFO*) handle->opaque;
59  res = fb_SerialRead( handle, pInfo->hSerial, value, pValuelen );
60 
61  FB_UNLOCK();
62 
63  return res;
64 }
65 
66 static int fb_DevComReadWstr( FB_FILE *handle, FB_WCHAR *value, size_t *pValuelen )
67 {
68  size_t len = *pValuelen * sizeof( FB_WCHAR );
69  return fb_DevComRead( handle, (void *)value, &len );
70 }
71 
72 static int fb_DevComTell( FB_FILE *handle, fb_off_t *pOffset )
73 {
74  int res;
75  DEV_COM_INFO *pInfo;
76 
77  DBG_ASSERT( pOffset!=NULL );
78 
79  FB_LOCK();
80 
81  pInfo = (DEV_COM_INFO*) handle->opaque;
82  res = fb_SerialGetRemaining( handle, pInfo->hSerial, pOffset );
83 
84  FB_UNLOCK();
85 
86  return res;
87 }
88 
89 static int fb_DevComEof( FB_FILE *handle )
90 {
91  int res;
93  DEV_COM_INFO *pInfo;
94 
95  FB_LOCK();
96 
97  pInfo = (DEV_COM_INFO*) handle->opaque;
98  res = fb_SerialGetRemaining( handle, pInfo->hSerial, &offset );
99  if( res!=FB_RTERROR_OK ) {
100  res = FB_TRUE;
101  } else {
102  res = offset==0;
103  }
104 
105  FB_UNLOCK();
106 
107  return res;
108 }
109 
111  fb_DevComEof,
113  NULL,
119  NULL,
120  NULL,
121  NULL,
122  NULL,
123  NULL
124 };
125 
126 int fb_DevComOpen( FB_FILE *handle, const char *filename, size_t filename_len )
127 {
128  DEV_COM_INFO *info;
129  char achDev[128];
130  const char *pchPos;
131  char *pchPosTmp;
132  size_t i, port, uiOption;
133  int iStopBits = -1;
134  int res = FB_RTERROR_OK;
135 
136  if (!fb_DevComTestProtocolEx( handle, filename, filename_len, &port ))
138 
139  if( port > 0 )
140  {
141  i = sprintf( achDev, "COM%u:", (int)port );
142  }
143  else
144  {
145  i = (strchr( filename, ':' ) - filename);
146  strncpy( achDev, filename, i );
147  }
148  achDev[i] = 0;
149 
150  FB_LOCK();
151 
152  if( handle->mode==FB_FILE_MODE_RANDOM ) {
153  handle->mode = FB_FILE_MODE_BINARY;
155  }
156 
157  /* Determine the port number and a normalized device name */
158  info = (DEV_COM_INFO*) calloc(1, sizeof(DEV_COM_INFO));
159  info->iPort = port;
160  info->pszDevice = strdup( achDev );
161 
162  /* Set defaults */
163  info->Options.uiSpeed = 300;
165  info->Options.uiDataBits = 7;
166  info->Options.DurationCTS = 1000;
167  info->Options.DurationDSR = 1000;
168 
169  pchPos = strchr( filename, ':' );
170  DBG_ASSERT( pchPos!=NULL );
171  ++pchPos;
172 
173  /* Process all passed options */
174  uiOption = 0;
175  while( res==FB_RTERROR_OK && *pchPos!=0 ) {
176  size_t uiOptionLength;
177  const char *pchPosEnd, *pchPosNext;
178  char *pszOption;
179 
180  /* skip white spaces */
181  while( *pchPos==' ' || *pchPos=='\t' )
182  ++pchPos;
183 
184  if( *pchPos==0 )
185  break;
186 
187  if( *pchPos==',' ) {
188  /* empty option ... ignore */
189  ++uiOption;
190  ++pchPos;
191  continue;
192  }
193 
194  /* Find end of option */
195  pchPosNext = strchr( pchPos, ',' );
196  if( pchPosNext==NULL ) {
197  pchPosNext = filename + filename_len;
198  pchPosEnd = pchPosNext - 1;
199  } else {
200  pchPosEnd = pchPosNext - 1;
201  ++pchPosNext;
202  }
203 
204  /* skip white spaces */
205  while( *pchPosEnd==' ' || *pchPosEnd=='\t' )
206  --pchPosEnd;
207  ++pchPosEnd;
208 
209  /* copy option to temporary buffer */
210  uiOptionLength = pchPosEnd - pchPos;
211  pszOption = malloc( uiOptionLength + 1 );
212  memcpy( pszOption, pchPos, uiOptionLength );
213  pszOption[uiOptionLength] = 0;
214 
215  /* process option */
216  switch ( uiOption ) {
217  case 0:
218  /* baud rate */
219  info->Options.uiSpeed = strtoul( pszOption, &pchPosTmp, 10 );
220  if( *pchPosTmp!=0 ) {
222  }
223  break;
224 
225  case 1:
226  /* parity */
227  if( strcasecmp( pszOption, "N" )==0 ) {
229  } else if( strcasecmp( pszOption, "E" )==0 ) {
231  } else if( strcasecmp( pszOption, "PE" )==0 ) {
232  /* QB quirk */
233  info->Options.CheckParity = TRUE;
235  } else if( strcasecmp( pszOption, "O" )==0 ) {
237  } else if( strcasecmp( pszOption, "S" )==0 ) {
239  } else if( strcasecmp( pszOption, "M" )==0 ) {
241  } else {
243  }
244  break;
245 
246  case 2:
247  /* data bits */
248  info->Options.uiDataBits = strtoul( pszOption, &pchPosTmp, 10 );
249  if( *pchPosTmp!=0 ) {
251  }
252  break;
253 
254  case 3:
255  /* stop bits */
256  {
257  double dblStopBits = strtod( pszOption, &pchPosTmp );
258  if( *pchPosTmp!=0 ) {
260  } else {
261  if( dblStopBits==1.0 ) {
262  iStopBits = FB_SERIAL_STOP_BITS_1;
263  } else if( dblStopBits==1.5 ) {
264  iStopBits = FB_SERIAL_STOP_BITS_1_5;
265  } else if( dblStopBits==2.0 ) {
266  iStopBits = FB_SERIAL_STOP_BITS_2;
267  } else {
269  }
270  }
271  }
272  break;
273 
274  default:
275  /* extended options */
276  if( strncasecmp( pszOption, "CS", 2 )==0 ) {
277  info->Options.DurationCTS = strtoul( pszOption+2, &pchPosTmp, 10 );
278  if( *pchPosTmp!=0 ) {
280  }
281  } else if( strncasecmp( pszOption, "DS", 2 )==0 ) {
282  info->Options.DurationDSR = strtoul( pszOption+2, &pchPosTmp, 10 );
283  if( *pchPosTmp!=0 ) {
285  }
286  } else if( strncasecmp( pszOption, "CD", 2 )==0 ) {
287  info->Options.DurationCD = strtoul( pszOption+2, &pchPosTmp, 10 );
288  if( *pchPosTmp!=0 ) {
290  }
291  } else if( strncasecmp( pszOption, "OP", 2 )==0 ) {
292  info->Options.OpenTimeout = strtoul( pszOption+2, &pchPosTmp, 10 );
293  if( *pchPosTmp!=0 ) {
295  }
296  } else if( strncasecmp( pszOption, "TB", 2 )==0 ) {
297  info->Options.TransmitBuffer = strtoul( pszOption+2, &pchPosTmp, 10 );
298  if( *pchPosTmp!=0 ) {
300  }
301  } else if( strncasecmp( pszOption, "RB", 2 )==0 ) {
302  info->Options.ReceiveBuffer = strtoul( pszOption+2, &pchPosTmp, 10 );
303  if( *pchPosTmp!=0 ) {
305  }
306  } else if( strcasecmp( pszOption, "RS" )==0 ) {
307  info->Options.SuppressRTS = TRUE;
308  } else if( strcasecmp( pszOption, "LF" )==0 ) {
309  /* PB compatible */
310  info->Options.AddLF = TRUE;
311  } else if( strcasecmp( pszOption, "ASC" )==0 ) {
312  info->Options.AddLF = TRUE;
313  } else if( strcasecmp( pszOption, "BIN" )==0 ) {
314  info->Options.AddLF = FALSE;
315  } else if( strcasecmp( pszOption, "PE" )==0 ) {
316  info->Options.CheckParity = TRUE;
317  } else if( strcasecmp( pszOption, "DT" )==0 ) {
318  info->Options.KeepDTREnabled = TRUE;
319  } else if( strcasecmp( pszOption, "FE" )==0 ) {
320  info->Options.DiscardOnError = TRUE;
321  } else if( strcasecmp( pszOption, "ME" )==0 ) {
322  info->Options.IgnoreAllErrors = TRUE;
323  } else if( strncasecmp( pszOption, "IR", 2 )==0 ) {
324  info->Options.IRQNumber = strtoul( pszOption+2, &pchPosTmp, 10 );
325  if( *pchPosTmp!=0 ) {
327  }
328  } else {
330  }
331  break;
332  }
333 
334  pchPos = pchPosNext;
335  free(pszOption);
336  ++uiOption;
337  }
338 
339  /* QB quirk */
340  if( iStopBits==-1 ) {
341  if( info->Options.uiSpeed <= 110 ) {
342  if( info->Options.uiDataBits==5 ) {
343  iStopBits = FB_SERIAL_STOP_BITS_1_5;
344  } else {
345  iStopBits = FB_SERIAL_STOP_BITS_2;
346  }
347  } else {
348  iStopBits = FB_SERIAL_STOP_BITS_1;
349  }
350  }
351  info->Options.StopBits = (FB_SERIAL_STOP_BITS) iStopBits;
352 
353  if( res==FB_RTERROR_OK ) {
354  handle->width = 0;
355  res = fb_SerialOpen( handle, info->iPort, &info->Options, info->pszDevice, &info->hSerial );
356  }
357 
358  if( res == FB_RTERROR_OK ) {
359  handle->hooks = &hooks_dev_com;
360  handle->opaque = info;
361  handle->type = FB_FILE_TYPE_SERIAL;
362  } else {
363  if( info->pszDevice )
364  free( info->pszDevice );
365  free(info);
366  }
367 
368  FB_UNLOCK();
369 
370  return res;
371 }
372 
373 int fb_DevSerialSetWidth( const char *pszDevice, int width, int default_width )
374 {
375  int cur = ((default_width==-1) ? 0 : default_width);
376  size_t i, port;
377  char achDev[128];
378 
379  if( !fb_DevComTestProtocolEx( NULL, pszDevice, strlen(pszDevice), &port ) )
380  return 0;
381 
382  i = sprintf( achDev, "COM%u:", (int)port );
383  achDev[i] = 0;
384 
385  /* Test all printers. */
386  for( i=0;
387  i<FB_MAX_FILES;
388  ++i )
389  {
390  FB_FILE *tmp_handle = __fb_ctx.fileTB + i;
391  if( tmp_handle->hooks==&hooks_dev_com
392  && tmp_handle->redirection_to==NULL )
393  {
394  DEV_COM_INFO *tmp_info = (DEV_COM_INFO*) tmp_handle->opaque;
395  if( strcmp(tmp_info->pszDevice, achDev)==0 ) {
396  if( width!=-1 )
397  tmp_handle->width = width;
398  cur = tmp_handle->width;
399  break;
400  }
401  }
402  }
403 
404  return cur;
405 }