GCC Code Coverage Report


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