GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/devices.c
Date: 2026-05-04 21:11:01
Exec Total Coverage
Lines: 0 308 0.0%
Functions: 0 14 0.0%
Branches: 0 124 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, Stefan Meislinger |
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/system/devices.h"
30 #include "gate/strings.h"
31 #include "gate/results.h"
32 #include "gate/platforms.h"
33 #include "gate/debugging.h"
34
35
36 #if defined(GATE_SYS_WIN) && !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WINSTORE) && !defined(GATE_SYS_WIN16)
37 # define GATE_SYSTEM_DEVICES_WINAPI_IMPL 1
38 #elif defined(GATE_SYS_LINUX) && !defined(GATE_SYS_ANDROID)
39 # define GATE_SYSTEM_DEVICES_DBUS_IMPL 1
40 #else
41 # define GATE_SYSTEM_DEVICES_NO_IMPL 1
42 #endif
43
44
45 /* Generic implementation */
46
47 gate_result_t gate_device_entry_init(gate_device_entry_t* entry)
48 {
49 gate_mem_clear(entry, sizeof(gate_device_entry_t));
50 return GATE_RESULT_OK;
51 }
52 void gate_device_entry_release(gate_device_entry_t* entry)
53 {
54 gate_string_release(&entry->uid);
55 gate_string_release(&entry->name);
56 gate_string_release(&entry->device_class);
57 gate_string_release(&entry->device_type);
58 gate_string_release(&entry->device_path);
59 gate_string_release(&entry->hardware_id);
60 gate_string_release(&entry->mount_path);
61 }
62
63
64 struct find_bthle_device_param
65 {
66 gate_string_t const* uid;
67 gate_string_t const* address;
68 gate_device_bthle_t* device;
69 gate_result_t result;
70 };
71
72 static gate_bool_t GATE_CALL find_bthledevice(gate_device_bthle_t const* device, void* user_param)
73 {
74 gate_bool_t ret = true; /* continue device iteration */
75 struct find_bthle_device_param* param = (struct find_bthle_device_param*)user_param;
76
77 do
78 {
79 if (param->uid)
80 {
81 if (gate_str_compare(param->uid->str, param->uid->length, device->uid, gate_str_length(device->uid)) == 0)
82 {
83 gate_mem_copy(param->device, device, sizeof(gate_device_bthle_t));
84 param->result = GATE_RESULT_OK;
85 ret = false; /* cancel further device iteration */
86 break;
87 }
88 }
89 if (param->address)
90 {
91 if (gate_str_compare(param->address->str, param->address->length, device->address, gate_str_length(device->address)) == 0)
92 {
93 gate_mem_copy(param->device, device, sizeof(gate_device_bthle_t));
94 param->result = GATE_RESULT_OK;
95 ret = false; /* cancel further device iteration */
96 break;
97 }
98 }
99 } while (0);
100
101 return ret;
102 }
103
104 gate_result_t gate_device_bthle_get(gate_string_t const* uid, gate_device_bthle_t* device)
105 {
106 gate_result_t ret;
107 struct find_bthle_device_param param;
108 gate_mem_clear(&param, sizeof(param));
109 param.uid = uid;
110 param.address = NULL;
111 param.device = device;
112 param.result = GATE_RESULT_NOMATCH;
113 ret = gate_device_bthle_enum(&find_bthledevice, &param);
114 if (GATE_SUCCEEDED(ret))
115 {
116 ret = param.result;
117 }
118 return ret;
119 }
120
121 gate_result_t gate_device_bthle_get_by_address(gate_string_t const* address, gate_device_bthle_t* device)
122 {
123 gate_result_t ret;
124 struct find_bthle_device_param param;
125 gate_mem_clear(&param, sizeof(param));
126 param.uid = NULL;
127 param.address = address;
128 param.device = device;
129 param.result = GATE_RESULT_NOMATCH;
130 ret = gate_device_bthle_enum(&find_bthledevice, &param);
131 if (GATE_SUCCEEDED(ret))
132 {
133 ret = param.result;
134 }
135 return ret;
136 }
137
138
139
140
141 #if defined(GATE_SYSTEM_DEVICES_WINAPI_IMPL)
142
143 /* WIN32 implementation */
144 #include "gate/system/platform/device_cfgmgr.h"
145 #include "gate/system/platform/device_winbluetooth.h"
146
147 #ifndef DIGCF_PRESENT
148 #define DIGCF_PRESENT 0x00000002
149 #endif
150
151 #ifndef DIGCF_ALLCLASSES
152 #define DIGCF_ALLCLASSES 0x00000004
153 #endif
154
155 #ifndef INVALID_HANDLE_VALUE
156 #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
157 #endif
158
159 #ifndef FALSE
160 #define FALSE 0
161 #endif
162
163 #ifndef TRUE
164 #define TRUE 1
165 #endif
166
167 static gate_result_t gate_win32_device_entries_enum(gate_device_entry_callback_t callback, void* user_param)
168 {
169 gate_result_t ret = GATE_RESULT_FAILED;
170 PVOID hDevInfo = INVALID_HANDLE_VALUE;
171 SP_DEVINFO_DATA deviceInfoData;
172 DWORD ndx;
173 gate_win32_setupapi_t const* const setupapi = gate_win32_setupapi();
174
175 do
176 {
177 if (!setupapi->SetupApiDiGetClassDevs)
178 {
179 ret = GATE_RESULT_NOTSUPPORTED;
180 break;
181 }
182
183 //gate_platform.SetupDiGetClassDevs()
184 hDevInfo = setupapi->SetupApiDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
185 if (INVALID_HANDLE_VALUE == hDevInfo)
186 {
187 ret = GATE_RESULT_FAILED;
188 break;
189 }
190
191 deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
192
193 for (ndx = 0; setupapi->SetupApiDiEnumDeviceInfo(hDevInfo, ndx, &deviceInfoData); ++ndx)
194 {
195 /*TODO*/
196 }
197
198 } while (0);
199
200 if (INVALID_HANDLE_VALUE != hDevInfo)
201 {
202 setupapi->SetupApiDiDestroyDeviceInfoList(hDevInfo);
203 }
204
205 return ret;
206 }
207
208 gate_result_t gate_device_entries_enum(unsigned entry_source, gate_device_entry_callback_t callback, void* user_param)
209 {
210 switch (entry_source)
211 {
212 case GATE_DEVICE_ENTRY_SOURCE_OS: return gate_win32_device_entries_enum(callback, user_param);
213 case GATE_DEVICE_ENTRY_SOURCE_HARDWARE: return GATE_RESULT_NOTSUPPORTED;
214 default: return GATE_RESULT_INVALIDARG;
215 }
216 }
217
218 gate_result_t gate_device_bth_enum(gate_device_bth_enum_callback callback, void* param)
219 {
220 gate_result_t ret = GATE_RESULT_OK;
221 HANDLE hfind;
222 GATE_BLUETOOTH_DEVICE_SEARCH_PARAMS btdsp;
223 GATE_BLUETOOTH_DEVICE_INFO btdi;
224 gate_device_bth_t device;
225
226 if (!load_bth_functions())
227 {
228 return GATE_RESULT_NOTSUPPORTED;
229 }
230
231 btdsp.dwSize = sizeof(btdsp);
232 btdsp.fReturnAuthenticated = TRUE;
233 btdsp.fReturnRemembered = TRUE;
234 btdsp.fReturnUnknown = TRUE;
235 btdsp.fReturnConnected = TRUE;
236 btdsp.fIssueInquiry = FALSE;
237 btdsp.cTimeoutMultiplier = 0;
238 btdsp.hRadio = NULL;
239
240 btdi.dwSize = sizeof(btdi);
241 do
242 {
243
244 hfind = gate_bth.Win32BluetoothFindFirstDevice(&btdsp, &btdi);
245 if (hfind == NULL)
246 {
247 ret = GATE_RESULT_FAILED;
248 break;
249 }
250 do
251 {
252 gate_str_print_hex_byte(&device.address[0], 2, btdi.Address.rgBytes[0], true);
253 device.address[2] = '-';
254 gate_str_print_hex_byte(&device.address[3], 2, btdi.Address.rgBytes[1], true);
255 device.address[5] = '-';
256 gate_str_print_hex_byte(&device.address[6], 2, btdi.Address.rgBytes[2], true);
257 device.address[8] = '-';
258 gate_str_print_hex_byte(&device.address[9], 2, btdi.Address.rgBytes[3], true);
259 device.address[11] = '-';
260 gate_str_print_hex_byte(&device.address[12], 2, btdi.Address.rgBytes[4], true);
261 device.address[14] = '-';
262 gate_str_print_hex_byte(&device.address[15], 2, btdi.Address.rgBytes[5], true);
263 device.address[17] = '\0';
264
265 gate_str_utf16_2_utf8(btdi.szName, gate_str16_length(btdi.szName), device.name, sizeof(device.name));
266
267 device.device_class = btdi.ulClassofDevice;
268 device.connected = btdi.fConnected;
269 device.authenticated = btdi.fAuthenticated;
270 device.last_seen = 0;
271 device.last_used = 0;
272
273 if (callback != NULL)
274 {
275 if (!callback(&device, param))
276 {
277 break;
278 }
279 }
280
281 } while (gate_bth.Win32BluetoothFindNextDevice(hfind, &btdi));
282
283 } while (0);
284
285 if (hfind != NULL)
286 {
287 gate_bth.Win32BluetoothFindDeviceClose(hfind);
288 }
289
290 return ret;
291 }
292
293
294 struct gate_bthledevice_enum_struct
295 {
296 gate_result_t result;
297 gate_device_bthle_enum_callback_t callback;
298 void* userparam;
299 };
300
301 #ifndef BLUETOOTH_GATT_FLAG_NONE
302 #define BLUETOOTH_GATT_FLAG_NONE 0x00000000
303 #endif
304
305 #ifndef BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED
306 #define BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED 0x00000001
307 #endif
308
309 #ifndef BLUETOOTH_GATT_FLAG_CONNECTION_AUTHENTICATED
310 #define BLUETOOTH_GATT_FLAG_CONNECTION_AUTHENTICATED 0x00000002
311 #endif
312
313 #ifndef BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE
314 #define BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE 0x00000004
315 #endif
316
317 #ifndef BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE
318 #define BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE 0x00000008
319 #endif
320
321 #ifndef BLUETOOTH_GATT_FLAG_SIGNED_WRITE
322 #define BLUETOOTH_GATT_FLAG_SIGNED_WRITE 0x00000010
323 #endif
324
325 #ifndef BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE
326 #define BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE 0x00000020
327 #endif
328
329 #ifndef BLUETOOTH_GATT_FLAG_RETURN_ALL
330 #define BLUETOOTH_GATT_FLAG_RETURN_ALL 0x00000040
331 #endif
332
333
334 static gate_bool_t gate_win32_gate_bthle_device(LPCTSTR device_path, LPCTSTR friendly_name, void* user_param)
335 {
336 struct gate_bthledevice_enum_struct* param = (struct gate_bthledevice_enum_struct*)user_param;
337 gate_bool_t ret = true;
338 gate_device_bthle_t bthle_device;
339 gate_size_t len;
340 gate_size_t pos;
341 HANDLE hfile = INVALID_HANDLE_VALUE;
342 GATE_BTH_LE_GATT_SERVICE services[256];
343 USHORT servicecount = 0;
344 HRESULT hres;
345 USHORT ndx;
346
347 gate_mem_clear(&bthle_device, sizeof(bthle_device));
348
349 do
350 {
351 gate_win32_winstr_2_utf8(friendly_name, gate_win32_winstr_length(friendly_name), bthle_device.name, sizeof(bthle_device.name));
352
353 len = gate_win32_winstr_length(device_path);
354 gate_win32_winstr_2_utf8(device_path, len, bthle_device.uid, sizeof(bthle_device.uid));
355 pos = gate_win32_winstr_char_pos_last(device_path, len, '#');
356 if (GATE_STR_NPOS != pos)
357 {
358 len = pos;
359 pos = gate_win32_winstr_char_pos_last(device_path, len, '&');
360 if (GATE_STR_NPOS != pos)
361 {
362 gate_win32_winstr_2_utf8(&device_path[pos + 1], len - pos - 1, bthle_device.address, sizeof(bthle_device.address));
363 }
364 }
365
366 if (gate_bth.Win32BluetoothGATTGetServices != NULL)
367 {
368 hfile = gate_win32_createfile(device_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
369 OPEN_EXISTING, 0, 0, NULL);
370 if (hfile != INVALID_HANDLE_VALUE)
371 {
372 //hres = gate_bth.Win32BluetoothGATTGetIncludedServices(hfile, NULL, sizeof(services) / sizeof(services[0]), services, &servicecount, BLUETOOTH_GATT_FLAG_NONE);
373 hres = gate_bth.Win32BluetoothGATTGetServices(hfile, sizeof(services) / sizeof(services[0]), services, &servicecount, BLUETOOTH_GATT_FLAG_NONE);
374 if (servicecount > sizeof(bthle_device.services) / sizeof(bthle_device.services[0]))
375 {
376 servicecount = sizeof(bthle_device.services) / sizeof(bthle_device.services[0]);
377 }
378 for (ndx = 0; ndx != servicecount; ++ndx)
379 {
380 gate_win32_winguid_to_guid(&services[ndx].ServiceUuid.Value.LongUuid, &bthle_device.services[ndx].service_guid);
381 bthle_device.services[ndx].attribute_handle = services[ndx].AttributeHandle;
382 }
383 bthle_device.service_count = servicecount;
384 }
385 }
386
387 if (param->callback != NULL)
388 {
389 ret = param->callback(&bthle_device, param->userparam);
390 }
391 } while (0);
392
393 if (hfile != INVALID_HANDLE_VALUE)
394 {
395 CloseHandle(hfile);
396 }
397
398 return ret;
399 }
400
401 gate_result_t gate_device_bthle_enum(gate_device_bthle_enum_callback_t callback, void* userparam)
402 {
403 /* GUID_BTHPORT_DEVICE_INTERFACE */
404 /*static GUID const BlueToothInterfaceGuid = { 0x0850302A, 0xB344, 0x4fda, 0x9B, 0xE9, 0x90, 0x57, 0x6B, 0x8D, 0x46, 0xF0 };*/
405
406 /* GUID_BTH_DEVICE_INTERFACE: {00F40965-E89D-4487-9890-87C3ABB211F4} */
407 /*static GUID const BlueToothInterfaceGuid = { 0x00F40965, 0xE89D, 0x4487, 0x98, 0x90, 0x87, 0xC3, 0xAB, 0xB2, 0x11, 0xF4 };*/
408
409 /* GUID_BLUETOOTHLE_DEVICE_INTERFACE {781aee18-7733-4ce4-add0-91f41c67b592} */
410 static GUID const BlueToothInterfaceGuid = { 0x781aee18, 0x7733, 0x4ce4, 0xad, 0xd0, 0x91, 0xf4, 0x1c, 0x67, 0xb5, 0x92 };
411
412 /* GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE {6e3bb679-4372-40c8-9eaa-4509df260cd8} */
413 /* static GUID const BlueToothInterfaceGuid = { 0x6e3bb679, 0x4372, 0x40c8, 0x9e, 0xaa, 0x45, 0x09, 0xdf, 0x26, 0x0c, 0xd8 }; */
414
415 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
416 struct gate_bthledevice_enum_struct bthleparam;
417
418 if (!load_bth_functions())
419 {
420 return GATE_RESULT_NOTSUPPORTED;
421 }
422
423 bthleparam.result = GATE_RESULT_OK;
424 bthleparam.callback = callback;
425 bthleparam.userparam = userparam;
426
427 ret = gate_win32_device_enum(&BlueToothInterfaceGuid, &gate_win32_gate_bthle_device, &bthleparam);
428
429 if (GATE_SUCCEEDED(ret))
430 {
431 ret = bthleparam.result;
432 }
433
434 return ret;
435 }
436
437 union gate_bthledevice_characteristic_impl
438 {
439 gate_device_bthle_characteristic_t charabase;
440 char buffer[4096];
441 };
442
443 union GATE_BTH_LE_GATT_CHARACTERISTIC_VALUE_IMPL
444 {
445 GATE_BTH_LE_GATT_CHARACTERISTIC_VALUE value;
446 char data[2048];
447 };
448
449 static void CALLBACK gate_device_bthle_service_event_cb(GATE_BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)
450 {
451 GATE_DEBUG_BREAKPOINT;
452 }
453
454
455 struct bthl_svc_param
456 {
457 TCHAR device_address[32];
458 TCHAR service_path[1024];
459 HANDLE handle;
460 };
461
462 static gate_bool_t gate_device_bthle_service_enum_cb(LPCTSTR device_path, LPCTSTR friendly_name, void* user_param)
463 {
464 struct bthl_svc_param* param = (struct bthl_svc_param*)user_param;
465 gate_size_t pos = gate_win32_winstr_pos(device_path, gate_win32_winstr_length(device_path), param->device_address, gate_win32_winstr_length(param->device_address), 0);
466 if (pos != GATE_STR_NPOS)
467 {
468 do
469 {
470 /* MAC address is part of service path -> we have found the right entry */
471 param->handle = gate_win32_createfile(device_path, GENERIC_READ | GENERIC_WRITE, 0,
472 OPEN_EXISTING, 0, 0, NULL);
473 if (INVALID_HANDLE_VALUE != param->handle)
474 {
475 break;
476 }
477
478 param->handle = gate_win32_createfile(device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
479 OPEN_EXISTING, 0, 0, NULL);
480 if (INVALID_HANDLE_VALUE != param->handle)
481 {
482 break;
483 }
484
485 param->handle = gate_win32_createfile(device_path, GENERIC_READ, FILE_SHARE_READ,
486 OPEN_EXISTING, 0, 0, NULL);
487 if (INVALID_HANDLE_VALUE != param->handle)
488 {
489 break;
490 }
491
492 } while (0);
493
494 if (INVALID_HANDLE_VALUE != param->handle)
495 {
496 /* SUCCESS: cancel further iteration */
497 return false;
498 }
499
500 }
501
502 /* continue further iteration */
503 return true;
504 }
505
506 static gate_result_t bthle_resolve_service(gate_device_bthle_t const* device,
507 gate_guid_t const* service_guid,
508 GATE_BTH_LE_GATT_SERVICE* ptr_svc,
509 HANDLE* ptr_handle)
510 {
511 gate_size_t n;
512 struct bthl_svc_param service_enum_param;
513 GUID win_service_guid;
514
515 service_enum_param.handle = INVALID_HANDLE_VALUE;
516
517 gate_win32_utf8_2_winstr(device->address, gate_str_length(device->address),
518 service_enum_param.device_address,
519 sizeof(service_enum_param.device_address) / sizeof(service_enum_param.device_address[0])
520 );
521 gate_win32_guid_to_winguid(service_guid, &win_service_guid);
522 if ((win_service_guid.Data2 == 0) && (win_service_guid.Data3 == 0))
523 {
524 /* simple GUID / SHORT-UID -> patch with default suffix "...-0000-1000-8000-00805f9b34fb" */
525 win_service_guid.Data3 = 0x1000;
526 win_service_guid.Data4[0] = 0x80;
527 win_service_guid.Data4[1] = 0x00;
528 win_service_guid.Data4[2] = 0x00;
529 win_service_guid.Data4[3] = 0x80;
530 win_service_guid.Data4[4] = 0x5f;
531 win_service_guid.Data4[5] = 0x9b;
532 win_service_guid.Data4[6] = 0x34;
533 win_service_guid.Data4[7] = 0xfb;
534 }
535 gate_win32_device_enum(&win_service_guid, &gate_device_bthle_service_enum_cb, &service_enum_param);
536
537 if (service_enum_param.handle == INVALID_HANDLE_VALUE)
538 {
539 return GATE_RESULT_NOTAVAILABLE;
540 }
541
542 //ptr_svc->AttributeHandle = service->attribute_handle;
543 gate_win32_guid_to_winguid(service_guid, &ptr_svc->ServiceUuid.Value.LongUuid);
544 ptr_svc->ServiceUuid.IsShortUuid = (ptr_svc->ServiceUuid.Value.LongUuid.Data2 == 0) && (ptr_svc->ServiceUuid.Value.LongUuid.Data3 == 0)
545 ? TRUE
546 : FALSE;
547
548 *ptr_handle = service_enum_param.handle;
549
550 for (n = 0; n != device->service_count; ++n)
551 {
552 if (gate_guid_equals(service_guid, &device->services[n].service_guid))
553 {
554 ptr_svc->AttributeHandle = device->services[n].attribute_handle;
555 return GATE_RESULT_OK;
556 }
557 }
558 return GATE_RESULT_NOMATCH;
559 }
560
561
562 static gate_result_t bthle_build_characteristic(HANDLE svc_handle, GATE_BTH_LE_GATT_CHARACTERISTIC* src,
563 union gate_bthledevice_characteristic_impl* dst)
564 {
565 gate_result_t ret = GATE_RESULT_FAILED;
566 GATE_BLUETOOTH_GATT_EVENT_HANDLE event_handle = NULL;
567 GATE_BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION event_parameter_in;
568 GATE_BTH_LE_GATT_EVENT_TYPE event_type = Gate_CharacteristicValueChangedEvent;
569 union GATE_BTH_LE_GATT_CHARACTERISTIC_VALUE_IMPL characteristic_value;
570 USHORT value_length = 0;
571 HRESULT hr;
572
573 gate_mem_clear(dst, sizeof(gate_device_bthle_characteristic_t));
574
575 do
576 {
577 /*
578 descriptorcount = sizeof(descriptors) / sizeof(descriptors[0]);
579 hr = gate_bth.Win32BluetoothGATTGetDescriptors(hfile, &charas[ndx], descriptorcount, &descriptors[0], &descriptorcount, 0);
580
581 if(SUCCEEDED(hr))
582 {
583 for(descr_ndx = 0; descr_ndx != descriptorcount; ++descr_ndx)
584 {
585 hr = gate_bth.Win32BluetoothGATTGetDescriptorValue(hfile, &descriptors[descr_ndx],
586 sizeof(buffer), ptr_descr_value, NULL, BLUETOOTH_GATT_FLAG_NONE);
587 if(SUCCEEDED(hr))
588 {
589 }
590 }
591 }
592 */
593
594 if (src->IsNotifiable)
595 {
596 event_parameter_in.NumCharacteristics = 1;
597 event_parameter_in.Characteristics[0] = *src;
598
599 hr = gate_bth.Win32BluetoothGATTRegisterEvent(svc_handle, event_type, &event_parameter_in,
600 (PGATE_FNBLUETOOTH_GATT_EVENT_CALLBACK)&gate_device_bthle_service_event_cb, NULL, &event_handle, BLUETOOTH_GATT_FLAG_NONE);
601 if (FAILED(hr))
602 {
603 break;
604 }
605 }
606
607 if (src->IsReadable)
608 {
609 gate_win32_winguid_to_guid(&src->CharacteristicUuid.Value.LongUuid, &dst->charabase.characteristic_guid);
610
611 hr = gate_bth.Win32BluetoothGATTGetCharacteristicValue(svc_handle, src, 0, NULL, &value_length,
612 BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE);
613
614 characteristic_value.value.DataSize = sizeof(characteristic_value);
615
616 hr = gate_bth.Win32BluetoothGATTGetCharacteristicValue(svc_handle, src, sizeof(characteristic_value),
617 &characteristic_value.value, &value_length,
618 BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE);
619 if (FAILED(hr))
620 {
621 hr = gate_bth.Win32BluetoothGATTGetCharacteristicValue(svc_handle, src, sizeof(characteristic_value),
622 &characteristic_value.value, &value_length,
623 BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE);
624 }
625 if (FAILED(hr))
626 {
627 ret = GATE_RESULT_FAILED;
628 break;
629 }
630 dst->charabase.flags |= GATE_DEVICE_BTHLE_FLAG_READABLE;
631 dst->charabase.data_length = characteristic_value.value.DataSize;
632 if (dst->charabase.data_length > sizeof(dst->buffer) - sizeof(dst->charabase))
633 {
634 /* reduce size of data to internal buffer */
635 dst->charabase.data_length = sizeof(dst->buffer) - sizeof(dst->charabase);
636 }
637 if (dst->charabase.data_length > 0)
638 {
639 gate_mem_copy(&dst->charabase.data[0], &characteristic_value.value.Data[0], dst->charabase.data_length);
640 }
641 }
642
643 if (src->IsWritable || src->IsWritableWithoutResponse)
644 {
645 dst->charabase.flags |= GATE_DEVICE_BTHLE_FLAG_WRITABLE;
646 }
647
648 ret = GATE_RESULT_OK;
649
650 } while (0);
651
652 if (event_handle != NULL)
653 {
654 gate_bth.Win32BluetoothGATTUnregisterEvent(event_handle, BLUETOOTH_GATT_FLAG_NONE);
655 }
656
657 return ret;
658
659 }
660
661
662
663 gate_result_t gate_device_bthle_service_enum(gate_device_bthle_t const* device, gate_device_bthle_service_t const* service,
664 gate_device_bthle_service_enum_callback_t callback, void* user_param)
665 {
666 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
667 gate_result_t result;
668 GATE_BTH_LE_GATT_SERVICE svc;
669 HANDLE svc_handle = INVALID_HANDLE_VALUE;
670 GATE_BTH_LE_GATT_CHARACTERISTIC charas[128];
671 USHORT characount = sizeof(charas) / sizeof(charas[0]);
672 union gate_bthledevice_characteristic_impl gate_chara;
673 USHORT ndx;
674 HRESULT hr;
675
676 do
677 {
678 if (!load_bth_functions())
679 {
680 ret = GATE_RESULT_NOTSUPPORTED;
681 break;
682 }
683
684 ret = bthle_resolve_service(device, &service->service_guid, &svc, &svc_handle);
685 GATE_BREAK_IF_FAILED(ret);
686 hr = gate_bth.Win32BluetoothGATTGetCharacteristics(svc_handle, &svc, characount, &charas[0], &characount, BLUETOOTH_GATT_FLAG_NONE);
687 if (FAILED(hr))
688 {
689 ret = GATE_RESULT_FAILED;
690 break;
691 }
692
693 ret = GATE_RESULT_OK;
694
695 for (ndx = 0; ndx != characount; ++ndx)
696 {
697 gate_mem_clear(&gate_chara, sizeof(gate_chara));
698
699 result = bthle_build_characteristic(svc_handle, &charas[ndx], &gate_chara);
700 if (GATE_FAILED(result))
701 {
702 continue;
703 }
704
705 if (callback != NULL)
706 {
707 if (!callback(&gate_chara.charabase, user_param))
708 {
709 ret = GATE_RESULT_CANCELED;
710 break;
711 }
712 }
713 }
714 ret = GATE_RESULT_OK;
715 } while (0);
716
717 if (svc_handle != INVALID_HANDLE_VALUE)
718 {
719 CloseHandle(svc_handle);
720 }
721
722 return ret;
723 }
724
725
726 gate_result_t gate_device_bthle_characteristic_get(gate_device_bthle_t const* device,
727 gate_guid_t const* service_guid,
728 gate_guid_t const* characteristic_guid,
729 char* buffer,
730 gate_size_t* buffer_len)
731 {
732 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
733 gate_guid_t current_chara_guid;
734 GATE_BTH_LE_GATT_SERVICE svc;
735 HANDLE svc_handle = INVALID_HANDLE_VALUE;
736 GATE_BTH_LE_GATT_CHARACTERISTIC charas[128];
737 USHORT characount = sizeof(charas) / sizeof(charas[0]);
738 union gate_bthledevice_characteristic_impl gate_chara;
739 USHORT ndx;
740 HRESULT hr;
741
742 do
743 {
744 if (!load_bth_functions())
745 {
746 ret = GATE_RESULT_NOTSUPPORTED;
747 break;
748 }
749 if (!buffer_len)
750 {
751 ret = GATE_RESULT_INVALIDARG;
752 break;
753 }
754
755 ret = bthle_resolve_service(device, service_guid, &svc, &svc_handle);
756 GATE_BREAK_IF_FAILED(ret);
757
758 hr = gate_bth.Win32BluetoothGATTGetCharacteristics(svc_handle, &svc, characount, &charas[0], &characount, BLUETOOTH_GATT_FLAG_NONE);
759 if (FAILED(hr))
760 {
761 ret = GATE_RESULT_FAILED;
762 break;
763 }
764
765 ret = GATE_RESULT_NOMATCH;
766 for (ndx = 0; ndx != characount; ++ndx)
767 {
768 gate_win32_winguid_to_guid(&charas[ndx].CharacteristicUuid.Value.LongUuid, &current_chara_guid);
769 if (gate_guid_equals(&current_chara_guid, characteristic_guid))
770 {
771 gate_mem_clear(&gate_chara, sizeof(gate_chara));
772 ret = bthle_build_characteristic(svc_handle, &charas[ndx], &gate_chara);
773 GATE_BREAK_IF_FAILED(ret);
774
775 if (!buffer)
776 {
777 /* just return the size of the value */
778 *buffer_len = gate_chara.charabase.data_length;
779 }
780 else
781 {
782 if (*buffer_len > gate_chara.charabase.data_length)
783 {
784 *buffer_len = gate_chara.charabase.data_length;
785 }
786 if (*buffer_len > 0)
787 {
788 gate_mem_copy(buffer, gate_chara.charabase.data, *buffer_len);
789 }
790 }
791 break;
792 }
793 }
794 } while (0);
795
796 if (svc_handle != INVALID_HANDLE_VALUE)
797 {
798 CloseHandle(svc_handle);
799 }
800
801 return ret;
802 }
803
804 GATE_SYSTEM_API gate_result_t gate_device_bthle_characteristic_set(gate_device_bthle_t const* device,
805 gate_guid_t const* service_guid,
806 gate_guid_t const* characteristic_guid,
807 char const* buffer,
808 gate_size_t buffer_len)
809 {
810 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
811 gate_guid_t current_chara_guid;
812 GATE_BTH_LE_GATT_SERVICE svc;
813 HANDLE svc_handle = INVALID_HANDLE_VALUE;
814 GATE_BTH_LE_GATT_CHARACTERISTIC charas[128];
815 USHORT characount = sizeof(charas) / sizeof(charas[0]);
816 USHORT ndx;
817 HRESULT hr;
818 ULONG64 rel_context = 0;
819 union GATE_BTH_LE_GATT_CHARACTERISTIC_VALUE_IMPL value;
820
821 do
822 {
823 if (!load_bth_functions())
824 {
825 ret = GATE_RESULT_NOTSUPPORTED;
826 break;
827 }
828 if (!buffer_len)
829 {
830 ret = GATE_RESULT_INVALIDARG;
831 break;
832 }
833
834 if (buffer_len > (sizeof(value.data) - sizeof(value.value)))
835 {
836 ret = GATE_RESULT_BUFFERTOOSMALL;
837 break;
838 }
839
840 gate_mem_copy(&value.value.Data[0], buffer, buffer_len);
841 value.value.DataSize = (ULONG)buffer_len;
842
843 ret = bthle_resolve_service(device, service_guid, &svc, &svc_handle);
844 GATE_BREAK_IF_FAILED(ret);
845
846 hr = gate_bth.Win32BluetoothGATTGetCharacteristics(svc_handle, &svc, characount, &charas[0], &characount, BLUETOOTH_GATT_FLAG_NONE);
847 if (FAILED(hr))
848 {
849 ret = GATE_RESULT_FAILED;
850 break;
851 }
852
853 ret = GATE_RESULT_NOMATCH;
854 for (ndx = 0; ndx != characount; ++ndx)
855 {
856 gate_win32_winguid_to_guid(&charas[ndx].CharacteristicUuid.Value.LongUuid, &current_chara_guid);
857 if (gate_guid_equals(&current_chara_guid, characteristic_guid))
858 {
859 if (!charas[ndx].IsWritable)
860 {
861 ret = GATE_RESULT_ACCESSDENIED;
862 break;
863 }
864
865 hr = gate_bth.Win32BluetoothGATTSetCharacteristicValue(svc_handle, &charas[ndx], &value.value, rel_context, BLUETOOTH_GATT_FLAG_NONE);
866 if (FAILED(hr))
867 {
868 ret = GATE_RESULT_FAILED;
869 }
870 else
871 {
872 ret = GATE_RESULT_OK;
873 }
874 break;
875 }
876 }
877 } while (0);
878
879 if (svc_handle != INVALID_HANDLE_VALUE)
880 {
881 CloseHandle(svc_handle);
882 }
883
884 return ret;
885 }
886
887 #endif /* GATE_SYSTEM_DEVICES_WINAPI_IMPL */
888
889
890 #if defined(GATE_SYSTEM_DEVICES_DBUS_IMPL)
891
892 #include "gate/arrays.h"
893 #include "gate/utilities.h"
894
895 #include "gate/system/platform/linux_dbus_api.h"
896
897 gate_result_t gate_device_bth_enum(gate_device_bth_enum_callback callback, void* userparam)
898 {
899 gate_result_t ret;
900 gate_libdbus_t* dbus = NULL;
901
902 DBusError err;
903 DBusConnection* conn = NULL;
904 DBusMessage* msg = NULL;
905 DBusMessage* reply = NULL;
906 DBusMessageIter iter, dict_entry, iface_entry, prop_entry;
907 gate_bool_t continue_enum = true;
908
909 do
910 {
911 ret = gate_dbus_open_system_connection(&dbus, &conn);
912 GATE_BREAK_IF_FAILED(ret);
913
914 dbus->error_init(&err);
915 conn = dbus->bus_get(DBUS_BUS_SYSTEM, &err);
916 if (!conn)
917 {
918 ret = GATE_RESULT_FAILED;
919 break;
920 }
921
922 msg = dbus->message_new_method_call(
923 "org.bluez",
924 "/",
925 "org.freedesktop.DBus.ObjectManager",
926 "GetManagedObjects"
927 );
928 if (msg == NULL)
929 {
930 ret = GATE_RESULT_FAILED;
931 break;
932 }
933
934 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
935 if (!reply)
936 {
937 ret = GATE_RESULT_FAILED;
938 break;
939 }
940
941 if (!dbus->message_iter_init(reply, &iter))
942 {
943 ret = GATE_RESULT_FAILED;
944 break;
945 }
946
947 if (dbus->message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
948 {
949 ret = GATE_RESULT_INCORRECTTYPE;
950 break;
951 }
952
953 dbus->message_iter_recurse(&iter, &dict_entry);
954
955 while (continue_enum && (dbus->message_iter_get_arg_type(&dict_entry) == DBUS_TYPE_DICT_ENTRY))
956 {
957 DBusMessageIter object_path_iter, iface_array;
958 const char* object_path = NULL;
959
960 dbus->message_iter_recurse(&dict_entry, &object_path_iter);
961 dbus->message_iter_get_basic(&object_path_iter, &object_path);
962 dbus->message_iter_next(&object_path_iter);
963 dbus->message_iter_recurse(&object_path_iter, &iface_array);
964
965 while (continue_enum && (dbus->message_iter_get_arg_type(&iface_array) == DBUS_TYPE_DICT_ENTRY))
966 {
967 DBusMessageIter iface_dict;
968 char const* iface_name = NULL;
969
970 dbus->message_iter_recurse(&iface_array, &iface_dict);
971 dbus->message_iter_get_basic(&iface_dict, &iface_name);
972
973 if (gate_str_comp(iface_name, "org.bluez.Device1") == 0)
974 {
975 /* bluez.Device1 interface */
976 DBusMessageIter props;
977 gate_device_bth_t device;
978
979 dbus->message_iter_next(&iface_dict);
980 dbus->message_iter_recurse(&iface_dict, &props);
981
982 gate_mem_clear(&device, sizeof(device));
983 gate_str_print_text(device.uid, sizeof(device.uid), object_path, gate_str_length(object_path));
984
985 while (dbus->message_iter_get_arg_type(&props) == DBUS_TYPE_DICT_ENTRY)
986 {
987 DBusMessageIter prop, variant;
988 char const* prop_name = NULL;
989 DBusBasicValue value = GATE_INIT_EMPTY;
990
991 dbus->message_iter_recurse(&props, &prop);
992 dbus->message_iter_get_basic(&prop, &prop_name);
993
994 dbus->message_iter_next(&prop);
995 dbus->message_iter_recurse(&prop, &variant);
996
997 if (gate_str_comp(prop_name, "Name") == 0)
998 {
999 dbus->message_iter_get_basic(&variant, &value);
1000 gate_str_print_text(device.name, sizeof(device.name), value.str, gate_str_length(value.str));
1001 }
1002 else if (gate_str_comp(prop_name, "Alias") == 0)
1003 {
1004 dbus->message_iter_get_basic(&variant, &value);
1005 gate_str_print_text(device.name, sizeof(device.name), value.str, gate_str_length(value.str));
1006 }
1007 else if (gate_str_comp(prop_name, "Address") == 0)
1008 {
1009 dbus->message_iter_get_basic(&variant, &value);
1010 gate_str_print_text(device.address, sizeof(device.address), value.str, gate_str_length(value.str));
1011 }
1012 else if (gate_str_comp(prop_name, "Class") == 0)
1013 {
1014 dbus->message_iter_get_basic(&variant, &value);
1015 device.device_class = value.u32;
1016 }
1017 else if (gate_str_comp(prop_name, "Connected") == 0)
1018 {
1019 dbus->message_iter_get_basic(&variant, &value);
1020 device.connected = value.bool_val;
1021 }
1022 else if (gate_str_comp(prop_name, "Paired") == 0)
1023 {
1024 dbus->message_iter_get_basic(&variant, &value);
1025 device.authenticated = value.bool_val;
1026 }
1027 dbus->message_iter_next(&props);
1028 }
1029 continue_enum = callback(&device, userparam);
1030 }
1031 dbus->message_iter_next(&iface_array);
1032 }
1033 dbus->message_iter_next(&dict_entry);
1034 }
1035 ret = GATE_RESULT_OK;
1036 } while (0);
1037
1038 if (dbus != NULL)
1039 {
1040 if (reply) dbus->message_unref(reply);
1041 if (msg) dbus->message_unref(msg);
1042 if (conn) dbus->connection_unref(conn);
1043 dbus->error_free(&err);
1044 }
1045
1046 return ret;
1047 }
1048
1049
1050
1051 static char const* bthle_bus_name = "org.bluez";
1052 static char const* bthle_search_path = "/";
1053 static char const* bthle_search_iface = "org.freedesktop.DBus.ObjectManager";
1054 static char const* bthle_search_method = "GetManagedObjects";
1055 static char const* bthle_device_iface = "org.bluez.Device1";
1056 static char const* bthle_service_iface = "org.bluez.GattService1";
1057 static char const* bthle_prop_connected = "Connected";
1058 static char const* bthle_prop_address = "Address";
1059 static char const* bthle_prop_name = "Name";
1060
1061
1062 static gate_result_t bthle_list_devices(gate_libdbus_t* dbus, DBusConnection* conn,
1063 gate_arraylist_t device_paths_array)
1064 {
1065 gate_result_t ret = GATE_RESULT_FAILED;
1066 DBusError err = GATE_INIT_EMPTY;
1067 DBusMessage* msg = NULL;
1068 DBusMessage* reply = NULL;
1069 do
1070 {
1071 DBusMessageIter iter = GATE_INIT_EMPTY;
1072 DBusMessageIter array_iter = GATE_INIT_EMPTY;
1073
1074 dbus->error_init(&err);
1075 msg = dbus->message_new_method_call(bthle_bus_name, bthle_search_path, bthle_search_iface, bthle_search_method);
1076 if(msg == NULL)
1077 {
1078 ret = GATE_RESULT_FAILED;
1079 break;
1080 }
1081 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1082 if (dbus->error_is_set(&err))
1083 {
1084 ret = GATE_RESULT_EXECUTIONFAILED;
1085 break;
1086 }
1087
1088 dbus->message_iter_init(reply, &iter);
1089 dbus->message_iter_recurse(&iter, &array_iter);
1090
1091 for (;
1092 dbus->message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID;
1093 dbus->message_iter_next(&array_iter))
1094 {
1095 DBusMessageIter dict_entry_iter = GATE_INIT_EMPTY;
1096 DBusMessageIter iface_array_iter = GATE_INIT_EMPTY;
1097 DBusBasicValue object_path_value = GATE_INIT_EMPTY;
1098
1099 dbus->message_iter_recurse(&array_iter, &dict_entry_iter);
1100 dbus->message_iter_get_basic(&dict_entry_iter, &object_path_value);
1101
1102 /* requested object found: */
1103 dbus->message_iter_next(&dict_entry_iter);
1104 dbus->message_iter_recurse(&dict_entry_iter, &iface_array_iter);
1105
1106 for(;
1107 dbus->message_iter_get_arg_type(&iface_array_iter) != DBUS_TYPE_INVALID;
1108 dbus->message_iter_next(&iface_array_iter))
1109 {
1110 DBusMessageIter iface_entry_iter;
1111 DBusBasicValue iface_name_value;
1112
1113 dbus->message_iter_recurse(&iface_array_iter, &iface_entry_iter);
1114 dbus->message_iter_get_basic(&iface_entry_iter, &iface_name_value);
1115
1116 if (gate_str_comp(iface_name_value.str, bthle_device_iface) == 0)
1117 {
1118 /* a Device1 interface found */
1119 gate_string_t device_path;
1120 if (NULL != gate_string_create(&device_path, object_path_value.str, gate_str_length(object_path_value.str)))
1121 {
1122 gate_arraylist_add(device_paths_array, &device_path);
1123 gate_string_release(&device_path);
1124 }
1125 }
1126 } /* for(each value in object) */
1127 } /* for(each object in "bluez")*/
1128 ret = GATE_RESULT_OK;
1129 } while (0);
1130
1131 if (reply != NULL)
1132 {
1133 dbus->message_unref(reply);
1134 }
1135 if (msg != NULL)
1136 {
1137 dbus->message_unref(msg);
1138 }
1139
1140 dbus->error_free(&err);
1141 return ret;
1142 }
1143
1144
1145 static gate_result_t bthle_list_services(gate_libdbus_t* dbus, DBusConnection* conn,
1146 gate_string_t const* bth_path, gate_arraylist_t service_paths_array)
1147 {
1148 gate_result_t ret = GATE_RESULT_FAILED;
1149 DBusError err = GATE_INIT_EMPTY;
1150 DBusMessage* msg = NULL;
1151 DBusMessage* reply = NULL;
1152 do
1153 {
1154 DBusMessageIter iter = GATE_INIT_EMPTY;
1155 DBusMessageIter array_iter = GATE_INIT_EMPTY;
1156
1157 dbus->error_init(&err);
1158 msg = dbus->message_new_method_call(bthle_bus_name, bthle_search_path, bthle_search_iface, bthle_search_method);
1159 if(msg == NULL)
1160 {
1161 ret = GATE_RESULT_FAILED;
1162 break;
1163 }
1164 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1165 if (dbus->error_is_set(&err))
1166 {
1167 ret = GATE_RESULT_EXECUTIONFAILED;
1168 break;
1169 }
1170
1171 dbus->message_iter_init(reply, &iter);
1172 dbus->message_iter_recurse(&iter, &array_iter);
1173
1174 for (;
1175 dbus->message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID;
1176 dbus->message_iter_next(&array_iter))
1177 {
1178 DBusMessageIter dict_entry_iter = GATE_INIT_EMPTY;
1179 DBusMessageIter iface_array_iter = GATE_INIT_EMPTY;
1180 DBusBasicValue object_path_value = GATE_INIT_EMPTY;
1181
1182 dbus->message_iter_recurse(&array_iter, &dict_entry_iter);
1183 dbus->message_iter_get_basic(&dict_entry_iter, &object_path_value);
1184
1185 if (!gate_string_equals_str(bth_path, object_path_value.str))
1186 {
1187 /* object is not the requested one */
1188 continue;
1189 }
1190 /* requested object found: */
1191 dbus->message_iter_next(&dict_entry_iter);
1192 dbus->message_iter_recurse(&dict_entry_iter, &iface_array_iter);
1193
1194 for(;
1195 dbus->message_iter_get_arg_type(&iface_array_iter) != DBUS_TYPE_INVALID;
1196 dbus->message_iter_next(&iface_array_iter))
1197 {
1198 DBusMessageIter iface_entry_iter;
1199 DBusBasicValue iface_name_value;
1200
1201 dbus->message_iter_recurse(&iface_array_iter, &iface_entry_iter);
1202 dbus->message_iter_get_basic(&iface_entry_iter, &iface_name_value);
1203
1204 if (gate_str_comp(iface_name_value.str, bthle_service_iface) == 0)
1205 {
1206 /* a GATT service path was found */
1207 gate_string_t service_path;
1208 if (NULL != gate_string_create(&service_path, object_path_value.str, gate_str_length(object_path_value.str)))
1209 {
1210 gate_arraylist_add(service_paths_array, &service_path);
1211 gate_string_release(&service_path);
1212 }
1213 }
1214 } /* for(each value in object) */
1215 } /* for(each object in "bluez")*/
1216 ret = GATE_RESULT_OK;
1217 } while (0);
1218
1219 if (reply != NULL)
1220 {
1221 dbus->message_unref(reply);
1222 }
1223 if (msg != NULL)
1224 {
1225 dbus->message_unref(msg);
1226 }
1227
1228 dbus->error_free(&err);
1229 return ret;
1230 }
1231
1232
1233
1234 static gate_result_t bthle_read_characteristic_bytes(gate_libdbus_t* dbus, DBusConnection* conn,
1235 gate_string_t const* bth_path, gate_arraylist_t bytearray)
1236 {
1237 gate_result_t ret = GATE_RESULT_FAILED;
1238 gate_cstrbuffer_t path = GATE_INIT_EMPTY;
1239 DBusMessage* msg = NULL;
1240 DBusMessage* reply = NULL;
1241 DBusError err;
1242
1243 if (NULL == gate_cstrbuffer_create_string(&path, bth_path, false))
1244 {
1245 return GATE_RESULT_OUTOFMEMORY;
1246 }
1247
1248 do
1249 {
1250 DBusMessageIter args_iter;
1251 DBusMessageIter sub_array_iter;
1252 DBusMessageIter sub_dict_iter;
1253
1254 dbus->error_init(&err);
1255 msg = dbus->message_new_method_call(
1256 "org.bluez",
1257 gate_cstrbuffer_get(&path),
1258 "org.bluez.GattCharacteristic1",
1259 "ReadValue");
1260
1261 if (NULL == msg)
1262 {
1263 GATE_DEBUG_TRACE("dbus_message_new_method_call() failed");
1264 ret = GATE_RESULT_FAILED;
1265 break;
1266 }
1267
1268 dbus->message_iter_init_append(msg, &args_iter);
1269 dbus->message_iter_open_container(&args_iter, DBUS_TYPE_ARRAY, "{sv}", &sub_array_iter);
1270 dbus->message_iter_close_container(&args_iter, &sub_dict_iter);
1271
1272 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1273 if (dbus->error_is_set(&err))
1274 {
1275 ret = GATE_RESULT_EXECUTIONFAILED;
1276 break;
1277 }
1278 /* parse reply */
1279 dbus->message_iter_init(reply, &args_iter);
1280 if (dbus->message_iter_get_arg_type(&args_iter) != DBUS_TYPE_ARRAY)
1281 {
1282 ret = GATE_RESULT_INCORRECTTYPE;
1283 break;
1284 }
1285
1286 dbus->message_iter_recurse(&args_iter, &sub_array_iter);
1287
1288 while (dbus->message_iter_get_arg_type(&sub_array_iter) == DBUS_TYPE_BYTE)
1289 {
1290 gate_uint8_t b = 0;
1291 dbus->message_iter_get_basic(&sub_array_iter, &b);
1292 gate_arraylist_add(bytearray, &b);
1293 dbus->message_iter_next(&sub_array_iter);
1294 }
1295 ret = GATE_RESULT_OK;
1296 } while (0);
1297
1298 dbus->error_free(&err);
1299 if (NULL != reply)
1300 {
1301 dbus->message_unref(reply);
1302 }
1303 if (NULL != msg)
1304 {
1305 dbus->message_unref(msg);
1306 }
1307 gate_cstrbuffer_destroy(&path);
1308 return ret;
1309 }
1310
1311 static gate_result_t bthle_write_characteristic_bytes(gate_libdbus_t* dbus, DBusConnection* conn,
1312 gate_string_t const* bth_path, gate_uint8_t const* bytes, gate_size_t bytes_count)
1313 {
1314 gate_result_t ret = GATE_RESULT_FAILED;
1315 gate_cstrbuffer_t path = GATE_INIT_EMPTY;
1316 DBusMessage* msg = NULL;
1317
1318 if (NULL == gate_cstrbuffer_create_string(&path, bth_path, false))
1319 {
1320 return GATE_RESULT_OUTOFMEMORY;
1321 }
1322
1323 do
1324 {
1325 gate_size_t ndx;
1326 DBusMessageIter args;
1327 DBusMessageIter sub_array_iter;
1328 DBusMessageIter sub_dict_iter;
1329 DBusMessage* reply;
1330 DBusError err;
1331
1332 msg = dbus->message_new_method_call(
1333 "org.bluez",
1334 gate_cstrbuffer_get(&path),
1335 "org.bluez.GattCharacteristic1",
1336 "WriteValue");
1337
1338 if (NULL == msg)
1339 {
1340 GATE_DEBUG_TRACE("dbus_message_new_method_call() failed");
1341 ret = GATE_RESULT_FAILED;
1342 break;
1343 }
1344
1345 dbus->message_iter_init_append(msg, &args);
1346
1347 dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "y", &sub_array_iter);
1348 while(bytes_count-- > 0)
1349 {
1350 dbus->message_iter_append_basic(&sub_array_iter, DBUS_TYPE_BYTE, bytes);
1351 ++bytes;
1352 }
1353 dbus->message_iter_close_container(&args, &sub_array_iter);
1354
1355 dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &sub_dict_iter);
1356 dbus->message_iter_close_container(&args, &sub_dict_iter);
1357
1358 dbus->error_init(&err);
1359 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1360 ret = dbus->error_is_set(&err) ? GATE_RESULT_EXECUTIONFAILED : GATE_RESULT_OK;
1361 dbus->error_free(&err);
1362 if (reply != NULL)
1363 {
1364 dbus->message_unref(reply);
1365 }
1366 } while (0);
1367
1368 if (msg != NULL)
1369 {
1370 dbus->message_unref(msg);
1371 }
1372
1373 gate_cstrbuffer_destroy(&path);
1374 return ret;
1375 }
1376
1377
1378
1379 gate_result_t gate_device_bthle_enum(gate_device_bthle_enum_callback_t callback, void* userparam)
1380 {
1381 gate_result_t ret;
1382 gate_libdbus_t* dbus = NULL;
1383 DBusConnection* conn = NULL;
1384 gate_arraylist_t paths = NULL;
1385
1386 do
1387 {
1388 ret = gate_dbus_open_system_connection(&dbus, &conn);
1389 GATE_BREAK_IF_FAILED(ret);
1390
1391 paths = gate_util_stringarray_create();
1392 if (paths == NULL)
1393 {
1394 ret = GATE_RESULT_OUTOFMEMORY;
1395 break;
1396 }
1397
1398 ret = bthle_list_devices(dbus, conn, paths);
1399 GATE_BREAK_IF_FAILED(ret);
1400
1401 /* TODO */
1402
1403 } while (0);
1404
1405 gate_arraylist_release(paths);
1406
1407 if (conn != NULL)
1408 {
1409 dbus->connection_unref(conn);
1410 }
1411 return ret;
1412 }
1413
1414 gate_result_t gate_device_bthle_service_enum(gate_device_bthle_t const* device,
1415 gate_device_bthle_service_t const* service,
1416 gate_device_bthle_service_enum_callback_t callback, void* userparam)
1417 {
1418 (void)device;
1419 (void)service;
1420 (void)callback;
1421 (void)userparam;
1422 return GATE_RESULT_NOTIMPLEMENTED;
1423 }
1424
1425 gate_result_t gate_device_bthle_characteristic_get(gate_device_bthle_t const* device,
1426 gate_guid_t const* service_guid,
1427 gate_guid_t const* characteristic_guid,
1428 char* buffer,
1429 gate_size_t* buffer_len)
1430 {
1431 (void)device;
1432 (void)service_guid;
1433 (void)characteristic_guid;
1434 (void)buffer;
1435 (void)buffer_len;
1436 return GATE_RESULT_NOTIMPLEMENTED;
1437 }
1438
1439 gate_result_t gate_device_bthle_characteristic_set(gate_device_bthle_t const* device,
1440 gate_guid_t const* service_guid,
1441 gate_guid_t const* characteristic_guid,
1442 char const* buffer,
1443 gate_size_t buffer_len)
1444 {
1445 (void)device;
1446 (void)service_guid;
1447 (void)characteristic_guid;
1448 (void)buffer;
1449 (void)buffer_len;
1450 return GATE_RESULT_NOTIMPLEMENTED;
1451 }
1452
1453 #endif /* GATE_SYSTEM_DEVICES_DBUS_IMPL */
1454
1455
1456
1457 #if defined(GATE_SYSTEM_DEVICES_NO_IMPL)
1458
1459
1460 gate_result_t gate_device_bth_enum(gate_device_bth_enum_callback callback, void* userparam)
1461 {
1462 (void)callback;
1463 (void)userparam;
1464 return GATE_RESULT_NOTIMPLEMENTED;
1465 }
1466
1467 gate_result_t gate_device_bthle_enum(gate_device_bthle_enum_callback_t callback, void* userparam)
1468 {
1469 (void)callback;
1470 (void)userparam;
1471 return GATE_RESULT_NOTIMPLEMENTED;
1472 }
1473
1474 gate_result_t gate_device_bthle_service_enum(gate_device_bthle_t const* device,
1475 gate_device_bthle_service_t const* service,
1476 gate_device_bthle_service_enum_callback_t callback, void* userparam)
1477 {
1478 (void)device;
1479 (void)service;
1480 (void)callback;
1481 (void)userparam;
1482 return GATE_RESULT_NOTIMPLEMENTED;
1483 }
1484
1485 gate_result_t gate_device_bthle_characteristic_get(gate_device_bthle_t const* device,
1486 gate_guid_t const* service_guid,
1487 gate_guid_t const* characteristic_guid,
1488 char* buffer,
1489 gate_size_t* buffer_len)
1490 {
1491 (void)device;
1492 (void)service_guid;
1493 (void)characteristic_guid;
1494 (void)buffer;
1495 (void)buffer_len;
1496 return GATE_RESULT_NOTIMPLEMENTED;
1497 }
1498
1499 gate_result_t gate_device_bthle_characteristic_set(gate_device_bthle_t const* device,
1500 gate_guid_t const* service_guid,
1501 gate_guid_t const* characteristic_guid,
1502 char const* buffer,
1503 gate_size_t buffer_len)
1504 {
1505 (void)device;
1506 (void)service_guid;
1507 (void)characteristic_guid;
1508 (void)buffer;
1509 (void)buffer_len;
1510 return GATE_RESULT_NOTIMPLEMENTED;
1511 }
1512
1513
1514 #endif /* GATE_SYSTEM_DEVICES_NO_IMPL */
1515