lib_ble_client.py 32 KB

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