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