dmazzella / uble

Lightweight Bluetooth Low Energy driver written in pure python for micropython

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

i have a problem with aci_gap_create_connection

MatenatK opened this issue · comments

I tried to connect 2 BLE devices (server and client). First-time my server and client used STM32L476RG board and it fine, Next time I changed the client to STM32F767ZI but it doesn't work (same code). Do you have a cause of this phenomenon?

image

Can you provide a minimal test that i can use to check the problem?

This is my minimal testing, and my result

image

import pyb
import gc
import ustruct
import urandom
import utime
from micropython import const

gc.threshold(4096)

import logging
from binascii import hexlify

from bluetooth_low_energy.modules.st_microelectronics.spbtle_rf import SPBTLE_RF
from bluetooth_low_energy.protocols.hci.vendor_specifics.st_microelectronics.bluenrg_ms import event as st_event
from bluetooth_low_energy.protocols.hci.vendor_specifics.st_microelectronics.bluenrg_ms import constant as st_constant
from bluetooth_low_energy.protocols.hci import HCI_EVENT_PKT
from bluetooth_low_energy.protocols.hci import uart
from bluetooth_low_energy.protocols.hci import event
from bluetooth_low_energy.protocols.hci import status

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("examples.AppThT")

SCAN_P = const(0x4000)
SCAN_L = const(0x4000)

#Supervision timeout, arg in msec.
SUPERV_TIMEOUT = const(60)

#Connection period, arg in msec.
CONN_P = lambda x: int(x / 1.25)
#Connection length, arg in msec.
CONN_L = lambda x: int(x / 0.625)

CONN_P1 = CONN_P(50)
CONN_P2 = CONN_P(50)
CONN_L1 = CONN_L(1250)
CONN_L2 = CONN_L(1250)

class AppThT(SPBTLE_RF):

    def __init__(self, *args, **kwargs):
        super(AppThT, self).__init__(*args, **kwargs)

        self.bdaddr = bytes(reversed([0x12, 0x34, 0x00, 0xE1, 0x80, 0x02]))
        self.bdaddr_sever = bytes(reversed([0xe3, 0xbf, 0xb9, 0x03, 0x36, 0xe7]))
        self.charUuid128_TX = bytes(reversed([0xa3,0x2e,0x55,0x20,0xe4,0x77,0x11,0xe2,0xa9,0xe3,0x00,0x02,0xa5,0xd5,0xc5,0x1b]))
        self.charUuid128_RX = bytes(reversed([0x34,0x0a,0x1b,0x80,0xcf,0x4b,0x11,0xe1,0xac,0x36,0x00,0x02,0xa5,0xd5,0xc5,0x1b]))
        
        self.connection_handle = None
        
        self.name = b'PyBLE'

    def run(self, *args, **kwargs):
        def callback():
            if self.connection_handle is not None:
                pass

        super(AppThT, self).run(callback=callback, callback_time = 1000)

    def __start__(self):

        #Reset BlueNRG-MS
        self.reset()

        #Check Evt_Blue_Initialized
        if self.hci_wait_event(
                subevtcode=st_event.EVT_BLUE_HAL_INITIALIZED
            ).struct.reason_code != st_constant.RESET_NORMAL:
            raise ValueError("reason_code")

        #Get the BlueNRG FW versions
        version = self.get_version()
        log.info("current version %s", version)

        #Reset BlueNRG again otherwise we won't be able to change its MAC address.
        #aci_hal_write_config_data() must be the first command after reset otherwise it will fail.
        self.reset()

        #Check Evt_Blue_Initialized
        if self.hci_wait_event(
                subevtcode=st_event.EVT_BLUE_HAL_INITIALIZED
            ).struct.reason_code != st_constant.RESET_NORMAL:
            raise ValueError("reason_code")

            # Configure BlueNRG address as public (its public address is used)
        result = self.aci_hal_write_config_data(
            offset=st_constant.CONFIG_DATA_PUBADDR_OFFSET,
            length=st_constant.CONFIG_DATA_PUBADDR_LEN,
            data=self.bdaddr
        ).response_struct
        if result.status != status.BLE_STATUS_SUCCESS:
            raise ValueError("aci_hal_write_config_data status: {:02x}".format(
                result.status))
        log.debug("aci_hal_write_config_data PUBADDR: %02x", result.status)

        # Init BlueNRG GATT layer
        result = self.aci_gatt_init().response_struct
        if result.status != status.BLE_STATUS_SUCCESS:
            raise ValueError("aci_gatt_init status: {:02x}".format(
                result.status))
        log.debug("aci_gatt_init %02x", result.status)

        # Init BlueNRG GAP layer as peripheral or central
        result = self.aci_gap_init_IDB05A1(
            role=st_constant.GAP_CENTRAL_ROLE_IDB05A1,
            privacy_enabled=bool(st_constant.PRIVACY_DISABLED),
            device_name_char_len=len(self.name)).response_struct
        if result.status != status.BLE_STATUS_SUCCESS:
            raise ValueError("aci_gap_init status: {:02x}".format(
                result.status))
        log.debug("aci_gap_init %02x", result.status)

        result = self.aci_gap_set_auth_requirement(
            mitm_mode=st_constant.MITM_PROTECTION_REQUIRED,
            oob_enable=bool(st_constant.OOB_AUTH_DATA_ABSENT),
            oob_data=b'\x00'*16,
            min_encryption_key_size= const(7),
            max_encryption_key_size= const(16),
            use_fixed_pin=bool(st_constant.USE_FIXED_PIN_FOR_PAIRING),
            fixed_pin=123456,
            bonding_mode=st_constant.BONDING).response_struct
        if result.status != status.BLE_STATUS_SUCCESS:
            raise ValueError("aci_gap_set_auth_requirement status: {:02x}".format(
                result.status))
        log.debug("aci_gap_set_auth_requirement %02x", result.status)


        # Set output power level
        result = self.aci_hal_set_tx_power_level(
            en_high_power=1,
            pa_level=5).response_struct
        if result.status != status.BLE_STATUS_SUCCESS:
            raise ValueError("aci_hal_set_tx_power_level status: {:02x}".format(
                result.status))
        log.debug("aci_hal_set_tx_power_level %02x", result.status)

        # gap create connection
        result = self.aci_gap_create_connection(
            scan_interval = SCAN_P,
            scan_window = SCAN_L,
            peer_bdaddr_type = st_constant.RANDOM_ADDR,
            peer_bdaddr= self.bdaddr_sever,
            own_bdaddr_type= st_constant.PUBLIC_ADDR,
            conn_min_interval= CONN_P1,
            conn_max_interval= CONN_P2,
            conn_latency = 0,
            supervision_timeout = SUPERV_TIMEOUT,
            min_conn_length = CONN_L1,
            max_conn_length = CONN_L2).response_struct

        if result.status != status.BLE_STATUS_SUCCESS:
            raise ValueError("aci_gap_create_connection status: {:02x}".format(
                result.status))
        log.debug("aci_gap_create_connection %02x", result.status)
  
        print("Basic Initialized END")
        #END

    def __stop__(self):
        # Reset BlueNRG-MS
        self.reset()

    def __process__(self, evt):
        # Process event received from BlueNRG-MS
        hci_uart = uart.HCI_UART.from_buffer(evt)
        log.debug(hci_uart)

        if hci_uart.pkt_type == HCI_EVENT_PKT:
            hci_evt = event.HCI_EVENT.from_buffer(hci_uart.data)
            log.debug(hci_evt)

            if hci_evt.evtcode == event.EVT_DISCONN_COMPLETE:
                self.gap_disconnection_complete_cb()

            elif hci_evt.evtcode == event.EVT_LE_META_EVENT:
                if hci_evt.subevtcode == event.EVT_LE_CONN_COMPLETE:
                    self.gap_connection_complete_cb(
                        hci_evt.struct.peer_bdaddr,
                        hci_evt.struct.handle
                    )

            elif hci_evt.evtcode == event.EVT_VENDOR:

                if hci_evt.subevtcode == st_event.EVT_BLUE_GATT_ATTRIBUTE_MODIFIED:
                    self.attribute_modified_cb(
                        hci_evt.struct.attr_handle,
                        hci_evt.struct.data_length,
                        hci_evt.struct.att_data[:hci_evt.struct.data_length]
                    )

                elif hci_evt.subevtcode == st_event.EVT_BLUE_GATT_DISC_READ_CHAR_BY_UUID_RESP:
                    self.evt_gatt_disc_read_char_by_uuid_resp(hci_evt.struct.attr_handle)

                elif hci_evt.subevtcode == st_event.EVT_BLUE_GATT_NOTIFICATION:
                    log.debug("EVT_BLUE_GATT_NOTIFICATION")
                    self.notification_cb(
                        hci_evt.struct.conn_handle,
                        hci_evt.struct.attr_handle,
                        hci_evt.struct.event_data_length - 2,
                        hci_evt.struct.attr_value)

                elif hci_evt.subevtcode == st_event.EVT_BLUE_ATT_READ_RESP:
                    log.debug("EVT_BLUE_ATT_READ_RESP")
                    self.BlueAttReadResp(
                        hci_evt.struct.conn_handle,
                        hci_evt.struct.event_data_length,
                        hci_evt.struct.attribute_value)

                elif hci_evt.subevtcode == st_event.EVT_BLUE_GATT_PROCEDURE_COMPLETE:
                    # Wait for gatt procedure complete event trigger related to
                    # Discovery Charac by UUID
                    log.debug("EVT_BLUE_GATT_PROCEDURE_COMPLETE")
                    #log.info("EVT_BLUE_GATT_PROCEDURE_COMPLETE")

                elif hci_evt.subevtcode == st_event.EVT_BLUE_GATT_WRITE_PERMIT_REQ:
                    print("EVT_BLUE_GATT_WRITE_PERMIT_REQ")
                    result = self.aci_gatt_write_response(
                        conn_handle=self.connection_handle,
                        attr_handle=hci_evt.struct.attr_handle,
                        write_status=False,
                        err_code=0,
                        att_val_len=hci_evt.struct.data_length,
                        att_val=hci_evt.struct.data_buffer[:hci_evt.struct.data_length]
                        ).response_struct
                    if result.status != status.BLE_STATUS_SUCCESS:
                        self.attribute_modified_cb(
                            hci_evt.struct.attr_handle,
                            hci_evt.struct.data_length,
                            hci_evt.struct.data_buffer[:hci_evt.struct.data_length]
                        )

                elif hci_evt.subevtcode == st_event.EVT_BLUE_GATT_READ_PERMIT_REQ:
                    self.read_request_cb(hci_evt.struct.attr_handle)
                    
    def gap_connection_complete_cb(self, address, handle):
        log.info("gap_connection_complete_cb")     
        self.connection_handle = handle
        print("gap_connection_completeed = "+str(self.connection_handle))

    def gap_disconnection_complete_cb(self):
        log.info("gap_disconnection_complete_cb")
        self.connection_handle = None
        self.set_connectable()

    def attribute_modified_cb(self, handle, data_length, att_data):
        log.debug("attribute_modified_cb %04x %d %s",
                  handle, data_length, hexlify(att_data))

    def read_request_cb(self, handle):
        log.debug("read_request_cb %04x", handle)

        if self.connection_handle is not None:
            result = self.aci_gatt_allow_read(
                conn_handle=self.connection_handle).response_struct
            if result.status != status.BLE_STATUS_SUCCESS:
                raise ValueError("aci_gatt_allow_read status: {:02x}".format(
                    result.status))
            log.debug("aci_gatt_allow_read %02x", result.status)

With hardware i can test (pyboard 1.1, custom espruino pico with stm32f413) i have no issue with your code.

Have you successfully executed all the examples provided into this repo with the f7 hardware?

Yes F767 can run all of your examples (basic, sensor_demo, bluest_protocol)

STM32F767ZI efficiently works in server mode, but if it works as a client it has a problem with aci_gap_create_connection command.

Have you tried the IDB05A1 that work on the l4 on the f7?

Yes! F7 can run all of examples, L4 also.

I mean, did you try the same X-NUCLEO-IDB05A1 board on the F7 that work correctly on the L4?

Yes i did

can please send me board configuration files for the F7 and pins configuration for BlueNRG_MS?

I have attached my file below.
With this config, I can run your example as good.

f767zi

attached file: F767_con.zip

Can you please switch Logging level to DEBUG and paste me the output?

change:
log.info("gap_connection_complete_cb") to
log.info("gap_connection_complete_cb %s", hexlify(bytearray(reversed(address)), ":"))

and:
log.debug(hci_uart) to log.debug("%s", hci_uart)
log.debug(hci_evt) to log.debug("%s", hci_evt)

This is my result

image

Can you add some debug print into hci_send_cmd of bluenrg_ms.py?

I am sorry for this type of interaction but without hardware i can't help without your hand.

I have added print command into hci_send_cmd of bluenrg_ms.py and this is a result.

image

Can you add print after event = self.read(retry=retry)?

Yeah!

image

Can you please enable print for header, param and for event? and can you poste the result for L4 and F7?

OK, i got it!

image

Have you tried to to use another spi port?

Without hardware I can not verify the problem, for now I close the issue ...