lib_ble_client.py 32 KB

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