コード例 #1
0
def main(serial_port):
    # Create and open the device
    ble_device = BleDevice(serial_port)
    ble_device.configure()
    ble_device.open()

    # Set up desired security parameters
    ble_device.client.security.set_security_params(passcode_pairing=False, bond=False, lesc_pairing=False,
                                                   io_capabilities=IoCapabilities.DISPLAY_ONLY, out_of_band=False)
    ble_device.client.security.on_pairing_complete.register(on_client_pairing_complete)
    ble_device.client.security.on_passkey_display_required.register(on_passkey_display)
    ble_device.client.security.on_passkey_required.register(on_passkey_entry)
    ble_device.client.security.on_security_level_changed.register(on_security_level_changed)

    # Create and add the math service
    service = ble_device.database.add_service(constants.MATH_SERVICE_UUID)

    # Create and add the hex conversion characteristic to the service
    hex_conv_char = service.add_characteristic(constants.HEX_CONVERT_CHAR_UUID,
                                               constants.HEX_CONVERT_CHAR_PROPERTIES, "Test Data")
    # Register the callback for when a write occurs and subscription state changes
    hex_conv_char.on_write.register(on_hex_conversion_characteristic_write)
    hex_conv_char.on_subscription_change.register(on_gatts_subscription_state_changed)

    # Create and add the counting characteristic, initializing the data to [0, 0, 0, 0]
    counting_char = service.add_characteristic(constants.COUNTING_CHAR_UUID, constants.COUNTING_CHAR_PROPERTIES, [0]*4)
    counting_char.on_subscription_change.register(on_gatts_subscription_state_changed)

    # Create the thread for the counting characteristic
    counting_char_thread = CountingCharacteristicThread(counting_char)

    # Create and add the time service
    time_service = ble_device.database.add_service(constants.TIME_SERVICE_UUID)

    # Add the time characteristic and register the callback for when its read
    time_char = time_service.add_characteristic(constants.TIME_CHAR_UUID, constants.TIME_CHAR_PROPERTIES, "Time")
    time_char.on_read.register(on_time_char_read)

    # Initialize the advertising and scan response data
    adv_data = advertising.AdvertisingData(local_name=constants.PERIPHERAL_NAME, flags=0x06)
    scan_data = advertising.AdvertisingData(service_uuid128s=constants.TIME_SERVICE_UUID, has_more_uuid128_services=True)
    ble_device.advertiser.set_advertise_data(adv_data, scan_data)

    # Start advertising
    logger.info("Advertising")
    ble_device.client.on_connect.register(on_connect)
    ble_device.client.on_disconnect.register(on_disconnect)
    ble_device.advertiser.start(timeout_sec=0, auto_restart=True)

    # Create a waitable that will never fire, and wait for some time
    w = GenericWaitable()
    w.wait(60*30, exception_on_timeout=False)  # Keep device active for 30 mins

    # Cleanup
    counting_char_thread.join()
    logger.info("Done")
    ble_device.close()
コード例 #2
0
def _configure_device(dev_number, config, optional=False):
    env_key = BLATANN_DEV_ENVKEY_FORMAT.format(dev_number)
    comport = os.environ.get(env_key, None)
    if not comport:
        if optional:
            return None
        raise EnvironmentError(
            f"Environment variable {env_key} must be defined with the device's comport"
        )
    dev = BleDevice(comport,
                    bond_db_filename=BOND_DB_FILE_FMT.format(dev_number))
    dev.configure(**config)
    dev.event_logger.suppress(nrf_events.GapEvtAdvReport)
    return dev
コード例 #3
0
def main(serial_port):
    ble_device = BleDevice(serial_port)
    # Configure the BLE device to support MTU sizes which allow the max data length extension PDU size
    # Note this isn't 100% necessary as the default configuration sets the max to this value also
    ble_device.configure(att_mtu_max_size=MTU_SIZE_FOR_MAX_DLE)
    ble_device.open()

    # Create and add the Nordic UART service
    nus = nordic_uart.add_nordic_uart_service(ble_device.database)
    nus.on_data_received.register(on_data_rx)
    nus.on_write_complete.register(on_tx_complete)

    # Register listeners for when the client connects and disconnects
    ble_device.client.on_connect.register(on_connect)
    ble_device.client.on_disconnect.register(on_disconnect)
    ble_device.client.on_mtu_size_updated.register(on_mtu_size_update)

    # Configure the client to prefer the max MTU size
    ble_device.client.preferred_mtu_size = ble_device.max_mtu_size
    ble_device.client.set_connection_parameters(7.5, 15, 4000)

    # Advertise the service UUID
    adv_data = advertising.AdvertisingData(flags=0x06,
                                           local_name="Nordic UART Server")
    scan_data = advertising.AdvertisingData(
        service_uuid128s=nordic_uart.NORDIC_UART_SERVICE_UUID)

    ble_device.advertiser.set_advertise_data(adv_data, scan_data)

    logger.info("Advertising")

    ble_device.advertiser.start(timeout_sec=0, auto_restart=True)

    # Create a waitable that waits 5 minutes then exits
    w = GenericWaitable()
    try:
        w.wait(5 * 60, exception_on_timeout=False)
    except KeyboardInterrupt:
        pass
    finally:
        ble_device.close()
コード例 #4
0
def main(serial_port):
    # Open the BLE Device and suppress spammy log messages
    ble_device = BleDevice(serial_port)
    ble_device.event_logger.suppress(nrf_events.GapEvtAdvReport)
    # Configure the BLE device to support MTU sizes which allow the max data length extension PDU size
    # Note this isn't 100% necessary as the default configuration sets the max to this value also
    ble_device.configure(att_mtu_max_size=MTU_SIZE_FOR_MAX_DLE)
    ble_device.open()

    # Set scan duration for 4 seconds
    ble_device.scanner.set_default_scan_params(timeout_seconds=4)
    ble_device.set_default_peripheral_connection_params(10, 30, 4000)
    logger.info("Scanning for peripherals advertising UUID {}".format(
        nordic_uart.NORDIC_UART_SERVICE_UUID))

    target_address = None
    # Start scan and wait for it to complete
    scan_report = ble_device.scanner.start_scan().wait()
    # Search each peer's advertising data for the Nordic UART Service UUID to be advertised
    for report in scan_report.advertising_peers_found:
        if nordic_uart.NORDIC_UART_SERVICE_UUID in report.advertise_data.service_uuid128s and report.device_name == "Nordic UART Server":
            target_address = report.peer_address
            break

    if not target_address:
        logger.info("Did not find peripheral advertising Nordic UART service")
        return

    # Initiate connection and wait for it to finish
    logger.info("Found match: connecting to address {}".format(target_address))
    peer = ble_device.connect(target_address).wait()
    if not peer:
        logger.warning("Timed out connecting to device")
        return

    logger.info("Connected, conn_handle: {}".format(peer.conn_handle))

    logger.info("Exchanging MTU")
    peer.exchange_mtu(peer.max_mtu_size).wait(10)
    logger.info("MTU Exchange complete, discovering services")

    # Initiate service discovery and wait for it to complete
    _, event_args = peer.discover_services().wait(exception_on_timeout=False)
    logger.info("Service discovery complete! status: {}".format(
        event_args.status))

    uart_service = nordic_uart.find_nordic_uart_service(peer.database)
    if not uart_service:
        logger.info(
            "Failed to find Nordic UART service in peripheral database")
        peer.disconnect().wait()
        ble_device.close()
        return

    # Initialize the service
    uart_service.initialize().wait(5)
    uart_service.on_data_received.register(on_data_rx)

    while True:
        data = input("Enter data to send to peripheral (q to exit): ")
        if data == "q":
            break
        uart_service.write(data).wait(10)

    peer.disconnect().wait()
    ble_device.close()
コード例 #5
0
def main(serial_port):
    # Create and open the device
    ble_device = BleDevice(serial_port)
    ble_device.configure()
    ble_device.open()

    # Create the service
    service = ble_device.database.add_service(
        constants.DESC_EXAMPLE_SERVICE_UUID)

    # Create a characteristic and add some descriptors
    # NOTE: Some descriptors MUST be added during creation: SCCD, User Description, and Presentation Format
    #       CCCD is added automatically based on the characteristic's Notify and Indicate properties

    # Define the User Description properties and make it writable
    # The simplest use-case in which the user description is read-only can provide just the first parameter
    user_desc_props = gatts.GattsUserDescriptionProperties(
        "UTC Time",
        write=True,
        security_level=smp.SecurityLevel.OPEN,
        max_length=20,
        variable_length=True)
    # Define the presentation format. Returning the time in seconds so set exponent to 0
    presentation_format = PresentationFormat(fmt=Format.uint32,
                                             exponent=0,
                                             unit=Units.time_second)
    # Create the characteristic properties, including the SCCD, User Description, and Presentation Format
    char_props = gatts.GattsCharacteristicProperties(
        read=True,
        write=False,
        notify=True,
        max_length=Uint32.byte_count,
        variable_length=False,
        sccd=True,
        user_description=user_desc_props,
        presentation_format=presentation_format)
    char = service.add_characteristic(constants.DESC_EXAMPLE_CHAR_UUID,
                                      char_props, Uint32.encode(0))
    char.on_read.register(on_read)

    # Add another descriptor to the list
    char_range_value = Uint32.encode(5555) + Uint32.encode(2**32 - 1000)
    desc_props = GattsAttributeProperties(read=True,
                                          write=False,
                                          variable_length=False,
                                          max_length=len(char_range_value))
    char.add_descriptor(DescriptorUuid.valid_range, desc_props,
                        char_range_value)

    # Initialize the advertising and scan response data
    adv_data = advertising.AdvertisingData(
        local_name=constants.PERIPHERAL_NAME, flags=0x06)
    scan_data = advertising.AdvertisingData(
        service_uuid128s=constants.DESC_EXAMPLE_SERVICE_UUID,
        has_more_uuid128_services=False)
    ble_device.advertiser.set_advertise_data(adv_data, scan_data)

    # Start advertising
    logger.info("Advertising")
    ble_device.client.on_connect.register(on_connect)
    ble_device.client.on_disconnect.register(on_disconnect)
    ble_device.advertiser.start(timeout_sec=0, auto_restart=True)

    # Create a waitable that will never fire, and wait for some time
    w = GenericWaitable()
    w.wait(60 * 30,
           exception_on_timeout=False)  # Keep device active for 30 mins

    logger.info("Done")
    ble_device.close()
コード例 #6
0
def main(serial_port):
    # Create and open the device
    ble_device = BleDevice(serial_port)
    ble_device.configure()
    ble_device.open()

    ble_device.scanner.set_default_scan_params(timeout_seconds=4)

    # Set the target to the peripheral's advertised name
    target_device_name = constants.PERIPHERAL_NAME

    logger.info("Scanning for '{}'".format(target_device_name))
    target_address = example_utils.find_target_device(ble_device, target_device_name)

    if not target_address:
        logger.info("Did not find target peripheral")
        return

    # Initiate the connection and wait for it to finish
    logger.info("Found match: connecting to address {}".format(target_address))
    peer = ble_device.connect(target_address).wait()
    if not peer:
        logger.warning("Timed out connecting to device")
        return
    logger.info("Connected, conn_handle: {}".format(peer.conn_handle))

    # Wait up to 10 seconds for service discovery to complete
    _, event_args = peer.discover_services().wait(10, exception_on_timeout=False)
    logger.info("Service discovery complete! status: {}".format(event_args.status))

    # Find the Time characteristic
    time_char = peer.database.find_characteristic(constants.DESC_EXAMPLE_CHAR_UUID)
    if not time_char:
        logger.info("Did not find the time characteristic")
    else:
        logger.info("Reading all characteristic attributes")
        for attr in time_char.attributes:
            logger.info(f"Reading UUID {attr.uuid} - {attr.uuid.description or '[unknown]'}")
            _, event_args = attr.read().wait(5)
            if event_args.status == GattStatusCode.success:
                # Show as hex unless it's the user descriptor UUID which should be a string
                if attr.uuid == DescriptorUuid.user_description:
                    value = event_args.value.decode("utf8")
                else:
                    value = binascii.hexlify(event_args.value)
                logger.info(f"    Value: {value}")
            else:
                logger.warning(f"    Failed to read attribute, status: {event_args.status}")

        # Read the characteristic's Presentation Format descriptor directly and decode the value
        presentation_fmt_desc = time_char.find_descriptor(DescriptorUuid.presentation_format)
        if presentation_fmt_desc:
            # Read, then decode the value using the PresentationFormat type
            logger.info("Reading the presentation format descriptor directly")
            _, event_args = presentation_fmt_desc.read().wait(5)
            if event_args.status == GattStatusCode.success:
                try:
                    fmt = PresentationFormat.decode(event_args.value)
                    logger.info(f"Presentation Format: {str(fmt.format)}, Exponent: {fmt.exponent}, Unit: {str(fmt.unit)}")
                except Exception as e:
                    logger.error("Failed to decode the presentation format descriptor")
                    logger.exception(e)
        else:
            logger.info("Failed to find the presentation format descriptor")

    # Clean up
    logger.info("Disconnecting from peripheral")
    peer.disconnect().wait()
    ble_device.close()