lib_ble_client.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2019 Espressif Systems (Shanghai) PTE LTD
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. # DBus-Bluez BLE library
  18. from __future__ import print_function
  19. import sys
  20. import time
  21. import traceback
  22. try:
  23. from future.moves.itertools import zip_longest
  24. import dbus
  25. import dbus.mainloop.glib
  26. from gi.repository import GLib
  27. except ImportError as e:
  28. if 'linux' not in sys.platform:
  29. sys.exit("Error: Only supported on Linux platform")
  30. print(e)
  31. print("Install packages `libgirepository1.0-dev gir1.2-gtk-3.0 libcairo2-dev libdbus-1-dev libdbus-glib-1-dev` for resolving the issue")
  32. print("Run `pip install -r $IDF_PATH/tools/ble/requirements.txt` for resolving the issue")
  33. raise
  34. import lib_gatt
  35. import lib_gap
  36. srv_added_old_cnt = 0
  37. srv_added_new_cnt = 0
  38. verify_signal_check = 0
  39. blecent_retry_check_cnt = 0
  40. verify_service_cnt = 0
  41. verify_readchars_cnt = 0
  42. blecent_adv_uuid = '1811'
  43. gatt_app_obj_check = False
  44. gatt_app_reg_check = False
  45. adv_data_check = False
  46. adv_reg_check = False
  47. read_req_check = False
  48. write_req_check = False
  49. subscribe_req_check = False
  50. ble_hr_chrc = False
  51. DISCOVERY_START = False
  52. SIGNAL_CAUGHT = False
  53. TEST_CHECKS_PASS = False
  54. ADV_STOP = False
  55. SERVICES_RESOLVED = False
  56. SERVICE_UUID_FOUND = False
  57. BLUEZ_SERVICE_NAME = 'org.bluez'
  58. DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
  59. DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
  60. ADAPTER_IFACE = 'org.bluez.Adapter1'
  61. DEVICE_IFACE = 'org.bluez.Device1'
  62. GATT_MANAGER_IFACE = 'org.bluez.GattManager1'
  63. LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
  64. GATT_SERVICE_IFACE = 'org.bluez.GattService1'
  65. GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
  66. ADAPTER_ON = False
  67. DEVICE_CONNECTED = False
  68. GATT_APP_REGISTERED = False
  69. ADV_REGISTERED = False
  70. ADV_ACTIVE_INSTANCE = False
  71. CHRC_VALUE_CNT = False
  72. # Set up the main loop.
  73. dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
  74. dbus.mainloop.glib.threads_init()
  75. # Set up the event main loop.
  76. event_loop = GLib.MainLoop()
  77. def verify_signal_is_caught():
  78. global verify_signal_check
  79. verify_signal_check += 1
  80. if (not SIGNAL_CAUGHT and verify_signal_check == 15) or (SIGNAL_CAUGHT):
  81. if event_loop.is_running():
  82. event_loop.quit()
  83. return False # polling for checks will stop
  84. return True # polling will continue
  85. def set_props_status(props):
  86. """
  87. Set Adapter status if it is powered on or off
  88. """
  89. global ADAPTER_ON, SERVICES_RESOLVED, GATT_OBJ_REMOVED, GATT_APP_REGISTERED, \
  90. ADV_REGISTERED, ADV_ACTIVE_INSTANCE, DEVICE_CONNECTED, CHRC_VALUE, CHRC_VALUE_CNT, \
  91. SIGNAL_CAUGHT
  92. is_service_uuid = False
  93. # Signal caught for change in Adapter Powered property
  94. if 'Powered' in props:
  95. if props['Powered'] == 1:
  96. SIGNAL_CAUGHT = True
  97. ADAPTER_ON = True
  98. else:
  99. SIGNAL_CAUGHT = True
  100. ADAPTER_ON = False
  101. if 'ServicesResolved' in props:
  102. if props['ServicesResolved'] == 1:
  103. SIGNAL_CAUGHT = True
  104. SERVICES_RESOLVED = True
  105. else:
  106. SIGNAL_CAUGHT = True
  107. SERVICES_RESOLVED = False
  108. if 'UUIDs' in props:
  109. # Signal caught for add/remove GATT data having service uuid
  110. for uuid in props['UUIDs']:
  111. if blecent_adv_uuid in uuid:
  112. is_service_uuid = True
  113. if not is_service_uuid:
  114. # Signal caught for removing GATT data having service uuid
  115. # and for unregistering GATT application
  116. GATT_APP_REGISTERED = False
  117. lib_gatt.GATT_APP_OBJ = False
  118. if 'ActiveInstances' in props:
  119. # Signal caught for Advertising - add/remove Instances property
  120. if props['ActiveInstances'] == 1:
  121. ADV_ACTIVE_INSTANCE = True
  122. elif props['ActiveInstances'] == 0:
  123. ADV_ACTIVE_INSTANCE = False
  124. ADV_REGISTERED = False
  125. lib_gap.ADV_OBJ = False
  126. if 'Connected' in props:
  127. # Signal caught for device connect/disconnect
  128. if props['Connected'] == 1:
  129. SIGNAL_CAUGHT = True
  130. DEVICE_CONNECTED = True
  131. else:
  132. SIGNAL_CAUGHT = True
  133. DEVICE_CONNECTED = False
  134. if 'Value' in props:
  135. # Signal caught for change in chars value
  136. if ble_hr_chrc:
  137. CHRC_VALUE_CNT += 1
  138. print(props['Value'])
  139. if CHRC_VALUE_CNT == 10:
  140. SIGNAL_CAUGHT = True
  141. return False
  142. return False
  143. def props_change_handler(iface, changed_props, invalidated):
  144. """
  145. PropertiesChanged Signal handler.
  146. Catch and print information about PropertiesChanged signal.
  147. """
  148. if iface == ADAPTER_IFACE:
  149. set_props_status(changed_props)
  150. if iface == LE_ADVERTISING_MANAGER_IFACE:
  151. set_props_status(changed_props)
  152. if iface == DEVICE_IFACE:
  153. set_props_status(changed_props)
  154. if iface == GATT_CHRC_IFACE:
  155. set_props_status(changed_props)
  156. class BLE_Bluez_Client:
  157. def __init__(self, iface, devname=None, devaddr=None):
  158. self.bus = None
  159. self.device = None
  160. self.devname = devname
  161. self.devaddr = devaddr
  162. self.iface = iface
  163. self.ble_objs = None
  164. self.props_iface_obj = None
  165. self.adapter_path = []
  166. self.adapter = None
  167. self.services = []
  168. self.srv_uuid = []
  169. self.chars = {}
  170. self.char_uuid = []
  171. try:
  172. self.bus = dbus.SystemBus()
  173. om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE)
  174. self.ble_objs = om_iface_obj.GetManagedObjects()
  175. except Exception as e:
  176. print(e)
  177. def __del__(self):
  178. try:
  179. print("Test Exit")
  180. except Exception as e:
  181. print(e)
  182. sys.exit(1)
  183. def set_adapter(self):
  184. '''
  185. Discover Bluetooth Adapter
  186. Power On Bluetooth Adapter
  187. '''
  188. global verify_signal_check, SIGNAL_CAUGHT, ADAPTER_ON
  189. verify_signal_check = 0
  190. ADAPTER_ON = False
  191. try:
  192. print("discovering adapter...")
  193. for path, interfaces in self.ble_objs.items():
  194. adapter = interfaces.get(ADAPTER_IFACE)
  195. if adapter is not None:
  196. if path.endswith(self.iface):
  197. self.adapter = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), ADAPTER_IFACE)
  198. # Create Properties Interface object only after adapter is found
  199. self.props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), DBUS_PROP_IFACE)
  200. self.adapter_path = [path, interfaces]
  201. # Check adapter status - power on/off
  202. set_props_status(interfaces[ADAPTER_IFACE])
  203. break
  204. if self.adapter is None:
  205. raise Exception("Bluetooth adapter not found")
  206. if self.props_iface_obj is None:
  207. raise Exception("Properties interface not found")
  208. print("bluetooth adapter discovered")
  209. # Check if adapter is already powered on
  210. if ADAPTER_ON:
  211. print("Adapter already powered on")
  212. return True
  213. # Power On Adapter
  214. print("powering on adapter...")
  215. self.props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler)
  216. self.props_iface_obj.Set(ADAPTER_IFACE, "Powered", dbus.Boolean(1))
  217. SIGNAL_CAUGHT = False
  218. GLib.timeout_add_seconds(5, verify_signal_is_caught)
  219. event_loop.run()
  220. if ADAPTER_ON:
  221. print("bluetooth adapter powered on")
  222. return True
  223. else:
  224. raise Exception("Failure: bluetooth adapter not powered on")
  225. except Exception:
  226. print(traceback.format_exc())
  227. return False
  228. def connect(self):
  229. '''
  230. Connect to the device discovered
  231. Retry 10 times to discover and connect to device
  232. '''
  233. global DISCOVERY_START, SIGNAL_CAUGHT, DEVICE_CONNECTED, verify_signal_check
  234. device_found = False
  235. DEVICE_CONNECTED = False
  236. try:
  237. self.adapter.StartDiscovery()
  238. print("\nStarted Discovery")
  239. DISCOVERY_START = True
  240. for retry_cnt in range(10,0,-1):
  241. verify_signal_check = 0
  242. try:
  243. if self.device is None:
  244. print("\nConnecting to device...")
  245. # Wait for device to be discovered
  246. time.sleep(5)
  247. device_found = self.get_device()
  248. if device_found:
  249. self.device.Connect(dbus_interface=DEVICE_IFACE)
  250. time.sleep(15)
  251. SIGNAL_CAUGHT = False
  252. GLib.timeout_add_seconds(5, verify_signal_is_caught)
  253. event_loop.run()
  254. if DEVICE_CONNECTED:
  255. print("\nConnected to device")
  256. return True
  257. else:
  258. raise Exception
  259. except Exception as e:
  260. print(e)
  261. print("\nRetries left", retry_cnt - 1)
  262. continue
  263. # Device not found
  264. return False
  265. except Exception:
  266. print(traceback.format_exc())
  267. self.device = None
  268. return False
  269. def get_device(self):
  270. '''
  271. Discover device based on device name
  272. and device address and connect
  273. '''
  274. dev_path = None
  275. om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE)
  276. self.ble_objs = om_iface_obj.GetManagedObjects()
  277. for path, interfaces in self.ble_objs.items():
  278. if DEVICE_IFACE not in interfaces.keys():
  279. continue
  280. device_addr_iface = (path.replace('_', ':')).lower()
  281. dev_addr = self.devaddr.lower()
  282. if dev_addr in device_addr_iface and \
  283. interfaces[DEVICE_IFACE].get("Name") == self.devname:
  284. dev_path = path
  285. break
  286. if dev_path is None:
  287. raise Exception("\nBLE device not found")
  288. device_props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, dev_path), DBUS_PROP_IFACE)
  289. device_props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler)
  290. self.device = self.bus.get_object(BLUEZ_SERVICE_NAME, dev_path)
  291. return True
  292. def srvc_iface_added_handler(self, path, interfaces):
  293. '''
  294. Add services found as lib_ble_client obj
  295. '''
  296. if self.device and path.startswith(self.device.object_path):
  297. if GATT_SERVICE_IFACE in interfaces.keys():
  298. service = self.bus.get_object(BLUEZ_SERVICE_NAME, path)
  299. uuid = service.Get(GATT_SERVICE_IFACE, 'UUID', dbus_interface=DBUS_PROP_IFACE)
  300. if uuid not in self.srv_uuid:
  301. self.srv_uuid.append(uuid)
  302. if path not in self.services:
  303. self.services.append(path)
  304. def verify_service_uuid_found(self, service_uuid):
  305. '''
  306. Verify service uuid found
  307. '''
  308. global SERVICE_UUID_FOUND
  309. srv_uuid_found = [uuid for uuid in self.srv_uuid if service_uuid in uuid]
  310. if srv_uuid_found:
  311. SERVICE_UUID_FOUND = True
  312. def get_services(self, service_uuid=None):
  313. '''
  314. Retrieve Services found in the device connected
  315. '''
  316. global SIGNAL_CAUGHT, SERVICE_UUID_FOUND, SERVICES_RESOLVED, verify_signal_check
  317. verify_signal_check = 0
  318. SERVICE_UUID_FOUND = False
  319. SERVICES_RESOLVED = False
  320. SIGNAL_CAUGHT = False
  321. try:
  322. om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE)
  323. self.ble_objs = om_iface_obj.GetManagedObjects()
  324. for path, interfaces in self.ble_objs.items():
  325. self.srvc_iface_added_handler(path, interfaces)
  326. # If services not found, then they may not have been added yet on dbus
  327. if not self.services:
  328. GLib.timeout_add_seconds(5, verify_signal_is_caught)
  329. om_iface_obj.connect_to_signal('InterfacesAdded', self.srvc_iface_added_handler)
  330. event_loop.run()
  331. if not SERVICES_RESOLVED:
  332. raise Exception("Services not found...")
  333. if service_uuid:
  334. self.verify_service_uuid_found(service_uuid)
  335. if not SERVICE_UUID_FOUND:
  336. raise Exception("Service with uuid: %s not found..." % service_uuid)
  337. # Services found
  338. return self.srv_uuid
  339. except Exception:
  340. print(traceback.format_exc())
  341. return False
  342. def chrc_iface_added_handler(self, path, interfaces):
  343. '''
  344. Add services found as lib_ble_client obj
  345. '''
  346. global chrc, chrc_discovered, SIGNAL_CAUGHT
  347. chrc_val = None
  348. if self.device and path.startswith(self.device.object_path):
  349. if GATT_CHRC_IFACE in interfaces.keys():
  350. chrc = self.bus.get_object(BLUEZ_SERVICE_NAME, path)
  351. chrc_props = chrc.GetAll(GATT_CHRC_IFACE,
  352. dbus_interface=DBUS_PROP_IFACE)
  353. chrc_flags = chrc_props['Flags']
  354. if 'read' in chrc_flags:
  355. chrc_val = chrc.ReadValue({}, dbus_interface=GATT_CHRC_IFACE)
  356. uuid = chrc_props['UUID']
  357. self.chars[path] = chrc_val, chrc_flags, uuid
  358. SIGNAL_CAUGHT = True
  359. def read_chars(self):
  360. '''
  361. Read characteristics found in the device connected
  362. '''
  363. global iface_added, chrc_discovered, SIGNAL_CAUGHT, verify_signal_check
  364. verify_signal_check = 0
  365. chrc_discovered = False
  366. iface_added = False
  367. SIGNAL_CAUGHT = False
  368. try:
  369. om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE)
  370. self.ble_objs = om_iface_obj.GetManagedObjects()
  371. for path, interfaces in self.ble_objs.items():
  372. self.chrc_iface_added_handler(path, interfaces)
  373. # If chars not found, then they have not been added yet to interface
  374. time.sleep(15)
  375. if not self.chars:
  376. iface_added = True
  377. GLib.timeout_add_seconds(5, verify_signal_is_caught)
  378. om_iface_obj.connect_to_signal('InterfacesAdded', self.chars_iface_added_handler)
  379. event_loop.run()
  380. return self.chars
  381. except Exception:
  382. print(traceback.format_exc())
  383. return False
  384. def write_chars(self, write_val):
  385. '''
  386. Write characteristics to the device connected
  387. '''
  388. chrc = None
  389. chrc_val = None
  390. char_write_props = False
  391. try:
  392. for path, props in self.chars.items():
  393. if 'write' in props[1]: # check permission
  394. char_write_props = True
  395. chrc = self.bus.get_object(BLUEZ_SERVICE_NAME, path)
  396. chrc.WriteValue(write_val,{},dbus_interface=GATT_CHRC_IFACE)
  397. if 'read' in props[1]:
  398. chrc_val = chrc.ReadValue({}, dbus_interface=GATT_CHRC_IFACE)
  399. else:
  400. print("Warning: Cannot read value. Characteristic does not have read permission.")
  401. if not (ord(write_val) == int(chrc_val[0])):
  402. print("\nWrite Failed")
  403. return False
  404. self.chars[path] = chrc_val, props[1], props[2] # update value
  405. if not char_write_props:
  406. raise Exception("Failure: Cannot perform write operation. Characteristic does not have write permission.")
  407. return self.chars
  408. except Exception:
  409. print(traceback.format_exc())
  410. return False
  411. def hr_update_simulation(self, hr_srv_uuid, hr_char_uuid):
  412. '''
  413. Start Notifications
  414. Retrieve updated value
  415. Stop Notifications
  416. '''
  417. global ble_hr_chrc, verify_signal_check, SIGNAL_CAUGHT, CHRC_VALUE_CNT
  418. srv_path = None
  419. chrc = None
  420. uuid = None
  421. chrc_path = None
  422. chars_ret = None
  423. ble_hr_chrc = True
  424. CHRC_VALUE_CNT = 0
  425. try:
  426. # Get HR Measurement characteristic
  427. services = list(zip_longest(self.srv_uuid, self.services))
  428. for uuid, path in services:
  429. if hr_srv_uuid in uuid:
  430. srv_path = path
  431. break
  432. if srv_path is None:
  433. raise Exception("Failure: HR UUID:", hr_srv_uuid, "not found")
  434. chars_ret = self.read_chars()
  435. for path, props in chars_ret.items():
  436. if path.startswith(srv_path):
  437. chrc = self.bus.get_object(BLUEZ_SERVICE_NAME, path)
  438. chrc_path = path
  439. if hr_char_uuid in props[2]: # uuid
  440. break
  441. if chrc is None:
  442. raise Exception("Failure: Characteristics for service: ", srv_path, "not found")
  443. # Subscribe to notifications
  444. print("\nSubscribe to notifications: On")
  445. chrc.StartNotify(dbus_interface=GATT_CHRC_IFACE)
  446. chrc_props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, chrc_path), DBUS_PROP_IFACE)
  447. chrc_props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler)
  448. SIGNAL_CAUGHT = False
  449. verify_signal_check = 0
  450. GLib.timeout_add_seconds(5, verify_signal_is_caught)
  451. event_loop.run()
  452. chrc.StopNotify(dbus_interface=GATT_CHRC_IFACE)
  453. time.sleep(2)
  454. print("\nSubscribe to notifications: Off")
  455. ble_hr_chrc = False
  456. return True
  457. except Exception:
  458. print(traceback.format_exc())
  459. return False
  460. def create_gatt_app(self):
  461. '''
  462. Create GATT data
  463. Register GATT Application
  464. '''
  465. global gatt_app_obj, gatt_manager_iface_obj, GATT_APP_REGISTERED
  466. gatt_app_obj = None
  467. gatt_manager_iface_obj = None
  468. GATT_APP_REGISTERED = False
  469. lib_gatt.GATT_APP_OBJ = False
  470. try:
  471. gatt_app_obj = lib_gatt.Application(self.bus, self.adapter_path[0])
  472. gatt_manager_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME,self.adapter_path[0]), GATT_MANAGER_IFACE)
  473. gatt_manager_iface_obj.RegisterApplication(gatt_app_obj, {},
  474. reply_handler=self.gatt_app_handler,
  475. error_handler=self.gatt_app_error_handler)
  476. return True
  477. except Exception:
  478. print(traceback.format_exc())
  479. return False
  480. def gatt_app_handler(self):
  481. '''
  482. GATT Application Register success handler
  483. '''
  484. global GATT_APP_REGISTERED
  485. GATT_APP_REGISTERED = True
  486. def gatt_app_error_handler(self, error):
  487. '''
  488. GATT Application Register error handler
  489. '''
  490. global GATT_APP_REGISTERED
  491. GATT_APP_REGISTERED = False
  492. def start_advertising(self, adv_host_name, adv_iface_index, adv_type, adv_uuid):
  493. '''
  494. Create Advertising data
  495. Register Advertisement
  496. Start Advertising
  497. '''
  498. global le_adv_obj, le_adv_manager_iface_obj, ADV_ACTIVE_INSTANCE, ADV_REGISTERED
  499. le_adv_obj = None
  500. le_adv_manager_iface_obj = None
  501. le_adv_iface_path = None
  502. ADV_ACTIVE_INSTANCE = False
  503. ADV_REGISTERED = False
  504. lib_gap.ADV_OBJ = False
  505. try:
  506. print("Advertising started")
  507. gatt_app_ret = self.create_gatt_app()
  508. if not gatt_app_ret:
  509. raise Exception
  510. for path,interface in self.ble_objs.items():
  511. if LE_ADVERTISING_MANAGER_IFACE in interface:
  512. le_adv_iface_path = path
  513. if le_adv_iface_path is None:
  514. raise Exception('\n Cannot start advertising. LEAdvertisingManager1 Interface not found')
  515. le_adv_obj = lib_gap.Advertisement(self.bus, adv_iface_index, adv_type, adv_uuid, adv_host_name)
  516. le_adv_manager_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, le_adv_iface_path), LE_ADVERTISING_MANAGER_IFACE)
  517. le_adv_manager_iface_obj.RegisterAdvertisement(le_adv_obj.get_path(), {},
  518. reply_handler=self.adv_handler,
  519. error_handler=self.adv_error_handler)
  520. GLib.timeout_add_seconds(2, self.verify_blecent)
  521. event_loop.run()
  522. if TEST_CHECKS_PASS:
  523. return True
  524. else:
  525. raise Exception
  526. except Exception:
  527. print(traceback.format_exc())
  528. return False
  529. def adv_handler(self):
  530. '''
  531. Advertisement Register success handler
  532. '''
  533. global ADV_REGISTERED
  534. ADV_REGISTERED = True
  535. def adv_error_handler(self, error):
  536. '''
  537. Advertisement Register error handler
  538. '''
  539. global ADV_REGISTERED
  540. ADV_REGISTERED = False
  541. def verify_blecent(self):
  542. """
  543. Verify blecent test commands are successful
  544. """
  545. global blecent_retry_check_cnt, gatt_app_obj_check, gatt_app_reg_check,\
  546. adv_data_check, adv_reg_check, read_req_check, write_req_check,\
  547. subscribe_req_check, TEST_CHECKS_PASS
  548. # Get device when connected
  549. if not self.device:
  550. om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE)
  551. self.ble_objs = om_iface_obj.GetManagedObjects()
  552. for path, interfaces in self.ble_objs.items():
  553. if DEVICE_IFACE not in interfaces.keys():
  554. continue
  555. device_props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), DBUS_PROP_IFACE)
  556. device_props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler)
  557. self.device = self.bus.get_object(BLUEZ_SERVICE_NAME, path)
  558. # Check for failures after 10 retries
  559. if blecent_retry_check_cnt == 10:
  560. # check for failures
  561. if not gatt_app_obj_check:
  562. print("Failure: GATT Data could not be created")
  563. if not gatt_app_reg_check:
  564. print("Failure: GATT Application could not be registered")
  565. if not adv_data_check:
  566. print("Failure: Advertising data could not be created")
  567. if not adv_reg_check:
  568. print("Failure: Advertisement could not be registered")
  569. if not read_req_check:
  570. print("Failure: Read Request not received")
  571. if not write_req_check:
  572. print("Failure: Write Request not received")
  573. if not subscribe_req_check:
  574. print("Failure: Subscribe Request not received")
  575. # Blecent Test failed
  576. TEST_CHECKS_PASS = False
  577. if subscribe_req_check:
  578. lib_gatt.alert_status_char_obj.StopNotify()
  579. else:
  580. # Check for success
  581. if not gatt_app_obj_check and lib_gatt.GATT_APP_OBJ:
  582. print("GATT Data created")
  583. gatt_app_obj_check = True
  584. if not gatt_app_reg_check and GATT_APP_REGISTERED:
  585. print("GATT Application registered")
  586. gatt_app_reg_check = True
  587. if not adv_data_check and lib_gap.ADV_OBJ:
  588. print("Advertising data created")
  589. adv_data_check = True
  590. if not adv_reg_check and ADV_REGISTERED and ADV_ACTIVE_INSTANCE:
  591. print("Advertisement registered")
  592. adv_reg_check = True
  593. if not read_req_check and lib_gatt.CHAR_READ:
  594. read_req_check = True
  595. if not write_req_check and lib_gatt.CHAR_WRITE:
  596. write_req_check = True
  597. if not subscribe_req_check and lib_gatt.CHAR_SUBSCRIBE:
  598. subscribe_req_check = True
  599. if read_req_check and write_req_check and subscribe_req_check:
  600. # all checks passed
  601. # Blecent Test passed
  602. TEST_CHECKS_PASS = True
  603. lib_gatt.alert_status_char_obj.StopNotify()
  604. if (blecent_retry_check_cnt == 10 or TEST_CHECKS_PASS):
  605. if event_loop.is_running():
  606. event_loop.quit()
  607. return False # polling for checks will stop
  608. # Increment retry count
  609. blecent_retry_check_cnt += 1
  610. # Default return True - polling for checks will continue
  611. return True
  612. def verify_blecent_disconnect(self):
  613. """
  614. Verify cleanup is successful
  615. """
  616. global blecent_retry_check_cnt, gatt_app_obj_check, gatt_app_reg_check,\
  617. adv_data_check, adv_reg_check, ADV_STOP
  618. if blecent_retry_check_cnt == 0:
  619. gatt_app_obj_check = False
  620. gatt_app_reg_check = False
  621. adv_data_check = False
  622. adv_reg_check = False
  623. # Check for failures after 10 retries
  624. if blecent_retry_check_cnt == 10:
  625. # check for failures
  626. if not gatt_app_obj_check:
  627. print("Warning: GATT Data could not be removed")
  628. if not gatt_app_reg_check:
  629. print("Warning: GATT Application could not be unregistered")
  630. if not adv_data_check:
  631. print("Warning: Advertising data could not be removed")
  632. if not adv_reg_check:
  633. print("Warning: Advertisement could not be unregistered")
  634. # Blecent Test failed
  635. ADV_STOP = False
  636. else:
  637. # Check for success
  638. if not gatt_app_obj_check and not lib_gatt.GATT_APP_OBJ:
  639. print("GATT Data removed")
  640. gatt_app_obj_check = True
  641. if not gatt_app_reg_check and not GATT_APP_REGISTERED:
  642. print("GATT Application unregistered")
  643. gatt_app_reg_check = True
  644. if not adv_data_check and not adv_reg_check and not (ADV_REGISTERED or ADV_ACTIVE_INSTANCE or lib_gap.ADV_OBJ):
  645. print("Advertising data removed")
  646. print("Advertisement unregistered")
  647. adv_data_check = True
  648. adv_reg_check = True
  649. # all checks passed
  650. ADV_STOP = True
  651. if (blecent_retry_check_cnt == 10 or ADV_STOP):
  652. if event_loop.is_running():
  653. event_loop.quit()
  654. return False # polling for checks will stop
  655. # Increment retry count
  656. blecent_retry_check_cnt += 1
  657. # Default return True - polling for checks will continue
  658. return True
  659. def disconnect(self):
  660. '''
  661. Before application exits:
  662. Advertisement is unregistered
  663. Advertisement object created is removed from dbus
  664. GATT Application is unregistered
  665. GATT Application object created is removed from dbus
  666. Disconnect device if connected
  667. Adapter is powered off
  668. '''
  669. try:
  670. global blecent_retry_check_cnt, DISCOVERY_START, verify_signal_check, SIGNAL_CAUGHT
  671. blecent_retry_check_cnt = 0
  672. verify_signal_check = 0
  673. print("\nexiting from test...")
  674. self.props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler)
  675. if ADV_REGISTERED:
  676. # Unregister Advertisement
  677. le_adv_manager_iface_obj.UnregisterAdvertisement(le_adv_obj.get_path())
  678. # Remove Advertising data
  679. dbus.service.Object.remove_from_connection(le_adv_obj)
  680. if GATT_APP_REGISTERED:
  681. # Unregister GATT Application
  682. gatt_manager_iface_obj.UnregisterApplication(gatt_app_obj.get_path())
  683. # Remove GATT data
  684. dbus.service.Object.remove_from_connection(gatt_app_obj)
  685. GLib.timeout_add_seconds(5, self.verify_blecent_disconnect)
  686. event_loop.run()
  687. if ADV_STOP:
  688. print("Stop Advertising status: ", ADV_STOP)
  689. else:
  690. print("Warning: Stop Advertising status: ", ADV_STOP)
  691. # Disconnect device
  692. if self.device:
  693. print("disconnecting device...")
  694. self.device.Disconnect(dbus_interface=DEVICE_IFACE)
  695. if self.adapter:
  696. self.adapter.RemoveDevice(self.device)
  697. self.device = None
  698. if DISCOVERY_START:
  699. self.adapter.StopDiscovery()
  700. DISCOVERY_START = False
  701. time.sleep(15)
  702. SIGNAL_CAUGHT = False
  703. GLib.timeout_add_seconds(5, verify_signal_is_caught)
  704. event_loop.run()
  705. if not DEVICE_CONNECTED:
  706. print("device disconnected")
  707. else:
  708. print("Warning: device could not be disconnected")
  709. except Exception:
  710. print(traceback.format_exc())
  711. return False