class BlueGigaModule(BlueGigaCallbacks, ProcedureManager): def __init__(self, port, baud=115200, timeout=0.1): super(BlueGigaModule, self).__init__() self._api = BlueGigaAPI(port, callbacks=self, baud=baud, timeout=timeout) self.address = None self._module_info = None self.scan_responses = None self.connections = {} self._api.start_daemon() self.procedure_in_progress = False def pipe_logs_to_terminal(self, level=logging.INFO): term = logging.StreamHandler(sys.stdout) formatter = logging.Formatter(self._api._serial.portstr + ': %(asctime)s - %(name)s - %(levelname)s - %(message)s') term.setFormatter(formatter) api_logger = logging.getLogger("bgapi") api_logger.addHandler(term) api_logger.setLevel(level=level) def shutdown(self): self._api.stop_daemon() def get_module_info(self, timeout=0.5): start = time.time() if not self._module_info: self._api.ble_cmd_system_get_info() while not self._module_info and time.time() < start + timeout: pass return self._module_info def get_ble_address(self, timeout=0.5): self.start_procedure(GET_ADDRESS) self._api.ble_cmd_system_address_get() if not self.wait_for_procedure(timeout=timeout): raise BlueGigaModuleException("No response to get_ble_address!") else: return self.address def reset_ble_state(self): """ Disconnect, End Procedure, and Disable Advertising """ self._api.ble_cmd_gap_set_mode(gap_discoverable_mode['gap_non_discoverable'], gap_connectable_mode['gap_non_connectable']) for i in range(8): self.disconnect(i) self._api.ble_cmd_gap_end_procedure() def disconnect(self, connection): self.start_procedure(DISCONNECT) try: self._api.ble_cmd_connection_disconnect(connection=connection.handle) except AttributeError: self._api.ble_cmd_connection_disconnect(connection=connection) self.wait_for_procedure() def allow_bonding(self): self._api.ble_cmd_sm_set_bondable_mode(1) def disallow_bonding(self): self._api.ble_cmd_sm_set_bondable_mode(0) def delete_bonding(self): self._api.ble_cmd_sm_delete_bonding(0) def set_device_capabilities(self, mitm=True, keysize=16, io=sm_io_capability['sm_io_capability_noinputnooutput']): self._api.ble_cmd_sm_set_parameters(mitm=1 if mitm else 0, min_key_size=keysize, io_capabilities=io) def set_out_of_band_data(self, oob): self._api.ble_cmd_sm_set_oob_data(oob.decode("hex")) #------------- Response and Event Callbacks -------------# def ble_rsp_system_address_get(self, address): super(BlueGigaModule, self).ble_rsp_system_address_get(address) self.address = address self.procedure_complete(GET_ADDRESS) def ble_evt_connection_status(self, connection, flags, address, address_type, conn_interval, timeout, latency, bonding): super(BlueGigaModule, self).ble_evt_connection_status(connection, flags, address, address_type, conn_interval, timeout, latency, bonding) if flags & connection_status_mask['connection_completed']: conn = BLEConnection(api=self._api, handle=connection, address=address, address_type=address_type, interval=conn_interval, timeout=timeout, latency=latency, bonding=bonding) self.connections[connection] = conn self.most_recent_connection = conn self.procedure_complete(CONNECT) if flags & connection_status_mask['connection_encrypted']: self.connections[connection].flags = flags self.connections[connection].procedure_complete(START_ENCRYPTION) def ble_rsp_system_get_info(self, major, minor, patch, build, ll_version, protocol_version, hw): super(BlueGigaModule, self).ble_rsp_system_get_info(major, minor, patch, build, ll_version, protocol_version, hw) self._module_info = {"FW Version": "%d.%d.%d.%d" % (major, minor, patch, build), "Link Layer Version": "%d" % ll_version, "Protocol Version": "%d" % protocol_version, "Hardware Version": "%d" % hw} def ble_rsp_connection_disconnect(self, connection, result): super(BlueGigaModule, self).ble_rsp_connection_disconnect(connection, result) if result == 0x0186: # Not Connected self.procedure_complete(DISCONNECT) def ble_evt_connection_disconnected(self, connection, reason): super(BlueGigaModule, self).ble_evt_connection_disconnected(connection, reason) self.procedure_complete(DISCONNECT)