lib_ble_client.py 28 KB

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