1# Copyright 2018 Espressif Systems (Shanghai) PTE LTD 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15 16from __future__ import print_function 17 18from . import ble_cli 19from .transport import Transport 20 21 22class Transport_BLE(Transport): 23 def __init__(self, devname, service_uuid, nu_lookup): 24 # Expect service UUID like '0000ffff-0000-1000-8000-00805f9b34fb' 25 for name in nu_lookup.keys(): 26 # Calculate characteristic UUID for each endpoint 27 nu_lookup[name] = service_uuid[:4] + '{:02x}'.format( 28 int(nu_lookup[name], 16) & int(service_uuid[4:8], 16)) + service_uuid[8:] 29 30 # Get BLE client module 31 self.cli = ble_cli.get_client() 32 33 # Use client to connect to BLE device and bind to service 34 if not self.cli.connect(devname=devname, iface='hci0', 35 chrc_names=nu_lookup.keys(), 36 fallback_srv_uuid=service_uuid): 37 raise RuntimeError('Failed to initialize transport') 38 39 # Irrespective of provided parameters, let the client 40 # generate a lookup table by reading advertisement data 41 # and characteristic user descriptors 42 self.name_uuid_lookup = self.cli.get_nu_lookup() 43 44 # If that doesn't work, use the lookup table provided as parameter 45 if self.name_uuid_lookup is None: 46 self.name_uuid_lookup = nu_lookup 47 # Check if expected characteristics are provided by the service 48 for name in self.name_uuid_lookup.keys(): 49 if not self.cli.has_characteristic(self.name_uuid_lookup[name]): 50 raise RuntimeError("'" + name + "' endpoint not found") 51 52 def __del__(self): 53 # Make sure device is disconnected before application gets closed 54 try: 55 self.disconnect() 56 except Exception: 57 pass 58 59 def disconnect(self): 60 self.cli.disconnect() 61 62 def send_data(self, ep_name, data): 63 # Write (and read) data to characteristic corresponding to the endpoint 64 if ep_name not in self.name_uuid_lookup.keys(): 65 raise RuntimeError('Invalid endpoint : ' + ep_name) 66 return self.cli.send_data(self.name_uuid_lookup[ep_name], data) 67