def displayCapabilities(self): capabilitiesList = [] for capability in self.capabilities: capabilitiesList.append([ capability, (io.colorize("yes", "green") if self.emitter.hasCapabilities(capability) else io.colorize( "no", "red")) ]) io.chart(["Capability", "Available"], capabilitiesList)
def updatePrompt(self, address=""): if address is None: address = "" self.prompt = io.colorize( "[PRX|" + (" " + str(self.currentChannel) if len( str(self.currentChannel)) != 2 else str(self.currentChannel)) + ("|" + address if address != "" else "") + "]: ", "cyan")
def showCharacteristics(self,startHandle,endHandle,title="Characteristics"): ''' This method displays the GATT characteristics described as attributes included in the Database and provide a mechanism to only select the characteristics between two handles (it is mainly used in order to print the characteristics included in a Service). :param startHandle: first ATT handle :type startHandle: int :param endHandle: last ATT handle :type endHandle: int :param title: Title of the chart :type title: str ''' formattedCharacteristics = [] for i in range(startHandle,endHandle): if i < len(self.attributes): att = self.attributes[i] if att.type == UUID(name="Characteristic Declaration"): declarationHandle = "0x{:04x}".format(att.handle) characteristic = CharacteristicDeclaration(data=att.value[::-1]) uuid16 = ("0x{:04x}".format(characteristic.UUID.UUID16) if characteristic.UUID.UUID16 is not None else "" ) uuid128 = (characteristic.UUID.UUID128.hex() if characteristic.UUID.UUID128 is not None else "" ) name = (characteristic.UUID.name if characteristic.UUID.name is not None else "" ) valueHandle = "0x{:04x}".format(characteristic.valueHandle) value = self.attributes[characteristic.valueHandle].value value = (value.replace(b"\x00",b"").decode("ascii") if utils.isPrintable(value) else value.hex() ) permissions = ",".join(characteristic.permissionsFlag.permissions) startDescriptor = characteristic.valueHandle + 1 descriptors = "" while (startDescriptor < len(self.attributes) and self.attributes[startDescriptor] is not None and (self.attributes[startDescriptor].type != UUID(name="Characteristic Declaration") and self.attributes[startDescriptor].type != UUID(name="Primary Service") and self.attributes[startDescriptor].type != UUID(name="Secondary Service"))): descriptor = self.attributes[startDescriptor] namedesc = CharacteristicDescriptor(UUID=descriptor.type).UUID.name valuedesc = (descriptor.value.replace(b"\x00",b"").decode("ascii") if utils.isPrintable(descriptor.value) else descriptor.value.hex() ) startSymbol = "" if descriptors == "" else "\n" descriptors += startSymbol + namedesc +" : "+ valuedesc startDescriptor += 1 formattedCharacteristics.append([declarationHandle, valueHandle, uuid16, uuid128, name,permissions,value,descriptors]) io.chart(["Declaration Handle","Value Handle","UUID16","UUID128","Name","Permissions", "Value","Descriptors"] ,formattedCharacteristics, io.colorize(title, "yellow") )
def __init__(self,prompt=io.colorize(" ~~> ", "cyan")): ''' This constructor initializes the interpreter instance. :param prompt: string used to generate the prompt :type prompt: str ''' self.prompt = prompt self.running = True self.availableCommands = ["exit"]
def connections(self): counter = 1 connectionsList = [] for connection in self.emitter.getConnections(): connectionsList.append([str(counter),connection["address"], connection["handle"]]) counter += 1 if connectionsList == []: io.fail("No active connections !") else: io.chart(["Identifier", "Address", "Handle"],connectionsList,io.colorize("Active connections","yellow"))
def showargs(self): ''' This method displays a chart describing the available input parameters for the loaded module. ''' for module in self.modules: currentArgs = [] for argument in module["module"].args: argName = (module["name"]+"."+argument) if len(self.modules)>1 else argument argValue = module["module"].args[argument] currentArgs.append([argName, argValue]) io.chart(["Name","Value"],currentArgs,io.colorize(module["name"],"yellow"))
def showargs(self): ''' This method displays a chart describing the available input parameters for the loaded module. ''' for module in self.modules: currentArgs = [] if "shortcut" not in module: for argument in module["module"].args: argName = (module["name"]+"."+argument) if len(self.modules)>1 else argument argValue = module["module"].args[argument] currentArgs.append([argName, argValue]) io.chart(["Name","Value"],currentArgs,io.colorize(module["name"],"yellow")) else: for argument in module["mapping"]: argName = (module["name"]+"."+argument) if len(self.modules)>1 else argument if module["mapping"][argument]["value"] is not None: argValue = module["mapping"][argument]["value"] else: argValue = "<auto>" currentArgs.append([argName, argValue]) io.chart(["Name", "Value"], currentArgs,io.colorize(module["name"],"green"))
def printServices(self, services, title="Services"): formattedServices = [] for service in services: startHandle = "0x{:04x}".format(service["startHandle"]) endHandle = "0x{:04x}".format(service["endHandle"]) uuid16 = (hex(service["uuid"].UUID16) if service["uuid"].UUID16 is not None else "") uuid128 = (service["uuid"].UUID128.hex() if service["uuid"].UUID128 is not None else "") name = (service["uuid"].name if service["uuid"].name is not None else "") formattedServices.append( [startHandle, endHandle, uuid16, uuid128, name]) io.chart(["Start Handle", "End Handle", "UUID16", "UUID128", "Name"], formattedServices, io.colorize(title, "yellow"))
def printAttributes(self, attributes): formattedAttributes = [] for attribute in attributes: aType = ble.UUID(data=attribute["type"]) if aType.name is not None: attributeType = aType.name elif aType.UUID16 is not None: attributeType = hex(aType.UUID16) else: attributeType = aType.UUID128.hex() attributeValue = attribute["value"].replace( b"\x00", b"").decode("ascii") if utils.isPrintable( attribute["value"]) else attribute["value"].hex() attributeHandle = "0x{:04x}".format(attribute["handle"]) formattedAttributes.append( [attributeHandle, attributeType, attributeValue]) io.chart(["Attribute Handle", "Attribute Type", "Attribute Value"], formattedAttributes, io.colorize("Attributes", "yellow"))
def load(self, moduleName: "!method:_autocompleteModules"): ''' This method allows to load a module according to its name. It allows to load a sequence of modules by using the pipe (``|``) symbol. :param moduleName: name of the module (or sequence of modules) to load :type moduleName: str :Example: >>> app.load('ble_info') >>> app.load('ble_connect|ble_discover') ''' modules = moduleName.split("|") if "|" in moduleName else [moduleName] tmpModules = [] counter = 1 noError = True for m in modules: output = self.loader.load(m) if output is not None: io.info("Module " + m + " loaded !") tmpModules.append({ "name": m + str(counter) if len(modules) > 1 else m, "module": output }) counter += 1 for argument in output.args: if self.config.dataExists(m, argument): output.args[argument] = self.config.getData( m, argument) else: io.fail("Unknown module " + m + " !") noError = False break if noError: self.modules = tmpModules self.prompt = io.colorize(" << " + moduleName + " >>~~> ", "cyan")
def showServices(self): ''' This method displays the GATT services described as attributes included in the Database. ''' formattedServices = [] for att in self.attributes: if att is not None and (att.type == UUID(name="Primary Service") or att.type == UUID(name="Secondary Service")): startHandle = "0x{:04x}".format(att.handle) service = Service(data=att.value[::-1]) serviceName = service.UUID.name if service.UUID.name is not None else "" serviceUUID16 = "0x{:04x}".format(service.UUID.UUID16) if service.UUID.UUID16 is not None else "" serviceUUID128 = service.UUID.UUID128.hex() if service.UUID.UUID128 is not None else "" if len(formattedServices) > 0: formattedServices[-1][1] = "0x{:04x}".format(att.handle - 1) formattedServices.append([startHandle,"0x{:04x}".format(0xFFFF),serviceUUID16, serviceUUID128,serviceName]) io.chart(["Start Handle","End Handle", "UUID16", "UUID128", "Name"], formattedServices, io.colorize("Services", "yellow") ) return formattedServices
def __init__(self, prompt=io.colorize(" ~~> ", "cyan"), autocompletion=True, suggestion=True): ''' This constructor initializes the interpreter instance. :param prompt: string used to generate the prompt :type prompt: str :param autocompletion: boolean indicating if the autocompletion mode is enabled :type autocompletion: bool :param suggestion: boolean indicating if the suggestion mode is enabled :type suggestion: bool ''' self.prompt = prompt self.running = True self.autocompletionMode = autocompletion self.suggestionMode = suggestion self.suggestion = "" self.usage = "" self.cursorOffset = 0 self.availableCommands = ["exit"]
def show(self): ''' This method displays a chart to present the ATT level vision of the attributes included in the Database. ''' formattedAttributes = [] for att in self.attributes: if att is not None: aType = att.type if aType.name is not None: attributeType = aType.name elif aType.UUID16 is not None: attributeType = hex(aType.UUID16) else: attributeType = aType.UUID128.hex() attributeValue = att.value.replace(b"\x00",b"").decode("ascii") if utils.isPrintable(att.value) else att.value.hex() attributeHandle = "0x{:04x}".format(att.handle) formattedAttributes.append([attributeHandle, attributeType,attributeValue]) io.chart(["Attribute Handle", "Attribute Type", "Attribute Value"], formattedAttributes, io.colorize("Attributes","yellow") )
def printCharacteristics(self, characteristics, title="Characteristics"): formattedCharacteristics = [] for characteristic in characteristics: declarationHandle = "0x{:04x}".format( characteristic["declarationHandle"]) valueHandle = "0x{:04x}".format(characteristic["valueHandle"]) permissionsFlag = ",".join(characteristic["permissionsFlag"]) uuid16 = (hex(characteristic["uuid"].UUID16) if characteristic["uuid"].UUID16 is not None else "") uuid128 = (characteristic["uuid"].UUID128.hex() if characteristic["uuid"].UUID128 is not None else "") name = (characteristic["uuid"].name if characteristic["uuid"].name is not None else "") value = (characteristic["value"].replace(b"\x00", b"").decode("ascii") if utils.isPrintable(characteristic["value"]) else characteristic["value"].hex()) descriptors = "" if "descriptors" in characteristic: for desc in characteristic["descriptors"]: namedesc = ble.CharacteristicDescriptor( data=desc["type"]).UUID.name valuedesc = ( desc["value"].replace(b"\x00", b"").decode("ascii") if utils.isPrintable(desc["value"]) and len(desc["value"]) > 0 else desc["value"].hex()) endSymbol = "\n" if characteristic["descriptors"][ -1] != desc else "" descriptors += namedesc + " : " + valuedesc + endSymbol formattedCharacteristics.append([ declarationHandle, valueHandle, uuid16, uuid128, name, permissionsFlag, value, descriptors ]) io.chart([ "Declaration Handle", "Value Handle", "UUID16", "UUID128", "Name", "Permissions", "Value", "Descriptors" ], formattedCharacteristics, io.colorize(title, "yellow"))
def updatePrompt(self, address=""): self.prompt = io.colorize( "[SLAVE" + ("|" + address if address != "" else "") + "]: ", "cyan")
def load(self,moduleName:"!method:_autocompleteModules"): ''' This method allows to load a module according to its name. It allows to load a sequence of modules by using the pipe (``|``) symbol. :param moduleName: name of the module (or sequence of modules) to load :type moduleName: str :Example: >>> app.load('ble_info') >>> app.load('ble_connect|ble_discover') ''' modules = moduleName.split("|") if "|" in moduleName else [moduleName] tmpModules = [] counter = 1 noError = True for m in modules: output = self.loader.load(m) if output is not None: io.info("Module "+m+" loaded !") tmpModules.append({"name":m+str(counter) if len(modules) > 1 else m,"module":output}) counter+=1 for argument in output.args: if self.config.dataExists(m,argument): output.args[argument] = self.config.getData(m,argument) elif m in self.loadedShortcuts: io.info("Shortcut "+m+" loaded !") shortcutModules = [] shortcutClasses = [] shortcutCounter = 1 shortcutModulesList = self.loadedShortcuts[m]["modules"].split("|") for n in shortcutModulesList: output = self.loader.load(n) shortcutModules.append({ "name":n+str(shortcutCounter) if len(shortcutModulesList) > 1 else n, "module":output }) for argument in self.loadedShortcuts[m]["mapping"]: mapping = self.loadedShortcuts[m]["mapping"][argument] if mapping["value"] is not None: self._set(argument,mapping["value"],[shortcutModules[-1]]) shortcutCounter+=1 tmpModules.append({ "name":m+str(counter) if len(modules) > 1 else m, "shortcut":shortcutModules, "mapping":self.loadedShortcuts[m]["mapping"] }) counter+=1 else: io.fail("Unknown module "+m+" !") noError = False break if noError: self.modules = tmpModules self.prompt = io.colorize(" << "+moduleName+" >>~~> ","cyan")