GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/devices.c
Date: 2026-06-21 00:38:37
Exec Total Coverage
Lines: 0 618 0.0%
Functions: 0 21 0.0%
Branches: 0 290 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_chara_iface = "org.bluez.GattCharacteristic1";
1058 static char const* bthle_prop_connected = "Connected";
1059 static char const* bthle_prop_address = "Address";
1060 static char const* bthle_prop_name = "Name";
1061
1062
1063 static gate_result_t bthle_list_devices(gate_libdbus_t* dbus, DBusConnection* conn,
1064 gate_arraylist_t device_paths_array)
1065 {
1066 gate_result_t ret = GATE_RESULT_FAILED;
1067 DBusError err = GATE_INIT_EMPTY;
1068 DBusMessage* msg = NULL;
1069 DBusMessage* reply = NULL;
1070 do
1071 {
1072 DBusMessageIter iter = GATE_INIT_EMPTY;
1073 DBusMessageIter array_iter = GATE_INIT_EMPTY;
1074
1075 dbus->error_init(&err);
1076 msg = dbus->message_new_method_call(bthle_bus_name, bthle_search_path, bthle_search_iface, bthle_search_method);
1077 if(msg == NULL)
1078 {
1079 ret = GATE_RESULT_FAILED;
1080 break;
1081 }
1082 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1083 if (dbus->error_is_set(&err))
1084 {
1085 ret = GATE_RESULT_EXECUTIONFAILED;
1086 break;
1087 }
1088
1089 dbus->message_iter_init(reply, &iter);
1090 dbus->message_iter_recurse(&iter, &array_iter);
1091
1092 for (;
1093 dbus->message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID;
1094 dbus->message_iter_next(&array_iter))
1095 {
1096 DBusMessageIter dict_entry_iter = GATE_INIT_EMPTY;
1097 DBusMessageIter iface_array_iter = GATE_INIT_EMPTY;
1098 DBusBasicValue object_path_value = GATE_INIT_EMPTY;
1099
1100 dbus->message_iter_recurse(&array_iter, &dict_entry_iter);
1101 dbus->message_iter_get_basic(&dict_entry_iter, &object_path_value);
1102
1103 /* requested object found: */
1104 dbus->message_iter_next(&dict_entry_iter);
1105 dbus->message_iter_recurse(&dict_entry_iter, &iface_array_iter);
1106
1107 for(;
1108 dbus->message_iter_get_arg_type(&iface_array_iter) != DBUS_TYPE_INVALID;
1109 dbus->message_iter_next(&iface_array_iter))
1110 {
1111 DBusMessageIter iface_entry_iter;
1112 DBusBasicValue iface_name_value;
1113
1114 dbus->message_iter_recurse(&iface_array_iter, &iface_entry_iter);
1115 dbus->message_iter_get_basic(&iface_entry_iter, &iface_name_value);
1116
1117 if (gate_str_comp(iface_name_value.str, bthle_device_iface) == 0)
1118 {
1119 /* a Device1 interface found */
1120 gate_string_t device_path;
1121 if (NULL != gate_string_create(&device_path, object_path_value.str, gate_str_length(object_path_value.str)))
1122 {
1123 gate_arraylist_add(device_paths_array, &device_path);
1124 gate_string_release(&device_path);
1125 }
1126 }
1127 } /* for(each value in object) */
1128 } /* for(each object in "bluez")*/
1129 ret = GATE_RESULT_OK;
1130 } while (0);
1131
1132 if (reply != NULL)
1133 {
1134 dbus->message_unref(reply);
1135 }
1136 if (msg != NULL)
1137 {
1138 dbus->message_unref(msg);
1139 }
1140
1141 dbus->error_free(&err);
1142 return ret;
1143 }
1144
1145
1146 static gate_result_t bthle_list_services(gate_libdbus_t* dbus, DBusConnection* conn,
1147 gate_string_t const* bth_path, gate_arraylist_t service_paths_array)
1148 {
1149 gate_result_t ret = GATE_RESULT_FAILED;
1150 DBusError err = GATE_INIT_EMPTY;
1151 DBusMessage* msg = NULL;
1152 DBusMessage* reply = NULL;
1153 do
1154 {
1155 DBusMessageIter iter = GATE_INIT_EMPTY;
1156 DBusMessageIter array_iter = GATE_INIT_EMPTY;
1157
1158 dbus->error_init(&err);
1159 msg = dbus->message_new_method_call(bthle_bus_name, bthle_search_path, bthle_search_iface, bthle_search_method);
1160 if(msg == NULL)
1161 {
1162 ret = GATE_RESULT_FAILED;
1163 break;
1164 }
1165 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1166 if (dbus->error_is_set(&err))
1167 {
1168 ret = GATE_RESULT_EXECUTIONFAILED;
1169 break;
1170 }
1171
1172 dbus->message_iter_init(reply, &iter);
1173 dbus->message_iter_recurse(&iter, &array_iter);
1174
1175 for (;
1176 dbus->message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID;
1177 dbus->message_iter_next(&array_iter))
1178 {
1179 DBusMessageIter dict_entry_iter = GATE_INIT_EMPTY;
1180 DBusMessageIter iface_array_iter = GATE_INIT_EMPTY;
1181 DBusBasicValue object_path_value = GATE_INIT_EMPTY;
1182
1183 dbus->message_iter_recurse(&array_iter, &dict_entry_iter);
1184 dbus->message_iter_get_basic(&dict_entry_iter, &object_path_value);
1185
1186 if (!gate_str_starts_with(object_path_value.str, gate_str_length(object_path_value.str), bth_path->str, bth_path->length))
1187 {
1188 continue;
1189 }
1190
1191 /* requested object found: */
1192 dbus->message_iter_next(&dict_entry_iter); /* move to interface dict */
1193 dbus->message_iter_recurse(&dict_entry_iter, &iface_array_iter);
1194
1195 for(;
1196 dbus->message_iter_get_arg_type(&iface_array_iter) != DBUS_TYPE_INVALID;
1197 dbus->message_iter_next(&iface_array_iter))
1198 {
1199 DBusMessageIter iface_entry_iter;
1200 DBusBasicValue iface_name_value;
1201
1202 dbus->message_iter_recurse(&iface_array_iter, &iface_entry_iter);
1203 dbus->message_iter_get_basic(&iface_entry_iter, &iface_name_value);
1204
1205 if (gate_str_comp(iface_name_value.str, bthle_service_iface) == 0)
1206 {
1207 /* a GATT service path was found */
1208 gate_string_t service_path;
1209 if (NULL != gate_string_create(&service_path, object_path_value.str, gate_str_length(object_path_value.str)))
1210 {
1211 gate_arraylist_add(service_paths_array, &service_path);
1212 gate_string_release(&service_path);
1213 }
1214 }
1215 } /* for(each value in object) */
1216 } /* for(each object in "bluez")*/
1217 ret = GATE_RESULT_OK;
1218 } while (0);
1219
1220 if (reply != NULL)
1221 {
1222 dbus->message_unref(reply);
1223 }
1224 if (msg != NULL)
1225 {
1226 dbus->message_unref(msg);
1227 }
1228
1229 dbus->error_free(&err);
1230 return ret;
1231 }
1232
1233 static gate_result_t bthle_get_service_guid(gate_libdbus_t* dbus, DBusConnection* conn, char const* bth_service_path, gate_guid_t* ptr_guid)
1234 {
1235 gate_result_t result;
1236 gate_value_t val;
1237 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, bth_service_path, bthle_service_iface, "UUID", &val);
1238 GATE_RETURN_IF_FAILED(result);
1239
1240 if(gate_value_type(&val) != GATE_TYPE_STRING)
1241 {
1242 result = GATE_RESULT_INCORRECTTYPE;
1243 }
1244 else
1245 {
1246 gate_string_t const* const ptr_uuid = gate_value_get_ptr(&val);
1247 result = gate_guid_parse_string(ptr_uuid->str, ptr_uuid->length, ptr_guid);
1248 }
1249 gate_value_release(&val);
1250 return result;
1251 }
1252
1253 static gate_result_t bthle_get_service_handle(gate_libdbus_t* dbus, DBusConnection* conn, char const* bth_service_path, gate_uint16_t* ptr_handle)
1254 {
1255 gate_result_t result;
1256 gate_value_t val;
1257 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, bth_service_path, bthle_service_iface, "Handle", &val);
1258 GATE_RETURN_IF_FAILED(result);
1259
1260 if (gate_value_type(&val) != GATE_TYPE_UI16)
1261 {
1262 result = GATE_RESULT_INCORRECTTYPE;
1263 }
1264 else
1265 {
1266 gate_uint16_t const* ptr_handle_value = gate_value_get_ptr(&val);
1267 *ptr_handle = *ptr_handle_value;
1268 }
1269 gate_value_release(&val);
1270 return result;
1271 }
1272
1273 static gate_result_t bthle_get_characteristic_service(gate_libdbus_t* dbus, DBusConnection* conn, char const* bth_characteristic_path, gate_string_t* service_path)
1274 {
1275 gate_result_t result;
1276 gate_value_t val;
1277 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, bth_characteristic_path, bthle_chara_iface, "Service", &val);
1278 GATE_RETURN_IF_FAILED(result);
1279
1280 if(gate_value_type(&val) != GATE_TYPE_STRING)
1281 {
1282 result = GATE_RESULT_INCORRECTTYPE;
1283 }
1284 else
1285 {
1286 gate_string_t const* const ptr_uuid = gate_value_get_ptr(&val);
1287 if (NULL == gate_string_clone(service_path, ptr_uuid))
1288 {
1289 result = GATE_RESULT_OUTOFMEMORY;
1290 }
1291 }
1292 gate_value_release(&val);
1293 return result;
1294 }
1295
1296 static gate_result_t bthle_get_characteristic_guid(gate_libdbus_t* dbus, DBusConnection* conn, char const* bth_characteristic_path, gate_guid_t* guid)
1297 {
1298 gate_result_t result;
1299 gate_value_t val;
1300 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, bth_characteristic_path, bthle_chara_iface, "UUID", &val);
1301 GATE_RETURN_IF_FAILED(result);
1302
1303 if(gate_value_type(&val) != GATE_TYPE_STRING)
1304 {
1305 result = GATE_RESULT_INCORRECTTYPE;
1306 }
1307 else
1308 {
1309 gate_string_t const* const ptr_uuid = gate_value_get_ptr(&val);
1310 result = gate_guid_parse_string(ptr_uuid->str, ptr_uuid->length, guid);
1311 }
1312 gate_value_release(&val);
1313 return result;
1314 }
1315
1316
1317 static gate_result_t bthle_get_service_path(gate_libdbus_t* dbus, DBusConnection* conn,
1318 gate_string_t const* bth_path, gate_guid_t const* service_guid, gate_string_t* service_path)
1319 {
1320 gate_result_t ret = GATE_RESULT_FAILED;
1321 DBusError err = GATE_INIT_EMPTY;
1322 DBusMessage* msg = NULL;
1323 DBusMessage* reply = NULL;
1324 do
1325 {
1326 DBusMessageIter iter = GATE_INIT_EMPTY;
1327 DBusMessageIter array_iter = GATE_INIT_EMPTY;
1328
1329 dbus->error_init(&err);
1330 msg = dbus->message_new_method_call(bthle_bus_name, bthle_search_path, bthle_search_iface, bthle_search_method);
1331 if(msg == NULL)
1332 {
1333 ret = GATE_RESULT_FAILED;
1334 break;
1335 }
1336 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1337 if (dbus->error_is_set(&err))
1338 {
1339 ret = GATE_RESULT_EXECUTIONFAILED;
1340 break;
1341 }
1342
1343 dbus->message_iter_init(reply, &iter);
1344 dbus->message_iter_recurse(&iter, &array_iter);
1345
1346 ret = GATE_RESULT_NOMATCH;
1347 for (;
1348 dbus->message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID;
1349 dbus->message_iter_next(&array_iter))
1350 {
1351 DBusMessageIter dict_entry_iter = GATE_INIT_EMPTY;
1352 DBusMessageIter iface_array_iter = GATE_INIT_EMPTY;
1353 DBusBasicValue object_path_value = GATE_INIT_EMPTY;
1354
1355 dbus->message_iter_recurse(&array_iter, &dict_entry_iter);
1356 dbus->message_iter_get_basic(&dict_entry_iter, &object_path_value);
1357
1358 if (!gate_str_starts_with(object_path_value.str, gate_str_length(object_path_value.str), bth_path->str, bth_path->length))
1359 {
1360 continue;
1361 }
1362
1363 /* requested object found: */
1364 dbus->message_iter_next(&dict_entry_iter); /* move to interface dict */
1365 dbus->message_iter_recurse(&dict_entry_iter, &iface_array_iter);
1366
1367 for(;
1368 dbus->message_iter_get_arg_type(&iface_array_iter) != DBUS_TYPE_INVALID;
1369 dbus->message_iter_next(&iface_array_iter))
1370 {
1371 DBusMessageIter iface_entry_iter;
1372 DBusBasicValue iface_name_value;
1373
1374 dbus->message_iter_recurse(&iface_array_iter, &iface_entry_iter);
1375 dbus->message_iter_get_basic(&iface_entry_iter, &iface_name_value);
1376
1377 if (gate_str_comp(iface_name_value.str, bthle_service_iface) == 0)
1378 {
1379 /* a GATT service path was found */
1380 gate_result_t result;
1381 gate_guid_t current_guid;
1382 result = bthle_get_service_guid(dbus, conn, object_path_value.str, &current_guid);
1383 GATE_CONTINUE_IF_FAILED(result);
1384
1385 if (gate_mem_compare(&current_guid, service_guid, sizeof(gate_guid_t)) == 0)
1386 {
1387 ret = (NULL == gate_string_create(service_path, object_path_value.str, gate_str_length(object_path_value.str)))
1388 ? GATE_RESULT_OUTOFMEMORY
1389 : GATE_RESULT_OK;
1390 break;
1391 }
1392 }
1393 } /* for(each value in object) */
1394 } /* for(each object in "bluez")*/
1395 ret = GATE_RESULT_OK;
1396 } while (0);
1397
1398 if (reply != NULL)
1399 {
1400 dbus->message_unref(reply);
1401 }
1402 if (msg != NULL)
1403 {
1404 dbus->message_unref(msg);
1405 }
1406
1407 dbus->error_free(&err);
1408 return ret;
1409 }
1410
1411
1412 static gate_result_t bthle_get_characteristics_path(gate_libdbus_t* dbus, DBusConnection* conn,
1413 gate_string_t const* bth_device_path, gate_guid_t const* service_guid, gate_guid_t const* chara_guid, gate_string_t* chara_path)
1414 {
1415 gate_result_t ret = GATE_RESULT_FAILED;
1416 DBusError err = GATE_INIT_EMPTY;
1417 DBusMessage* msg = NULL;
1418 DBusMessage* reply = NULL;
1419 gate_string_t bth_service_path = GATE_STRING_INIT_EMPTY;
1420 do
1421 {
1422 DBusMessageIter iter = GATE_INIT_EMPTY;
1423 DBusMessageIter array_iter = GATE_INIT_EMPTY;
1424 gate_bool_t continue_search = true;
1425
1426 ret = bthle_get_service_path(dbus, conn, bth_device_path, service_guid, &bth_service_path);
1427 GATE_BREAK_IF_FAILED(ret);
1428
1429 dbus->error_init(&err);
1430 msg = dbus->message_new_method_call(bthle_bus_name, bthle_search_path, bthle_search_iface, bthle_search_method);
1431 if(msg == NULL)
1432 {
1433 ret = GATE_RESULT_FAILED;
1434 break;
1435 }
1436 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1437 if (dbus->error_is_set(&err))
1438 {
1439 ret = GATE_RESULT_EXECUTIONFAILED;
1440 break;
1441 }
1442
1443 dbus->message_iter_init(reply, &iter);
1444 dbus->message_iter_recurse(&iter, &array_iter);
1445
1446 ret = GATE_RESULT_NOMATCH;
1447
1448 for (;
1449 dbus->message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID && continue_search;
1450 dbus->message_iter_next(&array_iter))
1451 {
1452 DBusMessageIter dict_entry_iter = GATE_INIT_EMPTY;
1453 DBusMessageIter iface_array_iter = GATE_INIT_EMPTY;
1454 DBusBasicValue object_path_value = GATE_INIT_EMPTY;
1455
1456 dbus->message_iter_recurse(&array_iter, &dict_entry_iter);
1457 dbus->message_iter_get_basic(&dict_entry_iter, &object_path_value);
1458
1459 if (!gate_str_starts_with(object_path_value.str, gate_str_length(object_path_value.str), bth_service_path.str, bth_service_path.length))
1460 {
1461 continue;
1462 }
1463
1464 /* object starting with service-path found: */
1465 dbus->message_iter_next(&dict_entry_iter); /* move to interface dict */
1466 dbus->message_iter_recurse(&dict_entry_iter, &iface_array_iter);
1467
1468 for(;
1469 dbus->message_iter_get_arg_type(&iface_array_iter) != DBUS_TYPE_INVALID;
1470 dbus->message_iter_next(&iface_array_iter))
1471 {
1472 DBusMessageIter iface_entry_iter;
1473 DBusBasicValue iface_name_value;
1474
1475 dbus->message_iter_recurse(&iface_array_iter, &iface_entry_iter);
1476 dbus->message_iter_get_basic(&iface_entry_iter, &iface_name_value);
1477
1478 if (gate_str_comp(iface_name_value.str, bthle_chara_iface) == 0)
1479 {
1480 /* a GATT characteristic path was found */
1481 gate_result_t result;
1482 gate_guid_t current_chara_guid;
1483
1484 result = bthle_get_characteristic_guid(dbus, conn, object_path_value.str, &current_chara_guid);
1485 if (GATE_SUCCEEDED(result) && (0 == gate_mem_compare(&current_chara_guid, chara_guid, sizeof(gate_guid_t))))
1486 {
1487 gate_string_t service_path;
1488 gate_guid_t current_service_guid;
1489 result = bthle_get_characteristic_service(dbus, conn, object_path_value.str, &service_path);
1490 if (GATE_SUCCEEDED(result))
1491 {
1492 result = bthle_get_service_guid(dbus, conn, service_path.str, &current_service_guid);
1493 if (GATE_SUCCEEDED(result) && (0 == gate_mem_compare(&current_service_guid, service_guid, sizeof(gate_guid_t))))
1494 {
1495 ret = (NULL == gate_string_create(chara_path, object_path_value.str, gate_str_length(object_path_value.str)))
1496 ? GATE_RESULT_OUTOFMEMORY
1497 : GATE_RESULT_OK;
1498 continue_search = true;
1499 }
1500 gate_string_release(&service_path);
1501 }
1502 }
1503 }
1504 } /* for(each value in object) */
1505 } /* for(each object in "bluez")*/
1506 } while (0);
1507
1508 gate_string_release(&bth_service_path);
1509
1510 if (reply != NULL)
1511 {
1512 dbus->message_unref(reply);
1513 }
1514 if (msg != NULL)
1515 {
1516 dbus->message_unref(msg);
1517 }
1518
1519 dbus->error_free(&err);
1520 return ret;
1521 }
1522
1523
1524
1525 static gate_result_t bthle_list_characteristics(gate_libdbus_t* dbus, DBusConnection* conn,
1526 gate_string_t const* bth_device_path, gate_guid_t const* service_guid, gate_arraylist_t characteristic_paths_array)
1527 {
1528 gate_result_t ret = GATE_RESULT_FAILED;
1529 DBusError err = GATE_INIT_EMPTY;
1530 DBusMessage* msg = NULL;
1531 DBusMessage* reply = NULL;
1532 gate_string_t bth_service_path = GATE_STRING_INIT_EMPTY;
1533 do
1534 {
1535 DBusMessageIter iter = GATE_INIT_EMPTY;
1536 DBusMessageIter array_iter = GATE_INIT_EMPTY;
1537
1538 ret = bthle_get_service_path(dbus, conn, bth_device_path, service_guid, &bth_service_path);
1539 GATE_BREAK_IF_FAILED(ret);
1540
1541 dbus->error_init(&err);
1542 msg = dbus->message_new_method_call(bthle_bus_name, bthle_search_path, bthle_search_iface, bthle_search_method);
1543 if(msg == NULL)
1544 {
1545 ret = GATE_RESULT_FAILED;
1546 break;
1547 }
1548 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1549 if (dbus->error_is_set(&err))
1550 {
1551 ret = GATE_RESULT_EXECUTIONFAILED;
1552 break;
1553 }
1554
1555 dbus->message_iter_init(reply, &iter);
1556 dbus->message_iter_recurse(&iter, &array_iter);
1557
1558 for (;
1559 dbus->message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID;
1560 dbus->message_iter_next(&array_iter))
1561 {
1562 DBusMessageIter dict_entry_iter = GATE_INIT_EMPTY;
1563 DBusMessageIter iface_array_iter = GATE_INIT_EMPTY;
1564 DBusBasicValue object_path_value = GATE_INIT_EMPTY;
1565
1566 dbus->message_iter_recurse(&array_iter, &dict_entry_iter);
1567 dbus->message_iter_get_basic(&dict_entry_iter, &object_path_value);
1568
1569 if (!gate_str_starts_with(object_path_value.str, gate_str_length(object_path_value.str), bth_service_path.str, bth_service_path.length))
1570 {
1571 continue;
1572 }
1573
1574 /* object starting with service-path found: */
1575 dbus->message_iter_next(&dict_entry_iter); /* move to interface dict */
1576 dbus->message_iter_recurse(&dict_entry_iter, &iface_array_iter);
1577
1578 for(;
1579 dbus->message_iter_get_arg_type(&iface_array_iter) != DBUS_TYPE_INVALID;
1580 dbus->message_iter_next(&iface_array_iter))
1581 {
1582 DBusMessageIter iface_entry_iter;
1583 DBusBasicValue iface_name_value;
1584
1585 dbus->message_iter_recurse(&iface_array_iter, &iface_entry_iter);
1586 dbus->message_iter_get_basic(&iface_entry_iter, &iface_name_value);
1587
1588 if (gate_str_comp(iface_name_value.str, bthle_chara_iface) == 0)
1589 {
1590 /* a GATT characteristic path was found */
1591 gate_string_t chara_path;
1592 //"UUID"
1593 //"Service"
1594 //"Value"
1595 if (NULL != gate_string_create(&chara_path, object_path_value.str, gate_str_length(object_path_value.str)))
1596 {
1597 gate_arraylist_add(characteristic_paths_array, &chara_path);
1598 gate_string_release(&chara_path);
1599 }
1600 }
1601 } /* for(each value in object) */
1602 } /* for(each object in "bluez")*/
1603 ret = GATE_RESULT_OK;
1604 } while (0);
1605
1606 gate_string_release(&bth_service_path);
1607
1608 if (reply != NULL)
1609 {
1610 dbus->message_unref(reply);
1611 }
1612 if (msg != NULL)
1613 {
1614 dbus->message_unref(msg);
1615 }
1616
1617 dbus->error_free(&err);
1618 return ret;
1619 }
1620
1621
1622
1623 static gate_result_t bthle_read_characteristic_bytes(gate_libdbus_t* dbus, DBusConnection* conn,
1624 gate_string_t const* bth_path, gate_blob_t* blob)
1625 {
1626 gate_result_t ret = GATE_RESULT_FAILED;
1627 gate_cstrbuffer_t path = GATE_INIT_EMPTY;
1628 DBusMessage* msg = NULL;
1629 DBusMessage* reply = NULL;
1630 DBusError err;
1631
1632 if (NULL == gate_cstrbuffer_create_string(&path, bth_path, false))
1633 {
1634 return GATE_RESULT_OUTOFMEMORY;
1635 }
1636
1637 do
1638 {
1639 DBusMessageIter args_iter;
1640 DBusMessageIter sub_array_iter;
1641 DBusMessageIter sub_dict_iter;
1642 gate_uint8_t buffer[4096];
1643 gate_size_t buffer_used = 0;
1644
1645 dbus->error_init(&err);
1646 msg = dbus->message_new_method_call(
1647 "org.bluez",
1648 gate_cstrbuffer_get(&path),
1649 "org.bluez.GattCharacteristic1",
1650 "ReadValue");
1651
1652 if (NULL == msg)
1653 {
1654 GATE_DEBUG_TRACE("dbus_message_new_method_call() failed");
1655 ret = GATE_RESULT_FAILED;
1656 break;
1657 }
1658
1659 dbus->message_iter_init_append(msg, &args_iter);
1660 if (!dbus->message_iter_open_container(&args_iter, DBUS_TYPE_ARRAY, "{sv}", &sub_dict_iter))
1661 {
1662 ret = GATE_RESULT_FAILED;
1663 break;
1664 }
1665 dbus->message_iter_close_container(&args_iter, &sub_dict_iter);
1666
1667 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1668 if (dbus->error_is_set(&err))
1669 {
1670 ret = GATE_RESULT_EXECUTIONFAILED;
1671 break;
1672 }
1673 /* parse reply */
1674 dbus->message_iter_init(reply, &args_iter);
1675 if (dbus->message_iter_get_arg_type(&args_iter) != DBUS_TYPE_ARRAY)
1676 {
1677 ret = GATE_RESULT_INCORRECTTYPE;
1678 break;
1679 }
1680
1681
1682 for(dbus->message_iter_recurse(&args_iter, &sub_array_iter);
1683 dbus->message_iter_get_arg_type(&sub_array_iter) == DBUS_TYPE_BYTE;
1684 dbus->message_iter_next(&sub_array_iter)
1685 )
1686 {
1687 gate_uint8_t b = 0;
1688 dbus->message_iter_get_basic(&sub_array_iter, &b);
1689 buffer[buffer_used] = b;
1690 ++buffer_used;
1691 if (buffer_used >= sizeof(buffer))
1692 {
1693 break;
1694 }
1695 }
1696
1697 if (NULL == gate_blob_create(blob, buffer, buffer_used))
1698 {
1699 ret = GATE_RESULT_OUTOFMEMORY;
1700 break;
1701 }
1702 ret = GATE_RESULT_OK;
1703 } while (0);
1704
1705 dbus->error_free(&err);
1706 if (NULL != reply)
1707 {
1708 dbus->message_unref(reply);
1709 }
1710 if (NULL != msg)
1711 {
1712 dbus->message_unref(msg);
1713 }
1714 gate_cstrbuffer_destroy(&path);
1715 return ret;
1716 }
1717
1718 static gate_result_t bthle_write_characteristic_bytes(gate_libdbus_t* dbus, DBusConnection* conn,
1719 gate_string_t const* bth_path, gate_uint8_t const* bytes, gate_size_t bytes_count)
1720 {
1721 gate_result_t ret = GATE_RESULT_FAILED;
1722 gate_cstrbuffer_t path = GATE_INIT_EMPTY;
1723 DBusMessage* msg = NULL;
1724
1725 if (NULL == gate_cstrbuffer_create_string(&path, bth_path, false))
1726 {
1727 return GATE_RESULT_OUTOFMEMORY;
1728 }
1729
1730 do
1731 {
1732 gate_size_t ndx;
1733 DBusMessageIter args;
1734 DBusMessageIter sub_array_iter;
1735 DBusMessageIter sub_dict_iter;
1736 DBusMessage* reply;
1737 DBusError err;
1738
1739 msg = dbus->message_new_method_call(
1740 "org.bluez",
1741 gate_cstrbuffer_get(&path),
1742 "org.bluez.GattCharacteristic1",
1743 "WriteValue");
1744
1745 if (NULL == msg)
1746 {
1747 GATE_DEBUG_TRACE("dbus_message_new_method_call() failed");
1748 ret = GATE_RESULT_FAILED;
1749 break;
1750 }
1751
1752 dbus->message_iter_init_append(msg, &args);
1753
1754 if (!dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "y", &sub_array_iter))
1755 {
1756 GATE_DEBUG_TRACE("dbus_message_iter_open_container() failed");
1757 ret = GATE_RESULT_FAILED;
1758 break;
1759 }
1760 while(bytes_count-- > 0)
1761 {
1762 dbus->message_iter_append_basic(&sub_array_iter, DBUS_TYPE_BYTE, bytes);
1763 ++bytes;
1764 }
1765 dbus->message_iter_close_container(&args, &sub_array_iter);
1766
1767 dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &sub_dict_iter);
1768 dbus->message_iter_close_container(&args, &sub_dict_iter);
1769
1770 dbus->error_init(&err);
1771 reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err);
1772 ret = dbus->error_is_set(&err) ? GATE_RESULT_EXECUTIONFAILED : GATE_RESULT_OK;
1773 dbus->error_free(&err);
1774 if (reply != NULL)
1775 {
1776 dbus->message_unref(reply);
1777 }
1778 } while (0);
1779
1780 if (msg != NULL)
1781 {
1782 dbus->message_unref(msg);
1783 }
1784
1785 gate_cstrbuffer_destroy(&path);
1786 return ret;
1787 }
1788
1789
1790
1791 gate_result_t gate_device_bthle_enum(gate_device_bthle_enum_callback_t callback, void* userparam)
1792 {
1793 gate_result_t ret;
1794 gate_libdbus_t* dbus = NULL;
1795 DBusConnection* conn = NULL;
1796 gate_arraylist_t paths = NULL;
1797
1798 do
1799 {
1800 gate_enumerator_t edevs;
1801 gate_string_t const* ptr_str_devpath;
1802
1803 ret = gate_dbus_open_system_connection(&dbus, &conn);
1804 GATE_BREAK_IF_FAILED(ret);
1805
1806 paths = gate_util_stringarray_create();
1807 if (paths == NULL)
1808 {
1809 ret = GATE_RESULT_OUTOFMEMORY;
1810 break;
1811 }
1812
1813 ret = bthle_list_devices(dbus, conn, paths);
1814 GATE_BREAK_IF_FAILED(ret);
1815
1816 if (NULL == gate_arraylist_enumerate(paths, &edevs))
1817 {
1818 ret = GATE_RESULT_OUTOFMEMORY;
1819 break;
1820 }
1821 GATE_FOR_ENUMERATOR(gate_string_t, ptr_str_devpath, &edevs)
1822 {
1823 gate_device_bthle_t bthle_dev = GATE_INIT_EMPTY;
1824 gate_value_t val;
1825 gate_result_t result;
1826 gate_arraylist_t services_array;
1827 gate_string_to_buffer(ptr_str_devpath, bthle_dev.uid, sizeof(bthle_dev.uid));
1828
1829 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, bthle_dev.uid, bthle_device_iface, "Address", &val);
1830 if(GATE_SUCCEEDED(result))
1831 {
1832 gate_type_id_t tid = gate_value_type(&val);
1833 if (tid == GATE_TYPE_STRING)
1834 {
1835 gate_string_t const* ptr_addr = (gate_string_t const*)gate_value_get_ptr(&val);
1836 gate_string_to_buffer(ptr_addr, bthle_dev.address, sizeof(bthle_dev.address));
1837 }
1838 gate_value_release(&val);
1839 }
1840 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, bthle_dev.uid, bthle_device_iface, "Name", &val);
1841 if(GATE_SUCCEEDED(result))
1842 {
1843 gate_type_id_t tid = gate_value_type(&val);
1844 if (tid == GATE_TYPE_STRING)
1845 {
1846 gate_string_t const* ptr_name = (gate_string_t const*)gate_value_get_ptr(&val);
1847 gate_string_to_buffer(ptr_name, bthle_dev.name, sizeof(bthle_dev.name));
1848 }
1849 gate_value_release(&val);
1850 }
1851
1852 services_array = gate_util_stringarray_create();
1853 if (services_array != NULL)
1854 {
1855 result = bthle_list_services(dbus, conn, ptr_str_devpath, services_array);
1856 if (GATE_SUCCEEDED(result))
1857 {
1858 gate_enumerator_t eservices;
1859 if (NULL != gate_arraylist_enumerate(services_array, &eservices))
1860 {
1861 gate_string_t const* ptr_str_svcpath;
1862 GATE_FOR_ENUMERATOR(gate_string_t, ptr_str_svcpath, &eservices)
1863 {
1864 gate_value_t val;
1865 gate_device_bthle_service_t* ptr_service = &bthle_dev.services[bthle_dev.service_count];
1866 result = bthle_get_service_guid(dbus, conn, ptr_str_svcpath->str, &ptr_service->service_guid);
1867 if (GATE_SUCCEEDED(result))
1868 {
1869 bthle_get_service_handle(dbus, conn, ptr_str_svcpath->str, &ptr_service->attribute_handle);
1870 ++bthle_dev.service_count;
1871 if (bthle_dev.service_count >= sizeof(bthle_dev.services) / sizeof(bthle_dev.services[0]))
1872 {
1873 /* 100 % filled, no further space left */
1874 break;
1875 }
1876 }
1877 }
1878 }
1879 }
1880 gate_arraylist_release(services_array);
1881 }
1882
1883 if (!callback(&bthle_dev, userparam))
1884 {
1885 break;
1886 }
1887 }
1888
1889 } while (0);
1890
1891 gate_arraylist_release(paths);
1892
1893 if (conn != NULL)
1894 {
1895 dbus->connection_unref(conn);
1896 }
1897 return ret;
1898 }
1899
1900 typedef struct bthle_characteristic_buffer
1901 {
1902 gate_device_bthle_characteristic_t chara;
1903 char buffer[512];
1904 } bthle_characteristic_buffer_t;
1905
1906 gate_result_t gate_device_bthle_service_enum(gate_device_bthle_t const* device,
1907 gate_device_bthle_service_t const* service,
1908 gate_device_bthle_service_enum_callback_t callback, void* userparam)
1909 {
1910 gate_result_t ret;
1911 gate_libdbus_t* dbus = NULL;
1912 DBusConnection* conn = NULL;
1913 gate_arraylist_t paths = NULL;
1914
1915 do
1916 {
1917 gate_enumerator_t edevs;
1918 gate_string_t const* ptr_str_devpath;
1919 gate_string_t device_uid;
1920
1921 ret = gate_dbus_open_system_connection(&dbus, &conn);
1922 GATE_BREAK_IF_FAILED(ret);
1923
1924 paths = gate_util_stringarray_create();
1925 if (paths == NULL)
1926 {
1927 ret = GATE_RESULT_OUTOFMEMORY;
1928 break;
1929 }
1930
1931 gate_string_create_static(&device_uid, device->uid);
1932 ret = bthle_list_characteristics(dbus, conn, &device_uid, &service->service_guid, paths);
1933 GATE_BREAK_IF_FAILED(ret);
1934
1935 if (NULL == gate_arraylist_enumerate(paths, &edevs))
1936 {
1937 ret = GATE_RESULT_OUTOFMEMORY;
1938 break;
1939 }
1940 GATE_FOR_ENUMERATOR(gate_string_t, ptr_str_devpath, &edevs)
1941 {
1942 bthle_characteristic_buffer_t charabuffer = GATE_INIT_EMPTY;
1943 gate_device_bthle_characteristic_t* ptr_chara = &charabuffer.chara;
1944 gate_result_t result;
1945 gate_value_t val;
1946
1947 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, ptr_str_devpath->str, bthle_chara_iface, "UUID", &val);
1948 if(GATE_SUCCEEDED(result))
1949 {
1950 if (gate_value_type(&val) == GATE_TYPE_STRING)
1951 {
1952 gate_string_t const* str_guid = (gate_string_t const*)gate_value_get_ptr(&val);
1953 gate_guid_parse_string(str_guid->str, str_guid->length, &ptr_chara->characteristic_guid);
1954 }
1955 gate_value_release(&val);
1956 }
1957 result = gate_dbus_property_get(dbus, conn, bthle_bus_name, ptr_str_devpath->str, bthle_chara_iface, "Value", &val);
1958 if(GATE_SUCCEEDED(result))
1959 {
1960 if (gate_value_type(&val) == GATE_TYPE_STRING)
1961 {
1962 gate_string_t const* str_value = (gate_string_t const*)gate_value_get_ptr(&val);
1963 ptr_chara->data_length = str_value->length > 512 ? 512 : str_value->length;
1964 gate_mem_copy(&ptr_chara->data[0], str_value->str, ptr_chara->data_length);
1965 }
1966 gate_value_release(&val);
1967 }
1968
1969 if (!callback(ptr_chara, userparam))
1970 {
1971 break;
1972 }
1973 }
1974
1975 } while (0);
1976
1977 gate_arraylist_release(paths);
1978
1979 if (conn != NULL)
1980 {
1981 dbus->connection_unref(conn);
1982 }
1983 return ret;
1984 }
1985
1986 gate_result_t gate_device_bthle_characteristic_get(gate_device_bthle_t const* device,
1987 gate_guid_t const* service_guid,
1988 gate_guid_t const* characteristic_guid,
1989 char* buffer,
1990 gate_size_t* buffer_len)
1991 {
1992 gate_result_t ret;
1993 gate_libdbus_t* dbus = NULL;
1994 DBusConnection* conn = NULL;
1995 gate_string_t chara_path = GATE_STRING_INIT_EMPTY;
1996 gate_blob_t blob = GATE_INIT_EMPTY;
1997
1998 do
1999 {
2000 gate_enumerator_t edevs;
2001 gate_string_t const* ptr_str_devpath;
2002 gate_string_t device_uid;
2003
2004 gate_string_create_static(&device_uid, device->uid);
2005
2006 ret = gate_dbus_open_system_connection(&dbus, &conn);
2007 GATE_BREAK_IF_FAILED(ret);
2008
2009 ret = bthle_get_characteristics_path(dbus, conn, &device_uid, service_guid, characteristic_guid, &chara_path);
2010 GATE_BREAK_IF_FAILED(ret);
2011
2012 ret = bthle_read_characteristic_bytes(dbus, conn, &chara_path, &blob);
2013 GATE_BREAK_IF_FAILED(ret);
2014
2015 if (buffer && buffer_len)
2016 {
2017 *buffer_len = gate_blob_get_bytes(&blob, 0, buffer, *buffer_len);
2018 }
2019 } while (0);
2020
2021 gate_blob_release(&blob);
2022 gate_string_release(&chara_path);
2023
2024 if (conn != NULL)
2025 {
2026 dbus->connection_unref(conn);
2027 }
2028 return ret;
2029 }
2030
2031 gate_result_t gate_device_bthle_characteristic_set(gate_device_bthle_t const* device,
2032 gate_guid_t const* service_guid,
2033 gate_guid_t const* characteristic_guid,
2034 char const* buffer,
2035 gate_size_t buffer_len)
2036 {
2037 gate_result_t ret;
2038 gate_libdbus_t* dbus = NULL;
2039 DBusConnection* conn = NULL;
2040 gate_string_t chara_path = GATE_STRING_INIT_EMPTY;
2041 gate_blob_t blob = GATE_INIT_EMPTY;
2042
2043 do
2044 {
2045 gate_enumerator_t edevs;
2046 gate_string_t const* ptr_str_devpath;
2047 gate_string_t device_uid;
2048
2049 gate_string_create_static(&device_uid, device->uid);
2050
2051 ret = gate_dbus_open_system_connection(&dbus, &conn);
2052 GATE_BREAK_IF_FAILED(ret);
2053
2054 ret = bthle_get_characteristics_path(dbus, conn, &device_uid, service_guid, characteristic_guid, &chara_path);
2055 GATE_BREAK_IF_FAILED(ret);
2056
2057 ret = bthle_write_characteristic_bytes(dbus, conn, &chara_path, buffer, buffer_len);
2058
2059 } while (0);
2060
2061 gate_blob_release(&blob);
2062 gate_string_release(&chara_path);
2063
2064 if (conn != NULL)
2065 {
2066 dbus->connection_unref(conn);
2067 }
2068 return ret;
2069 }
2070
2071 #endif /* GATE_SYSTEM_DEVICES_DBUS_IMPL */
2072
2073
2074
2075 #if defined(GATE_SYSTEM_DEVICES_NO_IMPL)
2076
2077
2078 gate_result_t gate_device_bth_enum(gate_device_bth_enum_callback callback, void* userparam)
2079 {
2080 (void)callback;
2081 (void)userparam;
2082 return GATE_RESULT_NOTIMPLEMENTED;
2083 }
2084
2085 gate_result_t gate_device_bthle_enum(gate_device_bthle_enum_callback_t callback, void* userparam)
2086 {
2087 (void)callback;
2088 (void)userparam;
2089 return GATE_RESULT_NOTIMPLEMENTED;
2090 }
2091
2092 gate_result_t gate_device_bthle_service_enum(gate_device_bthle_t const* device,
2093 gate_device_bthle_service_t const* service,
2094 gate_device_bthle_service_enum_callback_t callback, void* userparam)
2095 {
2096 (void)device;
2097 (void)service;
2098 (void)callback;
2099 (void)userparam;
2100 return GATE_RESULT_NOTIMPLEMENTED;
2101 }
2102
2103 gate_result_t gate_device_bthle_characteristic_get(gate_device_bthle_t const* device,
2104 gate_guid_t const* service_guid,
2105 gate_guid_t const* characteristic_guid,
2106 char* buffer,
2107 gate_size_t* buffer_len)
2108 {
2109 (void)device;
2110 (void)service_guid;
2111 (void)characteristic_guid;
2112 (void)buffer;
2113 (void)buffer_len;
2114 return GATE_RESULT_NOTIMPLEMENTED;
2115 }
2116
2117 gate_result_t gate_device_bthle_characteristic_set(gate_device_bthle_t const* device,
2118 gate_guid_t const* service_guid,
2119 gate_guid_t const* characteristic_guid,
2120 char const* buffer,
2121 gate_size_t buffer_len)
2122 {
2123 (void)device;
2124 (void)service_guid;
2125 (void)characteristic_guid;
2126 (void)buffer;
2127 (void)buffer_len;
2128 return GATE_RESULT_NOTIMPLEMENTED;
2129 }
2130
2131
2132 #endif /* GATE_SYSTEM_DEVICES_NO_IMPL */
2133