GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/serialports.c
Date: 2026-02-03 22:06:38
Exec Total Coverage
Lines: 22 196 11.2%
Functions: 2 17 11.8%
Branches: 4 89 4.5%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/io/serialports.h"
30 #include "gate/threading.h"
31 #include "gate/results.h"
32 #include "gate/debugging.h"
33
34 #if defined(GATE_SYS_WIN16)
35 # define GATE_IO_SERIALPORTS_WIN16_IMPL 1
36 #elif defined(GATE_SYS_WIN)
37 # define GATE_IO_SERIALPORTS_WINAPI_IMPL 1
38 #elif defined(GATE_SYS_POSIX)
39 # define GATE_IO_SERIALPORTS_POSIX_IMPL 1
40 #elif defined(GATE_SYS_EFI)
41 # define GATE_IO_SERIALPORTS_EFI_IMPL 1
42 #elif defined(GATE_SYS_DOS)
43 # define GATE_IO_SERIALPORTS_DOS_IMPL 1
44 #else
45 # define GATE_IO_SERIALPORTS_NO_IMPL 1
46 #endif
47
48
49 typedef struct gate_serialport_stream
50 {
51 GATE_INTERFACE_VTBL(gate_resourcestream) const* vtbl;
52
53 gate_atomic_int_t ref_counter;
54 gate_serialport_t port_handle;
55 char buffer[4096];
56 gate_size_t buffer_used;
57
58 } gate_serialport_stream_t;
59
60 static void gate_serialport_stream_release(void* self)
61 {
62 gate_serialport_stream_t* stream = (gate_serialport_stream_t*)self;
63 if (0 == gate_atomic_int_dec(&stream->ref_counter))
64 {
65 gate_serialport_close(stream->port_handle);
66 gate_mem_dealloc(stream);
67 }
68 }
69 static int gate_serialport_stream_retain(void* self)
70 {
71 gate_serialport_stream_t* stream = (gate_serialport_stream_t*)self;
72 return gate_atomic_int_inc(&stream->ref_counter);
73 }
74 static char const* gate_serialport_stream_get_interface_name(void* self)
75 {
76 (void)self;
77 return GATE_INTERFACE_NAME_RESOURCESTREAM;
78 }
79 static gate_result_t gate_serialport_stream_peek(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
80 {
81 gate_serialport_stream_t* stream = (gate_serialport_stream_t*)self;
82 gate_result_t ret;
83
84 do
85 {
86 if (stream->buffer_used == 0)
87 {
88 ret = gate_serialport_read(stream->port_handle, &stream->buffer[0], sizeof(stream->buffer), &stream->buffer_used);
89 if (GATE_FAILED(ret))
90 {
91 stream->buffer_used = 0;
92 if (ret != GATE_RESULT_NODATA)
93 {
94 break;
95 }
96 }
97 }
98
99 ret = GATE_RESULT_OK;
100
101 if (stream->buffer_used != 0)
102 {
103 if (bufferlength > stream->buffer_used)
104 {
105 bufferlength = stream->buffer_used;
106 }
107 gate_mem_copy(buffer, &stream->buffer[0], bufferlength);
108 }
109 else
110 {
111 bufferlength = 0;
112 }
113
114 if (returned != NULL)
115 {
116 *returned = bufferlength;
117 }
118 } while (0);
119
120 return ret;
121 }
122 static gate_result_t gate_serialport_stream_read(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
123 {
124 gate_serialport_stream_t* stream = (gate_serialport_stream_t*)self;
125 gate_result_t ret;
126 gate_size_t bytesreceived = 0;
127 gate_uint32_t delay = 0;
128 static gate_uint32_t const max_delay = 50;
129 while (bytesreceived == 0)
130 {
131 ret = gate_serialport_stream_peek(self, buffer, bufferlength, &bytesreceived);
132 if (GATE_FAILED(ret))
133 {
134 break;
135 }
136 else
137 {
138 if (bytesreceived == 0)
139 {
140 gate_thread_sleep(delay);
141 if (delay < max_delay)
142 {
143 ++delay;
144 }
145 }
146 else
147 {
148 if (bytesreceived < stream->buffer_used)
149 {
150 gate_mem_move(&stream->buffer[0], &stream->buffer[bytesreceived], stream->buffer_used - bytesreceived);
151 stream->buffer_used -= bytesreceived;
152 }
153 else
154 {
155 stream->buffer_used = 0;
156 }
157 }
158 }
159 }
160 if (returned != NULL)
161 {
162 *returned = bytesreceived;
163 }
164 return ret;
165 }
166
167 static gate_result_t gate_serialport_stream_write(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
168 {
169 gate_serialport_stream_t* stream = (gate_serialport_stream_t*)self;
170 return gate_serialport_write(stream->port_handle, buffer, bufferlength, written);
171 }
172 static gate_result_t gate_serialport_stream_flush(void* self)
173 {
174 (void)self;
175 return GATE_RESULT_OK;
176 }
177
178 static gate_result_t gate_serialport_stream_get_resource(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
179 {
180 gate_result_t ret = GATE_RESULT_OK;
181 gate_serialport_stream_t* stream = (gate_serialport_stream_t*)self;
182
183 switch (resource_type)
184 {
185 case GATE_STREAM_RESOURCE_DEFAULT:
186 case GATE_STREAM_RESOURCE_INPUT:
187 case GATE_STREAM_RESOURCE_OUTPUT: *resource = (gate_uintptr_t)stream->port_handle;
188 default:
189 ret = GATE_RESULT_NOTSUPPORTED;
190 }
191 return ret;
192 }
193
194 static GATE_INTERFACE_VTBL(gate_resourcestream) gate_serialport_stream_vtbl;
195 static void gate_init_serialport_stream_vtbl()
196 {
197 if (!gate_serialport_stream_vtbl.get_interface_name)
198 {
199 GATE_INTERFACE_VTBL(gate_resourcestream) const local_vtbl =
200 {
201 &gate_serialport_stream_get_interface_name,
202 &gate_serialport_stream_release,
203 &gate_serialport_stream_retain,
204
205 &gate_serialport_stream_read,
206 &gate_serialport_stream_peek,
207 &gate_serialport_stream_write,
208 &gate_serialport_stream_flush,
209
210 &gate_serialport_stream_get_resource
211 };
212 gate_serialport_stream_vtbl = local_vtbl;
213 }
214 }
215
216 gate_result_t gate_serialport_openstream(
217 gate_string_t const* port_id, gate_uint32_t baudrate,
218 gate_enumint_t bits, gate_enumint_t parity, gate_enumint_t stopbits, gate_enumint_t flowcontrol,
219 gate_stream_t** stream)
220 {
221 gate_result_t ret;
222 gate_serialport_stream_t* ptr;
223
224 ptr = (gate_serialport_stream_t*)gate_mem_alloc(sizeof(gate_serialport_stream_t));
225 if (ptr == NULL)
226 {
227 ret = GATE_RESULT_OUTOFMEMORY;
228 }
229 else
230 {
231 gate_mem_clear(ptr, sizeof(gate_serialport_stream_t));
232 gate_init_serialport_stream_vtbl();
233 ptr->vtbl = &gate_serialport_stream_vtbl;
234 gate_atomic_int_init(&ptr->ref_counter, 1);
235 ptr->buffer_used = 0;
236 ret = gate_serialport_open(port_id, baudrate, bits, parity, stopbits, flowcontrol, 0, false, &ptr->port_handle);
237 if (GATE_FAILED(ret))
238 {
239 gate_mem_dealloc(ptr);
240 }
241 else
242 {
243 *stream = (gate_stream_t*)ptr;
244 }
245 }
246 return ret;
247 }
248
249
250 #if defined(GATE_SYS_WIN)
251
252 #include "gate/platforms.h"
253
254 static gate_result_t winapi_setup_comm(HANDLE hfile, DCB* dcb,
255 gate_uint32_t baudrate, unsigned bits, unsigned parity, unsigned stopbits,
256 unsigned flowcontrol, gate_uint32_t timeout, gate_bool_t asynchronous)
257 {
258 gate_result_t ret = GATE_RESULT_FAILED;
259
260 do
261 {
262 #if !defined(GATE_SYS_WIN16)
263 dcb->DCBlength = sizeof(dcb);
264 #endif
265 if (FALSE == GetCommState(hfile, dcb))
266 {
267 gate_win32_print_lasterror(&ret, NULL, 0);
268 break;
269 }
270 if (baudrate != 0)
271 {
272 dcb->BaudRate = baudrate;
273 }
274 dcb->ByteSize = (BYTE)bits;
275 dcb->fParity = TRUE;
276 dcb->fNull = FALSE;
277 dcb->fBinary = TRUE;
278 #if !defined(GATE_SYS_WIN16)
279 dcb->fAbortOnError = FALSE;
280 #endif
281
282 switch (parity)
283 {
284 case GATE_SERIALPORT_PARITY_ODD: { dcb->Parity = ODDPARITY; break; }
285 case GATE_SERIALPORT_PARITY_EVEN: { dcb->Parity = EVENPARITY; break; }
286 case GATE_SERIALPORT_PARITY_MARK: { dcb->Parity = MARKPARITY; break; }
287 case GATE_SERIALPORT_PARITY_SPACE: { dcb->Parity = SPACEPARITY; break; }
288 case GATE_SERIALPORT_PARITY_NONE:
289 default: { dcb->Parity = NOPARITY; break; }
290 }
291
292 switch (stopbits)
293 {
294 case GATE_SERIALPORT_STOPBITS_1_5: { dcb->StopBits = ONE5STOPBITS; break; }
295 case GATE_SERIALPORT_STOPBITS_2_0: { dcb->StopBits = TWOSTOPBITS; break; }
296 case GATE_SERIALPORT_STOPBITS_1_0:
297 default: { dcb->StopBits = ONESTOPBIT; break; }
298 }
299
300 switch (flowcontrol)
301 {
302 case GATE_SERIALPORT_FLOWCTRL_HARDWARE:
303 {
304 dcb->fInX = FALSE;
305 dcb->fOutX = FALSE;
306 dcb->fOutxDsrFlow = FALSE;
307 dcb->fOutxCtsFlow = FALSE;
308 #if defined(GATE_SYS_WIN16)
309 dcb->fDtrDisable = 0;
310 dcb->fRtsDisable = 0;
311 #else
312 dcb->fDtrControl = DTR_CONTROL_ENABLE;
313 dcb->fRtsControl = RTS_CONTROL_ENABLE;
314 #endif
315 break;
316 }
317 case GATE_SERIALPORT_FLOWCTRL_HANDSHAKE:
318 {
319 dcb->fInX = FALSE;
320 dcb->fOutX = FALSE;
321 dcb->fOutxDsrFlow = FALSE;
322 dcb->fOutxCtsFlow = FALSE;
323 #if defined(GATE_SYS_WIN16)
324 dcb->fDtrDisable = 0;
325 dcb->fRtsDisable = 0;
326 #else
327 dcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
328 dcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
329 #endif
330 break;
331 }
332 case GATE_SERIALPORT_FLOWCTRL_XON:
333 {
334 dcb->fInX = TRUE;
335 dcb->fOutX = TRUE;
336 dcb->fOutxDsrFlow = FALSE;
337 dcb->fOutxCtsFlow = FALSE;
338 #if defined(GATE_SYS_WIN16)
339 dcb->fDtrDisable = 1;
340 dcb->fRtsDisable = 1;
341 #else
342 dcb->fDtrControl = DTR_CONTROL_DISABLE;
343 dcb->fRtsControl = RTS_CONTROL_DISABLE;
344 #endif
345 break;
346 }
347 case GATE_SERIALPORT_FLOWCTRL_NONE:
348 default:
349 {
350 dcb->fInX = FALSE;
351 dcb->fOutX = FALSE;
352 dcb->fOutxDsrFlow = FALSE;
353 dcb->fOutxCtsFlow = FALSE;
354 #if defined(GATE_SYS_WIN16)
355 dcb->fDtrDisable = 1;
356 dcb->fRtsDisable = 1;
357 #else
358 dcb->fDtrControl = DTR_CONTROL_DISABLE;
359 dcb->fRtsControl = RTS_CONTROL_DISABLE;
360 #endif
361 break;
362 }
363 }
364
365 #if defined(GATE_SYS_WIN16)
366 if (0 != SetCommState(dcb))
367 #else
368 if (FALSE == SetCommState(hfile, dcb))
369 #endif
370 {
371 gate_win32_print_lasterror(&ret, NULL, 0);
372 break;
373 }
374 ret = GATE_RESULT_OK;
375 } while (0);
376
377 return ret;
378 }
379
380 #endif
381
382
383 #if defined(GATE_IO_SERIALPORTS_WIN16_IMPL)
384
385 #define GATE_IO_SERIALPORTS_DEFAULT_READ_BUFFER 1024
386 #define GATE_IO_SERIALPORTS_DEFAULT_WRITE_BUFFER 128
387
388 #include "tchar.h"
389
390 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
391 {
392 return GATE_RESULT_NOTSUPPORTED;
393 }
394
395 gate_result_t gate_serialport_open(
396 gate_string_t const* port_id, gate_uint32_t baudrate,
397 gate_enumint_t bits, gate_enumint_t parity, gate_enumint_t stopbits, gate_enumint_t flowcontrol,
398 gate_uint32_t timeout, gate_bool_t asynchronous, gate_serialport_t* port_handle)
399 {
400 gate_result_t ret = GATE_RESULT_FAILED;
401 char port_name[256];
402 int handle = -1;
403 DCB dcb;
404 do
405 {
406 handle = OpenComm(port_name, GATE_IO_SERIALPORTS_DEFAULT_READ_BUFFER, GATE_IO_SERIALPORTS_DEFAULT_WRITE_BUFFER);
407 if (handle < 0)
408 {
409 ret = GATE_RESULT_FAILED;
410 break;
411 }
412
413 ret = winapi_setup_comm(handle, &dcb, baudrate, bits, parity, stopbits, flowcontrol, timeout, asynchronous);
414 GATE_BREAK_IF_FAILED(ret);
415
416 if (port_handle)
417 {
418 *port_handle = (gate_serialport_t)handle;
419 handle = -1;
420 }
421 ret = GATE_RESULT_OK;
422 } while (0);
423
424 if (handle >= 0)
425 {
426 CloseComm(handle);
427 }
428
429 return ret;
430 }
431
432 gate_result_t gate_serialport_close(gate_serialport_t port_handle)
433 {
434 int handle = (int)port_handle;
435 if (handle < 0)
436 {
437 return GATE_RESULT_INVALIDARG;
438 }
439 else
440 {
441 CloseComm(handle);
442 return GATE_RESULT_OK;
443 }
444
445 }
446 gate_result_t gate_serialport_read(gate_serialport_t port_handle, char* buffer, gate_size_t bufferlen, gate_size_t* bytesreceived)
447 {
448 int handle = (int)port_handle;
449 int result;
450
451 if (bufferlen > GATE_IO_SERIALPORTS_DEFAULT_READ_BUFFER)
452 {
453 bufferlen = GATE_IO_SERIALPORTS_DEFAULT_READ_BUFFER;
454 }
455 result = ReadComm(handle, &buffer[0], (int)bufferlen);
456 if (result < 0)
457 {
458 if (bytesreceived)
459 {
460 *bytesreceived = (gate_size_t)(-result);
461 }
462 return GATE_RESULT_FAILED;
463 }
464 else
465 {
466 if (bytesreceived)
467 {
468 *bytesreceived = (gate_size_t)result;
469
470 }
471 return GATE_RESULT_OK;
472 }
473 }
474 gate_result_t gate_serialport_write(gate_serialport_t port_handle, char const* buffer, gate_size_t bufferlen, gate_size_t* byteswritten)
475 {
476 int handle = (int)port_handle;
477 int result;
478
479 if (bufferlen > GATE_IO_SERIALPORTS_DEFAULT_WRITE_BUFFER)
480 {
481 bufferlen = GATE_IO_SERIALPORTS_DEFAULT_WRITE_BUFFER;
482 }
483 result = WriteComm(handle, &buffer[0], (int)bufferlen);
484 if (result < 0)
485 {
486 if (byteswritten)
487 {
488 *byteswritten = (gate_size_t)(-result);
489 }
490 return GATE_RESULT_FAILED;
491 }
492 else
493 {
494 if (byteswritten)
495 {
496 *byteswritten = (gate_size_t)result;
497 }
498 return GATE_RESULT_OK;
499 }
500 }
501
502
503 #endif /* GATE_IO_SERIALPORTS_WIN16_IMPL */
504
505
506
507 #if defined(GATE_IO_SERIALPORTS_WINAPI_IMPL)
508
509 # include "gate/platforms.h"
510 # include "gate/platform/windows/win32registry.h"
511
512
513 #if defined(GATE_SYS_WINCE)
514
515 typedef struct
516 {
517 gate_serialport_enum_callback_t callback;
518 void* userparam;
519 //gate_win32_registry_enum_keys
520
521 } gate_serialport_enum_registry_param_t;
522
523 static gate_bool_t gate_serialport_enum_registry_callback(LPCTSTR base_path, LPCTSTR sub_path, void* userparam)
524 {
525 gate_bool_t ret = true;
526 gate_serialport_enum_registry_param_t* param = (gate_serialport_enum_registry_param_t*)userparam;
527 gate_result_t result;
528 char com_name[GATE_MAX_FILENAME_LENGTH];
529 gate_size_t com_name_used;
530 TCHAR com_key[GATE_MAX_FILEPATH_LENGTH];
531 gate_size_t com_key_used;
532 char com_descr[GATE_MAX_FILENAME_LENGTH];
533 gate_size_t com_descr_used = sizeof(com_descr);
534
535 do
536 {
537 result = gate_win32_registry_read_str(GATE_WIN32_REGISTRY_LOCALMACHINE, sub_path, _T("Name"),
538 com_name, sizeof(com_name), &com_name_used);
539 if (GATE_FAILED(result))
540 {
541 break;
542 }
543
544 if (0 != gate_str_pos(com_name, com_name_used, "COM", 3, 0))
545 {
546 break;
547 }
548
549 com_key[0] = 0;
550 com_descr[0] = 0;
551
552 result = gate_win32_registry_read_winstr(GATE_WIN32_REGISTRY_LOCALMACHINE, sub_path, _T("Key"),
553 com_key, sizeof(com_key) / sizeof(com_key[0]), &com_key_used);
554 if (GATE_SUCCEEDED(result))
555 {
556 gate_win32_registry_read_str(GATE_WIN32_REGISTRY_LOCALMACHINE, com_key, _T("FriendlyName"),
557 com_descr, sizeof(com_descr), &com_descr_used);
558 }
559
560 if (param->callback)
561 {
562 ret = param->callback(com_name, com_descr, param->userparam);
563 }
564 } while (0);
565 return ret;
566 }
567
568
569 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
570 {
571 gate_result_t ret = GATE_RESULT_OK;
572 gate_serialport_enum_registry_param_t param;
573
574 param.callback = callback;
575 param.userparam = userparam;
576
577 ret = gate_win32_registry_enum_keys(GATE_WIN32_REGISTRY_LOCALMACHINE, _T("Drivers\\Active\\"),
578 &gate_serialport_enum_registry_callback, &param);
579
580 return ret;
581 }
582
583 #elif defined(GATE_SYS_WINSTORE) /* defined(GATE_SYS_WINCE) */
584
585 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
586 {
587 return GATE_RESULT_NOTSUPPORTED;
588 }
589
590 #else /* defined(GATE_SYS_WINSTORE) */
591
592 # include <setupapi.h>
593
594 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
595 {
596 gate_result_t ret = GATE_RESULT_FAILED;
597 DWORD dwClassCount = 0;
598 DWORD ndxClass;
599 DWORD ndxInfo;
600 GUID classGuids[256];
601 HDEVINFO hdevinfo;
602 SP_DEVINFO_DATA devinfo_data;
603 HKEY hKey;
604 DWORD dwType;
605 TCHAR buffer[GATE_MAX_FILENAME_LENGTH * 2];
606 DWORD bufferlen;
607 char portid[GATE_MAX_FILENAME_LENGTH * 2];
608 char descr[GATE_MAX_FILENAME_LENGTH * 2];
609 gate_bool_t continueEnum = true;
610 gate_win32_setupapi_t const* const setupapi = gate_win32_setupapi();
611
612 do
613 {
614 if ((setupapi->SetupApiDiDestroyDeviceInfoList == NULL)
615 || (setupapi->SetupApiDiGetClassDevs == NULL)
616 || (setupapi->SetupApiDiEnumDeviceInfo == NULL)
617 || (setupapi->SetupApiDiGetDeviceRegistryProperty == NULL)
618 || (setupapi->SetupApiDiClassGuidsFromName == NULL)
619 || (setupapi->SetupApiDiOpenDevRegKey == NULL)
620 || (gate_platform.AdvRegQueryValueEx == NULL)
621 || (gate_platform.AdvRegCloseKey == NULL)
622 )
623 {
624 ret = GATE_RESULT_NOTSUPPORTED;
625 break;
626 }
627
628 if (!setupapi->SetupApiDiClassGuidsFromName(_T("Ports"), classGuids, sizeof(classGuids) / sizeof(classGuids[0]), &dwClassCount))
629 {
630 ret = GATE_RESULT_FAILED;
631 break;
632 }
633
634 devinfo_data.cbSize = sizeof(devinfo_data);
635
636 for (ndxClass = 0; continueEnum && (ndxClass != dwClassCount); ++ndxClass)
637 {
638 hdevinfo = (HDEVINFO)setupapi->SetupApiDiGetClassDevs(&classGuids[ndxClass], NULL, NULL, DIGCF_PRESENT);
639 if (INVALID_HANDLE_VALUE == hdevinfo)
640 {
641 continue;
642 }
643
644 for (ndxInfo = 0; continueEnum && setupapi->SetupApiDiEnumDeviceInfo(hdevinfo, ndxInfo, &devinfo_data); ++ndxInfo)
645 {
646 hKey = setupapi->SetupApiDiOpenDevRegKey(hdevinfo, &devinfo_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
647 if (hKey == INVALID_HANDLE_VALUE)
648 {
649 continue;
650 }
651
652 dwType = 0;
653 bufferlen = sizeof(buffer) - sizeof(buffer[0]);
654
655 if (ERROR_SUCCESS == gate_platform.AdvRegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (LPBYTE)buffer, &bufferlen))
656 {
657 if (REG_SZ == dwType)
658 {
659 buffer[bufferlen / sizeof(TCHAR)] = 0;
660 }
661 if (0 != gate_win32_winstr_2_utf8(buffer, bufferlen / sizeof(TCHAR), portid, sizeof(portid)))
662 {
663 if (setupapi->SetupApiDiGetDeviceRegistryProperty(hdevinfo, &devinfo_data, SPDRP_FRIENDLYNAME, NULL, (PBYTE)&buffer[0], sizeof(buffer), &bufferlen))
664 {
665 gate_win32_winstr_2_utf8(buffer, bufferlen / sizeof(TCHAR), descr, sizeof(descr));
666 }
667 else
668 {
669 descr[0] = 0;
670 }
671 continueEnum &= callback(portid, descr, userparam);
672 }
673 }
674 gate_platform.AdvRegCloseKey(hKey);
675 }
676 setupapi->SetupApiDiDestroyDeviceInfoList(hdevinfo);
677 ret = GATE_RESULT_OK;
678 }
679 } while (0);
680 return ret;
681 }
682 #endif
683
684
685 gate_result_t gate_serialport_open(
686 gate_string_t const* port_id, gate_uint32_t baudrate,
687 gate_enumint_t bits, gate_enumint_t parity, gate_enumint_t stopbits, gate_enumint_t flowcontrol,
688 gate_uint32_t timeout, gate_bool_t asynchronous, gate_serialport_t* port_handle)
689 {
690 gate_result_t ret;
691 TCHAR path[GATE_MAX_FILENAME_LENGTH * 2] = _T("\\\\.\\");
692 HANDLE hfile = INVALID_HANDLE_VALUE;
693 DCB dcb;
694 #if !defined(GATE_SYS_WIN16)
695 COMMTIMEOUTS cto;
696 #endif
697
698 do
699 {
700 gate_win32_utf8_2_winstr(port_id->str, port_id->length, &path[4], sizeof(path) / sizeof(path[0]) - 5);
701 hfile = gate_win32_createfile(path, GENERIC_READ | GENERIC_WRITE, 0, OPEN_EXISTING, 0,
702 (asynchronous ? FILE_FLAG_OVERLAPPED : 0), NULL);
703 if (hfile == INVALID_HANDLE_VALUE)
704 {
705 gate_win32_print_lasterror(&ret, NULL, 0);
706 break;
707 }
708
709 ret = winapi_setup_comm(hfile, &dcb, baudrate, bits, parity, stopbits, flowcontrol, timeout, asynchronous);
710 GATE_BREAK_IF_FAILED(ret);
711
712 if (timeout != 0)
713 {
714 #if !defined(GATE_SYS_WIN16)
715 if (GetCommTimeouts(hfile, &cto))
716 {
717 cto.ReadIntervalTimeout = 0;
718 cto.ReadTotalTimeoutMultiplier = 0;
719 cto.ReadTotalTimeoutConstant = 10;
720
721 /*
722 cto.ReadIntervalTimeout = MAXDWORD;
723 cto.ReadTotalTimeoutConstant = timeout;
724 cto.ReadIntervalTimeout = 0;
725 cto.ReadTotalTimeoutMultiplier = 0;
726 cto.ReadTotalTimeoutConstant = 0;
727 */
728
729 cto.WriteTotalTimeoutMultiplier = 1;
730 cto.WriteTotalTimeoutConstant = 1;
731 /*
732 cto.WriteTotalTimeoutConstant = readTimeout ? *readTimeout : 100;
733 */
734
735 SetCommTimeouts(hfile, &cto);
736 }
737 #endif
738 }
739 /*
740 SetCommMask(hfile, EV_RXCHAR | EV_TXEMPTY);
741 */
742
743 *port_handle = (gate_serialport_t)hfile;
744 hfile = INVALID_HANDLE_VALUE;
745 ret = GATE_RESULT_OK;
746 } while (0);
747
748 if ((hfile != INVALID_HANDLE_VALUE) && (hfile != (HANDLE)NULL))
749 {
750 CloseHandle(hfile);
751 }
752
753 return ret;
754 }
755 gate_result_t gate_serialport_close(gate_serialport_t port_handle)
756 {
757 HANDLE hfile = (HANDLE)port_handle;
758 /*
759 SetCommMask(hfile, 0);
760 */
761 CloseHandle(hfile);
762 return GATE_RESULT_OK;
763 }
764 gate_result_t gate_serialport_read(gate_serialport_t port_handle, char* buffer, gate_size_t bufferlen, gate_size_t* bytesreceived)
765 {
766 gate_result_t ret;
767 HANDLE hfile = (HANDLE)port_handle;
768 DWORD bytesread;
769 DWORD dwError = 0;
770 COMSTAT status = GATE_INIT_EMPTY;
771
772 do
773 {
774 if (ClearCommError(hfile, &dwError, &status))
775 {
776 if (status.cbInQue == 0)
777 {
778 ret = GATE_RESULT_NODATA;
779 break;
780 }
781 if (status.cbInQue < bufferlen)
782 {
783 bufferlen = (gate_size_t)status.cbInQue;
784 }
785 }
786 if (FALSE == gate_win32_readfile(hfile, buffer, (DWORD)bufferlen, &bytesread, NULL))
787 {
788 gate_win32_print_lasterror(&ret, NULL, 0);
789 break;
790 }
791 if (bytesreceived != NULL)
792 {
793 *bytesreceived = (gate_size_t)bytesread;
794 }
795 ret = GATE_RESULT_OK;
796
797 } while (0);
798
799 return ret;
800 }
801
802 gate_result_t gate_serialport_write(gate_serialport_t port_handle, char const* buffer, gate_size_t bufferlen, gate_size_t* byteswritten)
803 {
804 gate_result_t ret;
805 HANDLE hfile = (HANDLE)port_handle;
806 DWORD written;
807
808 do
809 {
810 if (FALSE == gate_win32_writefile(hfile, buffer, (DWORD)bufferlen, &written, NULL))
811 {
812 gate_win32_print_lasterror(&ret, NULL, 0);
813 break;
814 }
815 if (byteswritten != NULL)
816 {
817 *byteswritten = (gate_size_t)written;
818 }
819 ret = GATE_RESULT_OK;
820 } while (0);
821
822 return ret;
823 }
824
825 #endif /* GATE_IO_SERIALPORTS_WINAPI_IMPL */
826
827
828
829
830 #if defined(GATE_IO_SERIALPORTS_POSIX_IMPL)
831
832 #include "gate/platforms.h"
833 #include "gate/files.h"
834
835 #include <termios.h>
836 #include <unistd.h>
837 #include <fcntl.h>
838
839 struct gate_serialport_enum_dir_param
840 {
841 gate_serialport_enum_callback_t callback;
842 void* callback_param;
843 };
844
845 71 static gate_bool_t gate_serialport_enum_dir_cb(gate_file_entry_t const* entry, void* userparam)
846 {
847 71 struct gate_serialport_enum_dir_param* param = (struct gate_serialport_enum_dir_param*)userparam;
848 71 gate_bool_t ret = true;
849 char path[GATE_MAX_FILEPATH_LENGTH];
850 gate_result_t result;
851 gate_string_t sub_dir_path;
852 71 gate_string_create_static(&sub_dir_path, entry->path);
853
854 do
855 {
856 /* check if listed sysfs exists */
857 71 result = gate_file_exists(&sub_dir_path);
858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 GATE_BREAK_IF_FAILED(result);
859
860 /* check if sysfs entry as a "device" subelement (filter non-serial-port TTY entries) */
861 142 gate_file_build_path(
862 path, sizeof(path),
863 71 gate_string_ptr(&sub_dir_path, 0), gate_string_length(&sub_dir_path),
864 "device", 6);
865 71 gate_string_create_static(&sub_dir_path, path);
866 71 result = gate_file_exists(&sub_dir_path);
867
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 4 times.
71 GATE_BREAK_IF_FAILED(result);
868
869 /* check if device node exists */
870 4 gate_file_build_path(path, sizeof(path), "/dev", 4, entry->name, gate_str_length(entry->name));
871 4 gate_string_create_static(&sub_dir_path, path);
872 4 result = gate_file_exists(&sub_dir_path);
873
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 GATE_BREAK_IF_FAILED(result);
874
875 /* we have a serial device, send it to the user */
876 ret = param->callback(entry->name, path, param->callback_param);
877 } while (0);
878
879 71 return ret;
880 }
881
882 1 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
883 {
884 1 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
885 static gate_string_t const sys_dir = { "/sys/class/tty", 14, NULL };
886 struct gate_serialport_enum_dir_param param;
887
888 1 param.callback = callback;
889 1 param.callback_param = userparam;
890
891 1 ret = gate_file_list(&sys_dir, &gate_serialport_enum_dir_cb, &param);
892 1 return ret;
893 }
894
895 static speed_t get_baud_speed(gate_uint32_t baudrate)
896 {
897 switch(baudrate)
898 {
899 case GATE_SERIALPORT_BAUDRATE_110: return B110;
900 case GATE_SERIALPORT_BAUDRATE_300: return B300;
901 case GATE_SERIALPORT_BAUDRATE_600: return B600;
902 case GATE_SERIALPORT_BAUDRATE_1200: return B1200;
903 case GATE_SERIALPORT_BAUDRATE_2400: return B2400;
904 case GATE_SERIALPORT_BAUDRATE_4800: return B4800;
905 case GATE_SERIALPORT_BAUDRATE_9600: return B9600;
906 /*case GATE_SERIALPORT_BAUDRATE_14400: return B14400;*/
907 case GATE_SERIALPORT_BAUDRATE_19200: return B19200;
908 /*case GATE_SERIALPORT_BAUDRATE_28800: return B28800;*/
909 case GATE_SERIALPORT_BAUDRATE_38400: return B38400;
910 /*case GATE_SERIALPORT_BAUDRATE_56000: return B56000;*/
911 #if defined(B57600)
912 case GATE_SERIALPORT_BAUDRATE_57600: return B57600;
913 #endif
914 #if defined(B115200)
915 case GATE_SERIALPORT_BAUDRATE_115200: return B115200;
916 #endif
917 #if defined(B128000)
918 case GATE_SERIALPORT_BAUDRATE_128000: return B128000;
919 #endif
920 #if defined(B230400)
921 case GATE_SERIALPORT_BAUDRATE_230400: return B230400;
922 #endif
923 #if defined(B256000)
924 case GATE_SERIALPORT_BAUDRATE_256000: return B256000;
925 #endif
926 #if defined(B460800)
927 case GATE_SERIALPORT_BAUDRATE_460800: return B460800;
928 #endif
929 #if defined(B921600)
930 case GATE_SERIALPORT_BAUDRATE_921600: return B921600;
931 #endif
932 default: return B0;
933 }
934 }
935
936 gate_result_t gate_serialport_open(
937 gate_string_t const* port_id, gate_uint32_t baudrate,
938 gate_enumint_t bits, gate_enumint_t parity, gate_enumint_t stopbits, gate_enumint_t flowcontrol,
939 gate_uint32_t timeout_ms, gate_bool_t asynchronous, gate_serialport_t* port_handle)
940 {
941 gate_result_t ret = GATE_RESULT_FAILED;
942 gate_platform_stream_t stream;
943
944 gate_platform_stream_set_invalid(&stream);
945 do
946 {
947 char path[GATE_MAX_FILEPATH_LENGTH] = GATE_INIT_EMPTY;
948 gate_strbuilder_t builder;
949 int fd;
950 int const native_flags = O_NOCTTY | O_NONBLOCK;
951 struct termios term_info;
952
953 /* generate "/dev/{portid}"" path */
954 gate_strbuilder_create_static(&builder, path, sizeof(path), 0);
955 gate_strbuilder_append_cstr(&builder, "/dev/");
956 gate_strbuilder_append_string(&builder, port_id);
957
958 /* open serial port device */
959 ret = gate_platform_stream_open(path, GATE_PLATFORM_STREAM_OPEN_READWRITE, native_flags, &stream);
960 GATE_BREAK_IF_FAILED(ret);
961
962 fd = (int)(gate_intptr_t)stream;
963 fcntl(fd, F_SETFL, 0); /* remove NONBLOCK */
964
965 gate_mem_clear(&term_info, sizeof(term_info));
966 if (0 != tcgetattr(fd, &term_info))
967 {
968 ret = GATE_RESULT_ACCESSDENIED;
969 break;
970 }
971
972 /* from cfmakeraw(): set TTY to raw mode */
973 term_info.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
974 term_info.c_oflag &= ~OPOST;
975 term_info.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
976
977 cfsetispeed(&term_info, get_baud_speed(baudrate));
978 cfsetospeed(&term_info, get_baud_speed(baudrate));
979
980 switch(parity)
981 {
982 case GATE_SERIALPORT_PARITY_NONE: term_info.c_cflag &= ~(PARENB | PARODD); break;
983 case GATE_SERIALPORT_PARITY_ODD: term_info.c_cflag |= (PARENB | PARODD); break;
984 case GATE_SERIALPORT_PARITY_EVEN: term_info.c_cflag |= (PARENB); term_info.c_cflag &= ~(PARODD); break;
985 #if defined(CMSPAR)
986 case GATE_SERIALPORT_PARITY_MARK: term_info.c_cflag |= CMSPAR; break;
987 case GATE_SERIALPORT_PARITY_SPACE: term_info.c_cflag |= CMSPAR; break;
988 #endif
989 default:
990 /* unsupported */
991 break;
992 }
993
994 term_info.c_cflag &= ~(CSIZE);
995 switch(bits)
996 {
997 case 5: term_info.c_cflag |= CS5; break;
998 case 6: term_info.c_cflag |= CS6; break;
999 case 7: term_info.c_cflag |= CS7; break;
1000 case 8: term_info.c_cflag |= CS8; break;
1001 default:
1002 /* unsupported */
1003 break;
1004 }
1005
1006 switch(stopbits)
1007 {
1008 case GATE_SERIALPORT_STOPBITS_1_0: term_info.c_cflag &= ~CSTOPB; break;
1009 case GATE_SERIALPORT_STOPBITS_1_5: term_info.c_cflag &= ~CSTOPB; break;
1010 case GATE_SERIALPORT_STOPBITS_2_0: term_info.c_cflag |= CSTOPB; break;
1011 default:
1012 /* unsupported */
1013 break;
1014 }
1015
1016 switch(flowcontrol)
1017 {
1018 case GATE_SERIALPORT_FLOWCTRL_NONE: term_info.c_cflag &= ~CRTSCTS; break;
1019 case GATE_SERIALPORT_FLOWCTRL_HARDWARE: term_info.c_cflag |= CRTSCTS; break;
1020 case GATE_SERIALPORT_FLOWCTRL_XON:
1021 case GATE_SERIALPORT_FLOWCTRL_HANDSHAKE:
1022 default:
1023 /* unsupported */
1024 break;
1025 }
1026
1027 term_info.c_cflag |= CREAD | CLOCAL;
1028
1029 if (timeout_ms == 0)
1030 {
1031 term_info.c_cc[VMIN] = 0; /* return immediately */
1032 term_info.c_cc[VTIME] = 0; /* no timeout -> no blocking */
1033 }
1034 else
1035 {
1036 gate_uint32_t hw_timeout = timeout_ms / 100;/* 1/10 seconds */
1037 if (hw_timeout == 0) hw_timeout = 1;
1038 if (hw_timeout > 255) hw_timeout = 255;
1039 term_info.c_cc[VMIN] = 0; /* return immediately */
1040 term_info.c_cc[VTIME] = (cc_t)hw_timeout; /* set timeout */
1041 }
1042
1043 if (tcsetattr(fd, TCSANOW, &term_info) != 0)
1044 {
1045 ret = GATE_RESULT_FAILED;
1046 break;
1047 }
1048
1049 tcflush(fd, TCIOFLUSH);
1050
1051 /* success case reached: */
1052 if (port_handle)
1053 {
1054 *port_handle = stream;
1055 gate_platform_stream_set_invalid(&stream);
1056 }
1057 ret = GATE_RESULT_OK;
1058 } while (0);
1059
1060 if (gate_platform_stream_valid(stream))
1061 {
1062 gate_platform_stream_close(stream);
1063 }
1064 return ret;
1065 }
1066
1067 gate_result_t gate_serialport_close(gate_serialport_t port_handle)
1068 {
1069 gate_platform_stream_t stream = (gate_platform_stream_t)port_handle;
1070 return gate_platform_stream_close(&stream);
1071 }
1072
1073 gate_result_t gate_serialport_read(gate_serialport_t port_handle, char* buffer, gate_size_t bufferlen, gate_size_t* bytesreceived)
1074 {
1075 gate_platform_stream_t const stream = (gate_platform_stream_t)port_handle;
1076 return gate_platform_stream_read(stream, buffer, bufferlen, bytesreceived);
1077 }
1078
1079 gate_result_t gate_serialport_write(gate_serialport_t port_handle, char const* buffer, gate_size_t bufferlen, gate_size_t* byteswritten)
1080 {
1081 gate_platform_stream_t const stream = (gate_platform_stream_t)port_handle;
1082 return gate_platform_stream_write(stream, buffer, bufferlen, byteswritten);
1083 }
1084
1085 #endif /* GATE_IO_SERIALPORTS_POSIX_IMPL */
1086
1087
1088
1089
1090 #if defined(GATE_IO_SERIALPORTS_EFI_IMPL)
1091
1092 #include "gate/platform/efi/efi_gate.h"
1093
1094 static char const* const gate_serial_port_efi_id = "COM";
1095
1096 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
1097 {
1098 gate_result_t result;
1099 void* ser_port = NULL;
1100
1101 result = gate_platform_efi_serport_get(&ser_port);
1102 if (GATE_SUCCEEDED(result))
1103 {
1104 if (callback)
1105 {
1106 callback(gate_serial_port_efi_id, "EFI Serial Port", userparam);
1107 }
1108 }
1109 return result;
1110 }
1111
1112 #define GATE_SERIALPORT_PARITY_NONE 0
1113 #define GATE_SERIALPORT_PARITY_ODD 1
1114 #define GATE_SERIALPORT_PARITY_EVEN 2
1115 #define GATE_SERIALPORT_PARITY_MARK 3
1116 #define GATE_SERIALPORT_PARITY_SPACE 4
1117
1118 #define GATE_SERIALPORT_STOPBITS_1_0 10
1119 #define GATE_SERIALPORT_STOPBITS_1_5 15
1120 #define GATE_SERIALPORT_STOPBITS_2_0 20
1121
1122 gate_result_t gate_serialport_open(
1123 gate_string_t const* port_id, gate_uint32_t baudrate,
1124 gate_enumint_t bits, gate_enumint_t parity, gate_enumint_t stopbits, gate_enumint_t flowcontrol,
1125 gate_uint32_t timeout_ms, gate_bool_t asynchronous, gate_serialport_t* port_handle)
1126 {
1127 gate_result_t ret = GATE_RESULT_FAILED;
1128 void* efi_ser_port = NULL;
1129 gate_uint8_t efi_parity = GATE_PLATFORM_EFI_SERIAL_PARITY_DEFAULT;
1130 gate_uint8_t efi_stopbits = GATE_PLATFORM_EFI_SERIAL_STOPBITS_DEFAULT;
1131
1132 do
1133 {
1134 if (!gate_string_equals_str(port_id, gate_serial_port_efi_id))
1135 {
1136 ret = GATE_RESULT_NOMATCH;
1137 break;
1138 }
1139
1140 ret = gate_platform_efi_serport_get(&efi_ser_port);
1141 GATE_BREAK_IF_FAILED(ret);
1142
1143 switch (parity)
1144 {
1145 case GATE_SERIALPORT_PARITY_NONE: efi_parity = GATE_PLATFORM_EFI_SERIAL_PARITY_NO; break;
1146 case GATE_SERIALPORT_PARITY_ODD: efi_parity = GATE_PLATFORM_EFI_SERIAL_PARITY_ODD; break;
1147 case GATE_SERIALPORT_PARITY_EVEN: efi_parity = GATE_PLATFORM_EFI_SERIAL_PARITY_EVEN; break;
1148 case GATE_SERIALPORT_PARITY_MARK: efi_parity = GATE_PLATFORM_EFI_SERIAL_PARITY_MARK; break;
1149 case GATE_SERIALPORT_PARITY_SPACE: efi_parity = GATE_PLATFORM_EFI_SERIAL_PARITY_SPACE; break;
1150 }
1151
1152 switch (stopbits)
1153 {
1154 case GATE_SERIALPORT_STOPBITS_1_0: efi_stopbits = GATE_PLATFORM_EFI_SERIAL_STOPBITS_1; break;
1155 case GATE_SERIALPORT_STOPBITS_1_5: efi_stopbits = GATE_PLATFORM_EFI_SERIAL_STOPBITS_15; break;
1156 case GATE_SERIALPORT_STOPBITS_2_0: efi_stopbits = GATE_PLATFORM_EFI_SERIAL_STOPBITS_2; break;
1157 }
1158
1159 ret = gate_platform_efi_serport_setup(efi_ser_port, baudrate, timeout_ms * 1000, efi_parity, bits, efi_stopbits);
1160 GATE_BREAK_IF_FAILED(ret);
1161
1162 if (port_handle)
1163 {
1164 *port_handle = efi_ser_port;
1165 }
1166 ret = GATE_RESULT_OK;
1167
1168 } while (0);
1169
1170 return ret;
1171 }
1172
1173 gate_result_t gate_serialport_close(gate_serialport_t port_handle)
1174 {
1175 (void)port_handle;
1176 return GATE_RESULT_OK;
1177 }
1178
1179 gate_result_t gate_serialport_read(gate_serialport_t port_handle, char* buffer, gate_size_t bufferlen, gate_size_t* bytesreceived)
1180 {
1181 gate_size_t received = 0;
1182 gate_result_t result = gate_platform_efi_serport_read(port_handle, (void*)buffer, bufferlen, &received);
1183 if (GATE_SUCCEEDED(result))
1184 {
1185 if (bytesreceived)
1186 {
1187 *bytesreceived = received;
1188 }
1189 if (received == 0)
1190 {
1191 result = GATE_RESULT_NODATA;
1192 }
1193 }
1194 else if (result == GATE_RESULT_TIMEOUT)
1195 {
1196 if (bytesreceived)
1197 {
1198 *bytesreceived = 0;
1199 }
1200 result = GATE_RESULT_NODATA;
1201 }
1202 return result;
1203 }
1204
1205 gate_result_t gate_serialport_write(gate_serialport_t port_handle, char const* buffer, gate_size_t bufferlen, gate_size_t* byteswritten)
1206 {
1207 return gate_platform_efi_serport_write(port_handle, (void const*)buffer, bufferlen, byteswritten);
1208 }
1209
1210 #endif /* GATE_IO_SERIALPORTS_EFI_IMPL */
1211
1212
1213 #if defined(GATE_IO_SERIALPORTS_DOS_IMPL)
1214
1215 #include <bios.h>
1216 #include "gate/times.h"
1217
1218 static gate_string_t const port_id_com1 = GATE_STRING_INIT_STATIC("COM1");
1219 static gate_string_t const port_id_com2 = GATE_STRING_INIT_STATIC("COM2");
1220 static gate_string_t const port_id_com3 = GATE_STRING_INIT_STATIC("COM3");
1221 static gate_string_t const port_id_com4 = GATE_STRING_INIT_STATIC("COM4");
1222 static gate_uint32_t port_timeout[4] = { 0 };
1223
1224 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
1225 {
1226 if (callback)
1227 {
1228 callback(port_id_com1.str, port_id_com1.str, userparam);
1229 callback(port_id_com2.str, port_id_com2.str, userparam);
1230 callback(port_id_com3.str, port_id_com3.str, userparam);
1231 callback(port_id_com4.str, port_id_com4.str, userparam);
1232 }
1233 return GATE_RESULT_OK;
1234 }
1235
1236 gate_result_t gate_serialport_open(
1237 gate_string_t const* port_id, gate_uint32_t baudrate,
1238 gate_enumint_t bits, gate_enumint_t parity, gate_enumint_t stopbits, gate_enumint_t flowcontrol,
1239 gate_uint32_t timeout_ms, gate_bool_t asynchronous, gate_serialport_t* port_handle)
1240 {
1241 unsigned config = 0;
1242 unsigned port = 0;
1243
1244 if (gate_string_equals(port_id, &port_id_com1))
1245 {
1246 port = 0;
1247 }
1248 else if (gate_string_equals(port_id, &port_id_com2))
1249 {
1250 port = 1;
1251 }
1252 else if (gate_string_equals(port_id, &port_id_com3))
1253 {
1254 port = 2;
1255 }
1256 else if (gate_string_equals(port_id, &port_id_com4))
1257 {
1258 port = 3;
1259 }
1260 else
1261 {
1262 return GATE_RESULT_INVALIDARG;
1263 }
1264
1265 if (asynchronous)
1266 {
1267 return GATE_RESULT_INVALIDARG;
1268 }
1269
1270 switch (flowcontrol)
1271 {
1272 case GATE_SERIALPORT_FLOWCTRL_NONE:
1273 break;
1274 default:
1275 return GATE_RESULT_INVALIDARG;
1276 }
1277
1278 switch (bits)
1279 {
1280 case 7:
1281 config |= _COM_CHR7;
1282 break;
1283 case 8:
1284 config |= _COM_CHR8;
1285 break;
1286 default:
1287 return GATE_RESULT_INVALIDARG;
1288 }
1289
1290 switch (parity)
1291 {
1292 case GATE_SERIALPORT_PARITY_NONE:
1293 config |= _COM_NOPARITY;
1294 break;
1295 case GATE_SERIALPORT_PARITY_ODD:
1296 config |= _COM_ODDPARITY;
1297 break;
1298 case GATE_SERIALPORT_PARITY_EVEN:
1299 config |= _COM_EVENPARITY;
1300 break;
1301 case GATE_SERIALPORT_PARITY_SPACE:
1302 config |= _COM_SPACEPARITY;
1303 break;
1304 default:
1305 return GATE_RESULT_INVALIDARG;
1306 }
1307
1308 switch (stopbits)
1309 {
1310 case GATE_SERIALPORT_STOPBITS_1_0:
1311 config |= _COM_STOP1;
1312 break;
1313 case GATE_SERIALPORT_STOPBITS_2_0:
1314 config |= _COM_STOP2;
1315 break;
1316 default:
1317 return GATE_RESULT_INVALIDARG;
1318 }
1319
1320 switch (baudrate)
1321 {
1322 case GATE_SERIALPORT_BAUDRATE_110:
1323 config |= _COM_110;
1324 break;
1325 case GATE_SERIALPORT_BAUDRATE_300:
1326 config |= _COM_300;
1327 break;
1328 case GATE_SERIALPORT_BAUDRATE_600:
1329 config |= _COM_600;
1330 break;
1331 case GATE_SERIALPORT_BAUDRATE_1200:
1332 config |= _COM_1200;
1333 break;
1334 case GATE_SERIALPORT_BAUDRATE_2400:
1335 config |= _COM_2400;
1336 break;
1337 case GATE_SERIALPORT_BAUDRATE_4800:
1338 config |= _COM_4800;
1339 break;
1340 case GATE_SERIALPORT_BAUDRATE_9600:
1341 config |= _COM_9600;
1342 break;
1343 default:
1344 return GATE_RESULT_INVALIDARG;
1345 }
1346
1347 _bios_serialcom(_COM_INIT, port, config);
1348 port_timeout[port] = timeout_ms;
1349 if (port_handle)
1350 {
1351 *port_handle = (gate_serialport_t)port;
1352 }
1353 return GATE_RESULT_OK;
1354 }
1355
1356 #define GATE_SERIALPORT_BIOS_STATUS_DATA_RECEIVED 0x0100
1357 #define GATE_SERIALPORT_BIOS_STATUS_OVERFLOW 0x0200
1358 #define GATE_SERIALPORT_BIOS_STATUS_PARITY_ERROR 0x0400
1359 #define GATE_SERIALPORT_BIOS_STATUS_PROTOCOL_ERROR 0x0800
1360 #define GATE_SERIALPORT_BIOS_STATUS_INTERRUPTION 0x1000
1361 #define GATE_SERIALPORT_BIOS_STATUS_HOLDREG 0x2000
1362 #define GATE_SERIALPORT_BIOS_STATUS_SHIFTREG 0x4000
1363 #define GATE_SERIALPORT_BIOS_STATUS_TIMEOUT 0x8000
1364
1365
1366 gate_result_t gate_serialport_close(gate_serialport_t port_handle)
1367 {
1368 (void)port_handle;
1369 return GATE_RESULT_OK;
1370 }
1371 gate_result_t gate_serialport_read(gate_serialport_t port_handle, char* buffer, gate_size_t bufferlen, gate_size_t* bytesreceived)
1372 {
1373 static unsigned const avail_mask = GATE_SERIALPORT_BIOS_STATUS_HOLDREG | GATE_SERIALPORT_BIOS_STATUS_SHIFTREG | GATE_SERIALPORT_BIOS_STATUS_DATA_RECEIVED;
1374 static unsigned const error_mask = GATE_SERIALPORT_BIOS_STATUS_TIMEOUT | GATE_SERIALPORT_BIOS_STATUS_OVERFLOW | GATE_SERIALPORT_BIOS_STATUS_PARITY_ERROR | GATE_SERIALPORT_BIOS_STATUS_PROTOCOL_ERROR;
1375 //static unsigned avail_mask = GATE_SERIALPORT_BIOS_STATUS_DATA_RECEIVED;
1376 unsigned port = (unsigned)port_handle;
1377 unsigned old_status = 0;
1378 unsigned timeout_ms = port_timeout[port];
1379 gate_timecounter_t now;
1380 gate_timecounter_t timeout_point;
1381
1382 gate_size_t received = 0;
1383 gate_timecounter_now(&now);
1384 timeout_point = gate_timecounter_add(now, (gate_int64_t)timeout_ms * 1000);
1385
1386 while ((received < bufferlen) && (now <= timeout_point))
1387 {
1388 unsigned status = _bios_serialcom(_COM_STATUS, port, 0);
1389 if (status != old_status)
1390 {
1391 old_status = status;
1392 }
1393 if ((status & avail_mask) == 0)
1394 {
1395 /* nothing to read */
1396 if (received > 0)
1397 {
1398 break;
1399 }
1400 }
1401 else
1402 {
1403 /* there is data to read */
1404 unsigned data = _bios_serialcom(_COM_RECEIVE, port, 0);
1405 if ((data & error_mask) == 0)
1406 {
1407 buffer[received] = (char)(data & 0xff);
1408 ++received;
1409 }
1410 break;
1411 }
1412 gate_timecounter_now(&now);
1413 }
1414
1415 if (received > 0)
1416 {
1417 if (bytesreceived)
1418 {
1419 *bytesreceived = received;
1420 }
1421 return GATE_RESULT_OK;
1422 }
1423 else
1424 {
1425 return GATE_RESULT_NODATA;
1426 }
1427 }
1428 gate_result_t gate_serialport_write(gate_serialport_t port_handle, char const* buffer, gate_size_t bufferlen, gate_size_t* byteswritten)
1429 {
1430 unsigned port = (unsigned)port_handle;
1431 unsigned written = 0;
1432
1433 while (bufferlen > 0)
1434 {
1435 unsigned chr = (unsigned char)*buffer;
1436 unsigned status = _bios_serialcom(_COM_SEND, port, chr);
1437 (void)status; /* TODO */
1438 --bufferlen;
1439 ++buffer;
1440 ++written;
1441 }
1442 if (byteswritten)
1443 {
1444 *byteswritten = written;
1445 }
1446 return GATE_RESULT_OK;
1447 }
1448
1449 #endif /* GATE_IO_SERIALPORTS_DOS_IMPL */
1450
1451
1452
1453
1454 #if defined(GATE_IO_SERIALPORTS_NO_IMPL)
1455
1456 gate_result_t gate_serialport_enum(gate_serialport_enum_callback_t callback, void* userparam)
1457 {
1458 GATE_UNUSED_ARG(callback);
1459 GATE_UNUSED_ARG(userparam);
1460 return GATE_RESULT_NOTIMPLEMENTED;
1461 }
1462
1463 gate_result_t gate_serialport_open(
1464 gate_string_t const* port_id, gate_uint32_t baudrate,
1465 gate_enumint_t bits, gate_enumint_t parity, gate_enumint_t stopbits, gate_enumint_t flowcontrol,
1466 gate_uint32_t timeout, gate_bool_t asynchronous, gate_serialport_t* port_handle)
1467 {
1468 GATE_UNUSED_ARG(port_id);
1469 GATE_UNUSED_ARG(baudrate);
1470 GATE_UNUSED_ARG(bits);
1471 GATE_UNUSED_ARG(parity);
1472 GATE_UNUSED_ARG(stopbits);
1473 GATE_UNUSED_ARG(flowcontrol);
1474 GATE_UNUSED_ARG(timeout);
1475 GATE_UNUSED_ARG(asynchronous);
1476 GATE_UNUSED_ARG(port_handle);
1477 return GATE_RESULT_NOTIMPLEMENTED;
1478 }
1479
1480 gate_result_t gate_serialport_close(gate_serialport_t port_handle)
1481 {
1482 GATE_UNUSED_ARG(port_handle);
1483 return GATE_RESULT_NOTIMPLEMENTED;
1484 }
1485 gate_result_t gate_serialport_read(gate_serialport_t port_handle, char* buffer, gate_size_t bufferlen, gate_size_t* bytesreceived)
1486 {
1487 GATE_UNUSED_ARG(port_handle);
1488 GATE_UNUSED_ARG(buffer);
1489 GATE_UNUSED_ARG(bufferlen);
1490 GATE_UNUSED_ARG(bytesreceived);
1491 return GATE_RESULT_NOTIMPLEMENTED;
1492 }
1493 gate_result_t gate_serialport_write(gate_serialport_t port_handle, char const* buffer, gate_size_t bufferlen, gate_size_t* byteswritten)
1494 {
1495 GATE_UNUSED_ARG(port_handle);
1496 GATE_UNUSED_ARG(buffer);
1497 GATE_UNUSED_ARG(bufferlen);
1498 GATE_UNUSED_ARG(byteswritten);
1499 return GATE_RESULT_NOTIMPLEMENTED;
1500 }
1501
1502 #endif /* GATE_IO_SERIALPORTS_NO_IMPL */
1503