diff --git a/include/zephyr/bluetooth/hci.h b/include/zephyr/bluetooth/hci.h index 70fa845027a..8dd7434e445 100644 --- a/include/zephyr/bluetooth/hci.h +++ b/include/zephyr/bluetooth/hci.h @@ -10,2980 +10,16 @@ #include #include -#include -#include -#include -#include #include #include -#include #include +#include #ifdef __cplusplus extern "C" { #endif -/* Special own address types for LL privacy (used in adv & scan parameters) */ -#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 -#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 -#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 - -#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe -#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff - -#define BT_ENC_KEY_SIZE_MIN 0x07 -#define BT_ENC_KEY_SIZE_MAX 0x10 - -#define BT_HCI_ADV_HANDLE_INVALID 0xff -#define BT_HCI_SYNC_HANDLE_INVALID 0xffff -#define BT_HCI_PAWR_SUBEVENT_MAX 128 - -struct bt_hci_evt_hdr { - uint8_t evt; - uint8_t len; -} __packed; -#define BT_HCI_EVT_HDR_SIZE 2 - -#define BT_ACL_START_NO_FLUSH 0x00 -#define BT_ACL_CONT 0x01 -#define BT_ACL_START 0x02 -#define BT_ACL_COMPLETE 0x03 - -#define BT_ACL_POINT_TO_POINT 0x00 -#define BT_ACL_BROADCAST 0x01 - -#define BT_ACL_HANDLE_MASK BIT_MASK(12) - -#define bt_acl_handle(h) ((h) & BT_ACL_HANDLE_MASK) -#define bt_acl_flags(h) ((h) >> 12) -#define bt_acl_flags_pb(f) ((f) & BIT_MASK(2)) -#define bt_acl_flags_bc(f) ((f) >> 2) -#define bt_acl_handle_pack(h, f) ((h) | ((f) << 12)) - -struct bt_hci_acl_hdr { - uint16_t handle; - uint16_t len; -} __packed; -#define BT_HCI_ACL_HDR_SIZE 4 - -#define BT_ISO_START 0x00 -#define BT_ISO_CONT 0x01 -#define BT_ISO_SINGLE 0x02 -#define BT_ISO_END 0x03 - -#define bt_iso_handle(h) ((h) & 0x0fff) -#define bt_iso_flags(h) ((h) >> 12) -#define bt_iso_flags_pb(f) ((f) & 0x0003) -#define bt_iso_flags_ts(f) (((f) >> 2) & 0x0001) -#define bt_iso_pack_flags(pb, ts) \ - (((pb) & 0x0003) | (((ts) & 0x0001) << 2)) -#define bt_iso_handle_pack(h, pb, ts) \ - ((h) | (bt_iso_pack_flags(pb, ts) << 12)) -#define bt_iso_hdr_len(h) ((h) & BIT_MASK(14)) - -#define BT_ISO_DATA_VALID 0x00 -#define BT_ISO_DATA_INVALID 0x01 -#define BT_ISO_DATA_NOP 0x02 - -#define bt_iso_pkt_len(h) ((h) & 0x3fff) -#define bt_iso_pkt_flags(h) ((h) >> 14) -#define bt_iso_pkt_len_pack(h, f) ((h) | ((f) << 14)) - -struct bt_hci_iso_data_hdr { - uint16_t sn; - uint16_t slen; -} __packed; -#define BT_HCI_ISO_DATA_HDR_SIZE 4 - -struct bt_hci_iso_ts_data_hdr { - uint32_t ts; - struct bt_hci_iso_data_hdr data; -} __packed; -#define BT_HCI_ISO_TS_DATA_HDR_SIZE 8 - -struct bt_hci_iso_hdr { - uint16_t handle; /* 12 bit handle, 2 bit PB flags, 1 bit TS_Flag, 1 bit RFU */ - uint16_t len; /* 14 bits, 2 bits RFU */ -} __packed; -#define BT_HCI_ISO_HDR_SIZE 4 - -struct bt_hci_cmd_hdr { - uint16_t opcode; - uint8_t param_len; -} __packed; -#define BT_HCI_CMD_HDR_SIZE 3 - -/* Supported Commands */ -#define BT_CMD_TEST(cmd, octet, bit) (cmd[octet] & BIT(bit)) -#define BT_CMD_LE_STATES(cmd) BT_CMD_TEST(cmd, 28, 3) - -#define BT_FEAT_TEST(feat, page, octet, bit) (feat[page][octet] & BIT(bit)) - -#define BT_FEAT_BREDR(feat) !BT_FEAT_TEST(feat, 0, 4, 5) -#define BT_FEAT_LE(feat) BT_FEAT_TEST(feat, 0, 4, 6) -#define BT_FEAT_EXT_FEATURES(feat) BT_FEAT_TEST(feat, 0, 7, 7) -#define BT_FEAT_HOST_SSP(feat) BT_FEAT_TEST(feat, 1, 0, 0) -#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0) - -#define BT_FEAT_LMP_ESCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 3, 7) -#define BT_FEAT_HV2_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 4) -#define BT_FEAT_HV3_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 5) -#define BT_FEAT_EV4_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 0) -#define BT_FEAT_EV5_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 1) -#define BT_FEAT_2EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 5) -#define BT_FEAT_3EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 6) -#define BT_FEAT_3SLOT_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 7) - -/* LE features */ -#define BT_LE_FEAT_BIT_ENC 0 -#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1 -#define BT_LE_FEAT_BIT_EXT_REJ_IND 2 -#define BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG 3 -#define BT_LE_FEAT_BIT_PING 4 -#define BT_LE_FEAT_BIT_DLE 5 -#define BT_LE_FEAT_BIT_PRIVACY 6 -#define BT_LE_FEAT_BIT_EXT_SCAN 7 -#define BT_LE_FEAT_BIT_PHY_2M 8 -#define BT_LE_FEAT_BIT_SMI_TX 9 -#define BT_LE_FEAT_BIT_SMI_RX 10 -#define BT_LE_FEAT_BIT_PHY_CODED 11 -#define BT_LE_FEAT_BIT_EXT_ADV 12 -#define BT_LE_FEAT_BIT_PER_ADV 13 -#define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 -#define BT_LE_FEAT_BIT_PWR_CLASS_1 15 -#define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 -#define BT_LE_FEAT_BIT_CONN_CTE_REQ 17 -#define BT_LE_FEAT_BIT_CONN_CTE_RESP 18 -#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX 19 -#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX 20 -#define BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD 21 -#define BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA 22 -#define BT_LE_FEAT_BIT_RX_CTE 23 -#define BT_LE_FEAT_BIT_PAST_SEND 24 -#define BT_LE_FEAT_BIT_PAST_RECV 25 -#define BT_LE_FEAT_BIT_SCA_UPDATE 26 -#define BT_LE_FEAT_BIT_REMOTE_PUB_KEY_VALIDATE 27 -#define BT_LE_FEAT_BIT_CIS_CENTRAL 28 -#define BT_LE_FEAT_BIT_CIS_PERIPHERAL 29 -#define BT_LE_FEAT_BIT_ISO_BROADCASTER 30 -#define BT_LE_FEAT_BIT_SYNC_RECEIVER 31 -#define BT_LE_FEAT_BIT_ISO_CHANNELS 32 -#define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 -#define BT_LE_FEAT_BIT_PWR_CHG_IND 34 -#define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 -#define BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP 36 -#define BT_LE_FEAT_BIT_CONN_SUBRATING 37 -#define BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP 38 -#define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 - -#define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43 -#define BT_LE_FEAT_BIT_PAWR_SCANNER 44 - -#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ - BIT((n) & 7)) - -#define BT_FEAT_LE_ENCR(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ENC) -#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_PARAM_REQ) -#define BT_FEAT_LE_PER_INIT_FEAT_XCHG(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG) -#define BT_FEAT_LE_DLE(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_DLE) -#define BT_FEAT_LE_PHY_2M(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PHY_2M) -#define BT_FEAT_LE_PHY_CODED(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PHY_CODED) -#define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PRIVACY) -#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_EXT_ADV) -#define BT_FEAT_LE_EXT_PER_ADV(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PER_ADV) -#define BT_FEAT_LE_CONNECTION_CTE_REQ(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_CTE_REQ) -#define BT_FEAT_LE_CONNECTION_CTE_RESP(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_CTE_RESP) -#define BT_FEAT_LE_CONNECTIONLESS_CTE_TX(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX) -#define BT_FEAT_LE_CONNECTIONLESS_CTE_RX(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX) -#define BT_FEAT_LE_ANT_SWITCH_TX_AOD(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD) -#define BT_FEAT_LE_ANT_SWITCH_RX_AOA(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA) -#define BT_FEAT_LE_RX_CTE(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_RX_CTE) -#define BT_FEAT_LE_PAST_SEND(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAST_SEND) -#define BT_FEAT_LE_PAST_RECV(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAST_RECV) -#define BT_FEAT_LE_CIS_CENTRAL(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CIS_CENTRAL) -#define BT_FEAT_LE_CIS_PERIPHERAL(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CIS_PERIPHERAL) -#define BT_FEAT_LE_ISO_BROADCASTER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ISO_BROADCASTER) -#define BT_FEAT_LE_SYNC_RECEIVER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_SYNC_RECEIVER) -#define BT_FEAT_LE_ISO_CHANNELS(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ISO_CHANNELS) -#define BT_FEAT_LE_PWR_CTRL_REQ(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PWR_CTRL_REQ) -#define BT_FEAT_LE_PWR_CHG_IND(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PWR_CHG_IND) -#define BT_FEAT_LE_PATH_LOSS_MONITOR(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PATH_LOSS_MONITOR) -#define BT_FEAT_LE_PER_ADV_ADI_SUPP(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP) -#define BT_FEAT_LE_CONN_SUBRATING(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_SUBRATING) -#define BT_FEAT_LE_CONN_SUBRATING_HOST_SUPP(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP) -#define BT_FEAT_LE_CHANNEL_CLASSIFICATION(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION) -#define BT_FEAT_LE_PAWR_ADVERTISER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAWR_ADVERTISER) -#define BT_FEAT_LE_PAWR_SCANNER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAWR_SCANNER) - -#define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \ - BT_FEAT_LE_CIS_PERIPHERAL(feat)) -#define BT_FEAT_LE_BIS(feat) (BT_FEAT_LE_ISO_BROADCASTER(feat) | \ - BT_FEAT_LE_SYNC_RECEIVER(feat)) -#define BT_FEAT_LE_ISO(feat) (BT_FEAT_LE_CIS(feat) | \ - BT_FEAT_LE_BIS(feat)) - -/* LE States */ -#define BT_LE_STATES_PER_CONN_ADV(states) (states & 0x0000004000000000) - -/* Bonding/authentication types */ -#define BT_HCI_NO_BONDING 0x00 -#define BT_HCI_NO_BONDING_MITM 0x01 -#define BT_HCI_DEDICATED_BONDING 0x02 -#define BT_HCI_DEDICATED_BONDING_MITM 0x03 -#define BT_HCI_GENERAL_BONDING 0x04 -#define BT_HCI_GENERAL_BONDING_MITM 0x05 - -/* - * MITM protection is enabled in SSP authentication requirements octet when - * LSB bit is set. - */ -#define BT_MITM 0x01 - -/* I/O capabilities */ -#define BT_IO_DISPLAY_ONLY 0x00 -#define BT_IO_DISPLAY_YESNO 0x01 -#define BT_IO_KEYBOARD_ONLY 0x02 -#define BT_IO_NO_INPUT_OUTPUT 0x03 - -/* SCO packet types */ -#define HCI_PKT_TYPE_HV1 0x0020 -#define HCI_PKT_TYPE_HV2 0x0040 -#define HCI_PKT_TYPE_HV3 0x0080 - -/* eSCO packet types */ -#define HCI_PKT_TYPE_ESCO_HV1 0x0001 -#define HCI_PKT_TYPE_ESCO_HV2 0x0002 -#define HCI_PKT_TYPE_ESCO_HV3 0x0004 -#define HCI_PKT_TYPE_ESCO_EV3 0x0008 -#define HCI_PKT_TYPE_ESCO_EV4 0x0010 -#define HCI_PKT_TYPE_ESCO_EV5 0x0020 -#define HCI_PKT_TYPE_ESCO_2EV3 0x0040 -#define HCI_PKT_TYPE_ESCO_3EV3 0x0080 -#define HCI_PKT_TYPE_ESCO_2EV5 0x0100 -#define HCI_PKT_TYPE_ESCO_3EV5 0x0200 - - -#define ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_HV1 | \ - HCI_PKT_TYPE_ESCO_HV2 | \ - HCI_PKT_TYPE_ESCO_HV3) -#define SCO_PKT_MASK (HCI_PKT_TYPE_HV1 | \ - HCI_PKT_TYPE_HV2 | \ - HCI_PKT_TYPE_HV3) -#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ - HCI_PKT_TYPE_ESCO_3EV3 | \ - HCI_PKT_TYPE_ESCO_2EV5 | \ - HCI_PKT_TYPE_ESCO_3EV5) - -/* HCI BR/EDR link types */ -#define BT_HCI_SCO 0x00 -#define BT_HCI_ACL 0x01 -#define BT_HCI_ESCO 0x02 - -/* OpCode Group Fields */ -#define BT_OGF_LINK_CTRL 0x01 -#define BT_OGF_BASEBAND 0x03 -#define BT_OGF_INFO 0x04 -#define BT_OGF_STATUS 0x05 -#define BT_OGF_LE 0x08 -#define BT_OGF_VS 0x3f - -/* Construct OpCode from OGF and OCF */ -#define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) - -/* Invalid opcode */ -#define BT_OP_NOP 0x0000 - -/* Obtain OGF from OpCode */ -#define BT_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) -/* Obtain OCF from OpCode */ -#define BT_OCF(opcode) ((opcode) & BIT_MASK(10)) - -#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) -struct bt_hci_op_inquiry { - uint8_t lap[3]; - uint8_t length; - uint8_t num_rsp; -} __packed; - -#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) - -#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) -struct bt_hci_cp_connect { - bt_addr_t bdaddr; - uint16_t packet_type; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint16_t clock_offset; - uint8_t allow_role_switch; -} __packed; - -#define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) -struct bt_hci_cp_disconnect { - uint16_t handle; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) -struct bt_hci_cp_connect_cancel { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_connect_cancel { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) -struct bt_hci_cp_accept_conn_req { - bt_addr_t bdaddr; - uint8_t role; -} __packed; - -#define BT_HCI_OP_SETUP_SYNC_CONN BT_OP(BT_OGF_LINK_CTRL, 0x0028) -struct bt_hci_cp_setup_sync_conn { - uint16_t handle; - uint32_t tx_bandwidth; - uint32_t rx_bandwidth; - uint16_t max_latency; - uint16_t content_format; - uint8_t retrans_effort; - uint16_t pkt_type; -} __packed; - -#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) -struct bt_hci_cp_accept_sync_conn_req { - bt_addr_t bdaddr; - uint32_t tx_bandwidth; - uint32_t rx_bandwidth; - uint16_t max_latency; - uint16_t content_format; - uint8_t retrans_effort; - uint16_t pkt_type; -} __packed; - -#define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) -struct bt_hci_cp_reject_conn_req { - bt_addr_t bdaddr; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_LINK_KEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000b) -struct bt_hci_cp_link_key_reply { - bt_addr_t bdaddr; - uint8_t link_key[16]; -} __packed; - -#define BT_HCI_OP_LINK_KEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000c) -struct bt_hci_cp_link_key_neg_reply { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_PIN_CODE_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000d) -struct bt_hci_cp_pin_code_reply { - bt_addr_t bdaddr; - uint8_t pin_len; - uint8_t pin_code[16]; -} __packed; -struct bt_hci_rp_pin_code_reply { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_PIN_CODE_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000e) -struct bt_hci_cp_pin_code_neg_reply { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_pin_code_neg_reply { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) -struct bt_hci_cp_auth_requested { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) -struct bt_hci_cp_set_conn_encrypt { - uint16_t handle; - uint8_t encrypt; -} __packed; - -#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) -struct bt_hci_cp_remote_name_request { - bt_addr_t bdaddr; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint16_t clock_offset; -} __packed; - -#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) -struct bt_hci_cp_remote_name_cancel { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_remote_name_cancel { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_READ_REMOTE_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001b) -struct bt_hci_cp_read_remote_features { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_READ_REMOTE_EXT_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001c) -struct bt_hci_cp_read_remote_ext_features { - uint16_t handle; - uint8_t page; -} __packed; - -#define BT_HCI_OP_READ_REMOTE_VERSION_INFO BT_OP(BT_OGF_LINK_CTRL, 0x001d) -struct bt_hci_cp_read_remote_version_info { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) -struct bt_hci_cp_io_capability_reply { - bt_addr_t bdaddr; - uint8_t capability; - uint8_t oob_data; - uint8_t authentication; -} __packed; - -#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) -#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) -struct bt_hci_cp_user_confirm_reply { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_user_confirm_reply { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) -struct bt_hci_cp_user_passkey_reply { - bt_addr_t bdaddr; - uint32_t passkey; -} __packed; - -#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) -struct bt_hci_cp_user_passkey_neg_reply { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) -struct bt_hci_cp_io_capability_neg_reply { - bt_addr_t bdaddr; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) -struct bt_hci_cp_set_event_mask { - uint8_t events[8]; -} __packed; - -#define BT_HCI_OP_RESET BT_OP(BT_OGF_BASEBAND, 0x0003) - -#define BT_HCI_OP_WRITE_LOCAL_NAME BT_OP(BT_OGF_BASEBAND, 0x0013) -struct bt_hci_write_local_name { - uint8_t local_name[248]; -} __packed; - -#define BT_HCI_OP_READ_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0015) -struct bt_hci_rp_read_conn_accept_timeout { - uint8_t status; - uint16_t conn_accept_timeout; -} __packed; - -#define BT_HCI_OP_WRITE_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0016) -struct bt_hci_cp_write_conn_accept_timeout { - uint16_t conn_accept_timeout; -} __packed; - -struct bt_hci_rp_write_conn_accept_timeout { - uint8_t status; -} __packed; - -#define BT_HCI_OP_WRITE_PAGE_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0018) - -#define BT_HCI_OP_WRITE_SCAN_ENABLE BT_OP(BT_OGF_BASEBAND, 0x001a) -#define BT_BREDR_SCAN_DISABLED 0x00 -#define BT_BREDR_SCAN_INQUIRY 0x01 -#define BT_BREDR_SCAN_PAGE 0x02 - -#define BT_HCI_OP_WRITE_CLASS_OF_DEVICE BT_OP(BT_OGF_BASEBAND, 0x0024) -struct bt_hci_cp_write_class_of_device { - uint8_t class_of_device[3]; -} __packed; - -#define BT_TX_POWER_LEVEL_CURRENT 0x00 -#define BT_TX_POWER_LEVEL_MAX 0x01 -#define BT_HCI_OP_READ_TX_POWER_LEVEL BT_OP(BT_OGF_BASEBAND, 0x002d) -struct bt_hci_cp_read_tx_power_level { - uint16_t handle; - uint8_t type; -} __packed; - -struct bt_hci_rp_read_tx_power_level { - uint8_t status; - uint16_t handle; - int8_t tx_power_level; -} __packed; - -#define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 -#define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 -#define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) -struct bt_hci_cp_set_ctl_to_host_flow { - uint8_t flow_enable; -} __packed; - -#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033) -struct bt_hci_cp_host_buffer_size { - uint16_t acl_mtu; - uint8_t sco_mtu; - uint16_t acl_pkts; - uint16_t sco_pkts; -} __packed; - -struct bt_hci_handle_count { - uint16_t handle; - uint16_t count; -} __packed; - -#define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) -struct bt_hci_cp_host_num_completed_packets { - uint8_t num_handles; - struct bt_hci_handle_count h[0]; -} __packed; - -#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) -struct bt_hci_cp_write_inquiry_mode { - uint8_t mode; -} __packed; - -#define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) -struct bt_hci_cp_write_ssp_mode { - uint8_t mode; -} __packed; - -#define BT_HCI_OP_SET_EVENT_MASK_PAGE_2 BT_OP(BT_OGF_BASEBAND, 0x0063) -struct bt_hci_cp_set_event_mask_page_2 { - uint8_t events_page_2[8]; -} __packed; - -#define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) -struct bt_hci_cp_write_le_host_supp { - uint8_t le; - uint8_t simul; -} __packed; - -#define BT_HCI_OP_WRITE_SC_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x007a) -struct bt_hci_cp_write_sc_host_supp { - uint8_t sc_support; -} __packed; - -#define BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007b) -struct bt_hci_cp_read_auth_payload_timeout { - uint16_t handle; -} __packed; - -struct bt_hci_rp_read_auth_payload_timeout { - uint8_t status; - uint16_t handle; - uint16_t auth_payload_timeout; -} __packed; - -#define BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007c) -struct bt_hci_cp_write_auth_payload_timeout { - uint16_t handle; - uint16_t auth_payload_timeout; -} __packed; - -struct bt_hci_rp_write_auth_payload_timeout { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_CONFIGURE_DATA_PATH BT_OP(BT_OGF_BASEBAND, 0x0083) -struct bt_hci_cp_configure_data_path { - uint8_t data_path_dir; - uint8_t data_path_id; - uint8_t vs_config_len; - uint8_t vs_config[0]; -} __packed; - -struct bt_hci_rp_configure_data_path { - uint8_t status; -} __packed; - -/* HCI version from Assigned Numbers */ -#define BT_HCI_VERSION_1_0B 0 -#define BT_HCI_VERSION_1_1 1 -#define BT_HCI_VERSION_1_2 2 -#define BT_HCI_VERSION_2_0 3 -#define BT_HCI_VERSION_2_1 4 -#define BT_HCI_VERSION_3_0 5 -#define BT_HCI_VERSION_4_0 6 -#define BT_HCI_VERSION_4_1 7 -#define BT_HCI_VERSION_4_2 8 -#define BT_HCI_VERSION_5_0 9 -#define BT_HCI_VERSION_5_1 10 -#define BT_HCI_VERSION_5_2 11 -#define BT_HCI_VERSION_5_3 12 -#define BT_HCI_VERSION_5_4 13 - -#define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) -struct bt_hci_rp_read_local_version_info { - uint8_t status; - uint8_t hci_version; - uint16_t hci_revision; - uint8_t lmp_version; - uint16_t manufacturer; - uint16_t lmp_subversion; -} __packed; - -#define BT_HCI_OP_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) -struct bt_hci_rp_read_supported_commands { - uint8_t status; - uint8_t commands[64]; -} __packed; - -#define BT_HCI_OP_READ_LOCAL_EXT_FEATURES BT_OP(BT_OGF_INFO, 0x0004) -struct bt_hci_cp_read_local_ext_features { - uint8_t page; -}; -struct bt_hci_rp_read_local_ext_features { - uint8_t status; - uint8_t page; - uint8_t max_page; - uint8_t ext_features[8]; -} __packed; - -#define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) -struct bt_hci_rp_read_local_features { - uint8_t status; - uint8_t features[8]; -} __packed; - -#define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) -struct bt_hci_rp_read_buffer_size { - uint8_t status; - uint16_t acl_max_len; - uint8_t sco_max_len; - uint16_t acl_max_num; - uint16_t sco_max_num; -} __packed; - -#define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) -struct bt_hci_rp_read_bd_addr { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -/* logic transport type bits as returned when reading supported codecs */ -#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_ACL BIT(0) -#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_SCO BIT(1) -#define BT_HCI_CODEC_TRANSPORT_MASK_LE_CIS BIT(2) -#define BT_HCI_CODEC_TRANSPORT_MASK_LE_BIS BIT(3) - -/* logic transport types for reading codec capabilities and controller delays */ -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_ACL 0x00 -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_SCO 0x01 -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_CIS 0x02 -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_BIS 0x03 - -/* audio datapath directions */ -#define BT_HCI_DATAPATH_DIR_HOST_TO_CTLR 0x00 -#define BT_HCI_DATAPATH_DIR_CTLR_TO_HOST 0x01 - -/* audio datapath IDs */ -#define BT_HCI_DATAPATH_ID_HCI 0x00 -#define BT_HCI_DATAPATH_ID_VS 0x01 -#define BT_HCI_DATAPATH_ID_VS_END 0xfe - -/* coding format assigned numbers, used for codec IDs */ -#define BT_HCI_CODING_FORMAT_ULAW_LOG 0x00 -#define BT_HCI_CODING_FORMAT_ALAW_LOG 0x01 -#define BT_HCI_CODING_FORMAT_CVSD 0x02 -#define BT_HCI_CODING_FORMAT_TRANSPARENT 0x03 -#define BT_HCI_CODING_FORMAT_LINEAR_PCM 0x04 -#define BT_HCI_CODING_FORMAT_MSBC 0x05 -#define BT_HCI_CODING_FORMAT_VS 0xFF - - -#define BT_HCI_OP_READ_CODECS BT_OP(BT_OGF_INFO, 0x000b) -struct bt_hci_std_codec_info { - uint8_t codec_id; -} __packed; -struct bt_hci_std_codecs { - uint8_t num_codecs; - struct bt_hci_std_codec_info codec_info[0]; -} __packed; -struct bt_hci_vs_codec_info { - uint16_t company_id; - uint16_t codec_id; -} __packed; -struct bt_hci_vs_codecs { - uint8_t num_codecs; - struct bt_hci_vs_codec_info codec_info[0]; -} __packed; -struct bt_hci_rp_read_codecs { - uint8_t status; - /* other fields filled in dynamically */ - uint8_t codecs[0]; -} __packed; - -#define BT_HCI_OP_READ_CODECS_V2 BT_OP(BT_OGF_INFO, 0x000d) -struct bt_hci_std_codec_info_v2 { - uint8_t codec_id; - uint8_t transports; /* bitmap */ -} __packed; -struct bt_hci_std_codecs_v2 { - uint8_t num_codecs; - struct bt_hci_std_codec_info_v2 codec_info[0]; -} __packed; -struct bt_hci_vs_codec_info_v2 { - uint16_t company_id; - uint16_t codec_id; - uint8_t transports; /* bitmap */ -} __packed; -struct bt_hci_vs_codecs_v2 { - uint8_t num_codecs; - struct bt_hci_vs_codec_info_v2 codec_info[0]; -} __packed; -struct bt_hci_rp_read_codecs_v2 { - uint8_t status; - /* other fields filled in dynamically */ - uint8_t codecs[0]; -} __packed; - -struct bt_hci_cp_codec_id { - uint8_t coding_format; - uint16_t company_id; - uint16_t vs_codec_id; -} __packed; - -#define BT_HCI_OP_READ_CODEC_CAPABILITIES BT_OP(BT_OGF_INFO, 0x000e) -struct bt_hci_cp_read_codec_capabilities { - struct bt_hci_cp_codec_id codec_id; - uint8_t transport; - uint8_t direction; -} __packed; -struct bt_hci_codec_capability_info { - uint8_t length; - uint8_t data[0]; -} __packed; -struct bt_hci_rp_read_codec_capabilities { - uint8_t status; - uint8_t num_capabilities; - /* other fields filled in dynamically */ - uint8_t capabilities[0]; -} __packed; - -#define BT_HCI_OP_READ_CTLR_DELAY BT_OP(BT_OGF_INFO, 0x000f) -struct bt_hci_cp_read_ctlr_delay { - struct bt_hci_cp_codec_id codec_id; - uint8_t transport; - uint8_t direction; - uint8_t codec_config_len; - uint8_t codec_config[0]; -} __packed; -struct bt_hci_rp_read_ctlr_delay { - uint8_t status; - uint8_t min_ctlr_delay[3]; - uint8_t max_ctlr_delay[3]; -} __packed; - -#define BT_HCI_OP_READ_RSSI BT_OP(BT_OGF_STATUS, 0x0005) -struct bt_hci_cp_read_rssi { - uint16_t handle; -} __packed; -struct bt_hci_rp_read_rssi { - uint8_t status; - uint16_t handle; - int8_t rssi; -} __packed; - -#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 -#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 - -#define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) -struct bt_hci_cp_read_encryption_key_size { - uint16_t handle; -} __packed; -struct bt_hci_rp_read_encryption_key_size { - uint8_t status; - uint16_t handle; - uint8_t key_size; -} __packed; - -/* BLE */ - -#define BT_HCI_OP_LE_SET_EVENT_MASK BT_OP(BT_OGF_LE, 0x0001) -struct bt_hci_cp_le_set_event_mask { - uint8_t events[8]; -} __packed; - -#define BT_HCI_OP_LE_READ_BUFFER_SIZE BT_OP(BT_OGF_LE, 0x0002) -struct bt_hci_rp_le_read_buffer_size { - uint8_t status; - uint16_t le_max_len; - uint8_t le_max_num; -} __packed; - -#define BT_HCI_OP_LE_READ_LOCAL_FEATURES BT_OP(BT_OGF_LE, 0x0003) -struct bt_hci_rp_le_read_local_features { - uint8_t status; - uint8_t features[8]; -} __packed; - -#define BT_HCI_OP_LE_SET_RANDOM_ADDRESS BT_OP(BT_OGF_LE, 0x0005) -struct bt_hci_cp_le_set_random_address { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_ADV_IND 0x00 -#define BT_HCI_ADV_DIRECT_IND 0x01 -#define BT_HCI_ADV_SCAN_IND 0x02 -#define BT_HCI_ADV_NONCONN_IND 0x03 -#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 -#define BT_HCI_ADV_SCAN_RSP 0x04 - -#define BT_LE_ADV_INTERVAL_MIN 0x0020 -#define BT_LE_ADV_INTERVAL_MAX 0x4000 -#define BT_LE_ADV_INTERVAL_DEFAULT 0x0800 - -#define BT_LE_ADV_CHAN_MAP_CHAN_37 0x01 -#define BT_LE_ADV_CHAN_MAP_CHAN_38 0x02 -#define BT_LE_ADV_CHAN_MAP_CHAN_39 0x04 -#define BT_LE_ADV_CHAN_MAP_ALL 0x07 - -#define BT_LE_ADV_FP_NO_FILTER 0x00 -#define BT_LE_ADV_FP_FILTER_SCAN_REQ 0x01 -#define BT_LE_ADV_FP_FILTER_CONN_IND 0x02 -#define BT_LE_ADV_FP_FILTER_BOTH 0x03 - -#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) -struct bt_hci_cp_le_set_adv_param { - uint16_t min_interval; - uint16_t max_interval; - uint8_t type; - uint8_t own_addr_type; - bt_addr_le_t direct_addr; - uint8_t channel_map; - uint8_t filter_policy; -} __packed; - -#define BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER BT_OP(BT_OGF_LE, 0x0007) -struct bt_hci_rp_le_read_chan_tx_power { - uint8_t status; - int8_t tx_power_level; -} __packed; - -#define BT_HCI_OP_LE_SET_ADV_DATA BT_OP(BT_OGF_LE, 0x0008) -struct bt_hci_cp_le_set_adv_data { - uint8_t len; - uint8_t data[31]; -} __packed; - -#define BT_HCI_OP_LE_SET_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0009) -struct bt_hci_cp_le_set_scan_rsp_data { - uint8_t len; - uint8_t data[31]; -} __packed; - -#define BT_HCI_LE_ADV_DISABLE 0x00 -#define BT_HCI_LE_ADV_ENABLE 0x01 - -#define BT_HCI_OP_LE_SET_ADV_ENABLE BT_OP(BT_OGF_LE, 0x000a) -struct bt_hci_cp_le_set_adv_enable { - uint8_t enable; -} __packed; - -/* Scan types */ -#define BT_HCI_OP_LE_SET_SCAN_PARAM BT_OP(BT_OGF_LE, 0x000b) -#define BT_HCI_LE_SCAN_PASSIVE 0x00 -#define BT_HCI_LE_SCAN_ACTIVE 0x01 - -#define BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER 0x00 -#define BT_HCI_LE_SCAN_FP_BASIC_FILTER 0x01 -#define BT_HCI_LE_SCAN_FP_EXT_NO_FILTER 0x02 -#define BT_HCI_LE_SCAN_FP_EXT_FILTER 0x03 - -struct bt_hci_cp_le_set_scan_param { - uint8_t scan_type; - uint16_t interval; - uint16_t window; - uint8_t addr_type; - uint8_t filter_policy; -} __packed; - -#define BT_HCI_OP_LE_SET_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x000c) - -#define BT_HCI_LE_SCAN_DISABLE 0x00 -#define BT_HCI_LE_SCAN_ENABLE 0x01 - -#define BT_HCI_LE_SCAN_FILTER_DUP_DISABLE 0x00 -#define BT_HCI_LE_SCAN_FILTER_DUP_ENABLE 0x01 - -struct bt_hci_cp_le_set_scan_enable { - uint8_t enable; - uint8_t filter_dup; -} __packed; - -#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) - -#define BT_HCI_LE_CREATE_CONN_FP_NO_FILTER 0x00 -#define BT_HCI_LE_CREATE_CONN_FP_FILTER 0x01 - -struct bt_hci_cp_le_create_conn { - uint16_t scan_interval; - uint16_t scan_window; - uint8_t filter_policy; - bt_addr_le_t peer_addr; - uint8_t own_addr_type; - uint16_t conn_interval_min; - uint16_t conn_interval_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; - -#define BT_HCI_OP_LE_CREATE_CONN_CANCEL BT_OP(BT_OGF_LE, 0x000e) - -#define BT_HCI_OP_LE_READ_FAL_SIZE BT_OP(BT_OGF_LE, 0x000f) -struct bt_hci_rp_le_read_fal_size { - uint8_t status; - uint8_t fal_size; -} __packed; - -#define BT_HCI_OP_LE_CLEAR_FAL BT_OP(BT_OGF_LE, 0x0010) - -#define BT_HCI_OP_LE_ADD_DEV_TO_FAL BT_OP(BT_OGF_LE, 0x0011) -struct bt_hci_cp_le_add_dev_to_fal { - bt_addr_le_t addr; -} __packed; - -#define BT_HCI_OP_LE_REM_DEV_FROM_FAL BT_OP(BT_OGF_LE, 0x0012) -struct bt_hci_cp_le_rem_dev_from_fal { - bt_addr_le_t addr; -} __packed; - -#define BT_HCI_OP_LE_CONN_UPDATE BT_OP(BT_OGF_LE, 0x0013) -struct hci_cp_le_conn_update { - uint16_t handle; - uint16_t conn_interval_min; - uint16_t conn_interval_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; - -#define BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF BT_OP(BT_OGF_LE, 0x0014) -struct bt_hci_cp_le_set_host_chan_classif { - uint8_t ch_map[5]; -} __packed; - -#define BT_HCI_OP_LE_READ_CHAN_MAP BT_OP(BT_OGF_LE, 0x0015) -struct bt_hci_cp_le_read_chan_map { - uint16_t handle; -} __packed; -struct bt_hci_rp_le_read_chan_map { - uint8_t status; - uint16_t handle; - uint8_t ch_map[5]; -} __packed; - -#define BT_HCI_OP_LE_READ_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0016) -struct bt_hci_cp_le_read_remote_features { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ENCRYPT BT_OP(BT_OGF_LE, 0x0017) -struct bt_hci_cp_le_encrypt { - uint8_t key[16]; - uint8_t plaintext[16]; -} __packed; -struct bt_hci_rp_le_encrypt { - uint8_t status; - uint8_t enc_data[16]; -} __packed; - -#define BT_HCI_OP_LE_RAND BT_OP(BT_OGF_LE, 0x0018) -struct bt_hci_rp_le_rand { - uint8_t status; - uint8_t rand[8]; -} __packed; - -#define BT_HCI_OP_LE_START_ENCRYPTION BT_OP(BT_OGF_LE, 0x0019) -struct bt_hci_cp_le_start_encryption { - uint16_t handle; - uint64_t rand; - uint16_t ediv; - uint8_t ltk[16]; -} __packed; - -#define BT_HCI_OP_LE_LTK_REQ_REPLY BT_OP(BT_OGF_LE, 0x001a) -struct bt_hci_cp_le_ltk_req_reply { - uint16_t handle; - uint8_t ltk[16]; -} __packed; -struct bt_hci_rp_le_ltk_req_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_LTK_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x001b) -struct bt_hci_cp_le_ltk_req_neg_reply { - uint16_t handle; -} __packed; -struct bt_hci_rp_le_ltk_req_neg_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_READ_SUPP_STATES BT_OP(BT_OGF_LE, 0x001c) -struct bt_hci_rp_le_read_supp_states { - uint8_t status; - uint8_t le_states[8]; -} __packed; - -#define BT_HCI_OP_LE_RX_TEST BT_OP(BT_OGF_LE, 0x001d) -struct bt_hci_cp_le_rx_test { - uint8_t rx_ch; -} __packed; - -#define BT_HCI_TEST_PKT_PAYLOAD_PRBS9 0x00 -#define BT_HCI_TEST_PKT_PAYLOAD_11110000 0x01 -#define BT_HCI_TEST_PKT_PAYLOAD_10101010 0x02 -#define BT_HCI_TEST_PKT_PAYLOAD_PRBS15 0x03 -#define BT_HCI_TEST_PKT_PAYLOAD_11111111 0x04 -#define BT_HCI_TEST_PKT_PAYLOAD_00000000 0x05 -#define BT_HCI_TEST_PKT_PAYLOAD_00001111 0x06 -#define BT_HCI_TEST_PKT_PAYLOAD_01010101 0x07 - -#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e) -struct bt_hci_cp_le_tx_test { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; -} __packed; - -#define BT_HCI_OP_LE_TEST_END BT_OP(BT_OGF_LE, 0x001f) -struct bt_hci_rp_le_test_end { - uint8_t status; - uint16_t rx_pkt_count; -} __packed; - -#define BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY BT_OP(BT_OGF_LE, 0x0020) -struct bt_hci_cp_le_conn_param_req_reply { - uint16_t handle; - uint16_t interval_min; - uint16_t interval_max; - uint16_t latency; - uint16_t timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; -struct bt_hci_rp_le_conn_param_req_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x0021) -struct bt_hci_cp_le_conn_param_req_neg_reply { - uint16_t handle; - uint8_t reason; -} __packed; -struct bt_hci_rp_le_conn_param_req_neg_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_SET_DATA_LEN BT_OP(BT_OGF_LE, 0x0022) -struct bt_hci_cp_le_set_data_len { - uint16_t handle; - uint16_t tx_octets; - uint16_t tx_time; -} __packed; -struct bt_hci_rp_le_set_data_len { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0023) -struct bt_hci_rp_le_read_default_data_len { - uint8_t status; - uint16_t max_tx_octets; - uint16_t max_tx_time; -} __packed; - -#define BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0024) -struct bt_hci_cp_le_write_default_data_len { - uint16_t max_tx_octets; - uint16_t max_tx_time; -} __packed; - -#define BT_HCI_OP_LE_P256_PUBLIC_KEY BT_OP(BT_OGF_LE, 0x0025) - -#define BT_HCI_OP_LE_GENERATE_DHKEY BT_OP(BT_OGF_LE, 0x0026) -struct bt_hci_cp_le_generate_dhkey { - uint8_t key[64]; -} __packed; - - -#define BT_HCI_OP_LE_GENERATE_DHKEY_V2 BT_OP(BT_OGF_LE, 0x005e) - -#define BT_HCI_LE_KEY_TYPE_GENERATED 0x00 -#define BT_HCI_LE_KEY_TYPE_DEBUG 0x01 - -struct bt_hci_cp_le_generate_dhkey_v2 { - uint8_t key[64]; - uint8_t key_type; -} __packed; - - -#define BT_HCI_OP_LE_ADD_DEV_TO_RL BT_OP(BT_OGF_LE, 0x0027) -struct bt_hci_cp_le_add_dev_to_rl { - bt_addr_le_t peer_id_addr; - uint8_t peer_irk[16]; - uint8_t local_irk[16]; -} __packed; - -#define BT_HCI_OP_LE_REM_DEV_FROM_RL BT_OP(BT_OGF_LE, 0x0028) -struct bt_hci_cp_le_rem_dev_from_rl { - bt_addr_le_t peer_id_addr; -} __packed; - -#define BT_HCI_OP_LE_CLEAR_RL BT_OP(BT_OGF_LE, 0x0029) - -#define BT_HCI_OP_LE_READ_RL_SIZE BT_OP(BT_OGF_LE, 0x002a) -struct bt_hci_rp_le_read_rl_size { - uint8_t status; - uint8_t rl_size; -} __packed; - -#define BT_HCI_OP_LE_READ_PEER_RPA BT_OP(BT_OGF_LE, 0x002b) -struct bt_hci_cp_le_read_peer_rpa { - bt_addr_le_t peer_id_addr; -} __packed; -struct bt_hci_rp_le_read_peer_rpa { - uint8_t status; - bt_addr_t peer_rpa; -} __packed; - -#define BT_HCI_OP_LE_READ_LOCAL_RPA BT_OP(BT_OGF_LE, 0x002c) -struct bt_hci_cp_le_read_local_rpa { - bt_addr_le_t peer_id_addr; -} __packed; -struct bt_hci_rp_le_read_local_rpa { - uint8_t status; - bt_addr_t local_rpa; -} __packed; - -#define BT_HCI_ADDR_RES_DISABLE 0x00 -#define BT_HCI_ADDR_RES_ENABLE 0x01 - -#define BT_HCI_OP_LE_SET_ADDR_RES_ENABLE BT_OP(BT_OGF_LE, 0x002d) -struct bt_hci_cp_le_set_addr_res_enable { - uint8_t enable; -} __packed; - -#define BT_HCI_OP_LE_SET_RPA_TIMEOUT BT_OP(BT_OGF_LE, 0x002e) -struct bt_hci_cp_le_set_rpa_timeout { - uint16_t rpa_timeout; -} __packed; - -#define BT_HCI_OP_LE_READ_MAX_DATA_LEN BT_OP(BT_OGF_LE, 0x002f) -struct bt_hci_rp_le_read_max_data_len { - uint8_t status; - uint16_t max_tx_octets; - uint16_t max_tx_time; - uint16_t max_rx_octets; - uint16_t max_rx_time; -} __packed; - -#define BT_HCI_LE_PHY_1M 0x01 -#define BT_HCI_LE_PHY_2M 0x02 -#define BT_HCI_LE_PHY_CODED 0x03 - -#define BT_HCI_OP_LE_READ_PHY BT_OP(BT_OGF_LE, 0x0030) -struct bt_hci_cp_le_read_phy { - uint16_t handle; -} __packed; -struct bt_hci_rp_le_read_phy { - uint8_t status; - uint16_t handle; - uint8_t tx_phy; - uint8_t rx_phy; -} __packed; - -#define BT_HCI_LE_PHY_TX_ANY BIT(0) -#define BT_HCI_LE_PHY_RX_ANY BIT(1) - -#define BT_HCI_LE_PHY_PREFER_1M BIT(0) -#define BT_HCI_LE_PHY_PREFER_2M BIT(1) -#define BT_HCI_LE_PHY_PREFER_CODED BIT(2) - -#define BT_HCI_OP_LE_SET_DEFAULT_PHY BT_OP(BT_OGF_LE, 0x0031) -struct bt_hci_cp_le_set_default_phy { - uint8_t all_phys; - uint8_t tx_phys; - uint8_t rx_phys; -} __packed; - -#define BT_HCI_LE_PHY_CODED_ANY 0x00 -#define BT_HCI_LE_PHY_CODED_S2 0x01 -#define BT_HCI_LE_PHY_CODED_S8 0x02 - -#define BT_HCI_OP_LE_SET_PHY BT_OP(BT_OGF_LE, 0x0032) -struct bt_hci_cp_le_set_phy { - uint16_t handle; - uint8_t all_phys; - uint8_t tx_phys; - uint8_t rx_phys; - uint16_t phy_opts; -} __packed; - -#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00 -#define BT_HCI_LE_MOD_INDEX_STABLE 0x01 - -#define BT_HCI_LE_RX_PHY_1M 0x01 -#define BT_HCI_LE_RX_PHY_2M 0x02 -#define BT_HCI_LE_RX_PHY_CODED 0x03 - -#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033) -struct bt_hci_cp_le_enh_rx_test { - uint8_t rx_ch; - uint8_t phy; - uint8_t mod_index; -} __packed; - -#define BT_HCI_LE_TX_PHY_1M 0x01 -#define BT_HCI_LE_TX_PHY_2M 0x02 -#define BT_HCI_LE_TX_PHY_CODED_S8 0x03 -#define BT_HCI_LE_TX_PHY_CODED_S2 0x04 - -#define BT_HCI_OP_LE_ENH_TX_TEST BT_OP(BT_OGF_LE, 0x0034) -struct bt_hci_cp_le_enh_tx_test { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; - uint8_t phy; -} __packed; - -#define BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR BT_OP(BT_OGF_LE, 0x0035) -struct bt_hci_cp_le_set_adv_set_random_addr { - uint8_t handle; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_LE_ADV_PROP_CONN BIT(0) -#define BT_HCI_LE_ADV_PROP_SCAN BIT(1) -#define BT_HCI_LE_ADV_PROP_DIRECT BIT(2) -#define BT_HCI_LE_ADV_PROP_HI_DC_CONN BIT(3) -#define BT_HCI_LE_ADV_PROP_LEGACY BIT(4) -#define BT_HCI_LE_ADV_PROP_ANON BIT(5) -#define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) - -#define BT_HCI_LE_PRIM_ADV_INTERVAL_MIN 0x000020 -#define BT_HCI_LE_PRIM_ADV_INTERVAL_MAX 0xFFFFFF - -#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 -#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 - -#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F - -#define BT_HCI_LE_ADV_HANDLE_MAX 0xEF - -#define BT_HCI_LE_EXT_ADV_SID_INVALID 0xFF - -#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) -struct bt_hci_cp_le_set_ext_adv_param { - uint8_t handle; - uint16_t props; - uint8_t prim_min_interval[3]; - uint8_t prim_max_interval[3]; - uint8_t prim_channel_map; - uint8_t own_addr_type; - bt_addr_le_t peer_addr; - uint8_t filter_policy; - int8_t tx_power; - uint8_t prim_adv_phy; - uint8_t sec_adv_max_skip; - uint8_t sec_adv_phy; - uint8_t sid; - uint8_t scan_req_notify_enable; -} __packed; -struct bt_hci_rp_le_set_ext_adv_param { - uint8_t status; - int8_t tx_power; -} __packed; - -#define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 -#define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 -#define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 -#define BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA 0x03 -#define BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA 0x04 - -#define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 -#define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 - -#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 - -#define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) -struct bt_hci_cp_le_set_ext_adv_data { - uint8_t handle; - uint8_t op; - uint8_t frag_pref; - uint8_t len; - uint8_t data[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0038) -struct bt_hci_cp_le_set_ext_scan_rsp_data { - uint8_t handle; - uint8_t op; - uint8_t frag_pref; - uint8_t len; - uint8_t data[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_EXT_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0039) -struct bt_hci_ext_adv_set { - uint8_t handle; - uint16_t duration; - uint8_t max_ext_adv_evts; -} __packed; - -struct bt_hci_cp_le_set_ext_adv_enable { - uint8_t enable; - uint8_t set_num; - struct bt_hci_ext_adv_set s[0]; -} __packed; - -#define BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN BT_OP(BT_OGF_LE, 0x003a) -struct bt_hci_rp_le_read_max_adv_data_len { - uint8_t status; - uint16_t max_adv_data_len; -} __packed; - -#define BT_HCI_OP_LE_READ_NUM_ADV_SETS BT_OP(BT_OGF_LE, 0x003b) -struct bt_hci_rp_le_read_num_adv_sets { - uint8_t status; - uint8_t num_sets; -} __packed; - -#define BT_HCI_OP_LE_REMOVE_ADV_SET BT_OP(BT_OGF_LE, 0x003c) -struct bt_hci_cp_le_remove_adv_set { - uint8_t handle; -} __packed; - -#define BT_HCI_OP_CLEAR_ADV_SETS BT_OP(BT_OGF_LE, 0x003d) - -#define BT_HCI_LE_PER_ADV_INTERVAL_MIN 0x0006 -#define BT_HCI_LE_PER_ADV_INTERVAL_MAX 0xFFFF - -#define BT_HCI_OP_LE_SET_PER_ADV_PARAM BT_OP(BT_OGF_LE, 0x003e) -struct bt_hci_cp_le_set_per_adv_param { - uint8_t handle; - uint16_t min_interval; - uint16_t max_interval; - uint16_t props; -} __packed; - -#define BT_HCI_LE_PER_ADV_OP_INTERM_FRAG 0x00 -#define BT_HCI_LE_PER_ADV_OP_FIRST_FRAG 0x01 -#define BT_HCI_LE_PER_ADV_OP_LAST_FRAG 0x02 -#define BT_HCI_LE_PER_ADV_OP_COMPLETE_DATA 0x03 - -#define BT_HCI_LE_PER_ADV_FRAG_MAX_LEN 252 - -#define BT_HCI_OP_LE_SET_PER_ADV_DATA BT_OP(BT_OGF_LE, 0x003f) -struct bt_hci_cp_le_set_per_adv_data { - uint8_t handle; - uint8_t op; - uint8_t len; - uint8_t data[0]; -} __packed; - -#define BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE BIT(0) -#define BT_HCI_LE_SET_PER_ADV_ENABLE_ADI BIT(1) - -#define BT_HCI_OP_LE_SET_PER_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0040) -struct bt_hci_cp_le_set_per_adv_enable { - uint8_t enable; - uint8_t handle; -} __packed; - -#define BT_HCI_OP_LE_SET_EXT_SCAN_PARAM BT_OP(BT_OGF_LE, 0x0041) -struct bt_hci_ext_scan_phy { - uint8_t type; - uint16_t interval; - uint16_t window; -} __packed; - -#define BT_HCI_LE_EXT_SCAN_PHY_1M BIT(0) -#define BT_HCI_LE_EXT_SCAN_PHY_2M BIT(1) -#define BT_HCI_LE_EXT_SCAN_PHY_CODED BIT(2) - -struct bt_hci_cp_le_set_ext_scan_param { - uint8_t own_addr_type; - uint8_t filter_policy; - uint8_t phys; - struct bt_hci_ext_scan_phy p[0]; -} __packed; - -/* Extends BT_HCI_LE_SCAN_FILTER_DUP */ -#define BT_HCI_LE_EXT_SCAN_FILTER_DUP_ENABLE_RESET 0x02 - -#define BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x0042) -struct bt_hci_cp_le_set_ext_scan_enable { - uint8_t enable; - uint8_t filter_dup; - uint16_t duration; - uint16_t period; -} __packed; - -#define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) -#define BT_HCI_OP_LE_EXT_CREATE_CONN_V2 BT_OP(BT_OGF_LE, 0x0085) -struct bt_hci_ext_conn_phy { - uint16_t scan_interval; - uint16_t scan_window; - uint16_t conn_interval_min; - uint16_t conn_interval_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; - -struct bt_hci_cp_le_ext_create_conn { - uint8_t filter_policy; - uint8_t own_addr_type; - bt_addr_le_t peer_addr; - uint8_t phys; - struct bt_hci_ext_conn_phy p[0]; -} __packed; - -struct bt_hci_cp_le_ext_create_conn_v2 { - uint8_t adv_handle; - uint8_t subevent; - uint8_t filter_policy; - uint8_t own_addr_type; - bt_addr_le_t peer_addr; - uint8_t phys; - struct bt_hci_ext_conn_phy p[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_PER_ADV_SUBEVENT_DATA BT_OP(BT_OGF_LE, 0x0082) -struct bt_hci_cp_le_set_pawr_subevent_data_element { - uint8_t subevent; - uint8_t response_slot_start; - uint8_t response_slot_count; - uint8_t subevent_data_length; - uint8_t subevent_data[0]; -} __packed; - -struct bt_hci_cp_le_set_pawr_subevent_data { - uint8_t adv_handle; - uint8_t num_subevents; - struct bt_hci_cp_le_set_pawr_subevent_data_element subevents[0]; -} __packed; - - -#define BT_HCI_OP_LE_SET_PER_ADV_RESPONSE_DATA BT_OP(BT_OGF_LE, 0x0083) -struct bt_hci_cp_le_set_pawr_response_data { - uint16_t sync_handle; - uint16_t request_event; - uint8_t request_subevent; - uint8_t response_subevent; - uint8_t response_slot; - uint8_t response_data_length; - uint8_t response_data[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_PER_ADV_SYNC_SUBEVENT BT_OP(BT_OGF_LE, 0x0084) -struct bt_hci_cp_le_set_pawr_sync_subevent { - uint16_t sync_handle; - uint16_t periodic_adv_properties; - uint8_t num_subevents; - uint8_t subevents[0]; -} __packed; - - -#define BT_HCI_OP_LE_SET_PER_ADV_PARAM_V2 BT_OP(BT_OGF_LE, 0x0086) -struct bt_hci_cp_le_set_per_adv_param_v2 { - uint8_t handle; - uint16_t min_interval; - uint16_t max_interval; - uint16_t props; - uint8_t num_subevents; - uint8_t subevent_interval; - uint8_t response_slot_delay; - uint8_t response_slot_spacing; - uint8_t num_response_slots; -} __packed; - - -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST BIT(0) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED BIT(1) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE BIT(2) - -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING 0 -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA BIT(0) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_1US BIT(1) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_2US BIT(2) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_CTE BIT(3) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE BIT(4) -/* Constants to check correctness of CTE type */ -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS 5 -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_INVALID_VALUE \ - (~BIT_MASK(BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS)) - -#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC BT_OP(BT_OGF_LE, 0x0044) -struct bt_hci_cp_le_per_adv_create_sync { - uint8_t options; - uint8_t sid; - bt_addr_le_t addr; - uint16_t skip; - uint16_t sync_timeout; - uint8_t cte_type; -} __packed; - -#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL BT_OP(BT_OGF_LE, 0x0045) - -#define BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x0046) -struct bt_hci_cp_le_per_adv_terminate_sync { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0047) -struct bt_hci_cp_le_add_dev_to_per_adv_list { - bt_addr_le_t addr; - uint8_t sid; -} __packed; - -#define BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0048) -struct bt_hci_cp_le_rem_dev_from_per_adv_list { - bt_addr_le_t addr; - uint8_t sid; -} __packed; - -#define BT_HCI_OP_LE_CLEAR_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0049) - -#define BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE BT_OP(BT_OGF_LE, 0x004a) -struct bt_hci_rp_le_read_per_adv_list_size { - uint8_t status; - uint8_t list_size; -} __packed; - -#define BT_HCI_OP_LE_READ_TX_POWER BT_OP(BT_OGF_LE, 0x004b) -struct bt_hci_rp_le_read_tx_power { - uint8_t status; - int8_t min_tx_power; - int8_t max_tx_power; -} __packed; - -#define BT_HCI_OP_LE_READ_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004c) -struct bt_hci_rp_le_read_rf_path_comp { - uint8_t status; - int16_t tx_path_comp; - int16_t rx_path_comp; -} __packed; - -#define BT_HCI_OP_LE_WRITE_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004d) -struct bt_hci_cp_le_write_rf_path_comp { - int16_t tx_path_comp; - int16_t rx_path_comp; -} __packed; - -#define BT_HCI_LE_PRIVACY_MODE_NETWORK 0x00 -#define BT_HCI_LE_PRIVACY_MODE_DEVICE 0x01 - -#define BT_HCI_OP_LE_SET_PRIVACY_MODE BT_OP(BT_OGF_LE, 0x004e) -struct bt_hci_cp_le_set_privacy_mode { - bt_addr_le_t id_addr; - uint8_t mode; -} __packed; - -#define BT_HCI_LE_TEST_CTE_DISABLED 0x00 -#define BT_HCI_LE_TEST_CTE_TYPE_ANY 0x00 -#define BT_HCI_LE_TEST_SLOT_DURATION_ANY 0x00 -#define BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY 0x00 - -#define BT_HCI_OP_LE_RX_TEST_V3 BT_OP(BT_OGF_LE, 0x004f) -struct bt_hci_cp_le_rx_test_v3 { - uint8_t rx_ch; - uint8_t phy; - uint8_t mod_index; - uint8_t expected_cte_len; - uint8_t expected_cte_type; - uint8_t slot_durations; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -#define BT_HCI_OP_LE_TX_TEST_V3 BT_OP(BT_OGF_LE, 0x0050) - -struct bt_hci_cp_le_tx_test_v3 { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; - uint8_t phy; - uint8_t cte_len; - uint8_t cte_type; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -/* Min and max Constant Tone Extension length in 8us units */ -#define BT_HCI_LE_CTE_LEN_MIN 0x2 -#define BT_HCI_LE_CTE_LEN_MAX 0x14 - -#define BT_HCI_LE_AOA_CTE 0x0 -#define BT_HCI_LE_AOD_CTE_1US 0x1 -#define BT_HCI_LE_AOD_CTE_2US 0x2 -#define BT_HCI_LE_NO_CTE 0xFF - -#define BT_HCI_LE_CTE_COUNT_MIN 0x1 -#define BT_HCI_LE_CTE_COUNT_MAX 0x10 - -#define BT_HCI_OP_LE_SET_CL_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0051) -struct bt_hci_cp_le_set_cl_cte_tx_params { - uint8_t handle; - uint8_t cte_len; - uint8_t cte_type; - uint8_t cte_count; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_CL_CTE_TX_ENABLE BT_OP(BT_OGF_LE, 0x0052) -struct bt_hci_cp_le_set_cl_cte_tx_enable { - uint8_t handle; - uint8_t cte_enable; -} __packed; - -#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US 0x1 -#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US 0x2 - -#define BT_HCI_LE_SAMPLE_CTE_ALL 0x0 -#define BT_HCI_LE_SAMPLE_CTE_COUNT_MIN 0x1 -#define BT_HCI_LE_SAMPLE_CTE_COUNT_MAX 0x10 - -#define BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE BT_OP(BT_OGF_LE, 0x0053) -struct bt_hci_cp_le_set_cl_cte_sampling_enable { - uint16_t sync_handle; - uint8_t sampling_enable; - uint8_t slot_durations; - uint8_t max_sampled_cte; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -struct bt_hci_rp_le_set_cl_cte_sampling_enable { - uint8_t status; - uint16_t sync_handle; -} __packed; - -#define BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS BT_OP(BT_OGF_LE, 0x0054) -struct bt_hci_cp_le_set_conn_cte_rx_params { - uint16_t handle; - uint8_t sampling_enable; - uint8_t slot_durations; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -struct bt_hci_rp_le_set_conn_cte_rx_params { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_LE_AOA_CTE_RSP BIT(0) -#define BT_HCI_LE_AOD_CTE_RSP_1US BIT(1) -#define BT_HCI_LE_AOD_CTE_RSP_2US BIT(2) - -#define BT_HCI_LE_SWITCH_PATTERN_LEN_MIN 0x2 -#define BT_HCI_LE_SWITCH_PATTERN_LEN_MAX 0x4B - -#define BT_HCI_OP_LE_SET_CONN_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0055) -struct bt_hci_cp_le_set_conn_cte_tx_params { - uint16_t handle; - uint8_t cte_types; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -struct bt_hci_rp_le_set_conn_cte_tx_params { - uint8_t status; - uint16_t handle; -} __packed; - -/* Interval between consecutive CTE request procedure starts in number of connection events. */ -#define BT_HCI_REQUEST_CTE_ONCE 0x0 -#define BT_HCI_REQUEST_CTE_INTERVAL_MIN 0x1 -#define BT_HCI_REQUEST_CTE_INTERVAL_MAX 0xFFFF - -#define BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE BT_OP(BT_OGF_LE, 0x0056) -struct bt_hci_cp_le_conn_cte_req_enable { - uint16_t handle; - uint8_t enable; - uint16_t cte_request_interval; - uint8_t requested_cte_length; - uint8_t requested_cte_type; -} __packed; - -struct bt_hci_rp_le_conn_cte_req_enable { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_CONN_CTE_RSP_ENABLE BT_OP(BT_OGF_LE, 0x0057) -struct bt_hci_cp_le_conn_cte_rsp_enable { - uint16_t handle; - uint8_t enable; -} __packed; - -struct bt_hci_rp_le_conn_cte_rsp_enable { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_LE_1US_AOD_TX BIT(0) -#define BT_HCI_LE_1US_AOD_RX BIT(1) -#define BT_HCI_LE_1US_AOA_RX BIT(2) - -#define BT_HCI_LE_NUM_ANT_MIN 0x1 -#define BT_HCI_LE_NUM_ANT_MAX 0x4B - -#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MIN 0x2 -#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MAX 0x4B - -#define BT_HCI_LE_MAX_CTE_LEN_MIN 0x2 -#define BT_HCI_LE_MAX_CTE_LEN_MAX 0x14 - -#define BT_HCI_OP_LE_READ_ANT_INFO BT_OP(BT_OGF_LE, 0x0058) -struct bt_hci_rp_le_read_ant_info { - uint8_t status; - uint8_t switch_sample_rates; - uint8_t num_ant; - uint8_t max_switch_pattern_len; - uint8_t max_cte_len; -}; - -#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_ENABLE BIT(0) -#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_FILTER_DUPLICATE BIT(1) - -#define BT_HCI_OP_LE_SET_PER_ADV_RECV_ENABLE BT_OP(BT_OGF_LE, 0x0059) -struct bt_hci_cp_le_set_per_adv_recv_enable { - uint16_t handle; - uint8_t enable; -} __packed; - -#define BT_HCI_OP_LE_PER_ADV_SYNC_TRANSFER BT_OP(BT_OGF_LE, 0x005a) -struct bt_hci_cp_le_per_adv_sync_transfer { - uint16_t conn_handle; - uint16_t service_data; - uint16_t sync_handle; -} __packed; - -struct bt_hci_rp_le_per_adv_sync_transfer { - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_OP_LE_PER_ADV_SET_INFO_TRANSFER BT_OP(BT_OGF_LE, 0x005b) -struct bt_hci_cp_le_per_adv_set_info_transfer { - uint16_t conn_handle; - uint16_t service_data; - uint8_t adv_handle; -} __packed; - -struct bt_hci_rp_le_per_adv_set_info_transfer { - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_LE_PAST_MODE_NO_SYNC 0x00 -#define BT_HCI_LE_PAST_MODE_NO_REPORTS 0x01 -#define BT_HCI_LE_PAST_MODE_SYNC 0x02 -#define BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES 0x03 - -#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOA BIT(0) -#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_1US BIT(1) -#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_2US BIT(2) -#define BT_HCI_LE_PAST_CTE_TYPE_NO_CTE BIT(3) -#define BT_HCI_LE_PAST_CTE_TYPE_ONLY_CTE BIT(4) - -#define BT_HCI_OP_LE_PAST_PARAM BT_OP(BT_OGF_LE, 0x005c) -struct bt_hci_cp_le_past_param { - uint16_t conn_handle; - uint8_t mode; - uint16_t skip; - uint16_t timeout; - uint8_t cte_type; -} __packed; - -struct bt_hci_rp_le_past_param { - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_OP_LE_DEFAULT_PAST_PARAM BT_OP(BT_OGF_LE, 0x005d) -struct bt_hci_cp_le_default_past_param { - uint8_t mode; - uint16_t skip; - uint16_t timeout; - uint8_t cte_type; -} __packed; - -struct bt_hci_rp_le_default_past_param { - uint8_t status; -} __packed; - -#define BT_HCI_OP_LE_READ_BUFFER_SIZE_V2 BT_OP(BT_OGF_LE, 0x0060) -struct bt_hci_rp_le_read_buffer_size_v2 { - uint8_t status; - uint16_t acl_max_len; - uint8_t acl_max_num; - uint16_t iso_max_len; - uint8_t iso_max_num; -} __packed; - -#define BT_HCI_OP_LE_READ_ISO_TX_SYNC BT_OP(BT_OGF_LE, 0x0061) -struct bt_hci_cp_le_read_iso_tx_sync { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_read_iso_tx_sync { - uint8_t status; - uint16_t handle; - uint16_t seq; - uint32_t timestamp; - uint8_t offset[3]; -} __packed; - -#define BT_HCI_OP_LE_SET_CIG_PARAMS BT_OP(BT_OGF_LE, 0x0062) -struct bt_hci_cis_params { - uint8_t cis_id; - uint16_t c_sdu; - uint16_t p_sdu; - uint8_t c_phy; - uint8_t p_phy; - uint8_t c_rtn; - uint8_t p_rtn; -} __packed; - -struct bt_hci_cp_le_set_cig_params { - uint8_t cig_id; - uint8_t c_interval[3]; - uint8_t p_interval[3]; - uint8_t sca; - uint8_t packing; - uint8_t framing; - uint16_t c_latency; - uint16_t p_latency; - uint8_t num_cis; - struct bt_hci_cis_params cis[0]; -} __packed; - -struct bt_hci_rp_le_set_cig_params { - uint8_t status; - uint8_t cig_id; - uint8_t num_handles; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_CIG_PARAMS_TEST BT_OP(BT_OGF_LE, 0x0063) -struct bt_hci_cis_params_test { - uint8_t cis_id; - uint8_t nse; - uint16_t c_sdu; - uint16_t p_sdu; - uint16_t c_pdu; - uint16_t p_pdu; - uint8_t c_phy; - uint8_t p_phy; - uint8_t c_bn; - uint8_t p_bn; -} __packed; - -struct bt_hci_cp_le_set_cig_params_test { - uint8_t cig_id; - uint8_t c_interval[3]; - uint8_t p_interval[3]; - uint8_t c_ft; - uint8_t p_ft; - uint16_t iso_interval; - uint8_t sca; - uint8_t packing; - uint8_t framing; - uint8_t num_cis; - struct bt_hci_cis_params_test cis[0]; -} __packed; - -struct bt_hci_rp_le_set_cig_params_test { - uint8_t status; - uint8_t cig_id; - uint8_t num_handles; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_OP_LE_CREATE_CIS BT_OP(BT_OGF_LE, 0x0064) -struct bt_hci_cis { - uint16_t cis_handle; - uint16_t acl_handle; -} __packed; - -struct bt_hci_cp_le_create_cis { - uint8_t num_cis; - struct bt_hci_cis cis[0]; -} __packed; - -#define BT_HCI_OP_LE_REMOVE_CIG BT_OP(BT_OGF_LE, 0x0065) -struct bt_hci_cp_le_remove_cig { - uint8_t cig_id; -} __packed; - -struct bt_hci_rp_le_remove_cig { - uint8_t status; - uint8_t cig_id; -} __packed; - -#define BT_HCI_OP_LE_ACCEPT_CIS BT_OP(BT_OGF_LE, 0x0066) -struct bt_hci_cp_le_accept_cis { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_REJECT_CIS BT_OP(BT_OGF_LE, 0x0067) -struct bt_hci_cp_le_reject_cis { - uint16_t handle; - uint8_t reason; -} __packed; - -struct bt_hci_rp_le_reject_cis { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_CREATE_BIG BT_OP(BT_OGF_LE, 0x0068) -struct bt_hci_cp_le_create_big { - uint8_t big_handle; - uint8_t adv_handle; - uint8_t num_bis; - uint8_t sdu_interval[3]; - uint16_t max_sdu; - uint16_t max_latency; - uint8_t rtn; - uint8_t phy; - uint8_t packing; - uint8_t framing; - uint8_t encryption; - uint8_t bcode[16]; -} __packed; - -#define BT_HCI_OP_LE_CREATE_BIG_TEST BT_OP(BT_OGF_LE, 0x0069) -struct bt_hci_cp_le_create_big_test { - uint8_t big_handle; - uint8_t adv_handle; - uint8_t num_bis; - uint8_t sdu_interval[3]; - uint16_t iso_interval; - uint8_t nse; - uint16_t max_sdu; - uint16_t max_pdu; - uint8_t phy; - uint8_t packing; - uint8_t framing; - uint8_t bn; - uint8_t irc; - uint8_t pto; - uint8_t encryption; - uint8_t bcode[16]; -} __packed; - -#define BT_HCI_OP_LE_TERMINATE_BIG BT_OP(BT_OGF_LE, 0x006a) -struct bt_hci_cp_le_terminate_big { - uint8_t big_handle; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_LE_BIG_CREATE_SYNC BT_OP(BT_OGF_LE, 0x006b) -struct bt_hci_cp_le_big_create_sync { - uint8_t big_handle; - uint16_t sync_handle; - uint8_t encryption; - uint8_t bcode[16]; - uint8_t mse; - uint16_t sync_timeout; - uint8_t num_bis; - uint8_t bis[0]; -} __packed; - -#define BT_HCI_OP_LE_BIG_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x006c) -struct bt_hci_cp_le_big_terminate_sync { - uint8_t big_handle; -} __packed; - -struct bt_hci_rp_le_big_terminate_sync { - uint8_t status; - uint8_t big_handle; -} __packed; - -#define BT_HCI_OP_LE_REQ_PEER_SC BT_OP(BT_OGF_LE, 0x006d) -struct bt_hci_cp_le_req_peer_sca { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_SETUP_ISO_PATH BT_OP(BT_OGF_LE, 0x006e) -struct bt_hci_cp_le_setup_iso_path { - uint16_t handle; - uint8_t path_dir; - uint8_t path_id; - struct bt_hci_cp_codec_id codec_id; - uint8_t controller_delay[3]; - uint8_t codec_config_len; - uint8_t codec_config[0]; -} __packed; - -struct bt_hci_rp_le_setup_iso_path { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_REMOVE_ISO_PATH BT_OP(BT_OGF_LE, 0x006f) -struct bt_hci_cp_le_remove_iso_path { - uint16_t handle; - uint8_t path_dir; -} __packed; - -struct bt_hci_rp_le_remove_iso_path { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_ISO_TEST_ZERO_SIZE_SDU 0 -#define BT_HCI_ISO_TEST_VARIABLE_SIZE_SDU 1 -#define BT_HCI_ISO_TEST_MAX_SIZE_SDU 2 - -#define BT_HCI_OP_LE_ISO_TRANSMIT_TEST BT_OP(BT_OGF_LE, 0x0070) -struct bt_hci_cp_le_iso_transmit_test { - uint16_t handle; - uint8_t payload_type; -} __packed; - -struct bt_hci_rp_le_iso_transmit_test { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ISO_RECEIVE_TEST BT_OP(BT_OGF_LE, 0x0071) -struct bt_hci_cp_le_iso_receive_test { - uint16_t handle; - uint8_t payload_type; -} __packed; - -struct bt_hci_rp_le_iso_receive_test { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ISO_READ_TEST_COUNTERS BT_OP(BT_OGF_LE, 0x0072) -struct bt_hci_cp_le_read_test_counters { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_read_test_counters { - uint8_t status; - uint16_t handle; - uint32_t received_cnt; - uint32_t missed_cnt; - uint32_t failed_cnt; -} __packed; - -#define BT_HCI_OP_LE_ISO_TEST_END BT_OP(BT_OGF_LE, 0x0073) -struct bt_hci_cp_le_iso_test_end { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_iso_test_end { - uint8_t status; - uint16_t handle; - uint32_t received_cnt; - uint32_t missed_cnt; - uint32_t failed_cnt; -} __packed; - -#define BT_HCI_OP_LE_SET_HOST_FEATURE BT_OP(BT_OGF_LE, 0x0074) -struct bt_hci_cp_le_set_host_feature { - uint8_t bit_number; - uint8_t bit_value; -} __packed; - -struct bt_hci_rp_le_set_host_feature { - uint8_t status; -} __packed; - -#define BT_HCI_OP_LE_READ_ISO_LINK_QUALITY BT_OP(BT_OGF_LE, 0x0075) -struct bt_hci_cp_le_read_iso_link_quality { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_read_iso_link_quality { - uint8_t status; - uint16_t handle; - uint32_t tx_unacked_packets; - uint32_t tx_flushed_packets; - uint32_t tx_last_subevent_packets; - uint32_t retransmitted_packets; - uint32_t crc_error_packets; - uint32_t rx_unreceived_packets; - uint32_t duplicate_packets; -} __packed; - -#define BT_HCI_OP_LE_TX_TEST_V4 BT_OP(BT_OGF_LE, 0x007B) - -struct bt_hci_cp_le_tx_test_v4 { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; - uint8_t phy; - uint8_t cte_len; - uint8_t cte_type; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -#define BT_HCI_TX_TEST_POWER_MIN -0x7F -#define BT_HCI_TX_TEST_POWER_MAX 0x14 - -#define BT_HCI_TX_TEST_POWER_MIN_SET 0x7E -#define BT_HCI_TX_TEST_POWER_MAX_SET 0x7F - -/* Helper structure for Tx power parameter in the HCI Tx Test v4 command. - * Previous parameter of this command is variable size so having separated structure - * for this parameter helps in command parameters unpacking. - */ -struct bt_hci_cp_le_tx_test_v4_tx_power { - int8_t tx_power; -} __packed; - -/* Event definitions */ - -#define BT_HCI_EVT_UNKNOWN 0x00 -#define BT_HCI_EVT_VENDOR 0xff - -#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 -struct bt_hci_evt_inquiry_complete { - uint8_t status; -} __packed; - -#define BT_HCI_EVT_CONN_COMPLETE 0x03 -struct bt_hci_evt_conn_complete { - uint8_t status; - uint16_t handle; - bt_addr_t bdaddr; - uint8_t link_type; - uint8_t encr_enabled; -} __packed; - -#define BT_HCI_EVT_CONN_REQUEST 0x04 -struct bt_hci_evt_conn_request { - bt_addr_t bdaddr; - uint8_t dev_class[3]; - uint8_t link_type; -} __packed; - -#define BT_HCI_EVT_DISCONN_COMPLETE 0x05 -struct bt_hci_evt_disconn_complete { - uint8_t status; - uint16_t handle; - uint8_t reason; -} __packed; - -#define BT_HCI_EVT_AUTH_COMPLETE 0x06 -struct bt_hci_evt_auth_complete { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 -struct bt_hci_evt_remote_name_req_complete { - uint8_t status; - bt_addr_t bdaddr; - uint8_t name[248]; -} __packed; - -#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 -struct bt_hci_evt_encrypt_change { - uint8_t status; - uint16_t handle; - uint8_t encrypt; -} __packed; - -#define BT_HCI_EVT_REMOTE_FEATURES 0x0b -struct bt_hci_evt_remote_features { - uint8_t status; - uint16_t handle; - uint8_t features[8]; -} __packed; - -#define BT_HCI_EVT_REMOTE_VERSION_INFO 0x0c -struct bt_hci_evt_remote_version_info { - uint8_t status; - uint16_t handle; - uint8_t version; - uint16_t manufacturer; - uint16_t subversion; -} __packed; - -#define BT_HCI_EVT_CMD_COMPLETE 0x0e -struct bt_hci_evt_cmd_complete { - uint8_t ncmd; - uint16_t opcode; -} __packed; - -struct bt_hci_evt_cc_status { - uint8_t status; -} __packed; - -#define BT_HCI_EVT_CMD_STATUS 0x0f -struct bt_hci_evt_cmd_status { - uint8_t status; - uint8_t ncmd; - uint16_t opcode; -} __packed; - -#define BT_HCI_EVT_HARDWARE_ERROR 0x10 -struct bt_hci_evt_hardware_error { - uint8_t hardware_code; -} __packed; - -#define BT_HCI_EVT_ROLE_CHANGE 0x12 -struct bt_hci_evt_role_change { - uint8_t status; - bt_addr_t bdaddr; - uint8_t role; -} __packed; - -#define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 -struct bt_hci_evt_num_completed_packets { - uint8_t num_handles; - struct bt_hci_handle_count h[0]; -} __packed; - -#define BT_HCI_EVT_PIN_CODE_REQ 0x16 -struct bt_hci_evt_pin_code_req { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_LINK_KEY_REQ 0x17 -struct bt_hci_evt_link_key_req { - bt_addr_t bdaddr; -} __packed; - -/* Link Key types */ -#define BT_LK_COMBINATION 0x00 -#define BT_LK_LOCAL_UNIT 0x01 -#define BT_LK_REMOTE_UNIT 0x02 -#define BT_LK_DEBUG_COMBINATION 0x03 -#define BT_LK_UNAUTH_COMBINATION_P192 0x04 -#define BT_LK_AUTH_COMBINATION_P192 0x05 -#define BT_LK_CHANGED_COMBINATION 0x06 -#define BT_LK_UNAUTH_COMBINATION_P256 0x07 -#define BT_LK_AUTH_COMBINATION_P256 0x08 - -#define BT_HCI_EVT_LINK_KEY_NOTIFY 0x18 -struct bt_hci_evt_link_key_notify { - bt_addr_t bdaddr; - uint8_t link_key[16]; - uint8_t key_type; -} __packed; - -/* Overflow link types */ -#define BT_OVERFLOW_LINK_SYNCH 0x00 -#define BT_OVERFLOW_LINK_ACL 0x01 -#define BT_OVERFLOW_LINK_ISO 0x02 - -#define BT_HCI_EVT_DATA_BUF_OVERFLOW 0x1a -struct bt_hci_evt_data_buf_overflow { - uint8_t link_type; -} __packed; - -#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 -struct bt_hci_evt_inquiry_result_with_rssi { - bt_addr_t addr; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint8_t cod[3]; - uint16_t clock_offset; - int8_t rssi; -} __packed; - -#define BT_HCI_EVT_REMOTE_EXT_FEATURES 0x23 -struct bt_hci_evt_remote_ext_features { - uint8_t status; - uint16_t handle; - uint8_t page; - uint8_t max_page; - uint8_t features[8]; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED_V2 0x24 -struct bt_hci_evt_le_per_adv_sync_established_v2 { - uint8_t status; - uint16_t handle; - uint8_t sid; - bt_addr_le_t adv_addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; - uint8_t num_subevents; - uint8_t subevent_interval; - uint8_t response_slot_delay; - uint8_t response_slot_spacing; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2 0x25 -struct bt_hci_evt_le_per_advertising_report_v2 { - uint16_t handle; - int8_t tx_power; - int8_t rssi; - uint8_t cte_type; - uint16_t periodic_event_counter; - uint8_t subevent; - uint8_t data_status; - uint8_t length; - uint8_t data[0]; -} __packed; - -#define BT_HCI_EVT_LE_PAST_RECEIVED_V2 0x26 -struct bt_hci_evt_le_past_received_v2 { - uint8_t status; - uint16_t conn_handle; - uint16_t service_data; - uint16_t sync_handle; - uint8_t adv_sid; - bt_addr_le_t addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; - uint8_t num_subevents; - uint8_t subevent_interval; - uint8_t response_slot_delay; - uint8_t response_slot_spacing; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SUBEVENT_DATA_REQUEST 0x27 -struct bt_hci_evt_le_per_adv_subevent_data_request { - uint8_t adv_handle; - uint8_t subevent_start; - uint8_t subevent_data_count; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_RESPONSE_REPORT 0x28 - -struct bt_hci_evt_le_per_adv_response { - int8_t tx_power; - int8_t rssi; - uint8_t cte_type; - uint8_t response_slot; - uint8_t data_status; - uint8_t data_length; - uint8_t data[0]; -} __packed; - -struct bt_hci_evt_le_per_adv_response_report { - uint8_t adv_handle; - uint8_t subevent; - uint8_t tx_status; - uint8_t num_responses; - struct bt_hci_evt_le_per_adv_response responses[0]; -} __packed; - -#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2 0x29 -struct bt_hci_evt_le_enh_conn_complete_v2 { - uint8_t status; - uint16_t handle; - uint8_t role; - bt_addr_le_t peer_addr; - bt_addr_t local_rpa; - bt_addr_t peer_rpa; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; - uint8_t clock_accuracy; - uint8_t adv_handle; - uint16_t sync_handle; -} __packed; - -#define BT_HCI_EVT_SYNC_CONN_COMPLETE 0x2c -struct bt_hci_evt_sync_conn_complete { - uint8_t status; - uint16_t handle; - bt_addr_t bdaddr; - uint8_t link_type; - uint8_t tx_interval; - uint8_t retansmission_window; - uint16_t rx_pkt_length; - uint16_t tx_pkt_length; - uint8_t air_mode; -} __packed; - -#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f -struct bt_hci_evt_extended_inquiry_result { - uint8_t num_reports; - bt_addr_t addr; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint8_t cod[3]; - uint16_t clock_offset; - int8_t rssi; - uint8_t eir[240]; -} __packed; - -#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 -struct bt_hci_evt_encrypt_key_refresh_complete { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_EVT_IO_CAPA_REQ 0x31 -struct bt_hci_evt_io_capa_req { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_IO_CAPA_RESP 0x32 -struct bt_hci_evt_io_capa_resp { - bt_addr_t bdaddr; - uint8_t capability; - uint8_t oob_data; - uint8_t authentication; -} __packed; - -#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 -struct bt_hci_evt_user_confirm_req { - bt_addr_t bdaddr; - uint32_t passkey; -} __packed; - -#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 -struct bt_hci_evt_user_passkey_req { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_SSP_COMPLETE 0x36 -struct bt_hci_evt_ssp_complete { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b -struct bt_hci_evt_user_passkey_notify { - bt_addr_t bdaddr; - uint32_t passkey; -} __packed; - -#define BT_HCI_EVT_LE_META_EVENT 0x3e -struct bt_hci_evt_le_meta_event { - uint8_t subevent; -} __packed; - -#define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 -struct bt_hci_evt_auth_payload_timeout_exp { - uint16_t handle; -} __packed; - -#define BT_HCI_ROLE_CENTRAL 0x00 -#define BT_HCI_ROLE_PERIPHERAL 0x01 - -#define BT_HCI_EVT_LE_CONN_COMPLETE 0x01 -struct bt_hci_evt_le_conn_complete { - uint8_t status; - uint16_t handle; - uint8_t role; - bt_addr_le_t peer_addr; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_LE_RSSI_NOT_AVAILABLE 0x7F - -#define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02 -struct bt_hci_evt_le_advertising_info { - uint8_t evt_type; - bt_addr_le_t addr; - uint8_t length; - uint8_t data[0]; -} __packed; -struct bt_hci_evt_le_advertising_report { - uint8_t num_reports; - struct bt_hci_evt_le_advertising_info adv_info[0]; -} __packed; - -#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 -struct bt_hci_evt_le_conn_update_complete { - uint8_t status; - uint16_t handle; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; -} __packed; - -#define BT_HCI_EVT_LE_REMOTE_FEAT_COMPLETE 0x04 -struct bt_hci_evt_le_remote_feat_complete { - uint8_t status; - uint16_t handle; - uint8_t features[8]; -} __packed; - -#define BT_HCI_EVT_LE_LTK_REQUEST 0x05 -struct bt_hci_evt_le_ltk_request { - uint16_t handle; - uint64_t rand; - uint16_t ediv; -} __packed; - -#define BT_HCI_EVT_LE_CONN_PARAM_REQ 0x06 -struct bt_hci_evt_le_conn_param_req { - uint16_t handle; - uint16_t interval_min; - uint16_t interval_max; - uint16_t latency; - uint16_t timeout; -} __packed; - -#define BT_HCI_EVT_LE_DATA_LEN_CHANGE 0x07 -struct bt_hci_evt_le_data_len_change { - uint16_t handle; - uint16_t max_tx_octets; - uint16_t max_tx_time; - uint16_t max_rx_octets; - uint16_t max_rx_time; -} __packed; - -#define BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE 0x08 -struct bt_hci_evt_le_p256_public_key_complete { - uint8_t status; - uint8_t key[64]; -} __packed; - -#define BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE 0x09 -struct bt_hci_evt_le_generate_dhkey_complete { - uint8_t status; - uint8_t dhkey[32]; -} __packed; - -#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE 0x0a -struct bt_hci_evt_le_enh_conn_complete { - uint8_t status; - uint16_t handle; - uint8_t role; - bt_addr_le_t peer_addr; - bt_addr_t local_rpa; - bt_addr_t peer_rpa; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b -struct bt_hci_evt_le_direct_adv_info { - uint8_t evt_type; - bt_addr_le_t addr; - bt_addr_le_t dir_addr; - int8_t rssi; -} __packed; -struct bt_hci_evt_le_direct_adv_report { - uint8_t num_reports; - struct bt_hci_evt_le_direct_adv_info direct_adv_info[0]; -} __packed; - -#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE 0x0c -struct bt_hci_evt_le_phy_update_complete { - uint8_t status; - uint16_t handle; - uint8_t tx_phy; - uint8_t rx_phy; -} __packed; - -#define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d - -#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) -#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) -#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) -#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) -#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) - -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_RX_FAILED 0xFF - -struct bt_hci_evt_le_ext_advertising_info { - uint16_t evt_type; - bt_addr_le_t addr; - uint8_t prim_phy; - uint8_t sec_phy; - uint8_t sid; - int8_t tx_power; - int8_t rssi; - uint16_t interval; - bt_addr_le_t direct_addr; - uint8_t length; - uint8_t data[0]; -} __packed; -struct bt_hci_evt_le_ext_advertising_report { - uint8_t num_reports; - struct bt_hci_evt_le_ext_advertising_info adv_info[0]; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED 0x0e -struct bt_hci_evt_le_per_adv_sync_established { - uint8_t status; - uint16_t handle; - uint8_t sid; - bt_addr_le_t adv_addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT 0x0f -struct bt_hci_evt_le_per_advertising_report { - uint16_t handle; - int8_t tx_power; - int8_t rssi; - uint8_t cte_type; - uint8_t data_status; - uint8_t length; - uint8_t data[0]; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SYNC_LOST 0x10 -struct bt_hci_evt_le_per_adv_sync_lost { - uint16_t handle; -} __packed; - -#define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 - -#define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 -struct bt_hci_evt_le_adv_set_terminated { - uint8_t status; - uint8_t adv_handle; - uint16_t conn_handle; - uint8_t num_completed_ext_adv_evts; -} __packed; - -#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 -struct bt_hci_evt_le_scan_req_received { - uint8_t handle; - bt_addr_le_t addr; -} __packed; - -#define BT_HCI_LE_CHAN_SEL_ALGO_1 0x00 -#define BT_HCI_LE_CHAN_SEL_ALGO_2 0x01 - -#define BT_HCI_EVT_LE_CHAN_SEL_ALGO 0x14 -struct bt_hci_evt_le_chan_sel_algo { - uint16_t handle; - uint8_t chan_sel_algo; -} __packed; - -#define BT_HCI_LE_CTE_CRC_OK 0x0 -#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME 0x1 -#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_OTHER 0x2 -#define BT_HCI_LE_CTE_INSUFFICIENT_RESOURCES 0xFF - -#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MIN 0x9 -#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MAX 0x52 - -#define BT_HCI_LE_CTE_REPORT_NO_VALID_SAMPLE 0x80 - -#define BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT 0x15 -struct bt_hci_le_iq_sample { - int8_t i; - int8_t q; -}; - -struct bt_hci_evt_le_connectionless_iq_report { - uint16_t sync_handle; - uint8_t chan_idx; - int16_t rssi; - uint8_t rssi_ant_id; - uint8_t cte_type; - uint8_t slot_durations; - uint8_t packet_status; - uint16_t per_evt_counter; - uint8_t sample_count; - struct bt_hci_le_iq_sample sample[0]; -} __packed; - -#define BT_HCI_EVT_LE_CONNECTION_IQ_REPORT 0x16 -struct bt_hci_evt_le_connection_iq_report { - uint16_t conn_handle; - uint8_t rx_phy; - uint8_t data_chan_idx; - int16_t rssi; - uint8_t rssi_ant_id; - uint8_t cte_type; - uint8_t slot_durations; - uint8_t packet_status; - uint16_t conn_evt_counter; - uint8_t sample_count; - struct bt_hci_le_iq_sample sample[0]; -} __packed; - -#define BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE 0x0 - -#define BT_HCI_EVT_LE_CTE_REQUEST_FAILED 0x17 -struct bt_hci_evt_le_cte_req_failed { - /* According to BT 5.3 Core Spec the status field may have following - * values: - * - BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE when received LL_CTE_RSP_PDU without CTE. - * - Other Controller error code for peer rejected request. - */ - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_EVT_LE_PAST_RECEIVED 0x18 -struct bt_hci_evt_le_past_received { - uint8_t status; - uint16_t conn_handle; - uint16_t service_data; - uint16_t sync_handle; - uint8_t adv_sid; - bt_addr_le_t addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_EVT_LE_CIS_ESTABLISHED 0x19 -struct bt_hci_evt_le_cis_established { - uint8_t status; - uint16_t conn_handle; - uint8_t cig_sync_delay[3]; - uint8_t cis_sync_delay[3]; - uint8_t c_latency[3]; - uint8_t p_latency[3]; - uint8_t c_phy; - uint8_t p_phy; - uint8_t nse; - uint8_t c_bn; - uint8_t p_bn; - uint8_t c_ft; - uint8_t p_ft; - uint16_t c_max_pdu; - uint16_t p_max_pdu; - uint16_t interval; -} __packed; - -#define BT_HCI_EVT_LE_CIS_REQ 0x1a -struct bt_hci_evt_le_cis_req { - uint16_t acl_handle; - uint16_t cis_handle; - uint8_t cig_id; - uint8_t cis_id; -} __packed; - -#define BT_HCI_EVT_LE_BIG_COMPLETE 0x1b -struct bt_hci_evt_le_big_complete { - uint8_t status; - uint8_t big_handle; - uint8_t sync_delay[3]; - uint8_t latency[3]; - uint8_t phy; - uint8_t nse; - uint8_t bn; - uint8_t pto; - uint8_t irc; - uint16_t max_pdu; - uint16_t iso_interval; - uint8_t num_bis; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_EVT_LE_BIG_TERMINATE 0x1c -struct bt_hci_evt_le_big_terminate { - uint8_t big_handle; - uint8_t reason; -} __packed; - -#define BT_HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d -struct bt_hci_evt_le_big_sync_established { - uint8_t status; - uint8_t big_handle; - uint8_t latency[3]; - uint8_t nse; - uint8_t bn; - uint8_t pto; - uint8_t irc; - uint16_t max_pdu; - uint16_t iso_interval; - uint8_t num_bis; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e -struct bt_hci_evt_le_big_sync_lost { - uint8_t big_handle; - uint8_t reason; -} __packed; - -#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE 0x1f -struct bt_hci_evt_le_req_peer_sca_complete { - uint8_t status; - uint16_t handle; - uint8_t sca; -} __packed; - -#define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 -struct bt_hci_evt_le_biginfo_adv_report { - uint16_t sync_handle; - uint8_t num_bis; - uint8_t nse; - uint16_t iso_interval; - uint8_t bn; - uint8_t pto; - uint8_t irc; - uint16_t max_pdu; - uint8_t sdu_interval[3]; - uint16_t max_sdu; - uint8_t phy; - uint8_t framing; - uint8_t encryption; -} __packed; - -/* Event mask bits */ - -#define BT_EVT_BIT(n) (1ULL << (n)) - -#define BT_EVT_MASK_INQUIRY_COMPLETE BT_EVT_BIT(0) -#define BT_EVT_MASK_CONN_COMPLETE BT_EVT_BIT(2) -#define BT_EVT_MASK_CONN_REQUEST BT_EVT_BIT(3) -#define BT_EVT_MASK_DISCONN_COMPLETE BT_EVT_BIT(4) -#define BT_EVT_MASK_AUTH_COMPLETE BT_EVT_BIT(5) -#define BT_EVT_MASK_REMOTE_NAME_REQ_COMPLETE BT_EVT_BIT(6) -#define BT_EVT_MASK_ENCRYPT_CHANGE BT_EVT_BIT(7) -#define BT_EVT_MASK_REMOTE_FEATURES BT_EVT_BIT(10) -#define BT_EVT_MASK_REMOTE_VERSION_INFO BT_EVT_BIT(11) -#define BT_EVT_MASK_HARDWARE_ERROR BT_EVT_BIT(15) -#define BT_EVT_MASK_ROLE_CHANGE BT_EVT_BIT(17) -#define BT_EVT_MASK_PIN_CODE_REQ BT_EVT_BIT(21) -#define BT_EVT_MASK_LINK_KEY_REQ BT_EVT_BIT(22) -#define BT_EVT_MASK_LINK_KEY_NOTIFY BT_EVT_BIT(23) -#define BT_EVT_MASK_DATA_BUFFER_OVERFLOW BT_EVT_BIT(25) -#define BT_EVT_MASK_INQUIRY_RESULT_WITH_RSSI BT_EVT_BIT(33) -#define BT_EVT_MASK_REMOTE_EXT_FEATURES BT_EVT_BIT(34) -#define BT_EVT_MASK_SYNC_CONN_COMPLETE BT_EVT_BIT(43) -#define BT_EVT_MASK_EXTENDED_INQUIRY_RESULT BT_EVT_BIT(46) -#define BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE BT_EVT_BIT(47) -#define BT_EVT_MASK_IO_CAPA_REQ BT_EVT_BIT(48) -#define BT_EVT_MASK_IO_CAPA_RESP BT_EVT_BIT(49) -#define BT_EVT_MASK_USER_CONFIRM_REQ BT_EVT_BIT(50) -#define BT_EVT_MASK_USER_PASSKEY_REQ BT_EVT_BIT(51) -#define BT_EVT_MASK_SSP_COMPLETE BT_EVT_BIT(53) -#define BT_EVT_MASK_USER_PASSKEY_NOTIFY BT_EVT_BIT(58) -#define BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) - -/* Page 2 */ -#define BT_EVT_MASK_NUM_COMPLETE_DATA_BLOCKS BT_EVT_BIT(8) -#define BT_EVT_MASK_TRIGG_CLOCK_CAPTURE BT_EVT_BIT(14) -#define BT_EVT_MASK_SYNCH_TRAIN_COMPLETE BT_EVT_BIT(15) -#define BT_EVT_MASK_SYNCH_TRAIN_RX BT_EVT_BIT(16) -#define BT_EVT_MASK_CL_PER_BC_RX BT_EVT_BIT(17) -#define BT_EVT_MASK_CL_PER_BC_TIMEOUT BT_EVT_BIT(18) -#define BT_EVT_MASK_TRUNC_PAGE_COMPLETE BT_EVT_BIT(19) -#define BT_EVT_MASK_PER_PAGE_RSP_TIMEOUT BT_EVT_BIT(20) -#define BT_EVT_MASK_CL_PER_BC_CH_MAP_CHANGE BT_EVT_BIT(21) -#define BT_EVT_MASK_INQUIRY_RSP_NOT BT_EVT_BIT(22) -#define BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP BT_EVT_BIT(23) -#define BT_EVT_MASK_SAM_STATUS_CHANGE BT_EVT_BIT(24) - -#define BT_EVT_MASK_LE_CONN_COMPLETE BT_EVT_BIT(0) -#define BT_EVT_MASK_LE_ADVERTISING_REPORT BT_EVT_BIT(1) -#define BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE BT_EVT_BIT(2) -#define BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE BT_EVT_BIT(3) -#define BT_EVT_MASK_LE_LTK_REQUEST BT_EVT_BIT(4) -#define BT_EVT_MASK_LE_CONN_PARAM_REQ BT_EVT_BIT(5) -#define BT_EVT_MASK_LE_DATA_LEN_CHANGE BT_EVT_BIT(6) -#define BT_EVT_MASK_LE_P256_PUBLIC_KEY_COMPLETE BT_EVT_BIT(7) -#define BT_EVT_MASK_LE_GENERATE_DHKEY_COMPLETE BT_EVT_BIT(8) -#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE BT_EVT_BIT(9) -#define BT_EVT_MASK_LE_DIRECT_ADV_REPORT BT_EVT_BIT(10) -#define BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE BT_EVT_BIT(11) -#define BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT BT_EVT_BIT(12) -#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED BT_EVT_BIT(13) -#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT BT_EVT_BIT(14) -#define BT_EVT_MASK_LE_PER_ADV_SYNC_LOST BT_EVT_BIT(15) -#define BT_EVT_MASK_LE_SCAN_TIMEOUT BT_EVT_BIT(16) -#define BT_EVT_MASK_LE_ADV_SET_TERMINATED BT_EVT_BIT(17) -#define BT_EVT_MASK_LE_SCAN_REQ_RECEIVED BT_EVT_BIT(18) -#define BT_EVT_MASK_LE_CHAN_SEL_ALGO BT_EVT_BIT(19) -#define BT_EVT_MASK_LE_CONNECTIONLESS_IQ_REPORT BT_EVT_BIT(20) -#define BT_EVT_MASK_LE_CONNECTION_IQ_REPORT BT_EVT_BIT(21) -#define BT_EVT_MASK_LE_CTE_REQUEST_FAILED BT_EVT_BIT(22) -#define BT_EVT_MASK_LE_PAST_RECEIVED BT_EVT_BIT(23) -#define BT_EVT_MASK_LE_CIS_ESTABLISHED BT_EVT_BIT(24) -#define BT_EVT_MASK_LE_CIS_REQ BT_EVT_BIT(25) -#define BT_EVT_MASK_LE_BIG_COMPLETE BT_EVT_BIT(26) -#define BT_EVT_MASK_LE_BIG_TERMINATED BT_EVT_BIT(27) -#define BT_EVT_MASK_LE_BIG_SYNC_ESTABLISHED BT_EVT_BIT(28) -#define BT_EVT_MASK_LE_BIG_SYNC_LOST BT_EVT_BIT(29) -#define BT_EVT_MASK_LE_REQ_PEER_SCA_COMPLETE BT_EVT_BIT(30) -#define BT_EVT_MASK_LE_PATH_LOSS_THRESHOLD BT_EVT_BIT(31) -#define BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING BT_EVT_BIT(32) -#define BT_EVT_MASK_LE_BIGINFO_ADV_REPORT BT_EVT_BIT(33) - -#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED_V2 BT_EVT_BIT(35) -#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT_V2 BT_EVT_BIT(36) -#define BT_EVT_MASK_LE_PAST_RECEIVED_V2 BT_EVT_BIT(37) -#define BT_EVT_MASK_LE_PER_ADV_SUBEVENT_DATA_REQ BT_EVT_BIT(38) -#define BT_EVT_MASK_LE_PER_ADV_RESPONSE_REPORT BT_EVT_BIT(39) -#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40) - /** Allocate a HCI command buffer. * * This function allocates a new buffer for a HCI command. It is given diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h new file mode 100644 index 00000000000..d9dff357d35 --- /dev/null +++ b/include/zephyr/bluetooth/hci_types.h @@ -0,0 +1,3086 @@ +/* hci.h - Bluetooth Host Control Interface types */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Special own address types for LL privacy (used in adv & scan parameters) */ +#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 +#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 +#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 + +#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe +#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff + +#define BT_ENC_KEY_SIZE_MIN 0x07 +#define BT_ENC_KEY_SIZE_MAX 0x10 + +#define BT_HCI_ADV_HANDLE_INVALID 0xff +#define BT_HCI_SYNC_HANDLE_INVALID 0xffff +#define BT_HCI_PAWR_SUBEVENT_MAX 128 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.3 HCI Synchronous Data Packets */ +struct bt_hci_sco_hdr { + uint16_t handle; /* 12 bit handle, 2 bit Packet Status Flag, 1 bit RFU */ + uint8_t len; +} __packed; +#define BT_HCI_SCO_HDR_SIZE 3 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.4 HCI Event Packet */ +struct bt_hci_evt_hdr { + uint8_t evt; + uint8_t len; +} __packed; +#define BT_HCI_EVT_HDR_SIZE 2 + +#define BT_ACL_START_NO_FLUSH 0x00 +#define BT_ACL_CONT 0x01 +#define BT_ACL_START 0x02 +#define BT_ACL_COMPLETE 0x03 + +#define BT_ACL_POINT_TO_POINT 0x00 +#define BT_ACL_BROADCAST 0x01 + +#define BT_ACL_HANDLE_MASK BIT_MASK(12) + +#define bt_acl_handle(h) ((h) & BT_ACL_HANDLE_MASK) +#define bt_acl_flags(h) ((h) >> 12) +#define bt_acl_flags_pb(f) ((f) & BIT_MASK(2)) +#define bt_acl_flags_bc(f) ((f) >> 2) +#define bt_acl_handle_pack(h, f) ((h) | ((f) << 12)) + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.2 ACL Data Packets */ +struct bt_hci_acl_hdr { + uint16_t handle; + uint16_t len; +} __packed; +#define BT_HCI_ACL_HDR_SIZE 4 + +#define BT_ISO_START 0x00 +#define BT_ISO_CONT 0x01 +#define BT_ISO_SINGLE 0x02 +#define BT_ISO_END 0x03 + +#define bt_iso_handle(h) ((h) & 0x0fff) +#define bt_iso_flags(h) ((h) >> 12) +#define bt_iso_flags_pb(f) ((f) & 0x0003) +#define bt_iso_flags_ts(f) (((f) >> 2) & 0x0001) +#define bt_iso_pack_flags(pb, ts) \ + (((pb) & 0x0003) | (((ts) & 0x0001) << 2)) +#define bt_iso_handle_pack(h, pb, ts) \ + ((h) | (bt_iso_pack_flags(pb, ts) << 12)) +#define bt_iso_hdr_len(h) ((h) & BIT_MASK(14)) + +#define BT_ISO_DATA_VALID 0x00 +#define BT_ISO_DATA_INVALID 0x01 +#define BT_ISO_DATA_NOP 0x02 + +#define bt_iso_pkt_len(h) ((h) & BIT_MASK(12)) +#define bt_iso_pkt_flags(h) ((h) >> 14) +#define bt_iso_pkt_len_pack(h, f) (((h) & BIT_MASK(12)) | ((f) << 14)) + +struct bt_hci_iso_data_hdr { + uint16_t sn; + uint16_t slen; /* 12 bit len, 2 bit RFU, 2 bit packet status */ +} __packed; +#define BT_HCI_ISO_DATA_HDR_SIZE 4 + +struct bt_hci_iso_ts_data_hdr { + uint32_t ts; + struct bt_hci_iso_data_hdr data; +} __packed; +#define BT_HCI_ISO_TS_DATA_HDR_SIZE 8 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.5 HCI ISO Data Packets */ +struct bt_hci_iso_hdr { + uint16_t handle; /* 12 bit handle, 2 bit PB flags, 1 bit TS_Flag, 1 bit RFU */ + uint16_t len; /* 14 bits, 2 bits RFU */ +} __packed; +#define BT_HCI_ISO_HDR_SIZE 4 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.1 HCI Command Packet */ +struct bt_hci_cmd_hdr { + uint16_t opcode; + uint8_t param_len; +} __packed; +#define BT_HCI_CMD_HDR_SIZE 3 + +/* Supported Commands */ +#define BT_CMD_TEST(cmd, octet, bit) (cmd[octet] & BIT(bit)) +#define BT_CMD_LE_STATES(cmd) BT_CMD_TEST(cmd, 28, 3) + +#define BT_FEAT_TEST(feat, page, octet, bit) (feat[page][octet] & BIT(bit)) + +#define BT_FEAT_BREDR(feat) !BT_FEAT_TEST(feat, 0, 4, 5) +#define BT_FEAT_LE(feat) BT_FEAT_TEST(feat, 0, 4, 6) +#define BT_FEAT_EXT_FEATURES(feat) BT_FEAT_TEST(feat, 0, 7, 7) +#define BT_FEAT_HOST_SSP(feat) BT_FEAT_TEST(feat, 1, 0, 0) +#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0) + +#define BT_FEAT_LMP_ESCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 3, 7) +#define BT_FEAT_HV2_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 4) +#define BT_FEAT_HV3_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 5) +#define BT_FEAT_EV4_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 0) +#define BT_FEAT_EV5_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 1) +#define BT_FEAT_2EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 5) +#define BT_FEAT_3EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 6) +#define BT_FEAT_3SLOT_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 7) + +/* LE features */ +#define BT_LE_FEAT_BIT_ENC 0 +#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1 +#define BT_LE_FEAT_BIT_EXT_REJ_IND 2 +#define BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG 3 +#define BT_LE_FEAT_BIT_PING 4 +#define BT_LE_FEAT_BIT_DLE 5 +#define BT_LE_FEAT_BIT_PRIVACY 6 +#define BT_LE_FEAT_BIT_EXT_SCAN 7 +#define BT_LE_FEAT_BIT_PHY_2M 8 +#define BT_LE_FEAT_BIT_SMI_TX 9 +#define BT_LE_FEAT_BIT_SMI_RX 10 +#define BT_LE_FEAT_BIT_PHY_CODED 11 +#define BT_LE_FEAT_BIT_EXT_ADV 12 +#define BT_LE_FEAT_BIT_PER_ADV 13 +#define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 +#define BT_LE_FEAT_BIT_PWR_CLASS_1 15 +#define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 +#define BT_LE_FEAT_BIT_CONN_CTE_REQ 17 +#define BT_LE_FEAT_BIT_CONN_CTE_RESP 18 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX 19 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX 20 +#define BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD 21 +#define BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA 22 +#define BT_LE_FEAT_BIT_RX_CTE 23 +#define BT_LE_FEAT_BIT_PAST_SEND 24 +#define BT_LE_FEAT_BIT_PAST_RECV 25 +#define BT_LE_FEAT_BIT_SCA_UPDATE 26 +#define BT_LE_FEAT_BIT_REMOTE_PUB_KEY_VALIDATE 27 +#define BT_LE_FEAT_BIT_CIS_CENTRAL 28 +#define BT_LE_FEAT_BIT_CIS_PERIPHERAL 29 +#define BT_LE_FEAT_BIT_ISO_BROADCASTER 30 +#define BT_LE_FEAT_BIT_SYNC_RECEIVER 31 +#define BT_LE_FEAT_BIT_ISO_CHANNELS 32 +#define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 +#define BT_LE_FEAT_BIT_PWR_CHG_IND 34 +#define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 +#define BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP 36 +#define BT_LE_FEAT_BIT_CONN_SUBRATING 37 +#define BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP 38 +#define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 + +#define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43 +#define BT_LE_FEAT_BIT_PAWR_SCANNER 44 + +#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ + BIT((n) & 7)) + +#define BT_FEAT_LE_ENCR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ENC) +#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_PARAM_REQ) +#define BT_FEAT_LE_PER_INIT_FEAT_XCHG(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG) +#define BT_FEAT_LE_DLE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_DLE) +#define BT_FEAT_LE_PHY_2M(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_2M) +#define BT_FEAT_LE_PHY_CODED(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_CODED) +#define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PRIVACY) +#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_EXT_ADV) +#define BT_FEAT_LE_EXT_PER_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_ADV) +#define BT_FEAT_LE_CONNECTION_CTE_REQ(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_CTE_REQ) +#define BT_FEAT_LE_CONNECTION_CTE_RESP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_CTE_RESP) +#define BT_FEAT_LE_CONNECTIONLESS_CTE_TX(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX) +#define BT_FEAT_LE_CONNECTIONLESS_CTE_RX(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX) +#define BT_FEAT_LE_ANT_SWITCH_TX_AOD(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD) +#define BT_FEAT_LE_ANT_SWITCH_RX_AOA(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA) +#define BT_FEAT_LE_RX_CTE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_RX_CTE) +#define BT_FEAT_LE_PAST_SEND(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAST_SEND) +#define BT_FEAT_LE_PAST_RECV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAST_RECV) +#define BT_FEAT_LE_CIS_CENTRAL(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CIS_CENTRAL) +#define BT_FEAT_LE_CIS_PERIPHERAL(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CIS_PERIPHERAL) +#define BT_FEAT_LE_ISO_BROADCASTER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ISO_BROADCASTER) +#define BT_FEAT_LE_SYNC_RECEIVER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_SYNC_RECEIVER) +#define BT_FEAT_LE_ISO_CHANNELS(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ISO_CHANNELS) +#define BT_FEAT_LE_PWR_CTRL_REQ(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PWR_CTRL_REQ) +#define BT_FEAT_LE_PWR_CHG_IND(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PWR_CHG_IND) +#define BT_FEAT_LE_PATH_LOSS_MONITOR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PATH_LOSS_MONITOR) +#define BT_FEAT_LE_PER_ADV_ADI_SUPP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP) +#define BT_FEAT_LE_CONN_SUBRATING(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_SUBRATING) +#define BT_FEAT_LE_CONN_SUBRATING_HOST_SUPP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP) +#define BT_FEAT_LE_CHANNEL_CLASSIFICATION(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION) +#define BT_FEAT_LE_PAWR_ADVERTISER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAWR_ADVERTISER) +#define BT_FEAT_LE_PAWR_SCANNER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAWR_SCANNER) + +#define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \ + BT_FEAT_LE_CIS_PERIPHERAL(feat)) +#define BT_FEAT_LE_BIS(feat) (BT_FEAT_LE_ISO_BROADCASTER(feat) | \ + BT_FEAT_LE_SYNC_RECEIVER(feat)) +#define BT_FEAT_LE_ISO(feat) (BT_FEAT_LE_CIS(feat) | \ + BT_FEAT_LE_BIS(feat)) + +/* LE States */ +#define BT_LE_STATES_PER_CONN_ADV(states) (states & 0x0000004000000000) + +/* Bonding/authentication types */ +#define BT_HCI_NO_BONDING 0x00 +#define BT_HCI_NO_BONDING_MITM 0x01 +#define BT_HCI_DEDICATED_BONDING 0x02 +#define BT_HCI_DEDICATED_BONDING_MITM 0x03 +#define BT_HCI_GENERAL_BONDING 0x04 +#define BT_HCI_GENERAL_BONDING_MITM 0x05 + +/* + * MITM protection is enabled in SSP authentication requirements octet when + * LSB bit is set. + */ +#define BT_MITM 0x01 + +/* I/O capabilities */ +#define BT_IO_DISPLAY_ONLY 0x00 +#define BT_IO_DISPLAY_YESNO 0x01 +#define BT_IO_KEYBOARD_ONLY 0x02 +#define BT_IO_NO_INPUT_OUTPUT 0x03 + +/* SCO packet types */ +#define HCI_PKT_TYPE_HV1 0x0020 +#define HCI_PKT_TYPE_HV2 0x0040 +#define HCI_PKT_TYPE_HV3 0x0080 + +/* eSCO packet types */ +#define HCI_PKT_TYPE_ESCO_HV1 0x0001 +#define HCI_PKT_TYPE_ESCO_HV2 0x0002 +#define HCI_PKT_TYPE_ESCO_HV3 0x0004 +#define HCI_PKT_TYPE_ESCO_EV3 0x0008 +#define HCI_PKT_TYPE_ESCO_EV4 0x0010 +#define HCI_PKT_TYPE_ESCO_EV5 0x0020 +#define HCI_PKT_TYPE_ESCO_2EV3 0x0040 +#define HCI_PKT_TYPE_ESCO_3EV3 0x0080 +#define HCI_PKT_TYPE_ESCO_2EV5 0x0100 +#define HCI_PKT_TYPE_ESCO_3EV5 0x0200 + + +#define ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_HV1 | \ + HCI_PKT_TYPE_ESCO_HV2 | \ + HCI_PKT_TYPE_ESCO_HV3) +#define SCO_PKT_MASK (HCI_PKT_TYPE_HV1 | \ + HCI_PKT_TYPE_HV2 | \ + HCI_PKT_TYPE_HV3) +#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ + HCI_PKT_TYPE_ESCO_3EV3 | \ + HCI_PKT_TYPE_ESCO_2EV5 | \ + HCI_PKT_TYPE_ESCO_3EV5) + +/* HCI BR/EDR link types */ +#define BT_HCI_SCO 0x00 +#define BT_HCI_ACL 0x01 +#define BT_HCI_ESCO 0x02 + +/* OpCode Group Fields */ +#define BT_OGF_LINK_CTRL 0x01 +#define BT_OGF_BASEBAND 0x03 +#define BT_OGF_INFO 0x04 +#define BT_OGF_STATUS 0x05 +#define BT_OGF_LE 0x08 +#define BT_OGF_VS 0x3f + +/* Construct OpCode from OGF and OCF */ +#define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) + +/* Invalid opcode */ +#define BT_OP_NOP 0x0000 + +/* Obtain OGF from OpCode */ +#define BT_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) +/* Obtain OCF from OpCode */ +#define BT_OCF(opcode) ((opcode) & BIT_MASK(10)) + +#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) +struct bt_hci_op_inquiry { + uint8_t lap[3]; + uint8_t length; + uint8_t num_rsp; +} __packed; + +#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) + +#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) +struct bt_hci_cp_connect { + bt_addr_t bdaddr; + uint16_t packet_type; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; + uint8_t allow_role_switch; +} __packed; + +#define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) +struct bt_hci_cp_disconnect { + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) +struct bt_hci_cp_connect_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_connect_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) +struct bt_hci_cp_accept_conn_req { + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_OP_SETUP_SYNC_CONN BT_OP(BT_OGF_LINK_CTRL, 0x0028) +struct bt_hci_cp_setup_sync_conn { + uint16_t handle; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) +struct bt_hci_cp_accept_sync_conn_req { + bt_addr_t bdaddr; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) +struct bt_hci_cp_reject_conn_req { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LINK_KEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000b) +struct bt_hci_cp_link_key_reply { + bt_addr_t bdaddr; + uint8_t link_key[16]; +} __packed; + +#define BT_HCI_OP_LINK_KEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000c) +struct bt_hci_cp_link_key_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000d) +struct bt_hci_cp_pin_code_reply { + bt_addr_t bdaddr; + uint8_t pin_len; + uint8_t pin_code[16]; +} __packed; +struct bt_hci_rp_pin_code_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000e) +struct bt_hci_cp_pin_code_neg_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_pin_code_neg_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) +struct bt_hci_cp_auth_requested { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) +struct bt_hci_cp_set_conn_encrypt { + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) +struct bt_hci_cp_remote_name_request { + bt_addr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) +struct bt_hci_cp_remote_name_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_remote_name_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001b) +struct bt_hci_cp_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_EXT_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001c) +struct bt_hci_cp_read_remote_ext_features { + uint16_t handle; + uint8_t page; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_VERSION_INFO BT_OP(BT_OGF_LINK_CTRL, 0x001d) +struct bt_hci_cp_read_remote_version_info { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) +struct bt_hci_cp_io_capability_reply { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) +#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) +struct bt_hci_cp_user_confirm_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_user_confirm_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) +struct bt_hci_cp_user_passkey_reply { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) +struct bt_hci_cp_user_passkey_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) +struct bt_hci_cp_io_capability_neg_reply { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) +struct bt_hci_cp_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_RESET BT_OP(BT_OGF_BASEBAND, 0x0003) + +#define BT_HCI_OP_WRITE_LOCAL_NAME BT_OP(BT_OGF_BASEBAND, 0x0013) +struct bt_hci_write_local_name { + uint8_t local_name[248]; +} __packed; + +#define BT_HCI_OP_READ_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0015) +struct bt_hci_rp_read_conn_accept_timeout { + uint8_t status; + uint16_t conn_accept_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0016) +struct bt_hci_cp_write_conn_accept_timeout { + uint16_t conn_accept_timeout; +} __packed; + +struct bt_hci_rp_write_conn_accept_timeout { + uint8_t status; +} __packed; + +#define BT_HCI_OP_WRITE_PAGE_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0018) + +#define BT_HCI_OP_WRITE_SCAN_ENABLE BT_OP(BT_OGF_BASEBAND, 0x001a) +#define BT_BREDR_SCAN_DISABLED 0x00 +#define BT_BREDR_SCAN_INQUIRY 0x01 +#define BT_BREDR_SCAN_PAGE 0x02 + +#define BT_HCI_OP_WRITE_CLASS_OF_DEVICE BT_OP(BT_OGF_BASEBAND, 0x0024) +struct bt_hci_cp_write_class_of_device { + uint8_t class_of_device[3]; +} __packed; + +#define BT_TX_POWER_LEVEL_CURRENT 0x00 +#define BT_TX_POWER_LEVEL_MAX 0x01 +#define BT_HCI_OP_READ_TX_POWER_LEVEL BT_OP(BT_OGF_BASEBAND, 0x002d) +struct bt_hci_cp_read_tx_power_level { + uint16_t handle; + uint8_t type; +} __packed; + +struct bt_hci_rp_read_tx_power_level { + uint8_t status; + uint16_t handle; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 +#define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 +#define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) +struct bt_hci_cp_set_ctl_to_host_flow { + uint8_t flow_enable; +} __packed; + +#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033) +struct bt_hci_cp_host_buffer_size { + uint16_t acl_mtu; + uint8_t sco_mtu; + uint16_t acl_pkts; + uint16_t sco_pkts; +} __packed; + +struct bt_hci_handle_count { + uint16_t handle; + uint16_t count; +} __packed; + +#define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) +struct bt_hci_cp_host_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) +struct bt_hci_cp_write_inquiry_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) +struct bt_hci_cp_write_ssp_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK_PAGE_2 BT_OP(BT_OGF_BASEBAND, 0x0063) +struct bt_hci_cp_set_event_mask_page_2 { + uint8_t events_page_2[8]; +} __packed; + +#define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) +struct bt_hci_cp_write_le_host_supp { + uint8_t le; + uint8_t simul; +} __packed; + +#define BT_HCI_OP_WRITE_SC_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x007a) +struct bt_hci_cp_write_sc_host_supp { + uint8_t sc_support; +} __packed; + +#define BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007b) +struct bt_hci_cp_read_auth_payload_timeout { + uint16_t handle; +} __packed; + +struct bt_hci_rp_read_auth_payload_timeout { + uint8_t status; + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007c) +struct bt_hci_cp_write_auth_payload_timeout { + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +struct bt_hci_rp_write_auth_payload_timeout { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_CONFIGURE_DATA_PATH BT_OP(BT_OGF_BASEBAND, 0x0083) +struct bt_hci_cp_configure_data_path { + uint8_t data_path_dir; + uint8_t data_path_id; + uint8_t vs_config_len; + uint8_t vs_config[0]; +} __packed; + +struct bt_hci_rp_configure_data_path { + uint8_t status; +} __packed; + +/* HCI version from Assigned Numbers */ +#define BT_HCI_VERSION_1_0B 0 +#define BT_HCI_VERSION_1_1 1 +#define BT_HCI_VERSION_1_2 2 +#define BT_HCI_VERSION_2_0 3 +#define BT_HCI_VERSION_2_1 4 +#define BT_HCI_VERSION_3_0 5 +#define BT_HCI_VERSION_4_0 6 +#define BT_HCI_VERSION_4_1 7 +#define BT_HCI_VERSION_4_2 8 +#define BT_HCI_VERSION_5_0 9 +#define BT_HCI_VERSION_5_1 10 +#define BT_HCI_VERSION_5_2 11 +#define BT_HCI_VERSION_5_3 12 +#define BT_HCI_VERSION_5_4 13 + +#define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) +struct bt_hci_rp_read_local_version_info { + uint8_t status; + uint8_t hci_version; + uint16_t hci_revision; + uint8_t lmp_version; + uint16_t manufacturer; + uint16_t lmp_subversion; +} __packed; + +#define BT_HCI_OP_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) +struct bt_hci_rp_read_supported_commands { + uint8_t status; + uint8_t commands[64]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_EXT_FEATURES BT_OP(BT_OGF_INFO, 0x0004) +struct bt_hci_cp_read_local_ext_features { + uint8_t page; +}; +struct bt_hci_rp_read_local_ext_features { + uint8_t status; + uint8_t page; + uint8_t max_page; + uint8_t ext_features[8]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) +struct bt_hci_rp_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) +struct bt_hci_rp_read_buffer_size { + uint8_t status; + uint16_t acl_max_len; + uint8_t sco_max_len; + uint16_t acl_max_num; + uint16_t sco_max_num; +} __packed; + +#define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) +struct bt_hci_rp_read_bd_addr { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +/* logic transport type bits as returned when reading supported codecs */ +#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_ACL BIT(0) +#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_SCO BIT(1) +#define BT_HCI_CODEC_TRANSPORT_MASK_LE_CIS BIT(2) +#define BT_HCI_CODEC_TRANSPORT_MASK_LE_BIS BIT(3) + +/* logic transport types for reading codec capabilities and controller delays */ +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_ACL 0x00 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_SCO 0x01 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_CIS 0x02 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_BIS 0x03 + +/* audio datapath directions */ +#define BT_HCI_DATAPATH_DIR_HOST_TO_CTLR 0x00 +#define BT_HCI_DATAPATH_DIR_CTLR_TO_HOST 0x01 + +/* audio datapath IDs */ +#define BT_HCI_DATAPATH_ID_HCI 0x00 +#define BT_HCI_DATAPATH_ID_VS 0x01 +#define BT_HCI_DATAPATH_ID_VS_END 0xfe + +/* coding format assigned numbers, used for codec IDs */ +#define BT_HCI_CODING_FORMAT_ULAW_LOG 0x00 +#define BT_HCI_CODING_FORMAT_ALAW_LOG 0x01 +#define BT_HCI_CODING_FORMAT_CVSD 0x02 +#define BT_HCI_CODING_FORMAT_TRANSPARENT 0x03 +#define BT_HCI_CODING_FORMAT_LINEAR_PCM 0x04 +#define BT_HCI_CODING_FORMAT_MSBC 0x05 +#define BT_HCI_CODING_FORMAT_VS 0xFF + + +#define BT_HCI_OP_READ_CODECS BT_OP(BT_OGF_INFO, 0x000b) +struct bt_hci_std_codec_info { + uint8_t codec_id; +} __packed; +struct bt_hci_std_codecs { + uint8_t num_codecs; + struct bt_hci_std_codec_info codec_info[0]; +} __packed; +struct bt_hci_vs_codec_info { + uint16_t company_id; + uint16_t codec_id; +} __packed; +struct bt_hci_vs_codecs { + uint8_t num_codecs; + struct bt_hci_vs_codec_info codec_info[0]; +} __packed; +struct bt_hci_rp_read_codecs { + uint8_t status; + /* other fields filled in dynamically */ + uint8_t codecs[0]; +} __packed; + +#define BT_HCI_OP_READ_CODECS_V2 BT_OP(BT_OGF_INFO, 0x000d) +struct bt_hci_std_codec_info_v2 { + uint8_t codec_id; + uint8_t transports; /* bitmap */ +} __packed; +struct bt_hci_std_codecs_v2 { + uint8_t num_codecs; + struct bt_hci_std_codec_info_v2 codec_info[0]; +} __packed; +struct bt_hci_vs_codec_info_v2 { + uint16_t company_id; + uint16_t codec_id; + uint8_t transports; /* bitmap */ +} __packed; +struct bt_hci_vs_codecs_v2 { + uint8_t num_codecs; + struct bt_hci_vs_codec_info_v2 codec_info[0]; +} __packed; +struct bt_hci_rp_read_codecs_v2 { + uint8_t status; + /* other fields filled in dynamically */ + uint8_t codecs[0]; +} __packed; + +struct bt_hci_cp_codec_id { + uint8_t coding_format; + uint16_t company_id; + uint16_t vs_codec_id; +} __packed; + +#define BT_HCI_OP_READ_CODEC_CAPABILITIES BT_OP(BT_OGF_INFO, 0x000e) +struct bt_hci_cp_read_codec_capabilities { + struct bt_hci_cp_codec_id codec_id; + uint8_t transport; + uint8_t direction; +} __packed; +struct bt_hci_codec_capability_info { + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_rp_read_codec_capabilities { + uint8_t status; + uint8_t num_capabilities; + /* other fields filled in dynamically */ + uint8_t capabilities[0]; +} __packed; + +#define BT_HCI_OP_READ_CTLR_DELAY BT_OP(BT_OGF_INFO, 0x000f) +struct bt_hci_cp_read_ctlr_delay { + struct bt_hci_cp_codec_id codec_id; + uint8_t transport; + uint8_t direction; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __packed; +struct bt_hci_rp_read_ctlr_delay { + uint8_t status; + uint8_t min_ctlr_delay[3]; + uint8_t max_ctlr_delay[3]; +} __packed; + +#define BT_HCI_OP_READ_RSSI BT_OP(BT_OGF_STATUS, 0x0005) +struct bt_hci_cp_read_rssi { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_rssi { + uint8_t status; + uint16_t handle; + int8_t rssi; +} __packed; + +#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 +#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 + +#define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) +struct bt_hci_cp_read_encryption_key_size { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_encryption_key_size { + uint8_t status; + uint16_t handle; + uint8_t key_size; +} __packed; + +/* BLE */ + +#define BT_HCI_OP_LE_SET_EVENT_MASK BT_OP(BT_OGF_LE, 0x0001) +struct bt_hci_cp_le_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE BT_OP(BT_OGF_LE, 0x0002) +struct bt_hci_rp_le_read_buffer_size { + uint8_t status; + uint16_t le_max_len; + uint8_t le_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_FEATURES BT_OP(BT_OGF_LE, 0x0003) +struct bt_hci_rp_le_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_LE_SET_RANDOM_ADDRESS BT_OP(BT_OGF_LE, 0x0005) +struct bt_hci_cp_le_set_random_address { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_ADV_IND 0x00 +#define BT_HCI_ADV_DIRECT_IND 0x01 +#define BT_HCI_ADV_SCAN_IND 0x02 +#define BT_HCI_ADV_NONCONN_IND 0x03 +#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 +#define BT_HCI_ADV_SCAN_RSP 0x04 + +#define BT_LE_ADV_INTERVAL_MIN 0x0020 +#define BT_LE_ADV_INTERVAL_MAX 0x4000 +#define BT_LE_ADV_INTERVAL_DEFAULT 0x0800 + +#define BT_LE_ADV_CHAN_MAP_CHAN_37 0x01 +#define BT_LE_ADV_CHAN_MAP_CHAN_38 0x02 +#define BT_LE_ADV_CHAN_MAP_CHAN_39 0x04 +#define BT_LE_ADV_CHAN_MAP_ALL 0x07 + +#define BT_LE_ADV_FP_NO_FILTER 0x00 +#define BT_LE_ADV_FP_FILTER_SCAN_REQ 0x01 +#define BT_LE_ADV_FP_FILTER_CONN_IND 0x02 +#define BT_LE_ADV_FP_FILTER_BOTH 0x03 + +#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) +struct bt_hci_cp_le_set_adv_param { + uint16_t min_interval; + uint16_t max_interval; + uint8_t type; + uint8_t own_addr_type; + bt_addr_le_t direct_addr; + uint8_t channel_map; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER BT_OP(BT_OGF_LE, 0x0007) +struct bt_hci_rp_le_read_chan_tx_power { + uint8_t status; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_DATA BT_OP(BT_OGF_LE, 0x0008) +struct bt_hci_cp_le_set_adv_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0009) +struct bt_hci_cp_le_set_scan_rsp_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_LE_ADV_DISABLE 0x00 +#define BT_HCI_LE_ADV_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADV_ENABLE BT_OP(BT_OGF_LE, 0x000a) +struct bt_hci_cp_le_set_adv_enable { + uint8_t enable; +} __packed; + +/* Scan types */ +#define BT_HCI_OP_LE_SET_SCAN_PARAM BT_OP(BT_OGF_LE, 0x000b) +#define BT_HCI_LE_SCAN_PASSIVE 0x00 +#define BT_HCI_LE_SCAN_ACTIVE 0x01 + +#define BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER 0x00 +#define BT_HCI_LE_SCAN_FP_BASIC_FILTER 0x01 +#define BT_HCI_LE_SCAN_FP_EXT_NO_FILTER 0x02 +#define BT_HCI_LE_SCAN_FP_EXT_FILTER 0x03 + +struct bt_hci_cp_le_set_scan_param { + uint8_t scan_type; + uint16_t interval; + uint16_t window; + uint8_t addr_type; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x000c) + +#define BT_HCI_LE_SCAN_DISABLE 0x00 +#define BT_HCI_LE_SCAN_ENABLE 0x01 + +#define BT_HCI_LE_SCAN_FILTER_DUP_DISABLE 0x00 +#define BT_HCI_LE_SCAN_FILTER_DUP_ENABLE 0x01 + +struct bt_hci_cp_le_set_scan_enable { + uint8_t enable; + uint8_t filter_dup; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) + +#define BT_HCI_LE_CREATE_CONN_FP_NO_FILTER 0x00 +#define BT_HCI_LE_CREATE_CONN_FP_FILTER 0x01 + +struct bt_hci_cp_le_create_conn { + uint16_t scan_interval; + uint16_t scan_window; + uint8_t filter_policy; + bt_addr_le_t peer_addr; + uint8_t own_addr_type; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN_CANCEL BT_OP(BT_OGF_LE, 0x000e) + +#define BT_HCI_OP_LE_READ_FAL_SIZE BT_OP(BT_OGF_LE, 0x000f) +struct bt_hci_rp_le_read_fal_size { + uint8_t status; + uint8_t fal_size; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_FAL BT_OP(BT_OGF_LE, 0x0010) + +#define BT_HCI_OP_LE_ADD_DEV_TO_FAL BT_OP(BT_OGF_LE, 0x0011) +struct bt_hci_cp_le_add_dev_to_fal { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_FAL BT_OP(BT_OGF_LE, 0x0012) +struct bt_hci_cp_le_rem_dev_from_fal { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_CONN_UPDATE BT_OP(BT_OGF_LE, 0x0013) +struct hci_cp_le_conn_update { + uint16_t handle; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF BT_OP(BT_OGF_LE, 0x0014) +struct bt_hci_cp_le_set_host_chan_classif { + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_CHAN_MAP BT_OP(BT_OGF_LE, 0x0015) +struct bt_hci_cp_le_read_chan_map { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_chan_map { + uint8_t status; + uint16_t handle; + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0016) +struct bt_hci_cp_le_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ENCRYPT BT_OP(BT_OGF_LE, 0x0017) +struct bt_hci_cp_le_encrypt { + uint8_t key[16]; + uint8_t plaintext[16]; +} __packed; +struct bt_hci_rp_le_encrypt { + uint8_t status; + uint8_t enc_data[16]; +} __packed; + +#define BT_HCI_OP_LE_RAND BT_OP(BT_OGF_LE, 0x0018) +struct bt_hci_rp_le_rand { + uint8_t status; + uint8_t rand[8]; +} __packed; + +#define BT_HCI_OP_LE_START_ENCRYPTION BT_OP(BT_OGF_LE, 0x0019) +struct bt_hci_cp_le_start_encryption { + uint16_t handle; + uint64_t rand; + uint16_t ediv; + uint8_t ltk[16]; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_REPLY BT_OP(BT_OGF_LE, 0x001a) +struct bt_hci_cp_le_ltk_req_reply { + uint16_t handle; + uint8_t ltk[16]; +} __packed; +struct bt_hci_rp_le_ltk_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x001b) +struct bt_hci_cp_le_ltk_req_neg_reply { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_ltk_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_SUPP_STATES BT_OP(BT_OGF_LE, 0x001c) +struct bt_hci_rp_le_read_supp_states { + uint8_t status; + uint8_t le_states[8]; +} __packed; + +#define BT_HCI_OP_LE_RX_TEST BT_OP(BT_OGF_LE, 0x001d) +struct bt_hci_cp_le_rx_test { + uint8_t rx_ch; +} __packed; + +#define BT_HCI_TEST_PKT_PAYLOAD_PRBS9 0x00 +#define BT_HCI_TEST_PKT_PAYLOAD_11110000 0x01 +#define BT_HCI_TEST_PKT_PAYLOAD_10101010 0x02 +#define BT_HCI_TEST_PKT_PAYLOAD_PRBS15 0x03 +#define BT_HCI_TEST_PKT_PAYLOAD_11111111 0x04 +#define BT_HCI_TEST_PKT_PAYLOAD_00000000 0x05 +#define BT_HCI_TEST_PKT_PAYLOAD_00001111 0x06 +#define BT_HCI_TEST_PKT_PAYLOAD_01010101 0x07 + +#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e) +struct bt_hci_cp_le_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; +} __packed; + +#define BT_HCI_OP_LE_TEST_END BT_OP(BT_OGF_LE, 0x001f) +struct bt_hci_rp_le_test_end { + uint8_t status; + uint16_t rx_pkt_count; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY BT_OP(BT_OGF_LE, 0x0020) +struct bt_hci_cp_le_conn_param_req_reply { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; +struct bt_hci_rp_le_conn_param_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x0021) +struct bt_hci_cp_le_conn_param_req_neg_reply { + uint16_t handle; + uint8_t reason; +} __packed; +struct bt_hci_rp_le_conn_param_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_DATA_LEN BT_OP(BT_OGF_LE, 0x0022) +struct bt_hci_cp_le_set_data_len { + uint16_t handle; + uint16_t tx_octets; + uint16_t tx_time; +} __packed; +struct bt_hci_rp_le_set_data_len { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0023) +struct bt_hci_rp_le_read_default_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0024) +struct bt_hci_cp_le_write_default_data_len { + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_P256_PUBLIC_KEY BT_OP(BT_OGF_LE, 0x0025) + +#define BT_HCI_OP_LE_GENERATE_DHKEY BT_OP(BT_OGF_LE, 0x0026) +struct bt_hci_cp_le_generate_dhkey { + uint8_t key[64]; +} __packed; + + +#define BT_HCI_OP_LE_GENERATE_DHKEY_V2 BT_OP(BT_OGF_LE, 0x005e) + +#define BT_HCI_LE_KEY_TYPE_GENERATED 0x00 +#define BT_HCI_LE_KEY_TYPE_DEBUG 0x01 + +struct bt_hci_cp_le_generate_dhkey_v2 { + uint8_t key[64]; + uint8_t key_type; +} __packed; + + +#define BT_HCI_OP_LE_ADD_DEV_TO_RL BT_OP(BT_OGF_LE, 0x0027) +struct bt_hci_cp_le_add_dev_to_rl { + bt_addr_le_t peer_id_addr; + uint8_t peer_irk[16]; + uint8_t local_irk[16]; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_RL BT_OP(BT_OGF_LE, 0x0028) +struct bt_hci_cp_le_rem_dev_from_rl { + bt_addr_le_t peer_id_addr; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_RL BT_OP(BT_OGF_LE, 0x0029) + +#define BT_HCI_OP_LE_READ_RL_SIZE BT_OP(BT_OGF_LE, 0x002a) +struct bt_hci_rp_le_read_rl_size { + uint8_t status; + uint8_t rl_size; +} __packed; + +#define BT_HCI_OP_LE_READ_PEER_RPA BT_OP(BT_OGF_LE, 0x002b) +struct bt_hci_cp_le_read_peer_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_peer_rpa { + uint8_t status; + bt_addr_t peer_rpa; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_RPA BT_OP(BT_OGF_LE, 0x002c) +struct bt_hci_cp_le_read_local_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_local_rpa { + uint8_t status; + bt_addr_t local_rpa; +} __packed; + +#define BT_HCI_ADDR_RES_DISABLE 0x00 +#define BT_HCI_ADDR_RES_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADDR_RES_ENABLE BT_OP(BT_OGF_LE, 0x002d) +struct bt_hci_cp_le_set_addr_res_enable { + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_SET_RPA_TIMEOUT BT_OP(BT_OGF_LE, 0x002e) +struct bt_hci_cp_le_set_rpa_timeout { + uint16_t rpa_timeout; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_DATA_LEN BT_OP(BT_OGF_LE, 0x002f) +struct bt_hci_rp_le_read_max_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_LE_PHY_1M 0x01 +#define BT_HCI_LE_PHY_2M 0x02 +#define BT_HCI_LE_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_READ_PHY BT_OP(BT_OGF_LE, 0x0030) +struct bt_hci_cp_le_read_phy { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_phy { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_LE_PHY_TX_ANY BIT(0) +#define BT_HCI_LE_PHY_RX_ANY BIT(1) + +#define BT_HCI_LE_PHY_PREFER_1M BIT(0) +#define BT_HCI_LE_PHY_PREFER_2M BIT(1) +#define BT_HCI_LE_PHY_PREFER_CODED BIT(2) + +#define BT_HCI_OP_LE_SET_DEFAULT_PHY BT_OP(BT_OGF_LE, 0x0031) +struct bt_hci_cp_le_set_default_phy { + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; +} __packed; + +#define BT_HCI_LE_PHY_CODED_ANY 0x00 +#define BT_HCI_LE_PHY_CODED_S2 0x01 +#define BT_HCI_LE_PHY_CODED_S8 0x02 + +#define BT_HCI_OP_LE_SET_PHY BT_OP(BT_OGF_LE, 0x0032) +struct bt_hci_cp_le_set_phy { + uint16_t handle; + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; + uint16_t phy_opts; +} __packed; + +#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00 +#define BT_HCI_LE_MOD_INDEX_STABLE 0x01 + +#define BT_HCI_LE_RX_PHY_1M 0x01 +#define BT_HCI_LE_RX_PHY_2M 0x02 +#define BT_HCI_LE_RX_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033) +struct bt_hci_cp_le_enh_rx_test { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; +} __packed; + +#define BT_HCI_LE_TX_PHY_1M 0x01 +#define BT_HCI_LE_TX_PHY_2M 0x02 +#define BT_HCI_LE_TX_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_PHY_CODED_S2 0x04 + +#define BT_HCI_OP_LE_ENH_TX_TEST BT_OP(BT_OGF_LE, 0x0034) +struct bt_hci_cp_le_enh_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR BT_OP(BT_OGF_LE, 0x0035) +struct bt_hci_cp_le_set_adv_set_random_addr { + uint8_t handle; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_LE_ADV_PROP_CONN BIT(0) +#define BT_HCI_LE_ADV_PROP_SCAN BIT(1) +#define BT_HCI_LE_ADV_PROP_DIRECT BIT(2) +#define BT_HCI_LE_ADV_PROP_HI_DC_CONN BIT(3) +#define BT_HCI_LE_ADV_PROP_LEGACY BIT(4) +#define BT_HCI_LE_ADV_PROP_ANON BIT(5) +#define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) + +#define BT_HCI_LE_PRIM_ADV_INTERVAL_MIN 0x000020 +#define BT_HCI_LE_PRIM_ADV_INTERVAL_MAX 0xFFFFFF + +#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 +#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 + +#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F + +#define BT_HCI_LE_ADV_HANDLE_MAX 0xEF + +#define BT_HCI_LE_EXT_ADV_SID_INVALID 0xFF + +#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) +struct bt_hci_cp_le_set_ext_adv_param { + uint8_t handle; + uint16_t props; + uint8_t prim_min_interval[3]; + uint8_t prim_max_interval[3]; + uint8_t prim_channel_map; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t filter_policy; + int8_t tx_power; + uint8_t prim_adv_phy; + uint8_t sec_adv_max_skip; + uint8_t sec_adv_phy; + uint8_t sid; + uint8_t scan_req_notify_enable; +} __packed; +struct bt_hci_rp_le_set_ext_adv_param { + uint8_t status; + int8_t tx_power; +} __packed; + +#define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA 0x03 +#define BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA 0x04 + +#define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 +#define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 + +#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 + +#define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) +struct bt_hci_cp_le_set_ext_adv_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0038) +struct bt_hci_cp_le_set_ext_scan_rsp_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0039) +struct bt_hci_ext_adv_set { + uint8_t handle; + uint16_t duration; + uint8_t max_ext_adv_evts; +} __packed; + +struct bt_hci_cp_le_set_ext_adv_enable { + uint8_t enable; + uint8_t set_num; + struct bt_hci_ext_adv_set s[0]; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN BT_OP(BT_OGF_LE, 0x003a) +struct bt_hci_rp_le_read_max_adv_data_len { + uint8_t status; + uint16_t max_adv_data_len; +} __packed; + +#define BT_HCI_OP_LE_READ_NUM_ADV_SETS BT_OP(BT_OGF_LE, 0x003b) +struct bt_hci_rp_le_read_num_adv_sets { + uint8_t status; + uint8_t num_sets; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ADV_SET BT_OP(BT_OGF_LE, 0x003c) +struct bt_hci_cp_le_remove_adv_set { + uint8_t handle; +} __packed; + +#define BT_HCI_OP_CLEAR_ADV_SETS BT_OP(BT_OGF_LE, 0x003d) + +#define BT_HCI_LE_PER_ADV_INTERVAL_MIN 0x0006 +#define BT_HCI_LE_PER_ADV_INTERVAL_MAX 0xFFFF + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM BT_OP(BT_OGF_LE, 0x003e) +struct bt_hci_cp_le_set_per_adv_param { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; +} __packed; + +#define BT_HCI_LE_PER_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_PER_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_PER_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_PER_ADV_OP_COMPLETE_DATA 0x03 + +#define BT_HCI_LE_PER_ADV_FRAG_MAX_LEN 252 + +#define BT_HCI_OP_LE_SET_PER_ADV_DATA BT_OP(BT_OGF_LE, 0x003f) +struct bt_hci_cp_le_set_per_adv_data { + uint8_t handle; + uint8_t op; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE BIT(0) +#define BT_HCI_LE_SET_PER_ADV_ENABLE_ADI BIT(1) + +#define BT_HCI_OP_LE_SET_PER_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0040) +struct bt_hci_cp_le_set_per_adv_enable { + uint8_t enable; + uint8_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_PARAM BT_OP(BT_OGF_LE, 0x0041) +struct bt_hci_ext_scan_phy { + uint8_t type; + uint16_t interval; + uint16_t window; +} __packed; + +#define BT_HCI_LE_EXT_SCAN_PHY_1M BIT(0) +#define BT_HCI_LE_EXT_SCAN_PHY_2M BIT(1) +#define BT_HCI_LE_EXT_SCAN_PHY_CODED BIT(2) + +struct bt_hci_cp_le_set_ext_scan_param { + uint8_t own_addr_type; + uint8_t filter_policy; + uint8_t phys; + struct bt_hci_ext_scan_phy p[0]; +} __packed; + +/* Extends BT_HCI_LE_SCAN_FILTER_DUP */ +#define BT_HCI_LE_EXT_SCAN_FILTER_DUP_ENABLE_RESET 0x02 + +#define BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x0042) +struct bt_hci_cp_le_set_ext_scan_enable { + uint8_t enable; + uint8_t filter_dup; + uint16_t duration; + uint16_t period; +} __packed; + +#define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) +#define BT_HCI_OP_LE_EXT_CREATE_CONN_V2 BT_OP(BT_OGF_LE, 0x0085) +struct bt_hci_ext_conn_phy { + uint16_t scan_interval; + uint16_t scan_window; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +struct bt_hci_cp_le_ext_create_conn { + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +struct bt_hci_cp_le_ext_create_conn_v2 { + uint8_t adv_handle; + uint8_t subevent; + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_SUBEVENT_DATA BT_OP(BT_OGF_LE, 0x0082) +struct bt_hci_cp_le_set_pawr_subevent_data_element { + uint8_t subevent; + uint8_t response_slot_start; + uint8_t response_slot_count; + uint8_t subevent_data_length; + uint8_t subevent_data[0]; +} __packed; + +struct bt_hci_cp_le_set_pawr_subevent_data { + uint8_t adv_handle; + uint8_t num_subevents; + struct bt_hci_cp_le_set_pawr_subevent_data_element subevents[0]; +} __packed; + + +#define BT_HCI_OP_LE_SET_PER_ADV_RESPONSE_DATA BT_OP(BT_OGF_LE, 0x0083) +struct bt_hci_cp_le_set_pawr_response_data { + uint16_t sync_handle; + uint16_t request_event; + uint8_t request_subevent; + uint8_t response_subevent; + uint8_t response_slot; + uint8_t response_data_length; + uint8_t response_data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_SYNC_SUBEVENT BT_OP(BT_OGF_LE, 0x0084) +struct bt_hci_cp_le_set_pawr_sync_subevent { + uint16_t sync_handle; + uint16_t periodic_adv_properties; + uint8_t num_subevents; + uint8_t subevents[0]; +} __packed; + + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM_V2 BT_OP(BT_OGF_LE, 0x0086) +struct bt_hci_cp_le_set_per_adv_param_v2 { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; + uint8_t num_response_slots; +} __packed; + + +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST BIT(0) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED BIT(1) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE BIT(2) + +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING 0 +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA BIT(0) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_1US BIT(1) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_2US BIT(2) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_CTE BIT(3) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE BIT(4) +/* Constants to check correctness of CTE type */ +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS 5 +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_INVALID_VALUE \ + (~BIT_MASK(BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS)) + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC BT_OP(BT_OGF_LE, 0x0044) +struct bt_hci_cp_le_per_adv_create_sync { + uint8_t options; + uint8_t sid; + bt_addr_le_t addr; + uint16_t skip; + uint16_t sync_timeout; + uint8_t cte_type; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL BT_OP(BT_OGF_LE, 0x0045) + +#define BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x0046) +struct bt_hci_cp_le_per_adv_terminate_sync { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0047) +struct bt_hci_cp_le_add_dev_to_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0048) +struct bt_hci_cp_le_rem_dev_from_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0049) + +#define BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE BT_OP(BT_OGF_LE, 0x004a) +struct bt_hci_rp_le_read_per_adv_list_size { + uint8_t status; + uint8_t list_size; +} __packed; + +#define BT_HCI_OP_LE_READ_TX_POWER BT_OP(BT_OGF_LE, 0x004b) +struct bt_hci_rp_le_read_tx_power { + uint8_t status; + int8_t min_tx_power; + int8_t max_tx_power; +} __packed; + +#define BT_HCI_OP_LE_READ_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004c) +struct bt_hci_rp_le_read_rf_path_comp { + uint8_t status; + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_OP_LE_WRITE_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004d) +struct bt_hci_cp_le_write_rf_path_comp { + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_LE_PRIVACY_MODE_NETWORK 0x00 +#define BT_HCI_LE_PRIVACY_MODE_DEVICE 0x01 + +#define BT_HCI_OP_LE_SET_PRIVACY_MODE BT_OP(BT_OGF_LE, 0x004e) +struct bt_hci_cp_le_set_privacy_mode { + bt_addr_le_t id_addr; + uint8_t mode; +} __packed; + +#define BT_HCI_LE_TEST_CTE_DISABLED 0x00 +#define BT_HCI_LE_TEST_CTE_TYPE_ANY 0x00 +#define BT_HCI_LE_TEST_SLOT_DURATION_ANY 0x00 +#define BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY 0x00 + +#define BT_HCI_OP_LE_RX_TEST_V3 BT_OP(BT_OGF_LE, 0x004f) +struct bt_hci_cp_le_rx_test_v3 { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; + uint8_t expected_cte_len; + uint8_t expected_cte_type; + uint8_t slot_durations; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST_V3 BT_OP(BT_OGF_LE, 0x0050) + +struct bt_hci_cp_le_tx_test_v3 { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; + uint8_t cte_len; + uint8_t cte_type; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +/* Min and max Constant Tone Extension length in 8us units */ +#define BT_HCI_LE_CTE_LEN_MIN 0x2 +#define BT_HCI_LE_CTE_LEN_MAX 0x14 + +#define BT_HCI_LE_AOA_CTE 0x0 +#define BT_HCI_LE_AOD_CTE_1US 0x1 +#define BT_HCI_LE_AOD_CTE_2US 0x2 +#define BT_HCI_LE_NO_CTE 0xFF + +#define BT_HCI_LE_CTE_COUNT_MIN 0x1 +#define BT_HCI_LE_CTE_COUNT_MAX 0x10 + +#define BT_HCI_OP_LE_SET_CL_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0051) +struct bt_hci_cp_le_set_cl_cte_tx_params { + uint8_t handle; + uint8_t cte_len; + uint8_t cte_type; + uint8_t cte_count; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_CL_CTE_TX_ENABLE BT_OP(BT_OGF_LE, 0x0052) +struct bt_hci_cp_le_set_cl_cte_tx_enable { + uint8_t handle; + uint8_t cte_enable; +} __packed; + +#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US 0x1 +#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US 0x2 + +#define BT_HCI_LE_SAMPLE_CTE_ALL 0x0 +#define BT_HCI_LE_SAMPLE_CTE_COUNT_MIN 0x1 +#define BT_HCI_LE_SAMPLE_CTE_COUNT_MAX 0x10 + +#define BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE BT_OP(BT_OGF_LE, 0x0053) +struct bt_hci_cp_le_set_cl_cte_sampling_enable { + uint16_t sync_handle; + uint8_t sampling_enable; + uint8_t slot_durations; + uint8_t max_sampled_cte; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_cl_cte_sampling_enable { + uint8_t status; + uint16_t sync_handle; +} __packed; + +#define BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS BT_OP(BT_OGF_LE, 0x0054) +struct bt_hci_cp_le_set_conn_cte_rx_params { + uint16_t handle; + uint8_t sampling_enable; + uint8_t slot_durations; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_conn_cte_rx_params { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_LE_AOA_CTE_RSP BIT(0) +#define BT_HCI_LE_AOD_CTE_RSP_1US BIT(1) +#define BT_HCI_LE_AOD_CTE_RSP_2US BIT(2) + +#define BT_HCI_LE_SWITCH_PATTERN_LEN_MIN 0x2 +#define BT_HCI_LE_SWITCH_PATTERN_LEN_MAX 0x4B + +#define BT_HCI_OP_LE_SET_CONN_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0055) +struct bt_hci_cp_le_set_conn_cte_tx_params { + uint16_t handle; + uint8_t cte_types; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_conn_cte_tx_params { + uint8_t status; + uint16_t handle; +} __packed; + +/* Interval between consecutive CTE request procedure starts in number of connection events. */ +#define BT_HCI_REQUEST_CTE_ONCE 0x0 +#define BT_HCI_REQUEST_CTE_INTERVAL_MIN 0x1 +#define BT_HCI_REQUEST_CTE_INTERVAL_MAX 0xFFFF + +#define BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE BT_OP(BT_OGF_LE, 0x0056) +struct bt_hci_cp_le_conn_cte_req_enable { + uint16_t handle; + uint8_t enable; + uint16_t cte_request_interval; + uint8_t requested_cte_length; + uint8_t requested_cte_type; +} __packed; + +struct bt_hci_rp_le_conn_cte_req_enable { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_CTE_RSP_ENABLE BT_OP(BT_OGF_LE, 0x0057) +struct bt_hci_cp_le_conn_cte_rsp_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +struct bt_hci_rp_le_conn_cte_rsp_enable { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_LE_1US_AOD_TX BIT(0) +#define BT_HCI_LE_1US_AOD_RX BIT(1) +#define BT_HCI_LE_1US_AOA_RX BIT(2) + +#define BT_HCI_LE_NUM_ANT_MIN 0x1 +#define BT_HCI_LE_NUM_ANT_MAX 0x4B + +#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MIN 0x2 +#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MAX 0x4B + +#define BT_HCI_LE_MAX_CTE_LEN_MIN 0x2 +#define BT_HCI_LE_MAX_CTE_LEN_MAX 0x14 + +#define BT_HCI_OP_LE_READ_ANT_INFO BT_OP(BT_OGF_LE, 0x0058) +struct bt_hci_rp_le_read_ant_info { + uint8_t status; + uint8_t switch_sample_rates; + uint8_t num_ant; + uint8_t max_switch_pattern_len; + uint8_t max_cte_len; +}; + +#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_ENABLE BIT(0) +#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_FILTER_DUPLICATE BIT(1) + +#define BT_HCI_OP_LE_SET_PER_ADV_RECV_ENABLE BT_OP(BT_OGF_LE, 0x0059) +struct bt_hci_cp_le_set_per_adv_recv_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_SYNC_TRANSFER BT_OP(BT_OGF_LE, 0x005a) +struct bt_hci_cp_le_per_adv_sync_transfer { + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; +} __packed; + +struct bt_hci_rp_le_per_adv_sync_transfer { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_SET_INFO_TRANSFER BT_OP(BT_OGF_LE, 0x005b) +struct bt_hci_cp_le_per_adv_set_info_transfer { + uint16_t conn_handle; + uint16_t service_data; + uint8_t adv_handle; +} __packed; + +struct bt_hci_rp_le_per_adv_set_info_transfer { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_LE_PAST_MODE_NO_SYNC 0x00 +#define BT_HCI_LE_PAST_MODE_NO_REPORTS 0x01 +#define BT_HCI_LE_PAST_MODE_SYNC 0x02 +#define BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES 0x03 + +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOA BIT(0) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_1US BIT(1) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_2US BIT(2) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_CTE BIT(3) +#define BT_HCI_LE_PAST_CTE_TYPE_ONLY_CTE BIT(4) + +#define BT_HCI_OP_LE_PAST_PARAM BT_OP(BT_OGF_LE, 0x005c) +struct bt_hci_cp_le_past_param { + uint16_t conn_handle; + uint8_t mode; + uint16_t skip; + uint16_t timeout; + uint8_t cte_type; +} __packed; + +struct bt_hci_rp_le_past_param { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_OP_LE_DEFAULT_PAST_PARAM BT_OP(BT_OGF_LE, 0x005d) +struct bt_hci_cp_le_default_past_param { + uint8_t mode; + uint16_t skip; + uint16_t timeout; + uint8_t cte_type; +} __packed; + +struct bt_hci_rp_le_default_past_param { + uint8_t status; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE_V2 BT_OP(BT_OGF_LE, 0x0060) +struct bt_hci_rp_le_read_buffer_size_v2 { + uint8_t status; + uint16_t acl_max_len; + uint8_t acl_max_num; + uint16_t iso_max_len; + uint8_t iso_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_ISO_TX_SYNC BT_OP(BT_OGF_LE, 0x0061) +struct bt_hci_cp_le_read_iso_tx_sync { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_iso_tx_sync { + uint8_t status; + uint16_t handle; + uint16_t seq; + uint32_t timestamp; + uint8_t offset[3]; +} __packed; + +#define BT_HCI_ISO_CIG_ID_MAX 0xFE +#define BT_HCI_ISO_CIS_COUNT_MAX 0x1F +#define BT_HCI_ISO_SDU_INTERVAL_MIN 0x0000FF +#define BT_HCI_ISO_SDU_INTERVAL_MAX 0x0FFFFF +#define BT_HCI_ISO_WORST_CASE_SCA_VALID_MASK 0x07 +#define BT_HCI_ISO_PACKING_VALID_MASK 0x01 +#define BT_HCI_ISO_FRAMING_VALID_MASK 0x01 +#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MIN 0x0005 +#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MAX 0x0FA0 +#define BT_HCI_ISO_CIS_ID_VALID_MAX 0xEF +#define BT_HCI_ISO_MAX_SDU_VALID_MASK 0x0FFF +#define BT_HCI_ISO_PHY_VALID_MASK 0x07 +#define BT_HCI_ISO_INTERVAL_MIN 0x0004 +#define BT_HCI_ISO_INTERVAL_MAX 0x0C80 + +#define BT_HCI_OP_LE_SET_CIG_PARAMS BT_OP(BT_OGF_LE, 0x0062) +struct bt_hci_cis_params { + uint8_t cis_id; + uint16_t c_sdu; + uint16_t p_sdu; + uint8_t c_phy; + uint8_t p_phy; + uint8_t c_rtn; + uint8_t p_rtn; +} __packed; + +struct bt_hci_cp_le_set_cig_params { + uint8_t cig_id; + uint8_t c_interval[3]; + uint8_t p_interval[3]; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint16_t c_latency; + uint16_t p_latency; + uint8_t num_cis; + struct bt_hci_cis_params cis[0]; +} __packed; + +struct bt_hci_rp_le_set_cig_params { + uint8_t status; + uint8_t cig_id; + uint8_t num_handles; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_CIG_PARAMS_TEST BT_OP(BT_OGF_LE, 0x0063) +struct bt_hci_cis_params_test { + uint8_t cis_id; + uint8_t nse; + uint16_t c_sdu; + uint16_t p_sdu; + uint16_t c_pdu; + uint16_t p_pdu; + uint8_t c_phy; + uint8_t p_phy; + uint8_t c_bn; + uint8_t p_bn; +} __packed; + +struct bt_hci_cp_le_set_cig_params_test { + uint8_t cig_id; + uint8_t c_interval[3]; + uint8_t p_interval[3]; + uint8_t c_ft; + uint8_t p_ft; + uint16_t iso_interval; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint8_t num_cis; + struct bt_hci_cis_params_test cis[0]; +} __packed; + +struct bt_hci_rp_le_set_cig_params_test { + uint8_t status; + uint8_t cig_id; + uint8_t num_handles; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CIS BT_OP(BT_OGF_LE, 0x0064) +struct bt_hci_cis { + uint16_t cis_handle; + uint16_t acl_handle; +} __packed; + +struct bt_hci_cp_le_create_cis { + uint8_t num_cis; + struct bt_hci_cis cis[0]; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_CIG BT_OP(BT_OGF_LE, 0x0065) +struct bt_hci_cp_le_remove_cig { + uint8_t cig_id; +} __packed; + +struct bt_hci_rp_le_remove_cig { + uint8_t status; + uint8_t cig_id; +} __packed; + +#define BT_HCI_OP_LE_ACCEPT_CIS BT_OP(BT_OGF_LE, 0x0066) +struct bt_hci_cp_le_accept_cis { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_REJECT_CIS BT_OP(BT_OGF_LE, 0x0067) +struct bt_hci_cp_le_reject_cis { + uint16_t handle; + uint8_t reason; +} __packed; + +struct bt_hci_rp_le_reject_cis { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CREATE_BIG BT_OP(BT_OGF_LE, 0x0068) +struct bt_hci_cp_le_create_big { + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint8_t sdu_interval[3]; + uint16_t max_sdu; + uint16_t max_latency; + uint8_t rtn; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t encryption; + uint8_t bcode[16]; +} __packed; + +#define BT_HCI_OP_LE_CREATE_BIG_TEST BT_OP(BT_OGF_LE, 0x0069) +struct bt_hci_cp_le_create_big_test { + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint8_t sdu_interval[3]; + uint16_t iso_interval; + uint8_t nse; + uint16_t max_sdu; + uint16_t max_pdu; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t bn; + uint8_t irc; + uint8_t pto; + uint8_t encryption; + uint8_t bcode[16]; +} __packed; + +#define BT_HCI_OP_LE_TERMINATE_BIG BT_OP(BT_OGF_LE, 0x006a) +struct bt_hci_cp_le_terminate_big { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LE_BIG_CREATE_SYNC BT_OP(BT_OGF_LE, 0x006b) +struct bt_hci_cp_le_big_create_sync { + uint8_t big_handle; + uint16_t sync_handle; + uint8_t encryption; + uint8_t bcode[16]; + uint8_t mse; + uint16_t sync_timeout; + uint8_t num_bis; + uint8_t bis[0]; +} __packed; + +#define BT_HCI_OP_LE_BIG_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x006c) +struct bt_hci_cp_le_big_terminate_sync { + uint8_t big_handle; +} __packed; + +struct bt_hci_rp_le_big_terminate_sync { + uint8_t status; + uint8_t big_handle; +} __packed; + +#define BT_HCI_OP_LE_REQ_PEER_SC BT_OP(BT_OGF_LE, 0x006d) +struct bt_hci_cp_le_req_peer_sca { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SETUP_ISO_PATH BT_OP(BT_OGF_LE, 0x006e) +struct bt_hci_cp_le_setup_iso_path { + uint16_t handle; + uint8_t path_dir; + uint8_t path_id; + struct bt_hci_cp_codec_id codec_id; + uint8_t controller_delay[3]; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __packed; + +struct bt_hci_rp_le_setup_iso_path { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ISO_PATH BT_OP(BT_OGF_LE, 0x006f) +struct bt_hci_cp_le_remove_iso_path { + uint16_t handle; + uint8_t path_dir; +} __packed; + +struct bt_hci_rp_le_remove_iso_path { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_ISO_TEST_ZERO_SIZE_SDU 0 +#define BT_HCI_ISO_TEST_VARIABLE_SIZE_SDU 1 +#define BT_HCI_ISO_TEST_MAX_SIZE_SDU 2 + +#define BT_HCI_OP_LE_ISO_TRANSMIT_TEST BT_OP(BT_OGF_LE, 0x0070) +struct bt_hci_cp_le_iso_transmit_test { + uint16_t handle; + uint8_t payload_type; +} __packed; + +struct bt_hci_rp_le_iso_transmit_test { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ISO_RECEIVE_TEST BT_OP(BT_OGF_LE, 0x0071) +struct bt_hci_cp_le_iso_receive_test { + uint16_t handle; + uint8_t payload_type; +} __packed; + +struct bt_hci_rp_le_iso_receive_test { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ISO_READ_TEST_COUNTERS BT_OP(BT_OGF_LE, 0x0072) +struct bt_hci_cp_le_read_test_counters { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_test_counters { + uint8_t status; + uint16_t handle; + uint32_t received_cnt; + uint32_t missed_cnt; + uint32_t failed_cnt; +} __packed; + +#define BT_HCI_OP_LE_ISO_TEST_END BT_OP(BT_OGF_LE, 0x0073) +struct bt_hci_cp_le_iso_test_end { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_iso_test_end { + uint8_t status; + uint16_t handle; + uint32_t received_cnt; + uint32_t missed_cnt; + uint32_t failed_cnt; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_FEATURE BT_OP(BT_OGF_LE, 0x0074) +struct bt_hci_cp_le_set_host_feature { + uint8_t bit_number; + uint8_t bit_value; +} __packed; + +struct bt_hci_rp_le_set_host_feature { + uint8_t status; +} __packed; + +#define BT_HCI_OP_LE_READ_ISO_LINK_QUALITY BT_OP(BT_OGF_LE, 0x0075) +struct bt_hci_cp_le_read_iso_link_quality { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_iso_link_quality { + uint8_t status; + uint16_t handle; + uint32_t tx_unacked_packets; + uint32_t tx_flushed_packets; + uint32_t tx_last_subevent_packets; + uint32_t retransmitted_packets; + uint32_t crc_error_packets; + uint32_t rx_unreceived_packets; + uint32_t duplicate_packets; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST_V4 BT_OP(BT_OGF_LE, 0x007B) + +struct bt_hci_cp_le_tx_test_v4 { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; + uint8_t cte_len; + uint8_t cte_type; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_TX_TEST_POWER_MIN -0x7F +#define BT_HCI_TX_TEST_POWER_MAX 0x14 + +#define BT_HCI_TX_TEST_POWER_MIN_SET 0x7E +#define BT_HCI_TX_TEST_POWER_MAX_SET 0x7F + +/* Helper structure for Tx power parameter in the HCI Tx Test v4 command. + * Previous parameter of this command is variable size so having separated structure + * for this parameter helps in command parameters unpacking. + */ +struct bt_hci_cp_le_tx_test_v4_tx_power { + int8_t tx_power; +} __packed; + +/* Event definitions */ + +#define BT_HCI_EVT_UNKNOWN 0x00 +#define BT_HCI_EVT_VENDOR 0xff + +#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 +struct bt_hci_evt_inquiry_complete { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CONN_COMPLETE 0x03 +struct bt_hci_evt_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t encr_enabled; +} __packed; + +#define BT_HCI_EVT_CONN_REQUEST 0x04 +struct bt_hci_evt_conn_request { + bt_addr_t bdaddr; + uint8_t dev_class[3]; + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_DISCONN_COMPLETE 0x05 +struct bt_hci_evt_disconn_complete { + uint8_t status; + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_AUTH_COMPLETE 0x06 +struct bt_hci_evt_auth_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +struct bt_hci_evt_remote_name_req_complete { + uint8_t status; + bt_addr_t bdaddr; + uint8_t name[248]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 +struct bt_hci_evt_encrypt_change { + uint8_t status; + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_EVT_REMOTE_FEATURES 0x0b +struct bt_hci_evt_remote_features { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_REMOTE_VERSION_INFO 0x0c +struct bt_hci_evt_remote_version_info { + uint8_t status; + uint16_t handle; + uint8_t version; + uint16_t manufacturer; + uint16_t subversion; +} __packed; + +#define BT_HCI_EVT_CMD_COMPLETE 0x0e +struct bt_hci_evt_cmd_complete { + uint8_t ncmd; + uint16_t opcode; +} __packed; + +struct bt_hci_evt_cc_status { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CMD_STATUS 0x0f +struct bt_hci_evt_cmd_status { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; +} __packed; + +#define BT_HCI_EVT_HARDWARE_ERROR 0x10 +struct bt_hci_evt_hardware_error { + uint8_t hardware_code; +} __packed; + +#define BT_HCI_EVT_ROLE_CHANGE 0x12 +struct bt_hci_evt_role_change { + uint8_t status; + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 +struct bt_hci_evt_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_EVT_PIN_CODE_REQ 0x16 +struct bt_hci_evt_pin_code_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_LINK_KEY_REQ 0x17 +struct bt_hci_evt_link_key_req { + bt_addr_t bdaddr; +} __packed; + +/* Link Key types */ +#define BT_LK_COMBINATION 0x00 +#define BT_LK_LOCAL_UNIT 0x01 +#define BT_LK_REMOTE_UNIT 0x02 +#define BT_LK_DEBUG_COMBINATION 0x03 +#define BT_LK_UNAUTH_COMBINATION_P192 0x04 +#define BT_LK_AUTH_COMBINATION_P192 0x05 +#define BT_LK_CHANGED_COMBINATION 0x06 +#define BT_LK_UNAUTH_COMBINATION_P256 0x07 +#define BT_LK_AUTH_COMBINATION_P256 0x08 + +#define BT_HCI_EVT_LINK_KEY_NOTIFY 0x18 +struct bt_hci_evt_link_key_notify { + bt_addr_t bdaddr; + uint8_t link_key[16]; + uint8_t key_type; +} __packed; + +/* Overflow link types */ +#define BT_OVERFLOW_LINK_SYNCH 0x00 +#define BT_OVERFLOW_LINK_ACL 0x01 +#define BT_OVERFLOW_LINK_ISO 0x02 + +#define BT_HCI_EVT_DATA_BUF_OVERFLOW 0x1a +struct bt_hci_evt_data_buf_overflow { + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 +struct bt_hci_evt_inquiry_result_with_rssi { + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; +} __packed; + +#define BT_HCI_EVT_REMOTE_EXT_FEATURES 0x23 +struct bt_hci_evt_remote_ext_features { + uint8_t status; + uint16_t handle; + uint8_t page; + uint8_t max_page; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED_V2 0x24 +struct bt_hci_evt_le_per_adv_sync_established_v2 { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2 0x25 +struct bt_hci_evt_le_per_advertising_report_v2 { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint16_t periodic_event_counter; + uint8_t subevent; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PAST_RECEIVED_V2 0x26 +struct bt_hci_evt_le_past_received_v2 { + uint8_t status; + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; + uint8_t adv_sid; + bt_addr_le_t addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SUBEVENT_DATA_REQUEST 0x27 +struct bt_hci_evt_le_per_adv_subevent_data_request { + uint8_t adv_handle; + uint8_t subevent_start; + uint8_t subevent_data_count; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_RESPONSE_REPORT 0x28 + +struct bt_hci_evt_le_per_adv_response { + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t response_slot; + uint8_t data_status; + uint8_t data_length; + uint8_t data[0]; +} __packed; + +struct bt_hci_evt_le_per_adv_response_report { + uint8_t adv_handle; + uint8_t subevent; + uint8_t tx_status; + uint8_t num_responses; + struct bt_hci_evt_le_per_adv_response responses[0]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2 0x29 +struct bt_hci_evt_le_enh_conn_complete_v2 { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; + uint8_t adv_handle; + uint16_t sync_handle; +} __packed; + +#define BT_HCI_EVT_SYNC_CONN_COMPLETE 0x2c +struct bt_hci_evt_sync_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t tx_interval; + uint8_t retansmission_window; + uint16_t rx_pkt_length; + uint16_t tx_pkt_length; + uint8_t air_mode; +} __packed; + +#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f +struct bt_hci_evt_extended_inquiry_result { + uint8_t num_reports; + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t eir[240]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 +struct bt_hci_evt_encrypt_key_refresh_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_REQ 0x31 +struct bt_hci_evt_io_capa_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_RESP 0x32 +struct bt_hci_evt_io_capa_resp { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 +struct bt_hci_evt_user_confirm_req { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 +struct bt_hci_evt_user_passkey_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_SSP_COMPLETE 0x36 +struct bt_hci_evt_ssp_complete { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b +struct bt_hci_evt_user_passkey_notify { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_LE_META_EVENT 0x3e +struct bt_hci_evt_le_meta_event { + uint8_t subevent; +} __packed; + +#define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 +struct bt_hci_evt_auth_payload_timeout_exp { + uint16_t handle; +} __packed; + +#define BT_HCI_ROLE_CENTRAL 0x00 +#define BT_HCI_ROLE_PERIPHERAL 0x01 + +#define BT_HCI_EVT_LE_CONN_COMPLETE 0x01 +struct bt_hci_evt_le_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_LE_RSSI_NOT_AVAILABLE 0x7F + +#define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02 +struct bt_hci_evt_le_advertising_info { + uint8_t evt_type; + bt_addr_le_t addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 +struct bt_hci_evt_le_conn_update_complete { + uint8_t status; + uint16_t handle; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; +} __packed; + +#define BT_HCI_EVT_LE_REMOTE_FEAT_COMPLETE 0x04 +struct bt_hci_evt_le_remote_feat_complete { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_LTK_REQUEST 0x05 +struct bt_hci_evt_le_ltk_request { + uint16_t handle; + uint64_t rand; + uint16_t ediv; +} __packed; + +#define BT_HCI_EVT_LE_CONN_PARAM_REQ 0x06 +struct bt_hci_evt_le_conn_param_req { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; +} __packed; + +#define BT_HCI_EVT_LE_DATA_LEN_CHANGE 0x07 +struct bt_hci_evt_le_data_len_change { + uint16_t handle; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE 0x08 +struct bt_hci_evt_le_p256_public_key_complete { + uint8_t status; + uint8_t key[64]; +} __packed; + +#define BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE 0x09 +struct bt_hci_evt_le_generate_dhkey_complete { + uint8_t status; + uint8_t dhkey[32]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE 0x0a +struct bt_hci_evt_le_enh_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b +struct bt_hci_evt_le_direct_adv_info { + uint8_t evt_type; + bt_addr_le_t addr; + bt_addr_le_t dir_addr; + int8_t rssi; +} __packed; +struct bt_hci_evt_le_direct_adv_report { + uint8_t num_reports; + struct bt_hci_evt_le_direct_adv_info direct_adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE 0x0c +struct bt_hci_evt_le_phy_update_complete { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d + +#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) +#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) +#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) + +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_RX_FAILED 0xFF + +struct bt_hci_evt_le_ext_advertising_info { + uint16_t evt_type; + bt_addr_le_t addr; + uint8_t prim_phy; + uint8_t sec_phy; + uint8_t sid; + int8_t tx_power; + int8_t rssi; + uint16_t interval; + bt_addr_le_t direct_addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_ext_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_ext_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED 0x0e +struct bt_hci_evt_le_per_adv_sync_established { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT 0x0f +struct bt_hci_evt_le_per_advertising_report { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_LOST 0x10 +struct bt_hci_evt_le_per_adv_sync_lost { + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 + +#define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 +struct bt_hci_evt_le_adv_set_terminated { + uint8_t status; + uint8_t adv_handle; + uint16_t conn_handle; + uint8_t num_completed_ext_adv_evts; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 +struct bt_hci_evt_le_scan_req_received { + uint8_t handle; + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_LE_CHAN_SEL_ALGO_1 0x00 +#define BT_HCI_LE_CHAN_SEL_ALGO_2 0x01 + +#define BT_HCI_EVT_LE_CHAN_SEL_ALGO 0x14 +struct bt_hci_evt_le_chan_sel_algo { + uint16_t handle; + uint8_t chan_sel_algo; +} __packed; + +#define BT_HCI_LE_CTE_CRC_OK 0x0 +#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME 0x1 +#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_OTHER 0x2 +#define BT_HCI_LE_CTE_INSUFFICIENT_RESOURCES 0xFF + +#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MIN 0x9 +#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MAX 0x52 + +#define BT_HCI_LE_CTE_REPORT_NO_VALID_SAMPLE 0x80 + +#define BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT 0x15 +struct bt_hci_le_iq_sample { + int8_t i; + int8_t q; +}; + +struct bt_hci_evt_le_connectionless_iq_report { + uint16_t sync_handle; + uint8_t chan_idx; + int16_t rssi; + uint8_t rssi_ant_id; + uint8_t cte_type; + uint8_t slot_durations; + uint8_t packet_status; + uint16_t per_evt_counter; + uint8_t sample_count; + struct bt_hci_le_iq_sample sample[0]; +} __packed; + +#define BT_HCI_EVT_LE_CONNECTION_IQ_REPORT 0x16 +struct bt_hci_evt_le_connection_iq_report { + uint16_t conn_handle; + uint8_t rx_phy; + uint8_t data_chan_idx; + int16_t rssi; + uint8_t rssi_ant_id; + uint8_t cte_type; + uint8_t slot_durations; + uint8_t packet_status; + uint16_t conn_evt_counter; + uint8_t sample_count; + struct bt_hci_le_iq_sample sample[0]; +} __packed; + +#define BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE 0x0 + +#define BT_HCI_EVT_LE_CTE_REQUEST_FAILED 0x17 +struct bt_hci_evt_le_cte_req_failed { + /* According to BT 5.3 Core Spec the status field may have following + * values: + * - BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE when received LL_CTE_RSP_PDU without CTE. + * - Other Controller error code for peer rejected request. + */ + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_EVT_LE_PAST_RECEIVED 0x18 +struct bt_hci_evt_le_past_received { + uint8_t status; + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; + uint8_t adv_sid; + bt_addr_le_t addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_CIS_ESTABLISHED 0x19 +struct bt_hci_evt_le_cis_established { + uint8_t status; + uint16_t conn_handle; + uint8_t cig_sync_delay[3]; + uint8_t cis_sync_delay[3]; + uint8_t c_latency[3]; + uint8_t p_latency[3]; + uint8_t c_phy; + uint8_t p_phy; + uint8_t nse; + uint8_t c_bn; + uint8_t p_bn; + uint8_t c_ft; + uint8_t p_ft; + uint16_t c_max_pdu; + uint16_t p_max_pdu; + uint16_t interval; +} __packed; + +#define BT_HCI_EVT_LE_CIS_REQ 0x1a +struct bt_hci_evt_le_cis_req { + uint16_t acl_handle; + uint16_t cis_handle; + uint8_t cig_id; + uint8_t cis_id; +} __packed; + +#define BT_HCI_EVT_LE_BIG_COMPLETE 0x1b +struct bt_hci_evt_le_big_complete { + uint8_t status; + uint8_t big_handle; + uint8_t sync_delay[3]; + uint8_t latency[3]; + uint8_t phy; + uint8_t nse; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint16_t iso_interval; + uint8_t num_bis; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_EVT_LE_BIG_TERMINATE 0x1c +struct bt_hci_evt_le_big_terminate { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d +struct bt_hci_evt_le_big_sync_established { + uint8_t status; + uint8_t big_handle; + uint8_t latency[3]; + uint8_t nse; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint16_t iso_interval; + uint8_t num_bis; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e +struct bt_hci_evt_le_big_sync_lost { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE 0x1f +struct bt_hci_evt_le_req_peer_sca_complete { + uint8_t status; + uint16_t handle; + uint8_t sca; +} __packed; + +#define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 +struct bt_hci_evt_le_biginfo_adv_report { + uint16_t sync_handle; + uint8_t num_bis; + uint8_t nse; + uint16_t iso_interval; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint8_t sdu_interval[3]; + uint16_t max_sdu; + uint8_t phy; + uint8_t framing; + uint8_t encryption; +} __packed; + +/* Event mask bits */ + +#define BT_EVT_BIT(n) (1ULL << (n)) + +#define BT_EVT_MASK_INQUIRY_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_CONN_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_CONN_REQUEST BT_EVT_BIT(3) +#define BT_EVT_MASK_DISCONN_COMPLETE BT_EVT_BIT(4) +#define BT_EVT_MASK_AUTH_COMPLETE BT_EVT_BIT(5) +#define BT_EVT_MASK_REMOTE_NAME_REQ_COMPLETE BT_EVT_BIT(6) +#define BT_EVT_MASK_ENCRYPT_CHANGE BT_EVT_BIT(7) +#define BT_EVT_MASK_REMOTE_FEATURES BT_EVT_BIT(10) +#define BT_EVT_MASK_REMOTE_VERSION_INFO BT_EVT_BIT(11) +#define BT_EVT_MASK_HARDWARE_ERROR BT_EVT_BIT(15) +#define BT_EVT_MASK_ROLE_CHANGE BT_EVT_BIT(17) +#define BT_EVT_MASK_PIN_CODE_REQ BT_EVT_BIT(21) +#define BT_EVT_MASK_LINK_KEY_REQ BT_EVT_BIT(22) +#define BT_EVT_MASK_LINK_KEY_NOTIFY BT_EVT_BIT(23) +#define BT_EVT_MASK_DATA_BUFFER_OVERFLOW BT_EVT_BIT(25) +#define BT_EVT_MASK_INQUIRY_RESULT_WITH_RSSI BT_EVT_BIT(33) +#define BT_EVT_MASK_REMOTE_EXT_FEATURES BT_EVT_BIT(34) +#define BT_EVT_MASK_SYNC_CONN_COMPLETE BT_EVT_BIT(43) +#define BT_EVT_MASK_EXTENDED_INQUIRY_RESULT BT_EVT_BIT(46) +#define BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE BT_EVT_BIT(47) +#define BT_EVT_MASK_IO_CAPA_REQ BT_EVT_BIT(48) +#define BT_EVT_MASK_IO_CAPA_RESP BT_EVT_BIT(49) +#define BT_EVT_MASK_USER_CONFIRM_REQ BT_EVT_BIT(50) +#define BT_EVT_MASK_USER_PASSKEY_REQ BT_EVT_BIT(51) +#define BT_EVT_MASK_SSP_COMPLETE BT_EVT_BIT(53) +#define BT_EVT_MASK_USER_PASSKEY_NOTIFY BT_EVT_BIT(58) +#define BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) + +/* Page 2 */ +#define BT_EVT_MASK_NUM_COMPLETE_DATA_BLOCKS BT_EVT_BIT(8) +#define BT_EVT_MASK_TRIGG_CLOCK_CAPTURE BT_EVT_BIT(14) +#define BT_EVT_MASK_SYNCH_TRAIN_COMPLETE BT_EVT_BIT(15) +#define BT_EVT_MASK_SYNCH_TRAIN_RX BT_EVT_BIT(16) +#define BT_EVT_MASK_CL_PER_BC_RX BT_EVT_BIT(17) +#define BT_EVT_MASK_CL_PER_BC_TIMEOUT BT_EVT_BIT(18) +#define BT_EVT_MASK_TRUNC_PAGE_COMPLETE BT_EVT_BIT(19) +#define BT_EVT_MASK_PER_PAGE_RSP_TIMEOUT BT_EVT_BIT(20) +#define BT_EVT_MASK_CL_PER_BC_CH_MAP_CHANGE BT_EVT_BIT(21) +#define BT_EVT_MASK_INQUIRY_RSP_NOT BT_EVT_BIT(22) +#define BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP BT_EVT_BIT(23) +#define BT_EVT_MASK_SAM_STATUS_CHANGE BT_EVT_BIT(24) + +#define BT_EVT_MASK_LE_CONN_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_LE_ADVERTISING_REPORT BT_EVT_BIT(1) +#define BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE BT_EVT_BIT(3) +#define BT_EVT_MASK_LE_LTK_REQUEST BT_EVT_BIT(4) +#define BT_EVT_MASK_LE_CONN_PARAM_REQ BT_EVT_BIT(5) +#define BT_EVT_MASK_LE_DATA_LEN_CHANGE BT_EVT_BIT(6) +#define BT_EVT_MASK_LE_P256_PUBLIC_KEY_COMPLETE BT_EVT_BIT(7) +#define BT_EVT_MASK_LE_GENERATE_DHKEY_COMPLETE BT_EVT_BIT(8) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE BT_EVT_BIT(9) +#define BT_EVT_MASK_LE_DIRECT_ADV_REPORT BT_EVT_BIT(10) +#define BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE BT_EVT_BIT(11) +#define BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT BT_EVT_BIT(12) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED BT_EVT_BIT(13) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT BT_EVT_BIT(14) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_LOST BT_EVT_BIT(15) +#define BT_EVT_MASK_LE_SCAN_TIMEOUT BT_EVT_BIT(16) +#define BT_EVT_MASK_LE_ADV_SET_TERMINATED BT_EVT_BIT(17) +#define BT_EVT_MASK_LE_SCAN_REQ_RECEIVED BT_EVT_BIT(18) +#define BT_EVT_MASK_LE_CHAN_SEL_ALGO BT_EVT_BIT(19) +#define BT_EVT_MASK_LE_CONNECTIONLESS_IQ_REPORT BT_EVT_BIT(20) +#define BT_EVT_MASK_LE_CONNECTION_IQ_REPORT BT_EVT_BIT(21) +#define BT_EVT_MASK_LE_CTE_REQUEST_FAILED BT_EVT_BIT(22) +#define BT_EVT_MASK_LE_PAST_RECEIVED BT_EVT_BIT(23) +#define BT_EVT_MASK_LE_CIS_ESTABLISHED BT_EVT_BIT(24) +#define BT_EVT_MASK_LE_CIS_REQ BT_EVT_BIT(25) +#define BT_EVT_MASK_LE_BIG_COMPLETE BT_EVT_BIT(26) +#define BT_EVT_MASK_LE_BIG_TERMINATED BT_EVT_BIT(27) +#define BT_EVT_MASK_LE_BIG_SYNC_ESTABLISHED BT_EVT_BIT(28) +#define BT_EVT_MASK_LE_BIG_SYNC_LOST BT_EVT_BIT(29) +#define BT_EVT_MASK_LE_REQ_PEER_SCA_COMPLETE BT_EVT_BIT(30) +#define BT_EVT_MASK_LE_PATH_LOSS_THRESHOLD BT_EVT_BIT(31) +#define BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING BT_EVT_BIT(32) +#define BT_EVT_MASK_LE_BIGINFO_ADV_REPORT BT_EVT_BIT(33) + +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED_V2 BT_EVT_BIT(35) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT_V2 BT_EVT_BIT(36) +#define BT_EVT_MASK_LE_PAST_RECEIVED_V2 BT_EVT_BIT(37) +#define BT_EVT_MASK_LE_PER_ADV_SUBEVENT_DATA_REQ BT_EVT_BIT(38) +#define BT_EVT_MASK_LE_PER_ADV_RESPONSE_REPORT BT_EVT_BIT(39) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40) + +/** HCI Error Codes, BT Core Spec v5.4 [Vol 1, Part F]. */ +#define BT_HCI_ERR_SUCCESS 0x00 +#define BT_HCI_ERR_UNKNOWN_CMD 0x01 +#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 +#define BT_HCI_ERR_HW_FAILURE 0x03 +#define BT_HCI_ERR_PAGE_TIMEOUT 0x04 +#define BT_HCI_ERR_AUTH_FAIL 0x05 +#define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06 +#define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07 +#define BT_HCI_ERR_CONN_TIMEOUT 0x08 +#define BT_HCI_ERR_CONN_LIMIT_EXCEEDED 0x09 +#define BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED 0x0a +#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b +#define BT_HCI_ERR_CMD_DISALLOWED 0x0c +#define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d +#define BT_HCI_ERR_INSUFFICIENT_SECURITY 0x0e +#define BT_HCI_ERR_BD_ADDR_UNACCEPTABLE 0x0f +#define BT_HCI_ERR_CONN_ACCEPT_TIMEOUT 0x10 +#define BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL 0x11 +#define BT_HCI_ERR_INVALID_PARAM 0x12 +#define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13 +#define BT_HCI_ERR_REMOTE_LOW_RESOURCES 0x14 +#define BT_HCI_ERR_REMOTE_POWER_OFF 0x15 +#define BT_HCI_ERR_LOCALHOST_TERM_CONN 0x16 +#define BT_HCI_ERR_REPEATED_ATTEMPTS 0x17 +#define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18 +#define BT_HCI_ERR_UNKNOWN_LMP_PDU 0x19 +#define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a +#define BT_HCI_ERR_SCO_OFFSET_REJECTED 0x1b +#define BT_HCI_ERR_SCO_INTERVAL_REJECTED 0x1c +#define BT_HCI_ERR_SCO_AIR_MODE_REJECTED 0x1d +#define BT_HCI_ERR_INVALID_LL_PARAM 0x1e +#define BT_HCI_ERR_UNSPECIFIED 0x1f +#define BT_HCI_ERR_UNSUPP_LL_PARAM_VAL 0x20 +#define BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define BT_HCI_ERR_LL_RESP_TIMEOUT 0x22 +#define BT_HCI_ERR_LL_PROC_COLLISION 0x23 +#define BT_HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24 +#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25 +#define BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED 0x26 +#define BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED 0x27 +#define BT_HCI_ERR_INSTANT_PASSED 0x28 +#define BT_HCI_ERR_PAIRING_NOT_SUPPORTED 0x29 +#define BT_HCI_ERR_DIFF_TRANS_COLLISION 0x2a +#define BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2c +#define BT_HCI_ERR_QOS_REJECTED 0x2d +#define BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED 0x2e +#define BT_HCI_ERR_INSUFF_SECURITY 0x2f +#define BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE 0x30 +#define BT_HCI_ERR_ROLE_SWITCH_PENDING 0x32 +#define BT_HCI_ERR_RESERVED_SLOT_VIOLATION 0x34 +#define BT_HCI_ERR_ROLE_SWITCH_FAILED 0x35 +#define BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE 0x36 +#define BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST 0x37 +#define BT_HCI_ERR_HOST_BUSY_PAIRING 0x38 +#define BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN 0x39 +#define BT_HCI_ERR_CONTROLLER_BUSY 0x3a +#define BT_HCI_ERR_UNACCEPT_CONN_PARAM 0x3b +#define BT_HCI_ERR_ADV_TIMEOUT 0x3c +#define BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL 0x3d +#define BT_HCI_ERR_CONN_FAIL_TO_ESTAB 0x3e +#define BT_HCI_ERR_MAC_CONN_FAILED 0x3f +#define BT_HCI_ERR_CLOCK_ADJUST_REJECTED 0x40 +#define BT_HCI_ERR_SUBMAP_NOT_DEFINED 0x41 +#define BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER 0x42 +#define BT_HCI_ERR_LIMIT_REACHED 0x43 +#define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44 +#define BT_HCI_ERR_PACKET_TOO_LONG 0x45 +#define BT_HCI_ERR_TOO_LATE 0x46 +#define BT_HCI_ERR_TOO_EARLY 0x47 + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ */ diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index f5c5ad66b5a..404d89cbf06 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -114,8 +114,7 @@ choice BT_LL_CHOICE Select the Bluetooth Link Layer to compile. config BT_LL_SW_SPLIT - bool "Software-based BLE Link Layer [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Software-based BLE Link Layer" select ENTROPY_GENERATOR help Use Zephyr software BLE Link Layer ULL LLL split implementation. @@ -143,31 +142,10 @@ config BT_CTLR_HCI_VS_BUILD_INFO character is required at the beginning to separate it from the already included information. -config BT_CTLR_AD_DATA_BACKUP - bool "Legacy AD Data backup" - depends on BT_PERIPHERAL || BT_CTLR_ADV_EXT - default y - help - Backup Legacy Advertising Data when switching to Legacy Directed or - to Extended Advertising mode, and restore it when switching back to - Legacy Non-Directed Advertising mode. - Application can disable this feature if not using Directed - Advertising or switch between Legacy and Extended Advertising. - -config BT_CTLR_HCI_ADV_HANDLE_MAPPING - bool "Advertising set handle mapping between HCI and LL" - depends on BT_CTLR_ADV_EXT - default y if BT_HCI_RAW - help - Enable mapping of advertising set handles between HCI and LL when - using external host since it can use arbitrary numbers as set handles - (as defined by Core specification) as opposed to LL which always uses - zero-based numbering. When using with Zephyr host this option can be - disabled to remove extra mapping logic. - config BT_CTLR_DUP_FILTER_LEN int "Number of addresses in the scan duplicate filter" depends on BT_OBSERVER + depends on BT_LL_SW_SPLIT default 16 help Set the number of unique BLE addresses that can be filtered as @@ -176,32 +154,16 @@ config BT_CTLR_DUP_FILTER_LEN config BT_CTLR_DUP_FILTER_ADV_SET_MAX int "Number of Extended Advertising Sets in the scan duplicate filter" depends on BT_OBSERVER && BT_CTLR_ADV_EXT && (BT_CTLR_DUP_FILTER_LEN > 0) + depends on BT_LL_SW_SPLIT range 1 16 default 1 help Set the number of unique Advertising Set ID per Bluetooth Low Energy addresses that can be filtered as duplicates while Extended Scanning. -config BT_CTLR_MESH_SCAN_FILTERS - int "Number of Mesh scan filters" - depends on BT_HCI_MESH_EXT - default 1 - range 1 15 - help - Set the number of unique Mesh Scan Filters available as part of - the Intel Mesh Vendor Specific Extensions. - -config BT_CTLR_MESH_SF_PATTERNS - int "Number of Mesh scan filter patterns" - depends on BT_HCI_MESH_EXT - default 15 - range 1 15 - help - Set the number of unique Mesh Scan Filter patterns available per - Scan Filter as part of the Intel Mesh Vendor Specific Extensions. - config BT_CTLR_RX_BUFFERS int "Number of Rx buffers" + depends on BT_LL_SW_SPLIT default 6 if BT_HCI_RAW default 1 range 1 18 @@ -238,6 +200,7 @@ config BT_CTLR_ISO_TX_BUFFER_SIZE int "Isochronous Tx buffer size" depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO range 1 4095 + default BT_ISO_TX_MTU if BT_ISO default 1 help Size of the Isochronous Tx buffers and the value returned in HCI LE @@ -324,14 +287,42 @@ config BT_CTLR_TX_PWR_PLUS_3 config BT_CTLR_TX_PWR_PLUS_2 bool "+2 dBm" - depends on HAS_HW_NRF_RADIO_TX_PWR_HIGH + depends on HAS_HW_NRF_RADIO_TX_PWR_HIGH || SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_PLUS_1 + bool "+1 dBm" + depends on SOC_SERIES_NRF53X config BT_CTLR_TX_PWR_0 bool "0 dBm" +config BT_CTLR_TX_PWR_MINUS_1 + bool "-1 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_2 + bool "-2 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_3 + bool "-3 dBm" + depends on SOC_SERIES_NRF53X + config BT_CTLR_TX_PWR_MINUS_4 bool "-4 dBm" +config BT_CTLR_TX_PWR_MINUS_5 + bool "-5 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_6 + bool "-6 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_7 + bool "-7 dBm" + depends on SOC_SERIES_NRF53X + config BT_CTLR_TX_PWR_MINUS_8 bool "-8 dBm" @@ -354,6 +345,31 @@ config BT_CTLR_TX_PWR_MINUS_40 endchoice +config BT_CTLR_TX_PWR_DBM + int + default 8 if BT_CTLR_TX_PWR_PLUS_8 + default 7 if BT_CTLR_TX_PWR_PLUS_7 + default 6 if BT_CTLR_TX_PWR_PLUS_6 + default 5 if BT_CTLR_TX_PWR_PLUS_5 + default 4 if BT_CTLR_TX_PWR_PLUS_4 + default 3 if BT_CTLR_TX_PWR_PLUS_3 + default 2 if BT_CTLR_TX_PWR_PLUS_2 + default 1 if BT_CTLR_TX_PWR_PLUS_1 + default 0 if BT_CTLR_TX_PWR_0 + default -1 if BT_CTLR_TX_PWR_MINUS_1 + default -2 if BT_CTLR_TX_PWR_MINUS_2 + default -3 if BT_CTLR_TX_PWR_MINUS_3 + default -4 if BT_CTLR_TX_PWR_MINUS_4 + default -5 if BT_CTLR_TX_PWR_MINUS_5 + default -6 if BT_CTLR_TX_PWR_MINUS_6 + default -7 if BT_CTLR_TX_PWR_MINUS_7 + default -8 if BT_CTLR_TX_PWR_MINUS_8 + default -12 if BT_CTLR_TX_PWR_MINUS_12 + default -16 if BT_CTLR_TX_PWR_MINUS_16 + default -20 if BT_CTLR_TX_PWR_MINUS_20 + default -30 if BT_CTLR_TX_PWR_MINUS_30 + default -40 if BT_CTLR_TX_PWR_MINUS_40 + config BT_CTLR_TX_PWR_ANTENNA int "Set TX power (dBm)" range -127 127 @@ -439,6 +455,7 @@ config BT_CTLR_DATA_LENGTH config BT_CTLR_DATA_LENGTH_MAX int "Maximum data length supported" depends on BT_CTLR_DATA_LENGTH + default BT_BUF_ACL_RX_SIZE if BT_BUF_ACL_RX_SIZE < 251 default 27 range 27 BT_BUF_ACL_RX_SIZE if BT_BUF_ACL_RX_SIZE < 251 range 27 251 @@ -476,10 +493,6 @@ config BT_CTLR_CONN_RSSI help Enable connection RSSI measurement. -config BT_CTLR_CHECK_SAME_PEER_CONN - bool - default BT_MAX_CONN > 1 && !BT_CTLR_ALLOW_SAME_PEER_CONN - endif # BT_CONN config BT_CTLR_FILTER_ACCEPT_LIST @@ -555,7 +568,6 @@ config BT_CTLR_ADV_EXT depends on BT_CTLR_ADV_EXT_SUPPORT select BT_CTLR_CHAN_SEL_2 if BT_LL_SW_SPLIT && BT_BROADCASTER select BT_CTLR_SCAN_REQ_NOTIFY if BT_LL_SW_SPLIT && BT_BROADCASTER - select BT_TICKER_EXT if BT_LL_SW_SPLIT default y if BT_EXT_ADV help Enable support for Bluetooth 5.0 LE Advertising Extensions in the @@ -591,22 +603,6 @@ config BT_CTLR_ADV_DATA_LEN_MAX help Maximum Extended Advertising Data Length. -config BT_CTLR_ADV_EXT_RX_PDU_LEN_MAX - int "Maximum Advertising Extensions Receive PDU Length" - depends on BT_OBSERVER - range 255 255 if BT_HCI_RAW - range 31 255 - default 255 - help - Maximum Advertising Extensions Receive PDU Length. - -config BT_CTLR_SCAN_DATA_LEN_MAX - int "Maximum Extended Scanning Data Length" - depends on BT_OBSERVER - range 31 1650 - help - Maximum Extended Scanning Data Length. - config BT_CTLR_ADV_PERIODIC bool "LE Periodic Advertising in Advertising State" depends on BT_BROADCASTER && BT_CTLR_ADV_PERIODIC_SUPPORT @@ -695,11 +691,6 @@ config BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING Enable filtering of periodic advertisements depending on type of Constant Tone Extension. -config BT_CTLR_CHECK_SAME_PEER_SYNC - # Hidden Kconfig to add same peer synchronization check - bool - default BT_PER_ADV_SYNC_MAX > 1 - config BT_CTLR_SYNC_TRANSFER_RECEIVER bool "Periodic Advertising Sync Transfer receiver" depends on BT_CTLR_SYNC_TRANSFER_RECEIVER_SUPPORT @@ -725,6 +716,7 @@ config BT_CTLR_ADV_ISO depends on BT_BROADCASTER && BT_CTLR_ADV_ISO_SUPPORT select BT_CTLR_ADV_PERIODIC select BT_CTLR_SET_HOST_FEATURE + default y if BT_ISO_BROADCASTER help Enable support for Bluetooth 5.2 LE Isochronous Advertising in the Controller. @@ -738,6 +730,7 @@ config BT_CTLR_SYNC_ISO depends on BT_OBSERVER && BT_CTLR_SYNC_ISO_SUPPORT select BT_CTLR_SYNC_PERIODIC select BT_CTLR_SET_HOST_FEATURE + default y if BT_ISO_SYNC_RECEIVER help Enable support for Bluetooth 5.2 LE Isochronous Advertising sync in the Controller. @@ -781,6 +774,14 @@ config BT_CTLR_ADV_ISO_PDU_LEN_MAX help Maximum Broadcast Isochronous Channel PDU Length. +config BT_CTLR_SCAN_SYNC_ISO_SET + int "LE ISO Broadcast Isochronous Groups Sync Sets" + depends on BT_CTLR_SYNC_ISO + range 1 64 + default 1 + help + Maximum supported broadcast isochronous groups (BIGs) sync sets. + config BT_CTLR_SYNC_ISO_STREAM_MAX int "Maximum supported ISO Synchronized Receiver Streams per Broadcast ISO group" depends on BT_CTLR_SYNC_ISO @@ -817,6 +818,7 @@ config BT_CTLR_SET_HOST_FEATURE config BT_CTLR_CENTRAL_ISO bool "LE Connected Isochronous Stream Central" if !BT_LL_SW_SPLIT depends on BT_CTLR_CENTRAL_ISO_SUPPORT && BT_CENTRAL + default y if BT_ISO_CENTRAL help Enable support for Bluetooth 5.2 LE Connected Isochronous Stream Central role in the Controller. @@ -829,6 +831,7 @@ config BT_CTLR_CENTRAL_ISO config BT_CTLR_PERIPHERAL_ISO bool "LE Connected Isochronous Stream Peripheral" if !BT_LL_SW_SPLIT depends on BT_CTLR_PERIPHERAL_ISO_SUPPORT && BT_PERIPHERAL + default y if BT_ISO_PERIPHERAL help Enable support for Bluetooth 5.2 LE Connected Isochronous Stream Peripheral role in the Controller. @@ -866,13 +869,6 @@ config BT_CTLR_CONN_ISO_STREAMS_PER_GROUP help Maximum supported CISes per CIG. -config BT_CTLR_CONN_ISO_HCI_DATAPATH_SKIP_INVALID_DATA - bool "Do not pass invalid SDUs on HCI datapath" - depends on BT_CTLR_CONN_ISO - help - This allows for applications to decide whether to - forward invalid SDUs through HCI upwards. - config BT_CTLR_CONN_ISO_PDU_LEN_MAX int "Maximum Connected Isochronous Channel PDU Length" depends on BT_CTLR_CONN_ISO @@ -898,27 +894,13 @@ config BT_CTLR_CONN_ISO_STREAMS_MAX_NSE help Maximum number of CIS subevents. -choice - prompt "CIS Creation Policy Selection" - default BT_CTLR_CONN_ISO_RELIABILITY_POLICY - -config BT_CTLR_CONN_ISO_RELIABILITY_POLICY - bool "CIS creation policy for reliability" - depends on BT_CTLR_CENTRAL_ISO - help - Select this option to use reliability policy for CIS creation. This - favors a CIS layout/configuration which utilizes the full range of the - Max_Transmission_Latency for maximum retransmission and payload - recovery. - -config BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY - bool "CIS creation policy for low latency" - depends on BT_CTLR_CENTRAL_ISO +config BT_CTLR_CONN_ISO_STREAMS_MAX_FT + int "LE Connected Isochronous Streams max flush timeout" + depends on BT_CTLR_CONN_ISO + range 1 255 + default 255 help - Select this option to use low latency policy for CIS creation. This - favors a CIS layout/configuration which compacts payload transmission - for lowest possible latency. -endchoice + Maximum number of CIS flush timeout events. config BT_CTLR_ISO bool @@ -968,11 +950,6 @@ config BT_CTLR_ASSERT_HANDLER and will be invoked whenever the controller code encounters an unrecoverable error. -config BT_CTLR_TEST - bool "Run in-system unit tests" - help - Run in-system unit tests - endif # BT_CTLR config BT_CTLR_DEBUG_PINS_CPUAPP diff --git a/subsys/bluetooth/controller/Kconfig.df b/subsys/bluetooth/controller/Kconfig.df index e3f460c7f51..981d1b8f1fc 100644 --- a/subsys/bluetooth/controller/Kconfig.df +++ b/subsys/bluetooth/controller/Kconfig.df @@ -3,17 +3,14 @@ # Copyright (c) 2020 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -# BT_CTLR_DF_SUPPORT is a wrapper for all DF features. -# If only certain DF features are supported, those should be selected -# individually. +# BT_CTLR_DF_SUPPORT is a wrapper for all DF features. It is referenced by Host +# to enable its DF related Kconfigs when build together with the Controller. +# It is required to enable it when Controller supports any DF related feature +# but particular features are selected individually. config BT_CTLR_DF_SUPPORT bool - depends on BT_LL_SW_SPLIT && !BT_CTLR_TIFS_HW - select BT_CTLR_DF_CTE_TX_SUPPORT - select BT_CTLR_DF_ANT_SWITCH_2US_SUPPORT - select BT_CTLR_DF_ANT_SWITCH_1US_SUPPORT - select BT_CTLR_DF_CTE_RX_SUPPORT - select BT_CTLR_DF_CTE_RX_SAMPLE_1US_SUPPORT + +if BT_CTLR_DF_SUPPORT config BT_CTLR_DF_CTE_TX_SUPPORT bool @@ -33,6 +30,8 @@ config BT_CTLR_DF_ANT_SWITCH_1US_SUPPORT config BT_CTLR_CTEINLINE_SUPPORT bool +endif # BT_CTLR_DF_SUPPORT + menuconfig BT_CTLR_DF bool "LE Direction Finding" depends on BT_CTLR_DF_CTE_TX_SUPPORT || BT_CTLR_DF_CTE_RX_SUPPORT diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index fa4483d7a30..84db5fddb10 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -8,9 +8,13 @@ if BT_LL_SW_SPLIT config BT_LLL_VENDOR_NORDIC bool "Use Nordic LLL" depends on SOC_COMPATIBLE_NRF - select BT_HAS_HCI_VS + depends on !$(dt_nodelabel_enabled,timer0) + depends on !$(dt_nodelabel_enabled,rtc0) + select ENTROPY_NRF5_RNG select ENTROPY_NRF5_BIAS_CORRECTION + + select BT_HAS_HCI_VS select BT_CTLR_LE_ENC_SUPPORT if !BT_CTLR_DATA_LENGTH_CLEAR && \ !BT_CTLR_PHY_2M_NRF select BT_CTLR_CONN_PARAM_REQ_SUPPORT @@ -20,7 +24,6 @@ config BT_LLL_VENDOR_NORDIC BT_CTLR_DATA_LENGTH_CLEAR select BT_CTLR_PRIVACY_SUPPORT if !SOC_SERIES_NRF51X select BT_CTLR_EXT_SCAN_FP_SUPPORT - select BT_CTLR_PHY_2M_SUPPORT if HAS_HW_NRF_RADIO_BLE_2M || \ BT_CTLR_PHY_2M_NRF select BT_CTLR_PHY_CODED_SUPPORT if HAS_HW_NRF_RADIO_BLE_CODED @@ -48,16 +51,11 @@ config BT_LLL_VENDOR_NORDIC select BT_TICKER_UPDATE if BT_BROADCASTER || BT_CONN || \ (BT_OBSERVER && BT_CTLR_ADV_EXT) - select BT_TICKER_NEXT_SLOT_GET if (BT_BROADCASTER && \ - BT_CTLR_ADV_EXT) || \ - BT_CTLR_ADV_PERIODIC + select BT_TICKER_REMAINDER if BT_CTLR_CENTRAL_ISO select BT_TICKER_REMAINDER_GET if BT_BROADCASTER && BT_CTLR_ADV_EXT select BT_TICKER_LAZY_GET if BT_CTLR_ADV_PERIODIC - select BT_TICKER_NEXT_SLOT_GET_MATCH if BT_TICKER_REMAINDER_GET default y - depends on !$(dt_nodelabel_enabled,timer0) - depends on !$(dt_nodelabel_enabled,rtc0) help Use Nordic Lower Link Layer implementation. @@ -76,6 +74,16 @@ config BT_LLL_VENDOR_OPENISA help Use OpenISA Lower Link Layer implementation. +# BT_CTLR_DF_SUPPORT is a wrapper for all DF features. Here we select features that are supported by +# Zephyr's BLE Controller. +config BT_CTLR_DF_SUPPORT + depends on BT_LL_SW_SPLIT && !BT_CTLR_TIFS_HW + select BT_CTLR_DF_CTE_TX_SUPPORT + select BT_CTLR_DF_ANT_SWITCH_2US_SUPPORT + select BT_CTLR_DF_ANT_SWITCH_1US_SUPPORT + select BT_CTLR_DF_CTE_RX_SUPPORT + select BT_CTLR_DF_CTE_RX_SAMPLE_1US_SUPPORT + config BT_CTLR_XTAL_ADVANCED_SUPPORT bool @@ -125,11 +133,116 @@ config BT_CTLR_SUBVERSION_NUMBER help Set the Subversion Number that will be used in VERSION_IND PDU. +config BT_CTLR_AD_DATA_BACKUP + bool "Legacy AD Data backup" + depends on BT_PERIPHERAL || BT_CTLR_ADV_EXT + default y + help + Backup Legacy Advertising Data when switching to Legacy Directed or + to Extended Advertising mode, and restore it when switching back to + Legacy Non-Directed Advertising mode. + Application can disable this feature if not using Directed + Advertising or switch between Legacy and Extended Advertising. + +config BT_CTLR_HCI_ADV_HANDLE_MAPPING + bool "Advertising set handle mapping between HCI and LL" + depends on BT_CTLR_ADV_EXT + default y if BT_HCI_RAW + help + Enable mapping of advertising set handles between HCI and LL when + using external host since it can use arbitrary numbers as set handles + (as defined by Core specification) as opposed to LL which always uses + zero-based numbering. When using with Zephyr host this option can be + disabled to remove extra mapping logic. + +config BT_CTLR_MESH_SCAN_FILTERS + int "Number of Mesh scan filters" + depends on BT_HCI_MESH_EXT + default 1 + range 1 15 + help + Set the number of unique Mesh Scan Filters available as part of + the Intel Mesh Vendor Specific Extensions. + +config BT_CTLR_MESH_SF_PATTERNS + int "Number of Mesh scan filter patterns" + depends on BT_HCI_MESH_EXT + default 15 + range 1 15 + help + Set the number of unique Mesh Scan Filter patterns available per + Scan Filter as part of the Intel Mesh Vendor Specific Extensions. + +config BT_CTLR_CHECK_SAME_PEER_CONN + bool + depends on BT_CONN + default BT_MAX_CONN > 1 && !BT_CTLR_ALLOW_SAME_PEER_CONN + +if BT_CTLR_ADV_EXT + +config BT_CTLR_ADV_EXT_RX_PDU_LEN_MAX + int "Maximum Advertising Extensions Receive PDU Length" + depends on BT_OBSERVER + range 255 255 if BT_HCI_RAW + range 31 255 + default 255 + help + Maximum Advertising Extensions Receive PDU Length. + +config BT_CTLR_SCAN_DATA_LEN_MAX + int "Maximum Extended Scanning Data Length" + depends on BT_OBSERVER + range 31 1650 + help + Maximum Extended Scanning Data Length. + +config BT_CTLR_CHECK_SAME_PEER_SYNC + # Hidden Kconfig to add same peer synchronization check + bool + depends on BT_CTLR_SYNC_PERIODIC + default BT_PER_ADV_SYNC_MAX > 1 + +endif # BT_CTLR_ADV_EXT + +config BT_CTLR_CONN_ISO_HCI_DATAPATH_SKIP_INVALID_DATA + bool "Do not pass invalid SDUs on HCI datapath" + depends on BT_CTLR_CONN_ISO + help + This allows for applications to decide whether to + forward invalid SDUs through HCI upwards. + config BT_CTLR_ADVANCED_FEATURES bool "Show advanced features" help Makes advanced features visible to controller developers. +choice + prompt "CIS Creation Policy Selection" + default BT_CTLR_CONN_ISO_RELIABILITY_POLICY + +config BT_CTLR_CONN_ISO_RELIABILITY_POLICY + bool "CIS creation policy for reliability" + depends on BT_CTLR_CENTRAL_ISO + help + Select this option to use reliability policy for CIS creation. This + favors a CIS layout/configuration which utilizes the full range of the + Max_Transmission_Latency for maximum retransmission and payload + recovery. + +config BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY + bool "CIS creation policy for low latency" + depends on BT_CTLR_CENTRAL_ISO + help + Select this option to use low latency policy for CIS creation. This + favors a CIS layout/configuration which compacts payload transmission + for lowest possible latency. +endchoice + +config BT_CTLR_TEST + bool "Run in-system unit tests" + help + Run in-system unit tests + menu "Advanced features" visible if BT_CTLR_ADVANCED_FEATURES @@ -148,6 +261,15 @@ config BT_CTLR_RPA_CACHE_SIZE Set the size of the Known Unknown Resolving List for LE Controller-based Software deferred Privacy. +config BT_CTLR_TRPA_CACHE_SIZE + int "LE Controller-based Software Privacy target RPA cache size" + depends on BT_CTLR_SW_DEFERRED_PRIVACY + default 4 + range 1 64 + help + Set the size of the Known Unknown Target RPA Resolving List for LE + Controller-based Software deferred Privacy. + config BT_CTLR_DATA_LENGTH_CLEAR bool "Data Length Support (Cleartext only)" depends on SOC_SERIES_NRF51X @@ -168,9 +290,7 @@ config BT_CTLR_PHY_2M_NRF config BT_CTLR_ADV_AUX_SET int "LE Extended Advertising Auxiliary Sets" depends on BT_BROADCASTER && BT_CTLR_ADV_EXT - range 1 BT_CTLR_ADV_SET if BT_CTLR_ADV_PERIODIC range 0 BT_CTLR_ADV_SET - default 1 if BT_CTLR_ADV_PERIODIC default BT_CTLR_ADV_SET help Maximum supported advertising auxiliary channel sets. @@ -349,14 +469,6 @@ config BT_CTLR_SCAN_AUX_SET help Maximum supported auxiliary channel scan sets. -config BT_CTLR_SCAN_SYNC_ISO_SET - int "LE ISO Broadcast Isochronous Groups Sync Sets" - depends on BT_CTLR_SYNC_ISO - range 1 64 - default 1 - help - Maximum supported broadcast isochronous groups (BIGs) sync sets. - config BT_CTLR_ADV_ENABLE_STRICT bool "Enforce Strict Advertising Enable/Disable" depends on BT_BROADCASTER @@ -371,6 +483,26 @@ config BT_CTLR_SCAN_ENABLE_STRICT Enforce returning HCI Error Command Disallowed on enabling/disabling already enabled/disabled scanning. +config BT_CTLR_ISOAL_SN_STRICT + bool "Enforce Strict Tx ISO Data Sequence Number use" + depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO + default y + help + Enforce strict sequencing of released payloads based on the TX SDU's + packet sequence number. This will be effective when fragmenting an + SDU into unframed PDUs. + + When enabled, this could result in an SDU being fragmented into + payload numbers that are expired (will be dropped), if the TX SDU + packet sequence numbers do not increment according to the SDU interval + and delivery of SDUs to the ISO-AL do not strictly follow the SDU + interval. + + When disabled, TX SDUs could be shifted from their stream aligned + position and fragmented into payloads that are less likely to be + dropped. This will result in better delivery of data to the receiver + but at the cost of creating skews in the received stream of SDUs. + config BT_CTLR_ZLI bool "Use Zero Latency IRQs" depends on ZERO_LATENCY_IRQS @@ -422,8 +554,9 @@ config BT_CTLR_SCHED_ADVANCED bool "Advanced scheduling" depends on BT_CTLR_SCHED_ADVANCED_SUPPORT && \ (BT_CONN || \ - (BT_CTLR_ADV_EXT && (BT_CTLR_ADV_AUX_SET > 1)) || \ + (BT_CTLR_ADV_EXT && (BT_CTLR_ADV_AUX_SET > 0)) || \ BT_CTLR_ADV_ISO) + select BT_TICKER_NEXT_SLOT_GET default y if BT_CENTRAL || (BT_BROADCASTER && BT_CTLR_ADV_EXT) || BT_CTLR_ADV_ISO help Enable non-overlapping placement of observer, initiator and central @@ -439,6 +572,19 @@ config BT_CTLR_SCHED_ADVANCED Disabling this feature will lead to overlapping role in timespace leading to skipped events amongst active roles. +config BT_CTLR_ASSERT_OVERHEAD_START + bool "Assert on Prepare Latency" + default y + help + Assert on increased Radio Event Prepare callback latencies due to + CPU usage overheads in the Controller implementation. + + Disabling this option permits the Controller to gracefully skip radio + events that are delayed due to CPU usage latencies; as long as the + radio event skips are not for every consecutive radio event interval, + otherwise leading to remote supervision timeout and possible missing + local disconnect events. + config BT_CTLR_CENTRAL_SPACING int "Central Connection Spacing" depends on BT_CTLR_SCHED_ADVANCED @@ -790,6 +936,12 @@ config BT_TICKER_UPDATE help This option enables Ticker Update interface. +config BT_TICKER_REMAINDER + bool "Ticker Remainder" + help + This option enables Ticker Start interface remainder parameter for + first expire timeout. + config BT_TICKER_JOB_IDLE_GET bool "Ticker Job Idle Get" default y if BT_TICKER_LOW_LAT @@ -801,14 +953,15 @@ config BT_TICKER_JOB_IDLE_GET config BT_TICKER_NEXT_SLOT_GET bool "Ticker Next Slot Get" - default y if BT_CENTRAL help This option enables ticker interface to iterate through active ticker nodes, returning tick to expire. config BT_TICKER_REMAINDER_GET bool "Ticker Next Slot Get with Remainder" - depends on BT_TICKER_NEXT_SLOT_GET + select BT_TICKER_NEXT_SLOT_GET + select BT_TICKER_NEXT_SLOT_GET_MATCH + default y help This option enables ticker interface to iterate through active ticker nodes, returning tick to expire and remainder from a reference @@ -816,7 +969,8 @@ config BT_TICKER_REMAINDER_GET config BT_TICKER_LAZY_GET bool "Ticker Next Slot Get with Lazy" - depends on BT_TICKER_NEXT_SLOT_GET + select BT_TICKER_NEXT_SLOT_GET + select BT_TICKER_NEXT_SLOT_GET_MATCH help This option enables ticker interface to iterate through active ticker nodes, returning tick to expire and lazy count from a reference @@ -834,6 +988,7 @@ config BT_TICKER_NEXT_SLOT_GET_MATCH config BT_TICKER_EXT bool "Ticker extensions" + depends on !BT_TICKER_LOW_LAT default y if BT_BROADCASTER help This option enables ticker extensions such as re-scheduling of @@ -849,6 +1004,16 @@ config BT_TICKER_EXT_SLOT_WINDOW_YIELD This options forces tickers with slot window extensions to yield to normal tickers and be placed at the end of their slot window. +config BT_TICKER_EXT_EXPIRE_INFO + bool "Ticker timeout with other ticker's expire information" + select BT_TICKER_EXT + help + This option enables ticker to return expiration info. The extended + ticker interface) is used to ask for expiration information for + another ticker id to be returned in the ticker callback. This utilises + the extended ticker interface and a callback function with a different + context to keep the current ticker interface as unchanged as possible. + config BT_TICKER_PRIORITY_SET bool "Tickers with priority based collision resolution" depends on BT_TICKER_EXT diff --git a/subsys/bluetooth/controller/coex/coex_ticker.c b/subsys/bluetooth/controller/coex/coex_ticker.c index fa5c22f3831..229e2f9e125 100644 --- a/subsys/bluetooth/controller/coex/coex_ticker.c +++ b/subsys/bluetooth/controller/coex/coex_ticker.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "controller/hal/ticker.h" #include "controller/ticker/ticker.h" diff --git a/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c b/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c index 8b9696e988b..5286fb4a993 100644 --- a/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c +++ b/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "hal/ticker.h" #include "ticker/ticker.h" diff --git a/subsys/bluetooth/controller/hal/cntr.h b/subsys/bluetooth/controller/hal/cntr.h index 39862c1a606..6b4303e6c06 100644 --- a/subsys/bluetooth/controller/hal/cntr.h +++ b/subsys/bluetooth/controller/hal/cntr.h @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include void cntr_init(void); uint32_t cntr_start(void); diff --git a/subsys/bluetooth/controller/hal/debug.h b/subsys/bluetooth/controller/hal/debug.h index ba776c480c7..9f2fc3d0c95 100644 --- a/subsys/bluetooth/controller/hal/debug.h +++ b/subsys/bluetooth/controller/hal/debug.h @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ - #include "common/assert.h" +#include "common/assert.h" #ifdef CONFIG_BT_CTLR_ASSERT_HANDLER void bt_ctlr_assert_handle(char *file, uint32_t line); @@ -27,4 +27,12 @@ void bt_ctlr_assert_handle(char *file, uint32_t line); BT_ASSERT_MSG(cond, fmt, ##__VA_ARGS__) #endif +#if defined(CONFIG_BT_CTLR_ASSERT_OVERHEAD_START) +#define LL_ASSERT_OVERHEAD(overhead) \ + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", \ + __func__, HAL_TICKER_TICKS_TO_US(overhead)); +#else /* !CONFIG_BT_CTLR_ASSERT_OVERHEAD_START */ +#define LL_ASSERT_OVERHEAD(overhead) ARG_UNUSED(overhead) +#endif /* !CONFIG_BT_CTLR_ASSERT_OVERHEAD_START */ + #include "hal/debug_vendor_hal.h" diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 55208dc340d..9ca905c44e0 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -17,10 +17,9 @@ #include -#include +#include #include #include -#include #include "../host/hci_ecc.h" @@ -862,6 +861,10 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt) #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) /* LE Set PA Params, LE Set PA Data, LE Set PA Enable */ rp->commands[37] |= BIT(2) | BIT(3) | BIT(4); +#if defined(CONFIG_BT_CTLR_ADV_ISO) + /* LE Create BIG, LE Create BIG Test, LE Terminate BIG */ + rp->commands[42] |= BIT(5) | BIT(6) | BIT(7); +#endif /* CONFIG_BT_CTLR_ADV_ISO */ #endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_BROADCASTER */ @@ -886,6 +889,10 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt) #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST */ /* LE Set PA Receive Enable */ rp->commands[40] |= BIT(5); +#if defined(CONFIG_BT_CTLR_SYNC_ISO) + /* LE BIG Create Sync, LE BIG Terminate Sync */ + rp->commands[43] |= BIT(0) | BIT(1); +#endif /* CONFIG_BT_CTLR_SYNC_ISO */ #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ #endif /* CONFIG_BT_CTLR_ADV_EXT */ @@ -1048,7 +1055,7 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt) /* LE Read ISO Link Quality */ rp->commands[44] |= BIT(2); #endif /* CONFIG_BT_CTLR_READ_ISO_LINK_QUALITY */ -#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */ +#endif /* CONFIG_BT_CTLR_SYNC_ISO || CONFIG_BT_CTLR_CONN_ISO */ #if defined(CONFIG_BT_CTLR_ISO) /* LE Setup ISO Data Path, LE Remove ISO Data Path */ @@ -1158,7 +1165,7 @@ static void read_codecs_v2(struct net_buf *buf, struct net_buf **evt) /* copy vendor specific codec information */ vs_codecs = (struct bt_hci_vs_codecs_v2 *)&rp->codecs[std_codecs_bytes]; vs_codecs->num_codecs = num_vs_codecs; - for (i = 0; i < num_std_codecs; i++) { + for (i = 0; i < num_vs_codecs; i++) { struct bt_hci_vs_codec_info_v2 *codec; codec = &vs_codecs->codec_info[i]; @@ -2017,26 +2024,21 @@ static void le_set_cig_parameters(struct net_buf *buf, struct net_buf **evt) rp = hci_cmd_complete(evt, sizeof(*rp) + cis_count * sizeof(uint16_t)); rp->cig_id = cig_id; - rp->num_handles = cis_count; /* Only apply parameters if all went well */ if (!status) { - status = ll_cig_parameters_commit(cig_id); + uint16_t handles[CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP]; - if (status == BT_HCI_ERR_SUCCESS) { - struct ll_conn_iso_group *cig; - uint16_t handle; + status = ll_cig_parameters_commit(cig_id, handles); - cig = ll_conn_iso_group_get_by_id(cig_id); - handle = UINT16_MAX; - - for (uint8_t i = 0; i < cis_count; i++) { - (void)ll_conn_iso_stream_get_by_group(cig, &handle); - rp->handle[i] = sys_cpu_to_le16(handle); + if (status == BT_HCI_ERR_SUCCESS) { + for (uint8_t j = 0; j < cis_count; j++) { + rp->handle[j] = sys_cpu_to_le16(handles[j]); } } } + rp->num_handles = status ? 0U : cis_count; rp->status = status; } @@ -2094,35 +2096,40 @@ static void le_set_cig_params_test(struct net_buf *buf, struct net_buf **evt) rp = hci_cmd_complete(evt, sizeof(*rp) + cis_count * sizeof(uint16_t)); rp->cig_id = cig_id; - rp->num_handles = cis_count; /* Only apply parameters if all went well */ if (!status) { - status = ll_cig_parameters_commit(cig_id); + uint16_t handles[CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP]; - if (status == BT_HCI_ERR_SUCCESS) { - struct ll_conn_iso_group *cig; - uint16_t handle; - - cig = ll_conn_iso_group_get_by_id(cig_id); - handle = UINT16_MAX; + status = ll_cig_parameters_commit(cig_id, handles); - for (uint8_t i = 0; i < cis_count; i++) { - (void)ll_conn_iso_stream_get_by_group(cig, &handle); - rp->handle[i] = sys_cpu_to_le16(handle); + if (status == BT_HCI_ERR_SUCCESS) { + for (uint8_t j = 0; j < cis_count; j++) { + rp->handle[j] = sys_cpu_to_le16(handles[j]); } } } + rp->num_handles = status ? 0U : cis_count; rp->status = status; } static void le_create_cis(struct net_buf *buf, struct net_buf **evt) { + uint16_t handle_used[CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP] = {0}; struct bt_hci_cp_le_create_cis *cmd = (void *)buf->data; uint8_t status; uint8_t i; + /* + * Only create a CIS if the Isochronous Channels (Host Support) feature bit + * is set. Refer to BT Spec v5.4 Vol 6 Part B Section 4.6.33.1. + */ + if (!(ll_feat_get() & BIT64(BT_LE_FEAT_BIT_ISO_CHANNELS))) { + *evt = cmd_status(BT_HCI_ERR_CMD_DISALLOWED); + return; + } + /* * Creating new CISes is disallowed until all previous CIS * established events have been generated @@ -2137,9 +2144,19 @@ static void le_create_cis(struct net_buf *buf, struct net_buf **evt) for (i = 0; !status && i < cmd->num_cis; i++) { uint16_t cis_handle; uint16_t acl_handle; + uint8_t cis_idx; cis_handle = sys_le16_to_cpu(cmd->cis[i].cis_handle); acl_handle = sys_le16_to_cpu(cmd->cis[i].acl_handle); + + cis_idx = LL_CIS_IDX_FROM_HANDLE(cis_handle); + if (handle_used[cis_idx]) { + /* Handle must be unique in request */ + status = BT_HCI_ERR_INVALID_PARAM; + break; + } + + handle_used[cis_idx]++; status = ll_cis_create_check(cis_handle, acl_handle); } @@ -3491,7 +3508,6 @@ static void le_set_ext_adv_enable(struct net_buf *buf, struct net_buf **evt) struct bt_hci_cp_le_set_ext_adv_enable *cmd = (void *)buf->data; struct bt_hci_ext_adv_set *s; uint8_t set_num; - uint8_t enable; uint8_t status; uint8_t handle; @@ -3506,14 +3522,26 @@ static void le_set_ext_adv_enable(struct net_buf *buf, struct net_buf **evt) return; } - /* FIXME: Implement disable of all advertising sets */ - *evt = cmd_complete_status(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); + status = ll_adv_disable_all(); + + *evt = cmd_complete_status(status); return; } + /* Check for duplicate handles */ + if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) { + for (uint8_t i = 0U; i < set_num - 1; i++) { + for (uint8_t j = i + 1U; j < set_num; j++) { + if (cmd->s[i].handle == cmd->s[j].handle) { + *evt = cmd_complete_status(BT_HCI_ERR_INVALID_PARAM); + return; + } + } + } + } + s = (void *) cmd->s; - enable = cmd->enable; do { status = ll_adv_set_by_hci_handle_get(s->handle, &handle); if (status) { @@ -3814,7 +3842,8 @@ static void le_set_ext_scan_enable(struct net_buf *buf, struct net_buf **evt) } #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ - status = ll_scan_enable(cmd->enable, cmd->duration, cmd->period); + status = ll_scan_enable(cmd->enable, sys_le16_to_cpu(cmd->duration), + sys_le16_to_cpu(cmd->period)); /* NOTE: As filter duplicates is implemented here in HCI source code, * enabling of already enabled scanning shall succeed after @@ -5449,6 +5478,12 @@ int hci_vendor_cmd_handle_common(uint16_t ocf, struct net_buf *cmd, vs_read_tx_power_level(cmd, evt); break; #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ + +#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) + case BT_OCF(BT_HCI_OP_VS_SET_MIN_NUM_USED_CHANS): + vs_set_min_used_chans(cmd, evt); + break; +#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_HCI_VS_EXT */ #if defined(CONFIG_BT_HCI_MESH_EXT) @@ -5457,12 +5492,6 @@ int hci_vendor_cmd_handle_common(uint16_t ocf, struct net_buf *cmd, break; #endif /* CONFIG_BT_HCI_MESH_EXT */ -#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) - case BT_OCF(BT_HCI_OP_VS_SET_MIN_NUM_USED_CHANS): - vs_set_min_used_chans(cmd, evt); - break; -#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ - default: return -EINVAL; } @@ -5649,7 +5678,7 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) iso_hdr = net_buf_pull_mem(buf, sizeof(*iso_hdr)); handle = sys_le16_to_cpu(iso_hdr->handle); - len = sys_le16_to_cpu(iso_hdr->len); + len = bt_iso_hdr_len(sys_le16_to_cpu(iso_hdr->len)); if (buf->len < len) { LOG_ERR("Invalid HCI ISO packet length"); @@ -5689,7 +5718,8 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) iso_data_hdr = net_buf_pull_mem(buf, sizeof(*iso_data_hdr)); len -= sizeof(*iso_data_hdr); sdu_frag_tx.packet_sn = sys_le16_to_cpu(iso_data_hdr->sn); - sdu_frag_tx.iso_sdu_length = sys_le16_to_cpu(iso_data_hdr->slen); + sdu_frag_tx.iso_sdu_length = + sys_le16_to_cpu(bt_iso_pkt_len(iso_data_hdr->slen)); } else { sdu_frag_tx.packet_sn = 0; sdu_frag_tx.iso_sdu_length = 0; @@ -5783,6 +5813,8 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) struct ll_adv_iso_set *adv_iso; struct lll_adv_iso *lll_iso; uint16_t stream_handle; + uint8_t target_event; + uint8_t event_offset; uint16_t slen; /* FIXME: Code only expects header present */ @@ -5808,33 +5840,34 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) return -EINVAL; } - /* FIXME: convey group start */ - sdu_frag_tx.grp_ref_point = 0; - - /* FIXME: temporary interface to enable ISOAL data Tx - * Create provide proper interface between client - * (using ISOAL target_event) and ISOAL, preferably - * without dependence on peeking at LL data. - * Problem is that client must specify a value greater - * than LL bisPayloadCounter or no data is sent. + /* Determine the target event and the first event offset after + * datapath setup. + * event_offset mitigates the possibility of first SDU being + * late on the datapath and avoid all subsequent SDUs being + * dropped for a said SDU interval. i.e. upper layer is not + * drifting, say first SDU dropped, hence subsequent SDUs all + * dropped, is mitigated by offsetting the grp_ref_point. + * + * It is ok to do the below for every received ISO data, ISOAL + * will not consider subsequent skewed target_event after the + * first use of target_event value. + * + * In BIG implementation in LLL, payload_count corresponds to + * the next BIG event, hence calculate grp_ref_point for next + * BIG event by incrementing the previous elapsed big_ref_point + * by one additional ISO interval. */ lll_iso = &adv_iso->lll; + target_event = lll_iso->payload_count / lll_iso->bn; + event_offset = ull_ref_get(&adv_iso->ull) ? 0U : 1U; + event_offset += lll_iso->latency_prepare; - /* FIXME: Remove the below temporary hack to buffer up ISO data - * if the SDU interval and ISO interval misalign. - */ - uint64_t pkt_seq_num = lll_iso->payload_count / lll_iso->bn; - - if (((pkt_seq_num - stream->pkt_seq_num) & BIT64_MASK(39)) <= - BIT64_MASK(38)) { - stream->pkt_seq_num = pkt_seq_num; - } else { - pkt_seq_num = stream->pkt_seq_num; - } - - sdu_frag_tx.target_event = pkt_seq_num; - - stream->pkt_seq_num++; + sdu_frag_tx.target_event = target_event + event_offset; + sdu_frag_tx.grp_ref_point = + isoal_get_wrapped_time_us(adv_iso->big_ref_point, + ((event_offset + 1U) * + lll_iso->iso_interval * + ISO_INT_UNIT_US)); /* Start Fragmentation */ /* FIXME: need to ensure ISO-AL returns proper isoal_status. @@ -5938,7 +5971,7 @@ static void dup_periodic_adv_reset(uint8_t addr_type, const uint8_t *addr, struct dup_ext_adv_set *adv_set; adv_set = &dup_mode->set[set_idx]; - if (adv_set->adi.sid != sid) { + if (PDU_ADV_ADI_SID_GET(&adv_set->adi) != sid) { continue; } @@ -5985,13 +6018,14 @@ static inline bool is_dup_or_update(struct dup_entry *dup, uint8_t adv_type, struct dup_ext_adv_set *adv_set; adv_set = &dup_mode->set[j]; - if (adv_set->adi.sid != adi->sid) { + if (PDU_ADV_ADI_SID_GET(&adv_set->adi) != PDU_ADV_ADI_SID_GET(adi)) { continue; } - if (adv_set->adi.did != adi->did) { + if (PDU_ADV_ADI_DID_GET(&adv_set->adi) != PDU_ADV_ADI_DID_GET(adi)) { /* report different DID */ - adv_set->adi.did = adi->did; + adv_set->adi.did_sid_packed[0] = adi->did_sid_packed[0]; + adv_set->adi.did_sid_packed[1] = adi->did_sid_packed[1]; /* set new data status */ if (data_status == BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE) { adv_set->data_cmplt = 1U; @@ -6372,7 +6406,7 @@ static void le_ext_adv_legacy_report(struct pdu_data *pdu_data, sep->num_reports = 1U; adv_info = (void *)(((uint8_t *)sep) + sizeof(*sep)); - adv_info->evt_type = evt_type_lookup[adv->type]; + adv_info->evt_type = sys_cpu_to_le16((uint16_t)evt_type_lookup[adv->type]); #if defined(CONFIG_BT_CTLR_PRIVACY) if (rl_idx < ll_rl_size_get()) { @@ -6563,7 +6597,7 @@ static void ext_adv_info_fill(uint8_t evt_type, uint8_t phy, uint8_t sec_phy, sep->num_reports = 1U; adv_info = (void *)(((uint8_t *)sep) + sizeof(*sep)); - adv_info->evt_type = evt_type; + adv_info->evt_type = sys_cpu_to_le16((uint16_t)evt_type); if (0) { #if defined(CONFIG_BT_CTLR_PRIVACY) @@ -6586,7 +6620,7 @@ static void ext_adv_info_fill(uint8_t evt_type, uint8_t phy, uint8_t sec_phy, adv_info->prim_phy = find_lsb_set(phy); adv_info->sec_phy = sec_phy; - adv_info->sid = (adi) ? adi->sid : BT_HCI_LE_EXT_ADV_SID_INVALID; + adv_info->sid = (adi) ? PDU_ADV_ADI_SID_GET(adi) : BT_HCI_LE_EXT_ADV_SID_INVALID; adv_info->tx_power = tx_pwr; adv_info->rssi = rssi; adv_info->interval = interval_le16; @@ -6856,8 +6890,8 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, ptr += sizeof(*adi); - LOG_DBG(" AdvDataInfo DID = 0x%x, SID = 0x%x", adi_curr->did, - adi_curr->sid); + LOG_DBG(" AdvDataInfo DID = 0x%x, SID = 0x%x", + PDU_ADV_ADI_DID_GET(adi_curr), PDU_ADV_ADI_SID_GET(adi_curr)); } if (h->aux_ptr) { @@ -6865,7 +6899,14 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, uint8_t aux_phy; aux_ptr = (void *)ptr; - if (PDU_ADV_AUX_PTR_PHY_GET(aux_ptr) > EXT_ADV_AUX_PHY_LE_CODED) { + + /* Don't report if invalid phy or AUX_ADV_IND was not received + * See BT Core 5.4, Vol 6, Part B, Section 4.4.3.5: + * If the Controller does not listen for or does not receive the + * AUX_ADV_IND PDU, no report shall be generated + */ + if ((node_rx_curr == node_rx && !node_rx_next) || + PDU_ADV_AUX_PTR_PHY_GET(aux_ptr) > EXT_ADV_AUX_PHY_LE_CODED) { struct node_rx_ftr *ftr; ftr = &node_rx->hdr.rx_ftr; @@ -6941,6 +6982,19 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, LOG_DBG(" AD Data (%u): ", data_len); } + if (data_len_total + data_len_curr > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { + /* Truncating advertising data + * Note that this has to be done at a PDU boundary, so stop + * processing nodes from this one forward + */ + if (scan_data) { + scan_data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; + } else { + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; + } + break; + } + if (node_rx_curr == node_rx) { evt_type = evt_type_curr; adv_addr_type = adv_addr_type_curr; @@ -7074,16 +7128,6 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, } } - /* Restrict data length to maximum scan data length */ - if (data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { - data_len_total = CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX; - if (data_len > data_len_total) { - data_len = data_len_total; - } - - data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; - } - /* Set directed advertising bit */ if (direct_addr) { evt_type |= BT_HCI_LE_ADV_EVT_TYPE_DIRECT; @@ -7123,16 +7167,6 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, return; } - /* Restrict scan response data length to maximum scan data length */ - if (scan_data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { - scan_data_len_total = CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX; - if (scan_data_len > scan_data_len_total) { - scan_data_len = scan_data_len_total; - } - - scan_data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; - } - /* Set scan response bit */ evt_type |= BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP; diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index b7bfa8c46e7..d4788efa37a 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -20,8 +20,7 @@ #include #include -#include -#include +#include #include #ifdef CONFIG_CLOCK_CONTROL_NRF diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index 9facc5452bc..464fcc94cf9 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -106,6 +106,8 @@ uint8_t ll_adv_enable(uint8_t handle, uint8_t enable, uint8_t ll_adv_enable(uint8_t enable); #endif /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */ +uint8_t ll_adv_disable_all(void); + uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, uint32_t sdu_interval, uint16_t max_sdu, uint16_t max_latency, uint8_t rtn, uint8_t phy, @@ -148,7 +150,7 @@ uint8_t ll_cis_parameters_set(uint8_t cis_id, uint16_t c_sdu, uint16_t p_sdu, uint8_t c_phy, uint8_t p_phy, uint8_t c_rtn, uint8_t p_rtn); -uint8_t ll_cig_parameters_commit(uint8_t cig_id); +uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles); uint8_t ll_cig_parameters_test_open(uint8_t cig_id, uint32_t c_interval, uint32_t p_interval, diff --git a/subsys/bluetooth/controller/include/ll_feat.h b/subsys/bluetooth/controller/include/ll_feat.h index 1ab2cf6c583..1eb2d86a1c3 100644 --- a/subsys/bluetooth/controller/include/ll_feat.h +++ b/subsys/bluetooth/controller/include/ll_feat.h @@ -201,12 +201,8 @@ #if defined(CONFIG_BT_CTLR_ADV_ISO) #define LL_FEAT_BIT_ISO_BROADCASTER BIT64(BT_LE_FEAT_BIT_ISO_BROADCASTER) -#if defined(CONFIG_BT_ISO_TX_MTU) #define LL_BIS_OCTETS_TX_MAX MIN(CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX, \ - CONFIG_BT_ISO_TX_MTU) -#else /* !CONFIG_BT_ISO_TX_MTU */ -#define LL_BIS_OCTETS_TX_MAX CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX -#endif /* !CONFIG_BT_ISO_TX_MTU */ + CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE) #else /* !CONFIG_BT_CTLR_ADV_ISO */ #define LL_FEAT_BIT_ISO_BROADCASTER 0 #define LL_BIS_OCTETS_TX_MAX 0 diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index 5e2db8f7c62..0a500cfd05e 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -13,8 +13,8 @@ #include -#include -#include +#include +#include #include "util/memq.h" @@ -34,10 +34,22 @@ #include -LOG_MODULE_REGISTER(bt_ctlr_isoal, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(bt_ctlr_isoal, LOG_LEVEL_INF); + +#define ISOAL_LOG_DBG(...) LOG_DBG(__VA_ARGS__) + +#if defined(ISOAL_DEBUG_VERBOSE) +#define ISOAL_LOG_DBGV(...) LOG_DBG(__VA_ARGS__) +#else +#define ISOAL_LOG_DBGV(...) (void) 0 +#endif /* ISOAL_DEBUG_VERBOSE */ #include "hal/debug.h" +#define FSM_TO_STR(s) (s == ISOAL_START ? "START" : \ + (s == ISOAL_CONTINUE ? "CONTINUE" : \ + (s == ISOAL_ERR_SPOOL ? "ERR SPOOL" : "???"))) + #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) /* Given the minimum payload, this defines the minimum number of bytes that * should be remaining in a TX PDU such that it would make inserting a new @@ -123,7 +135,61 @@ uint32_t isoal_get_wrapped_time_us(uint32_t time_now_us, int32_t time_diff_us) return result; } +/** + * @brief Check if a time difference calculation is valid and return the difference. + * @param time_before Subtrahend + * @param time_after Minuend + * @param result Difference if valid + * @return Validity - valid if time_after leads time_before with + * consideration for wrapping such that the + * difference can be calculated. + */ +static bool isoal_get_time_diff(uint32_t time_before, uint32_t time_after, uint32_t *result) +{ + bool valid = false; + + LL_ASSERT(time_before <= ISOAL_TIME_WRAPPING_POINT_US); + LL_ASSERT(time_after <= ISOAL_TIME_WRAPPING_POINT_US); + + if (time_before > time_after) { + if (time_before >= ISOAL_TIME_MID_POINT_US && + time_after <= ISOAL_TIME_MID_POINT_US) { + if ((time_before - time_after) <= ISOAL_TIME_SPAN_HALF_US) { + /* Time_before is after time_after and the result is invalid. */ + } else { + /* time_after has wrapped */ + *result = time_after + ISOAL_TIME_SPAN_FULL_US - time_before; + valid = true; + } + } + + /* Time_before is after time_after and the result is invalid. */ + } else { + /* Time_before <= time_after */ + *result = time_after - time_before; + if (*result <= ISOAL_TIME_SPAN_HALF_US) { + /* result is valid if it is within half the maximum + * time span. + */ + valid = true; + } else { + /* time_before has wrapped and the calculation is not + * valid as time_before is ahead of time_after. + */ + } + } + + return valid; +} + #if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) + +#define SET_RX_SDU_TIMESTAMP(_sink, _timestamp, _value) \ + _timestamp = _value; \ + ISOAL_LOG_DBGV("[%p] %s updated (%ld)", _sink, #_timestamp, _value); + +static void isoal_rx_framed_update_sdu_release(struct isoal_sink *sink); + /** * @brief Find free sink from statically-sized pool and allocate it * @details Implemented as linear search since pool is very small @@ -210,6 +276,7 @@ isoal_status_t isoal_sink_create( session->handle = handle; session->framed = framed; session->sdu_interval = sdu_interval; + session->iso_interval = iso_interval; session->burst_number = burst_number; /* Todo: Next section computing various constants, should potentially be a @@ -248,26 +315,28 @@ isoal_status_t isoal_sink_create( * BIG reference anchor point + * BIG_Sync_Delay + SDU_interval + ISO_Interval - Time_Offset. */ - if (role == BT_CONN_ROLE_PERIPHERAL) { - isoal_global.sink_state[*hdl].session.latency_unframed = - stream_sync_delay + ((flush_timeout - 1UL) * iso_interval_us); - - isoal_global.sink_state[*hdl].session.latency_framed = - stream_sync_delay + sdu_interval + (flush_timeout * iso_interval_us); - } else if (role == BT_CONN_ROLE_CENTRAL) { - isoal_global.sink_state[*hdl].session.latency_unframed = - stream_sync_delay - group_sync_delay - - (((iso_interval_us / sdu_interval) - 1UL) * iso_interval_us); - - isoal_global.sink_state[*hdl].session.latency_framed = - stream_sync_delay - group_sync_delay; - } else if (role == BT_ROLE_BROADCAST) { - isoal_global.sink_state[*hdl].session.latency_unframed = - group_sync_delay; - - isoal_global.sink_state[*hdl].session.latency_framed = - group_sync_delay + sdu_interval + iso_interval_us; - + if (role == ISOAL_ROLE_PERIPHERAL) { + if (framed) { + session->sdu_sync_const = stream_sync_delay + sdu_interval + + (flush_timeout * iso_interval_us); + } else { + session->sdu_sync_const = stream_sync_delay + + ((flush_timeout - 1UL) * iso_interval_us); + } + } else if (role == ISOAL_ROLE_CENTRAL) { + if (framed) { + session->sdu_sync_const = stream_sync_delay - group_sync_delay; + } else { + session->sdu_sync_const = stream_sync_delay - group_sync_delay - + (((iso_interval_us / sdu_interval) - 1UL) * + iso_interval_us); + } + } else if (role == ISOAL_ROLE_BROADCAST_SINK) { + if (framed) { + session->sdu_sync_const = group_sync_delay + sdu_interval + iso_interval_us; + } else { + session->sdu_sync_const = group_sync_delay; + } } else { LL_ASSERT(0); } @@ -283,20 +352,6 @@ isoal_status_t isoal_sink_create( return err; } -/** - * @brief Get reference to configuration struct - * - * @param hdl[in] Handle to new sink - * @return Reference to parameter struct, to be configured by caller - */ -struct isoal_sink_config *isoal_get_sink_param_ref(isoal_sink_handle_t hdl) -{ - LL_ASSERT(hdl < CONFIG_BT_CTLR_ISOAL_SINKS); - LL_ASSERT(isoal_global.sink_allocated[hdl] == ISOAL_ALLOC_STATE_TAKEN); - - return &isoal_global.sink_state[hdl].session.param; -} - /** * @brief Atomically enable latch-in of packets and SDU production * @param hdl[in] Handle of existing instance @@ -481,6 +536,9 @@ static isoal_status_t isoal_rx_buffered_emit_sdu(struct isoal_sink *sink, bool e sdu_status.collated_status = sdu_frag.sdu.status; } + ISOAL_LOG_DBG("[%p] SDU %u @TS=%u err=%X len=%u released\n", + sink, sdu_frag.sdu.sn, sdu_frag.sdu.timestamp, + sdu_status.collated_status, sdu_status.total_sdu_size); err |= session->sdu_emit(sink, &sdu_frag, &sdu_status); #if defined(ISOAL_BUFFER_RX_SDUS_ENABLE) @@ -498,12 +556,14 @@ static isoal_status_t isoal_rx_buffered_emit_sdu(struct isoal_sink *sink, bool e static isoal_status_t isoal_rx_try_emit_sdu(struct isoal_sink *sink, bool end_of_sdu) { + struct isoal_sink_session *session; struct isoal_sdu_production *sp; struct isoal_sdu_produced *sdu; isoal_status_t err; err = ISOAL_STATUS_OK; sp = &sink->sdu_production; + session = &sink->session; sdu = &sp->sdu; /* Emit a SDU */ @@ -541,6 +601,12 @@ static isoal_status_t isoal_rx_try_emit_sdu(struct isoal_sink *sink, bool end_of err = isoal_rx_buffered_emit_sdu(sink, end_of_sdu); sp->sdu_allocated = false; + if (end_of_sdu) { + isoal_rx_framed_update_sdu_release(sink); + sp->sdu_status = ISOAL_SDU_STATUS_VALID; + session->sn++; + } + /* update next state */ sink->sdu_production.sdu_state = next_state; } @@ -713,7 +779,7 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, sp->sdu_status = ISOAL_SDU_STATUS_VALID; sp->sdu_state = BT_ISO_START; sp->pdu_cnt = 1; - session->sn++; + sp->only_padding = pdu_padding; seq_err = false; /* The incoming time stamp for each PDU is expected to be the @@ -732,7 +798,7 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, * event that the PDU is associated with. */ anchorpoint = meta->timestamp; - latency = session->latency_unframed; + latency = session->sdu_sync_const; sdu = &sp->sdu; sdu->timestamp = isoal_get_wrapped_time_us(anchorpoint, latency); @@ -759,6 +825,7 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, last_pdu = (sp->pdu_cnt == session->pdus_per_sdu); end_of_packet = (llid == PDU_BIS_LLID_COMPLETE_END) || last_pdu || pdu_err; + sp->only_padding = sp->only_padding && pdu_padding; switch (sp->fsm) { case ISOAL_START: @@ -823,14 +890,29 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, * Host, there is no data and ISO_SDU_Length shall be set to zero. * * (2) Any error status received from the LL via the PDU status should - * set the relevant error conditions. + * set the relevant error conditions + * + * (3) Forcing lost data when receiving only padding PDUs for any SDU * - * (3) Missing end fragment handling. + * https://bluetooth.atlassian.net/browse/ES-22876 + * Request for Clarification - Recombination actions when only + * padding unframed PDUs are received: + * The clarification was to be rejected, but the discussion in the + * comments from March 3rd 2023 were interpretted as "We are + * expecting a PDU which ISOAL should convert into an SDU; + * instead we receive a padding PDU, which we cannot turn into a + * SDU, so the SDU wasn't received at all, and should be reported + * as such". + * + * (4) Missing end fragment handling. */ if (seq_err) { sp->sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; } else if (pdu_err && !pdu_padding) { sp->sdu_status |= meta->status; + } else if (last_pdu && sp->only_padding) { + /* Force lost data if only padding PDUs */ + sp->sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; } else if (last_pdu && (llid != PDU_BIS_LLID_COMPLETE_END) && (sp->fsm != ISOAL_ERR_SPOOL)) { /* END fragment never seen */ @@ -839,9 +921,14 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, /* Append valid PDU to SDU */ if (sp->fsm != ISOAL_ERR_SPOOL && (!pdu_padding || end_of_packet)) { + /* If only padding PDUs are received, an SDU should be released + * as missing (lost data) even if there are no actual errors. + * (Refer to error prioritisation above for details). + */ + bool append_as_padding = pdu_padding && !sp->only_padding; err |= isoal_rx_append_to_sdu(sink, pdu_meta, 0, length, end_of_packet, - pdu_padding); + append_as_padding); } /* Update next state */ @@ -850,6 +937,8 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, sp->prev_pdu_is_end = !pdu_err && llid == PDU_BIS_LLID_COMPLETE_END; sp->prev_pdu_is_padding = !pdu_err && pdu_padding; + sp->initialized = true; + return err; } @@ -876,6 +965,105 @@ static isoal_sdu_status_t isoal_check_seg_header(struct pdu_iso_sdu_sh *seg_hdr, return ISOAL_SDU_STATUS_LOST_DATA; } +/* Check available time reference and release any missing / lost SDUs + * + * Time tracking and release of lost SDUs for framed: + * + * Time tracking is implemented based on using the incoming time-stamps of the + * PDUs, which should correspond to the BIG / CIG reference anchorpoint of the + * current event, to track how time has advanced. The reference used is the + * reconstructed SDU synchronisation reference point. For the CIS peripheral and + * BIS receiver, this reference is ahead of the time-stamp (anchorpoint), + * however for the CIS central this reference will be before (i.e. in the past). + * Where the time offset is not available, an ISO interval is used in place of + * the time offset to create an approximate reference. + * + * This information is in-turn used to decided if SDUs are missing or lost and + * when they should be released. This approach is inherrently bursty with the + * most probable worst case burst being 2 x (ISO interval / SDU Interval) SDUs, + * which would occur when only padding is seen in one event followed by all the + * SDUs from the next event in one PDU. + */ +static isoal_status_t isoal_rx_framed_release_lost_sdus(struct isoal_sink *sink, + const struct isoal_pdu_rx *pdu_meta, + bool timestamp_valid, + uint32_t next_sdu_timestamp) +{ + struct isoal_sink_session *session; + struct isoal_sdu_production *sp; + struct isoal_sdu_produced *sdu; + isoal_status_t err; + uint32_t time_elapsed; + + sp = &sink->sdu_production; + session = &sink->session; + sdu = &sp->sdu; + + err = ISOAL_STATUS_OK; + + if (isoal_get_time_diff(sdu->timestamp, next_sdu_timestamp, &time_elapsed)) { + /* Time elapsed >= 0 */ + uint8_t lost_sdus; + + if (timestamp_valid) { + /* If there is a valid new time reference, then + * calculate the gap between the next SDUs expected + * time stamp and the actual reference, rounding at the + * mid point. + * 0 Next SDU is the SDU that provided the new time + * reference, no lost SDUs + * >0 Number of lost SDUs + */ + lost_sdus = (time_elapsed + (session->sdu_interval / 2)) / + session->sdu_interval; + ISOAL_LOG_DBGV("[%p] Next SDU timestamp (%lu) accurate", + sink, next_sdu_timestamp); + } else { + /* If there is no valid new time reference, then lost + * SDUs should only be released for every full + * SDU interval. This should include consideration that + * the next expected SDU's time stamp is the base for + * time_elapsed (i.e. +1). + */ + ISOAL_LOG_DBGV("[%p] Next SDU timestamp (%lu) approximate", + sink, next_sdu_timestamp); + lost_sdus = time_elapsed ? (time_elapsed / session->sdu_interval) + 1 : 0; + } + + ISOAL_LOG_DBGV("[%p] Releasing %u lost SDUs", sink, lost_sdus); + + while (lost_sdus > 0 && !err) { + sp->sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; + + err = isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); + lost_sdus--; + } + } + + return err; +} + +/* Update time tracking after release of an SDU. + * At present only required for framed PDUs. + */ +static void isoal_rx_framed_update_sdu_release(struct isoal_sink *sink) +{ + struct isoal_sink_session *session; + struct isoal_sdu_production *sp; + struct isoal_sdu_produced *sdu; + uint32_t timestamp; + + sp = &sink->sdu_production; + session = &sink->session; + sdu = &sp->sdu; + + if (session->framed) { + /* Update to the expected release time of the next SDU */ + timestamp = isoal_get_wrapped_time_us(sdu->timestamp, session->sdu_interval); + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + } +} + /** * @brief Consume a framed PDU: Copy contents into SDU(s) and emit to a sink * @details Destination sink may have an already partially built SDU @@ -893,6 +1081,7 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, struct isoal_sdu_produced *sdu; struct pdu_iso_sdu_sh *seg_hdr; struct node_rx_iso_meta *meta; + uint32_t iso_interval_us; uint32_t anchorpoint; uint8_t *end_of_pdu; uint32_t timeoffset; @@ -910,6 +1099,8 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, meta = pdu_meta->meta; sdu = &sp->sdu; + iso_interval_us = session->iso_interval * ISO_INT_UNIT_US; + err = ISOAL_STATUS_OK; next_state = ISOAL_START; pdu_err = (pdu_meta->meta->status != ISOAL_PDU_STATUS_VALID); @@ -932,6 +1123,21 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, seg_hdr = NULL; } + /* Calculate an approximate timestamp */ + timestamp = isoal_get_wrapped_time_us(meta->timestamp, + session->sdu_sync_const - iso_interval_us); + if (!sp->initialized) { + /* This should be the first PDU received in this session */ + /* Initialize a temporary timestamp for the next SDU */ + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + } + + if (pdu_padding && !pdu_err && !seq_err) { + /* Check and release missed SDUs on receiving padding PDUs */ + ISOAL_LOG_DBGV("[%p] Recevied padding", sink); + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, timestamp); + } + while (seg_hdr) { bool append = true; const uint8_t sc = seg_hdr->sc; @@ -940,29 +1146,38 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, if (sp->fsm == ISOAL_START) { sp->sdu_status = ISOAL_SDU_STATUS_VALID; sp->sdu_state = BT_ISO_START; - session->sn++; } + ISOAL_LOG_DBGV("[%p] State %s", sink, FSM_TO_STR(sp->fsm)); switch (sp->fsm) { case ISOAL_START: - timeoffset = seg_hdr->timeoffset; - anchorpoint = meta->timestamp; - latency = session->latency_framed; - timestamp = isoal_get_wrapped_time_us(anchorpoint, latency - timeoffset); - - if (!sc && !cmplt) { - /* The start of a new SDU, where not all SDU data is included in - * the current PDU, and additional PDUs are required to complete - * the SDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_CONTINUE; - } else if (!sc && cmplt) { - /* The start of a new SDU that contains the full SDU data in the - * current PDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_START; + if (!sc) { + /* Start segment, included time-offset */ + timeoffset = seg_hdr->timeoffset; + anchorpoint = meta->timestamp; + latency = session->sdu_sync_const; + timestamp = isoal_get_wrapped_time_us(anchorpoint, + latency - timeoffset); + ISOAL_LOG_DBGV("[%p] Segment Start @TS=%ld", sink, timestamp); + + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, true, + timestamp); + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + + if (cmplt) { + /* The start of a new SDU that contains the full SDU data in + * the current PDU. + */ + ISOAL_LOG_DBGV("[%p] Segment Single", sink); + next_state = ISOAL_START; + } else { + /* The start of a new SDU, where not all SDU data is + * included in the current PDU, and additional PDUs are + * required to complete the SDU. + */ + next_state = ISOAL_CONTINUE; + } + } else { /* Unsupported case */ err = ISOAL_STATUS_ERR_UNSPECIFIED; @@ -975,12 +1190,14 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, * to the previous data and additional PDUs are required to * complete the SDU. */ + ISOAL_LOG_DBGV("[%p] Segment Continue", sink); next_state = ISOAL_CONTINUE; } else if (sc && cmplt) { /* The continuation of a previous SDU. * Frame data is appended to previously received SDU data and * completes in the current PDU. */ + ISOAL_LOG_DBGV("[%p] Segment End", sink); next_state = ISOAL_START; } else { /* Unsupported case */ @@ -990,45 +1207,48 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, case ISOAL_ERR_SPOOL: /* In error state, search for valid next start of SDU */ - timeoffset = seg_hdr->timeoffset; - anchorpoint = meta->timestamp; - latency = session->latency_framed; - timestamp = isoal_get_wrapped_time_us(anchorpoint, latency - timeoffset); - - if (!sc && !cmplt) { - /* The start of a new SDU, where not all SDU data is included in - * the current PDU, and additional PDUs are required to complete - * the SDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_CONTINUE; - } else if (!sc && cmplt) { - /* The start of a new SDU that contains the full SDU data in the - * current PDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_START; + + if (!sc) { + /* Start segment, included time-offset */ + timeoffset = seg_hdr->timeoffset; + anchorpoint = meta->timestamp; + latency = session->sdu_sync_const; + timestamp = isoal_get_wrapped_time_us(anchorpoint, + latency - timeoffset); + ISOAL_LOG_DBGV("[%p] Segment Start @TS=%ld", sink, timestamp); + + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, true, + timestamp); + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + + if (cmplt) { + /* The start of a new SDU that contains the full SDU data + * in the current PDU. + */ + ISOAL_LOG_DBGV("[%p] Segment Single", sink); + next_state = ISOAL_START; + } else { + /* The start of a new SDU, where not all SDU data is + * included in the current PDU, and additional PDUs are + * required to complete the SDU. + */ + next_state = ISOAL_CONTINUE; + } + } else { /* Start not found yet, stay in Error state */ + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, + timestamp); append = false; next_state = ISOAL_ERR_SPOOL; } - /* TODO: Confirm if the sequence number must be updated even for an SDU - * with errors. - * BT Core V5.3 : Vol 6 Low Energy Controller : Part G IS0-AL: - * 2 ISOAL Features : - * The sequence number shall be incremented for each SDU_Interval, - * whether or not an SDU was received from or sent to the upper layer. - */ - if (next_state != ISOAL_ERR_SPOOL) { /* While in the Error state, received a valid start of the next SDU, * so SDU status and sequence number should be updated. */ sp->sdu_status = ISOAL_SDU_STATUS_VALID; /* sp->sdu_state will be set by next_state decided above */ - session->sn++; } break; } @@ -1050,11 +1270,12 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, /* Todo: check if effective len=0 what happens then? * We should possibly be able to send empty packets with only time stamp */ - + ISOAL_LOG_DBGV("[%p] Appending %lu bytes", sink, length); err |= isoal_rx_append_to_sdu(sink, pdu_meta, offset, length, cmplt, false); } /* Update next state */ + ISOAL_LOG_DBGV("[%p] Decoding: Next State %s", sink, FSM_TO_STR(next_state)); sp->fsm = next_state; /* Find next segment header, set to null if past end of PDU */ @@ -1078,6 +1299,7 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, */ next_state = ISOAL_ERR_SPOOL; + /* This maps directly to the HCI ISO Data packet Packet_Status_Flag by way of the * sdu_status in the SDU emitted. * BT Core V5.3 : Vol 4 HCI I/F : Part G HCI Func. Spec.: @@ -1090,41 +1312,48 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, * 0b10 Part(s) of the SDU were not received correctly. This is reported as * "lost data". */ + isoal_sdu_status_t next_sdu_status = ISOAL_SDU_STATUS_VALID; if (seq_err || seg_err) { - sp->sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; + next_sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; } else if (pdu_err) { - sp->sdu_status |= meta->status; + next_sdu_status |= meta->status; } - if (sp->fsm == ISOAL_START) { - /* Sequence number should be incremented if an error - * occurs at the beginning. + switch (sp->fsm) { + case ISOAL_START: + /* First release lost SDUs and then release a new SDU + * with errors. Since we have an SDU to release + * following any lost SDUs, lost SDUs handling should be + * similar to when a valid timestamp exists. */ - session->sn++; + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, true, timestamp); + sp->sdu_status = next_sdu_status; + err |= isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); + break; - if (sdu->timestamp == 0) { - /* Last timestamp is not valid so set an - * approximate timestamp - */ - anchorpoint = meta->timestamp; - latency = session->latency_framed; - timestamp = isoal_get_wrapped_time_us(anchorpoint, latency); + case ISOAL_CONTINUE: + /* If error occurs while an SDU is in production, + * release the SDU with errors and then check for lost + * SDUs. Since the SDU is already in production, the + * time stamp already set should be valid. + */ + sp->sdu_status = next_sdu_status; + err |= isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, timestamp); + break; - sdu->timestamp = timestamp; - } else { - /* Advance the timestamp by an SDU interval */ - sdu->timestamp += session->sdu_interval; - } + case ISOAL_ERR_SPOOL: + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, timestamp); + break; } - /* Flush current SDU with error if any */ - err |= isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); - /* Update next state */ + ISOAL_LOG_DBGV("[%p] Error: Next State %s", sink, FSM_TO_STR(next_state)); sink->sdu_production.fsm = next_state; } sp->prev_pdu_id = meta->payload_number; + sp->initialized = true; return err; } @@ -1156,53 +1385,6 @@ isoal_status_t isoal_rx_pdu_recombine(isoal_sink_handle_t sink_hdl, #endif /* CONFIG_BT_CTLR_SYNC_ISO || CONFIG_BT_CTLR_CONN_ISO */ #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) -/** - * @brief Check if a time difference calculation is valid and return the difference. - * @param time_before Subtrahend - * @param time_after Minuend - * @param result Difference if valid - * @return Validity - valid if time_after leads time_before with - * consideration for wrapping such that the - * difference can be calculated. - */ -static bool isoal_get_time_diff(uint32_t time_before, uint32_t time_after, uint32_t *result) -{ - bool valid = false; - - LL_ASSERT(time_before <= ISOAL_TIME_WRAPPING_POINT_US); - LL_ASSERT(time_after <= ISOAL_TIME_WRAPPING_POINT_US); - - if (time_before > time_after) { - if (time_before >= ISOAL_TIME_MID_POINT_US && - time_after <= ISOAL_TIME_MID_POINT_US) { - if ((time_before - time_after) <= ISOAL_TIME_SPAN_HALF_US) { - /* Time_before is after time_after and the result is invalid. */ - } else { - /* time_after has wrapped */ - *result = time_after + ISOAL_TIME_SPAN_FULL_US - time_before; - valid = true; - } - } - - /* Time_before is after time_after and the result is invalid. */ - } else { - /* Time_before <= time_after */ - *result = time_after - time_before; - if (*result <= ISOAL_TIME_SPAN_HALF_US) { - /* result is valid if it is within half the maximum - * time span. - */ - valid = true; - } else { - /* time_before has wrapped and the calculation is not - * valid as time_before is ahead of time_after. - */ - } - } - - return valid; -} - /** * @brief Find free source from statically-sized pool and allocate it * @details Implemented as linear search since pool is very small @@ -1347,20 +1529,6 @@ isoal_status_t isoal_source_create( return err; } -/** - * @brief Get reference to configuration struct - * - * @param hdl[in] Handle to new source - * @return Reference to parameter struct, to be configured by caller - */ -struct isoal_source_config *isoal_get_source_param_ref(isoal_source_handle_t hdl) -{ - LL_ASSERT(hdl < CONFIG_BT_CTLR_ISOAL_SOURCES); - LL_ASSERT(isoal_global.source_allocated[hdl] == ISOAL_ALLOC_STATE_TAKEN); - - return &isoal_global.source_state[hdl].session.param; -} - /** * @brief Atomically enable latch-in of packets and PDU production * @param hdl[in] Handle of existing instance @@ -1581,8 +1749,9 @@ uint16_t isoal_tx_unframed_get_next_payload_number(isoal_source_handle_t source_ /* Start of a new SDU */ time_diff_valid = false; time_diff = 0; + /* Adjust payload number */ - if (session->sn) { + if (IS_ENABLED(CONFIG_BT_CTLR_ISOAL_SN_STRICT) && session->sn) { /* Not the first SDU in this session, so reference * information should be valid. At this point, the * current payload number should be at the first PDU of @@ -1637,6 +1806,44 @@ uint16_t isoal_tx_unframed_get_next_payload_number(isoal_source_handle_t source_ return sdus_skipped; } +/* NOTE: Use of target_event and grp_ref_point as input from upper layer. + * + * For unframed: + * Before the modification to use the PSN to decide the position of an SDU in a + * stream of SDU, the target event was what was used in deciding the event for + * each SDU. This meant that there would possibly have been skews on the + * receiver for each SDU and we had trouble with LL/CIS/PER/BV-39-C which + * expects clustering within an event. + * + * After the change, the PSN is used to decide the position of an SDU in the + * stream anchored at the first PSN received. However for the first SDU + * (assume that PSN=0), it will be the target event that decides which event + * will be used for the fragmented payloads. Although the same interface from + * the original is retained, the target event and group reference point only + * impacts the event chosen for the first SDU and all subsequent SDUs will be + * decided relative to the first. + * + * The target event and related group reference point is still used to provide + * the ISO-AL with a notion of time, for example when storing information + * required for the TX Sync command. For example if for PSN 4, target event is + * 8 but event 7 is chosen as the correct position for the SDU with PSN 4, the + * group reference point stored is obtained by subtracting an ISO interval from + * the group reference provided with target event 8 to get the BIG/CIG reference + * for event 7. It is also expected that this value is the latest reference and + * is drift compensated. + * + * The PSN alone is not sufficient for this because as far as I am aware, host + * and controller have no common reference time for when CIG/BIG event 0 starts. + * Therefore I would expect it is possible to receive PSN 0 in event 2 for + * example. If the target event provided is event 3, then PSN 0 will be + * fragmented into payloads for event 3 and that will serve as the anchor for + * the stream and subsequent SDUs. If for example target event provided was + * event 2 instead, then it could very well be that PSN 0 might not be + * transmitted as is was received midway through event 2 and the payloads + * expired. If this happens then subsequent SDUs might also all be late for + * their transmission slots as they are positioned relative to PSN 0. + */ + /** * @brief Fragment received SDU and produce unframed PDUs * @details Destination source may have an already partially built PDU @@ -1720,9 +1927,10 @@ static isoal_status_t isoal_tx_unframed_produce(isoal_source_handle_t source_hdl * this seems to be the best candidate. */ if (actual_event != tx_sdu->target_event) { - actual_grp_ref_point = isoal_get_wrapped_time_us(tx_sdu->grp_ref_point, - ((actual_event - tx_sdu->target_event) * session->iso_interval * - ISO_INT_UNIT_US)); + actual_grp_ref_point = + isoal_get_wrapped_time_us(tx_sdu->grp_ref_point, + (actual_event - tx_sdu->target_event) * + session->iso_interval * ISO_INT_UNIT_US); } /* Store timing info for TX Sync command */ diff --git a/subsys/bluetooth/controller/ll_sw/isoal.h b/subsys/bluetooth/controller/ll_sw/isoal.h index f6a69e236f6..44f3504f1a6 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.h +++ b/subsys/bluetooth/controller/ll_sw/isoal.h @@ -4,10 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include - #if defined(CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS) && (CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0) #define ISOAL_BUFFER_RX_SDUS_ENABLE #endif /* CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0 */ @@ -24,7 +20,10 @@ typedef uint8_t isoal_status_t; #define ISOAL_STATUS_ERR_PDU_EMIT ((isoal_status_t) 0x20) /* PDU emission */ #define ISOAL_STATUS_ERR_UNSPECIFIED ((isoal_status_t) 0x80) /* Unspecified error */ -#define BT_ROLE_BROADCAST (BT_CONN_ROLE_PERIPHERAL + 1) +#define ISOAL_ROLE_CENTRAL (BT_CONN_ROLE_CENTRAL) +#define ISOAL_ROLE_PERIPHERAL (BT_CONN_ROLE_PERIPHERAL) +#define ISOAL_ROLE_BROADCAST_SOURCE (BT_CONN_ROLE_PERIPHERAL + 1U) +#define ISOAL_ROLE_BROADCAST_SINK (BT_CONN_ROLE_PERIPHERAL + 2U) /** Handle to a registered ISO Sub-System sink */ typedef uint8_t isoal_sink_handle_t; @@ -247,25 +246,18 @@ typedef isoal_status_t (*isoal_sink_sdu_write_cb)( const size_t consume_len ); - -struct isoal_sink_config { - enum isoal_mode mode; - /* TODO add SDU and PDU max length etc. */ -}; - struct isoal_sink_session { isoal_sink_sdu_alloc_cb sdu_alloc; isoal_sink_sdu_emit_cb sdu_emit; isoal_sink_sdu_write_cb sdu_write; - struct isoal_sink_config param; isoal_sdu_cnt_t sn; uint16_t handle; + uint16_t iso_interval; uint8_t pdus_per_sdu; uint8_t framed; uint8_t burst_number; uint32_t sdu_interval; - uint32_t latency_unframed; - uint32_t latency_framed; + uint32_t sdu_sync_const; }; struct isoal_sdu_production { @@ -282,7 +274,10 @@ struct isoal_sdu_production { /* Assumes that isoal_pdu_cnt_t is a uint64_t bit field */ uint64_t prev_pdu_is_end:1; uint64_t prev_pdu_is_padding:1; + /* Indicates that only padding PDUs have been received for this SDU */ + uint64_t only_padding:1; uint64_t sdu_allocated:1; + uint64_t initialized:1; enum { ISOAL_START, ISOAL_CONTINUE, @@ -363,18 +358,12 @@ typedef isoal_status_t (*isoal_source_pdu_emit_cb)( const uint16_t handle ); -struct isoal_source_config { - enum isoal_mode mode; - /* TODO add SDU and PDU max length etc. */ -}; - struct isoal_source_session { isoal_source_pdu_alloc_cb pdu_alloc; isoal_source_pdu_write_cb pdu_write; isoal_source_pdu_emit_cb pdu_emit; isoal_source_pdu_release_cb pdu_release; - struct isoal_source_config param; isoal_sdu_cnt_t sn; uint16_t last_input_sn; uint32_t last_input_time_stamp; @@ -442,8 +431,6 @@ isoal_status_t isoal_sink_create(uint16_t handle, isoal_sink_sdu_write_cb sdu_write, isoal_sink_handle_t *hdl); -struct isoal_sink_config *isoal_get_sink_param_ref(isoal_sink_handle_t hdl); - void isoal_sink_enable(isoal_sink_handle_t hdl); void isoal_sink_disable(isoal_sink_handle_t hdl); @@ -480,8 +467,6 @@ isoal_status_t isoal_source_create(uint16_t handle, isoal_source_pdu_release_cb pdu_release, isoal_source_handle_t *hdl); -struct isoal_source_config *isoal_get_source_param_ref(isoal_source_handle_t hdl); - void isoal_source_enable(isoal_source_handle_t hdl); void isoal_source_disable(isoal_source_handle_t hdl); diff --git a/subsys/bluetooth/controller/ll_sw/ll_addr.c b/subsys/bluetooth/controller/ll_sw/ll_addr.c index 2cb0f6381b1..096bec6638f 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_addr.c +++ b/subsys/bluetooth/controller/ll_sw/ll_addr.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ll_feat.c b/subsys/bluetooth/controller/ll_sw/ll_feat.c index 53c69aaf6b4..a1aaa99ba6d 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_feat.c +++ b/subsys/bluetooth/controller/ll_sw/ll_feat.c @@ -26,7 +26,7 @@ #include "ll_feat.h" #include "ll_settings.h" -#include +#include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/ll_settings.c b/subsys/bluetooth/controller/ll_sw/ll_settings.c index 75723e4cf62..6ca3bb67375 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_settings.c +++ b/subsys/bluetooth/controller/ll_sw/ll_settings.c @@ -4,12 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - #include -#include - #include "ll_settings.h" #include diff --git a/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c b/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c index c46b6b39969..3bafb7b3a34 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c +++ b/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 4f988ae3fb8..d2e23a5a7bb 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -15,11 +15,6 @@ #define TICKER_USER_ID_THREAD MAYFLY_CALL_ID_PROGRAM #define EVENT_PIPELINE_MAX 7 -#if defined(CONFIG_BT_CTLR_LOW_LAT_ULL) -#define EVENT_DONE_LINK_CNT 0 -#else -#define EVENT_DONE_LINK_CNT 1 -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ #define ADV_INT_UNIT_US 625U #define SCAN_INT_UNIT_US 625U @@ -186,6 +181,9 @@ enum { #else /* !CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_CTLR_SYNC_ISO */ #define BT_CTLR_CONN_ISO_STREAM_HANDLE_BASE (CONFIG_BT_MAX_CONN) #endif /* !CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_CTLR_SYNC_ISO */ +#define LL_CIS_HANDLE_BASE (BT_CTLR_CONN_ISO_STREAM_HANDLE_BASE) +#define LL_CIS_IDX_FROM_HANDLE(handle) \ + ((handle) - LL_CIS_HANDLE_BASE) #endif /* CONFIG_BT_CTLR_CONN_ISO */ #define TICKER_ID_ULL_BASE ((TICKER_ID_LLL_PREEMPT) + 1) @@ -316,6 +314,8 @@ enum node_rx_type { NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT, NODE_RX_TYPE_IQ_SAMPLE_REPORT_ULL_RELEASE, NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE, + /* Signals retention (ie non-release) of rx node */ + NODE_RX_TYPE_RETAIN, #if defined(CONFIG_BT_CTLR_USER_EXT) /* No entries shall be added after the NODE_RX_TYPE_USER_START/END */ @@ -593,9 +593,7 @@ void *ull_pdu_rx_alloc(void); void *ull_iso_pdu_rx_alloc_peek(uint8_t count); void *ull_iso_pdu_rx_alloc(void); void ull_rx_put(memq_link_t *link, void *rx); -void ull_rx_put_done(memq_link_t *link, void *done); void ull_rx_sched(void); -void ull_rx_sched_done(void); void ull_rx_put_sched(memq_link_t *link, void *rx); void ull_iso_rx_put(memq_link_t *link, void *rx); void ull_iso_rx_sched(void); diff --git a/subsys/bluetooth/controller/ll_sw/lll_adv.h b/subsys/bluetooth/controller/ll_sw/lll_adv.h index cb74ccb93ed..21723dfeb2f 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_adv.h +++ b/subsys/bluetooth/controller/ll_sw/lll_adv.h @@ -82,9 +82,11 @@ struct lll_adv_iso { uint8_t giv[8]; struct ccm ccm_tx; +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) /* contains the offset in ticks from the adv_sync pointing to this ISO */ uint32_t ticks_sync_pdu_offset; uint16_t iso_lazy; +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ uint16_t stream_handle[BT_CTLR_ADV_ISO_STREAM_MAX]; }; @@ -115,9 +117,11 @@ struct lll_adv_sync { struct pdu_adv *last_pdu; #endif /* CONFIG_BT_CTLR_ADV_PDU_LINK */ +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) /* contains the offset in us from adv_aux pointing to this sync */ uint32_t us_adv_sync_pdu_offset; uint16_t sync_lazy; +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ #if defined(CONFIG_BT_CTLR_ADV_ISO) struct lll_adv_iso *iso; diff --git a/subsys/bluetooth/controller/ll_sw/lll_adv_sync.h b/subsys/bluetooth/controller/ll_sw/lll_adv_sync.h index 661bbe2cd6f..af81b2c80b8 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_adv_sync.h +++ b/subsys/bluetooth/controller/ll_sw/lll_adv_sync.h @@ -8,6 +8,6 @@ int lll_adv_sync_init(void); int lll_adv_sync_reset(void); void lll_adv_sync_prepare(void *param); -extern uint16_t ull_adv_sync_lll_handle_get(struct lll_adv_sync *lll); +extern uint16_t ull_adv_sync_lll_handle_get(const struct lll_adv_sync *lll); extern void ull_adv_sync_lll_syncinfo_fill(struct pdu_adv *pdu, struct lll_adv_aux *lll_aux); diff --git a/subsys/bluetooth/controller/ll_sw/lll_chan.c b/subsys/bluetooth/controller/ll_sw/lll_chan.c index 3d66bbb5429..213fce38a8f 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_chan.c +++ b/subsys/bluetooth/controller/ll_sw/lll_chan.c @@ -5,6 +5,7 @@ */ #include +#include #include "hal/ccm.h" #include "hal/radio.h" diff --git a/subsys/bluetooth/controller/ll_sw/lll_chan.h b/subsys/bluetooth/controller/ll_sw/lll_chan.h index 6105cb6abf8..bfac6b40dfa 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_chan.h +++ b/subsys/bluetooth/controller/ll_sw/lll_chan.h @@ -4,17 +4,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -uint8_t lll_chan_sel_1(uint8_t *chan_use, uint8_t hop, uint16_t latency, uint8_t *chan_map, - uint8_t chan_count); +uint8_t lll_chan_sel_1(uint8_t *chan_use, uint8_t hop, uint16_t latency, + uint8_t *chan_map, uint8_t chan_count); uint16_t lll_chan_id(uint8_t *access_addr); uint8_t lll_chan_sel_2(uint16_t counter, uint16_t chan_id, uint8_t *chan_map, - uint8_t chan_count); + uint8_t chan_count); uint8_t lll_chan_iso_event(uint16_t counter, uint16_t chan_id, - uint8_t *chan_map, uint8_t chan_count, + const uint8_t *chan_map, uint8_t chan_count, uint16_t *prn_s, uint16_t *remap_idx); -uint8_t lll_chan_iso_subevent(uint16_t chan_id, uint8_t *chan_map, +uint8_t lll_chan_iso_subevent(uint16_t chan_id, const uint8_t *chan_map, uint8_t chan_count, uint16_t *prn_subevent_lu, uint16_t *remap_idx); diff --git a/subsys/bluetooth/controller/ll_sw/lll_common.c b/subsys/bluetooth/controller/ll_sw/lll_common.c index a91e933b402..ed35b4ddd08 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_common.c +++ b/subsys/bluetooth/controller/ll_sw/lll_common.c @@ -38,6 +38,8 @@ int lll_prepare(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, lll_prepare_cb_t prepare_cb, int8_t event_prio, struct lll_prepare_param *prepare_param) { + int err; + #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) int prio = event_prio; struct lll_hdr *hdr = prepare_param->param; @@ -60,20 +62,20 @@ int lll_prepare(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, prepare_param->prio = prio; #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ - return lll_prepare_resolve(is_abort_cb, abort_cb, prepare_cb, - prepare_param, 0, 0); + err = lll_prepare_resolve(is_abort_cb, abort_cb, prepare_cb, prepare_param, 0U, 0U); + + return err; } void lll_resume(void *param) { struct lll_event *next; - int ret; + int err; next = param; - ret = lll_prepare_resolve(next->is_abort_cb, next->abort_cb, - next->prepare_cb, &next->prepare_param, - next->is_resume, 1); - LL_ASSERT(!ret || ret == -EINPROGRESS); + err = lll_prepare_resolve(next->is_abort_cb, next->abort_cb, next->prepare_cb, + &next->prepare_param, next->is_resume, 1U); + LL_ASSERT(!err || err == -EINPROGRESS); } #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h index ea9f9749fe3..7fdf6bf48d5 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h @@ -4,6 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define LLL_CIS_FLUSH_NONE 0 +#define LLL_CIS_FLUSH_PENDING 1 +#define LLL_CIS_FLUSH_COMPLETE 2 + struct lll_conn_iso_stream_rxtx { uint64_t payload_count:39; /* cisPayloadCounter */ uint64_t phy_flags:1; /* S2 or S8 coding scheme */ @@ -12,6 +16,8 @@ struct lll_conn_iso_stream_rxtx { uint64_t bn:4; /* Burst number (BN) */ uint64_t phy:3; /* PHY */ uint64_t rfu:1; + uint8_t bn_curr:4; /* Current burst number */ + #if defined(CONFIG_BT_CTLR_LE_ENC) struct ccm ccm; @@ -39,11 +45,20 @@ struct lll_conn_iso_stream { uint8_t sn:1; /* Sequence number */ uint8_t nesn:1; /* Next expected sequence number */ uint8_t cie:1; /* Close isochronous event */ - uint8_t empty:1; /* 1 if CIS LLL has Tx-ed empty PDU */ - uint8_t flushed:1; /* 1 if CIS LLL has been flushed */ + uint8_t npi:1; /* 1 if CIS LLL has Tx-ed Null PDU Indicator */ + uint8_t flush:2; /* See states LLL_CIS_FLUSH_XXX */ uint8_t active:1; /* 1 if CIS LLL is active */ uint8_t datapath_ready_rx:1;/* 1 if datapath for RX is ready */ +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + /* Lazy at CIS active. Number of previously skipped CIG events that is + * determined when CIS is made active and subtracted from total CIG + * events that where skipped when this CIS gets to use radio for the + * first time. + */ + uint16_t lazy_active; +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + /* Resumption information */ uint8_t next_subevent; /* Next subevent to schedule */ @@ -53,6 +68,8 @@ struct lll_conn_iso_stream { memq_link_t *link_tx_free; }; +#define LLL_CONN_ISO_EVENT_COUNT_MAX BIT64_MASK(39) + struct lll_conn_iso_group { struct lll_hdr hdr; @@ -61,6 +78,10 @@ struct lll_conn_iso_group { uint8_t role:1; /* 0: CENTRAL, 1: PERIPHERAL*/ uint8_t paused:1; /* 1: CIG is paused */ + /* Accumulates LLL prepare callback latencies */ + uint16_t latency_prepare; + uint16_t latency_event; + /* Resumption information */ uint16_t resume_cis; /* CIS handle to schedule at resume */ @@ -93,6 +114,7 @@ ull_conn_iso_lll_stream_get_by_group(struct lll_conn_iso_group *cig_lll, uint16_t *handle_iter); extern struct lll_conn_iso_group * ull_conn_iso_lll_group_get_by_stream(struct lll_conn_iso_stream *cis_lll); +extern struct lll_conn_iso_stream *ull_conn_iso_lll_stream_get(uint16_t handle); extern void ull_conn_iso_lll_cis_established(struct lll_conn_iso_stream *cis_lll); extern void ll_iso_rx_put(memq_link_t *link, void *rx); diff --git a/subsys/bluetooth/controller/ll_sw/lll_filter.h b/subsys/bluetooth/controller/ll_sw/lll_filter.h index e3c1d0e7906..e319d6251eb 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_filter.h +++ b/subsys/bluetooth/controller/ll_sw/lll_filter.h @@ -86,6 +86,12 @@ struct lll_prpa_cache { uint8_t taken:1; bt_addr_t rpa; }; + +/* Cache of known unknown target RPAs */ +struct lll_trpa_cache { + uint8_t rl_idx; + bt_addr_t rpa; +}; #endif extern uint8_t ull_filter_lll_fal_match(struct lll_filter const *const filter, @@ -111,6 +117,7 @@ extern bool ull_filter_lll_rl_addr_resolve(uint8_t id_addr_type, extern bool ull_filter_lll_rl_enabled(void); #if defined(CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY) extern const struct lll_prpa_cache *ull_filter_lll_prpa_cache_get(void); +extern const struct lll_trpa_cache *ull_filter_lll_trpa_cache_get(void); typedef void (*resolve_callback_t)(void *param); extern uint8_t ull_filter_deferred_resolve(bt_addr_t *rpa, resolve_callback_t cb); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c index c566a86c3ab..01adf92467d 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c @@ -5,8 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - #include #include "hal/cntr.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h index 34cef5f9f69..93229080688 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h @@ -33,6 +33,7 @@ #define DEBUG_PIN9 BIT(DEBUG_PIN_IDX9) #if defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP) || \ (defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP_NS) && defined(CONFIG_BUILD_WITH_TFM)) +#include #define DEBUG_SETUP() \ do { \ soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX0, NRF_GPIO_PIN_SEL_NETWORK); \ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c index 82d12aebcde..fe3618bf340 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c @@ -7,8 +7,6 @@ #include -#include - #include #include "util/mem.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h index c621d01e5d9..a84e14cb9fb 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h @@ -3,6 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +#include "../radio/radio_nrf5_resources.h" #include "../radio/radio_nrf5_fem.h" #ifdef DPPI_PRESENT diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c index 1af23246bd6..7b72b1a4b93 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c @@ -5,13 +5,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include #include #include #include +#include #include #include @@ -445,7 +445,9 @@ void radio_pkt_configure(uint8_t bits_len, uint8_t max_len, uint8_t flags) /* To use same Data Channel PDU structure with nRF5 specific overhead * byte, include the S1 field in radio packet configuration. */ - if (pdu_type == RADIO_PKT_CONF_PDU_TYPE_DC) { + if ((pdu_type == RADIO_PKT_CONF_PDU_TYPE_DC) || + (pdu_type == RADIO_PKT_CONF_PDU_TYPE_BIS) || + (pdu_type == RADIO_PKT_CONF_PDU_TYPE_CIS)) { extra |= (RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos) & RADIO_PCNF0_S1INCL_Msk; #if defined(CONFIG_BT_CTLR_DF) @@ -592,7 +594,7 @@ static uint32_t last_pdu_end_us; uint32_t radio_is_done(void) { - if (NRF_RADIO->EVENTS_END != 0) { + if (NRF_RADIO->NRF_RADIO_TXRX_END_EVENT != 0) { /* On packet END event increment last packet end time value. * Note: this depends on the function being called exactly once * in the ISR function. @@ -1643,7 +1645,7 @@ void radio_gpio_pa_lna_disable(void) static uint8_t MALIGN(4) _ccm_scratch[(HAL_RADIO_PDU_LEN_MAX - 4) + 16]; -void *radio_ccm_rx_pkt_set(struct ccm *ccm, uint8_t phy, void *pkt) +static void *radio_ccm_ext_rx_pkt_set(struct ccm *cnf, uint8_t phy, uint8_t pdu_type, void *pkt) { uint32_t mode; @@ -1726,8 +1728,23 @@ void *radio_ccm_rx_pkt_set(struct ccm *ccm, uint8_t phy, void *pkt) NRF_CCM->MAXPACKETSIZE = max_len - 4U; #endif +#if defined(CONFIG_HAS_HW_NRF_CCM_HEADERMASK) + switch (pdu_type) { + case RADIO_PKT_CONF_PDU_TYPE_BIS: + NRF_CCM->HEADERMASK = 0xC3; /* mask CSSN and CSTF */ + break; + case RADIO_PKT_CONF_PDU_TYPE_CIS: + NRF_CCM->HEADERMASK = 0xA3; /* mask SN, NESN, CIE and NPI */ + break; + default: + /* Using default reset value of HEADERMASK */ + NRF_CCM->HEADERMASK = 0xE3; /* mask SN, NESN and MD */ + break; + } +#endif /* CONFIG_HAS_HW_NRF_CCM_HEADERMASK */ + NRF_CCM->MODE = mode; - NRF_CCM->CNFPTR = (uint32_t)ccm; + NRF_CCM->CNFPTR = (uint32_t)cnf; NRF_CCM->INPTR = (uint32_t)_pkt_scratch; NRF_CCM->OUTPTR = (uint32_t)pkt; NRF_CCM->SCRATCHPTR = (uint32_t)_ccm_scratch; @@ -1741,7 +1758,17 @@ void *radio_ccm_rx_pkt_set(struct ccm *ccm, uint8_t phy, void *pkt) return _pkt_scratch; } -void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt) +void *radio_ccm_rx_pkt_set(struct ccm *cnf, uint8_t phy, void *pkt) +{ + return radio_ccm_ext_rx_pkt_set(cnf, phy, RADIO_PKT_CONF_PDU_TYPE_DC, pkt); +} + +void *radio_ccm_iso_rx_pkt_set(struct ccm *cnf, uint8_t phy, uint8_t pdu_type, void *pkt) +{ + return radio_ccm_ext_rx_pkt_set(cnf, phy, pdu_type, pkt); +} + +static void *radio_ccm_ext_tx_pkt_set(struct ccm *cnf, uint8_t pdu_type, void *pkt) { uint32_t mode; @@ -1772,8 +1799,23 @@ void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt) NRF_CCM->MAXPACKETSIZE = max_len - 4U; #endif +#if defined(CONFIG_HAS_HW_NRF_CCM_HEADERMASK) + switch (pdu_type) { + case RADIO_PKT_CONF_PDU_TYPE_BIS: + NRF_CCM->HEADERMASK = 0xC3; /* mask CSSN and CSTF */ + break; + case RADIO_PKT_CONF_PDU_TYPE_CIS: + NRF_CCM->HEADERMASK = 0xA3; /* mask SN, NESN, CIE and NPI */ + break; + default: + /* Using default reset value of HEADERMASK */ + NRF_CCM->HEADERMASK = 0xE3; /* mask SN, NESN and MD */ + break; + } +#endif /* CONFIG_HAS_HW_NRF_CCM_HEADERMASK */ + NRF_CCM->MODE = mode; - NRF_CCM->CNFPTR = (uint32_t)ccm; + NRF_CCM->CNFPTR = (uint32_t)cnf; NRF_CCM->INPTR = (uint32_t)pkt; NRF_CCM->OUTPTR = (uint32_t)_pkt_scratch; NRF_CCM->SCRATCHPTR = (uint32_t)_ccm_scratch; @@ -1787,6 +1829,16 @@ void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt) return _pkt_scratch; } +void *radio_ccm_tx_pkt_set(struct ccm *cnf, void *pkt) +{ + return radio_ccm_ext_tx_pkt_set(cnf, RADIO_PKT_CONF_PDU_TYPE_DC, pkt); +} + +void *radio_ccm_iso_tx_pkt_set(struct ccm *cnf, uint8_t pdu_type, void *pkt) +{ + return radio_ccm_ext_tx_pkt_set(cnf, pdu_type, pkt); +} + uint32_t radio_ccm_is_done(void) { nrf_ccm_int_enable(NRF_CCM, CCM_INTENSET_ENDCRYPT_Msk); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h index 93ad9272d1a..600d7e95481 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h @@ -6,25 +6,25 @@ */ /* Set of macros related with Radio packet configuration flags */ -/* PDU type, 1 bit field*/ +/* PDU type, 2 bit field*/ #define RADIO_PKT_CONF_PDU_TYPE_POS (0U) -#define RADIO_PKT_CONF_PDU_TYPE_MSK BIT(RADIO_PKT_CONF_PDU_TYPE_POS) +#define RADIO_PKT_CONF_PDU_TYPE_MSK (BIT_MASK(2U)) #define RADIO_PKT_CONF_PDU_TYPE_AC (0U) #define RADIO_PKT_CONF_PDU_TYPE_DC (1U) -#define RADIO_PKT_CONF_PDU_TYPE_BIS (1U) -#define RADIO_PKT_CONF_PDU_TYPE_CIS (1U) +#define RADIO_PKT_CONF_PDU_TYPE_BIS (2U) +#define RADIO_PKT_CONF_PDU_TYPE_CIS (3U) /* PHY type, three bit field */ -#define RADIO_PKT_CONF_PHY_POS (1U) -#define RADIO_PKT_CONF_PHY_MSK (BIT_MASK(3U)) -#define RADIO_PKT_CONF_PHY_LEGACY (0U) -#define RADIO_PKT_CONF_PHY_1M (BIT(0U)) -#define RADIO_PKT_CONF_PHY_2M (BIT(1U)) -#define RADIO_PKT_CONF_PHY_CODED (BIT(2U)) +#define RADIO_PKT_CONF_PHY_POS (2U) +#define RADIO_PKT_CONF_PHY_MSK (BIT_MASK(3U)) +#define RADIO_PKT_CONF_PHY_LEGACY (0U) +#define RADIO_PKT_CONF_PHY_1M (BIT(0U)) +#define RADIO_PKT_CONF_PHY_2M (BIT(1U)) +#define RADIO_PKT_CONF_PHY_CODED (BIT(2U)) /* CTE enabled, 1 bit field */ -#define RADIO_PKT_CONF_CTE_POS (4U) -#define RADIO_PKT_CONF_CTE_MSK BIT(0) +#define RADIO_PKT_CONF_CTE_POS (5U) +#define RADIO_PKT_CONF_CTE_MSK (BIT_MASK(1U)) #define RADIO_PKT_CONF_CTE_DISABLED (0U) -#define RADIO_PKT_CONF_CTE_ENABLED (1U) +#define RADIO_PKT_CONF_CTE_ENABLED (1U) /* Macro to define length of the BLE packet length field in bits */ #define RADIO_PKT_CONF_LENGTH_8BIT (8U) @@ -164,7 +164,9 @@ void radio_gpio_pa_lna_enable(uint32_t trx_us); void radio_gpio_pa_lna_disable(void); void *radio_ccm_rx_pkt_set(struct ccm *ccm, uint8_t phy, void *pkt); +void *radio_ccm_iso_rx_pkt_set(struct ccm *ccm, uint8_t phy, uint8_t pdu_type, void *pkt); void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt); +void *radio_ccm_iso_tx_pkt_set(struct ccm *ccm, uint8_t pdu_type, void *pkt); uint32_t radio_ccm_is_done(void); uint32_t radio_ccm_mic_is_valid(void); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h index 88a0f048d4f..a03e55f519d 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h @@ -5,38 +5,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define HAL_RADIO_NS2US_CEIL(ns) ((ns + 999)/1000) -#define HAL_RADIO_NS2US_ROUND(ns) ((ns + 500)/1000) - -/* Use the timer instance ID, not NRF_TIMERx directly, so that it can be checked - * in radio_nrf5_ppi.h by the preprocessor. - */ -#define EVENT_TIMER_ID 0 -#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - */ -#define NRF_RADIO_TXRX_END_EVENT EVENTS_END -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. - * This is a default shortcut used to automatically disable Radio after end of PDU. - */ -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk +#include -/* Delay of EVENTS_PHYEND event on receive PDU without CTE inclded when CTEINLINE is enabled */ -#define RADIO_EVENTS_PHYEND_DELAY_US 16 +/* Common radio resources */ +#include "radio_nrf5_resources.h" -/* Delay of CCM TASKS_CRYPT start in number of bits for Radio Bit counter */ -#define CCM_TASKS_CRYPT_DELAY_BITS 3 - -/* EVENTS_TIMER capture register used for sampling TIMER time-stamps. */ -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 - -/* Define to reset PPI registration */ -#define NRF_PPI_NONE 0 +/* Helpers for radio timing conversions */ +#define HAL_RADIO_NS2US_CEIL(ns) ((ns + 999)/1000) +#define HAL_RADIO_NS2US_ROUND(ns) ((ns + 500)/1000) +/* SoC specific defines */ #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) #include "radio_sim_nrfxx.h" #elif defined(CONFIG_SOC_SERIES_NRF51X) @@ -54,7 +32,6 @@ #elif defined(CONFIG_SOC_NRF52833) #include "radio_nrf52833.h" #elif defined(CONFIG_SOC_NRF52840) -#include #include "radio_nrf52840.h" #elif defined(CONFIG_SOC_NRF5340_CPUNET) #include @@ -63,20 +40,23 @@ #error "Unsupported SoC." #endif -#if defined(CONFIG_SOC_SERIES_NRF51X) -#define HAL_RADIO_PDU_LEN_MAX (BIT(5) - 1) -#else -#define HAL_RADIO_PDU_LEN_MAX (BIT(8) - 1) -#endif - -#include +/* Define to reset PPI registration */ +#define NRF_PPI_NONE 0 /* This has to come before the ppi/dppi includes below. */ #include "radio_nrf5_fem.h" #if defined(PPI_PRESENT) +#include +#include "radio_nrf5_ppi_resources.h" #include "radio_nrf5_ppi.h" #elif defined(DPPI_PRESENT) +#include +#include +#include +#include +#include +#include "radio_nrf5_dppi_resources.h" #include "radio_nrf5_dppi.h" #else #error "PPI or DPPI abstractions missing." @@ -84,6 +64,13 @@ #include "radio_nrf5_txp.h" +/* SoC specific Radio PDU length field maximum value */ +#if defined(CONFIG_SOC_SERIES_NRF51X) +#define HAL_RADIO_PDU_LEN_MAX (BIT(5) - 1) +#else +#define HAL_RADIO_PDU_LEN_MAX (BIT(8) - 1) +#endif + /* Common NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h index c73ed742b6d..c1e27087150 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h @@ -5,11 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* TXEN->TXIDLE + TXIDLE->TX in microseconds. */ #define HAL_RADIO_NRF51_TXEN_TXIDLE_TX_US 140 #define HAL_RADIO_NRF51_TXEN_TXIDLE_TX_NS 140000 diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h index 77999d43028..93d2215e954 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h @@ -179,19 +179,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ - -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* TODO: Add any required setup for each radio event diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h index f4d82fae7f7..9e03963ae6c 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h @@ -181,18 +181,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* nRF52810 itself is not affected with these anomalies but it might be diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h index c09910b6cba..1247f6e69c0 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h @@ -336,57 +336,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extensio at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in - * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Use NRF_TIMER3 for PHYEND delay compensation because it has 6 channels available. - * In other cases NRF_TIMER1 with its 4 channels is enough. - */ -#define SW_SWITCH_TIMER NRF_TIMER3 -/* Allocate 2 adjacent channels for PHYEND delay compensation. Channels 4 and 5 will be used for it. - * It must be two channels because Radio TX/RX mode SW SWITCH uses two channels. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 4 -#else /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* SoC specific NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h index 667570bc4c4..33ba6fa1654 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h @@ -336,57 +336,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extensio at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in - * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Use NRF_TIMER3 for PHYEND delay compensation because it has 6 channels available. - * In other cases NRF_TIMER1 with its 4 channels is enough. - */ -#define SW_SWITCH_TIMER NRF_TIMER3 -/* Allocate 2 adjacent channels for PHYEND delay compensation. Channels 4 and 5 will be used for it. - * It must be two channels because Radio TX/RX mode SW SWITCH uses two channels. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 4 -#else /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* SoC specific NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h index 0a5f00a0b26..a5df5fe1cce 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h @@ -182,18 +182,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { if (nrf52_errata_102() || nrf52_errata_106() || nrf52_errata_107()) { diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h index d613382e236..18b53976d97 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h @@ -336,57 +336,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extension at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in - * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Use NRF_TIMER3 for PHYEND delay compensation because it has 6 channels available. - * In other cases NRF_TIMER1 with its 4 channels is enough. - */ -#define SW_SWITCH_TIMER NRF_TIMER3 -/* Allocate 2 adjacent channels for PHYEND delay compensation. Channels 4 and 5 will be used for it. - * It must be two channels because Radio TX/RX mode SW SWITCH uses two channels. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 4 -#else /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* SoC specific NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h index a169987437e..98fe83ebea7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /* NRF Radio HW timing constants * - provided in US and NS (for higher granularity) * - based on empirical measurements and sniffer logs @@ -337,25 +339,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* TODO: Add any required setup for each radio event diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h index 9e9015dc8c8..e0f43014508 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h @@ -337,56 +337,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 0 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extension at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU, after CTE is received or - * transmitted. In case there is no CTE in a PDU the EVENTS_PHYEND event is generated in the same - * instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Allocate 2 adjacent channels for PHYEND delay compensation. Use the same channels as for - * PHY CODED S2. The CTEINLINE may not be enabled for PHY CODED so PHYEND event is generated - * at the same instant as END event. Hence the channels are uesed interchangeably. - * That saves from use of another timer. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 2 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ - -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* nRF5340 supports +3dBm Tx Power using high voltage request, define +3dBm * value for Controller use. */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h index 7295f0e8d05..71e5ffa0e6f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h @@ -4,17 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#if defined(CONFIG_SOC_NRF5340_CPUNET) || defined(DPPI_PRESENT) - -#include -#include -#include -#include -#include -#include -#include - -#include "radio_nrf5_dppi_resources.h" static inline void hal_radio_nrf_ppi_channels_enable(uint32_t mask) { @@ -32,27 +21,35 @@ static inline void hal_radio_nrf_ppi_channels_disable(uint32_t mask) */ static inline void hal_radio_enable_on_tick_ppi_config_and_enable(uint8_t trx) { - nrf_timer_publish_set(EVENT_TIMER, NRF_TIMER_EVENT_COMPARE0, HAL_RADIO_ENABLE_ON_TICK_PPI); - if (trx) { - nrf_radio_subscribe_set(NRF_RADIO, - NRF_RADIO_TASK_TXEN, HAL_RADIO_ENABLE_TX_ON_TICK_PPI); + nrf_timer_publish_set(EVENT_TIMER, NRF_TIMER_EVENT_COMPARE0, + HAL_RADIO_ENABLE_TX_ON_TICK_PPI); + nrf_radio_subscribe_set(NRF_RADIO, NRF_RADIO_TASK_TXEN, + HAL_RADIO_ENABLE_TX_ON_TICK_PPI); /* Address nRF5340 Engineering A Errata 16 */ if (IS_ENABLED(CONFIG_BT_CTLR_TIFS_HW)) { - nrf_radio_subscribe_clear(NRF_RADIO, NRF_RADIO_TASK_RXEN); + nrf_radio_subscribe_clear(NRF_RADIO, + NRF_RADIO_TASK_RXEN); } + + nrf_dppi_channels_enable(NRF_DPPIC, + BIT(HAL_RADIO_ENABLE_TX_ON_TICK_PPI)); } else { - nrf_radio_subscribe_set(NRF_RADIO, - NRF_RADIO_TASK_RXEN, HAL_RADIO_ENABLE_RX_ON_TICK_PPI); + nrf_timer_publish_set(EVENT_TIMER, NRF_TIMER_EVENT_COMPARE0, + HAL_RADIO_ENABLE_RX_ON_TICK_PPI); + nrf_radio_subscribe_set(NRF_RADIO, NRF_RADIO_TASK_RXEN, + HAL_RADIO_ENABLE_RX_ON_TICK_PPI); /* Address nRF5340 Engineering A Errata 16 */ if (IS_ENABLED(CONFIG_BT_CTLR_TIFS_HW)) { - nrf_radio_subscribe_clear(NRF_RADIO, NRF_RADIO_TASK_TXEN); + nrf_radio_subscribe_clear(NRF_RADIO, + NRF_RADIO_TASK_TXEN); } - } - nrf_dppi_channels_enable(NRF_DPPIC, BIT(HAL_RADIO_ENABLE_ON_TICK_PPI)); + nrf_dppi_channels_enable(NRF_DPPIC, + BIT(HAL_RADIO_ENABLE_RX_ON_TICK_PPI)); + } } /******************************************************************************* @@ -585,6 +582,7 @@ static inline void hal_radio_sw_switch_coded_tx_config_set(uint8_t ppi_en, BIT(HAL_SW_SWITCH_TIMER_S8_DISABLE_PPI)); } +#if defined(CONFIG_BT_CTLR_PHY_CODED) && defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) static inline void hal_radio_sw_switch_coded_config_clear(uint8_t ppi_en, uint8_t ppi_dis, uint8_t cc_reg, uint8_t group_index) { @@ -597,6 +595,7 @@ static inline void hal_radio_sw_switch_coded_config_clear(uint8_t ppi_en, HAL_SW_SWITCH_RADIO_ENABLE_PPI_REGISTER_EVT( SW_SWITCH_TIMER_S2_EVTS_COMP(group_index)) = 0; } +#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ static inline void hal_radio_sw_switch_disable_group_clear(uint8_t ppi_dis, uint8_t cc_reg, uint8_t group_index) @@ -757,5 +756,3 @@ hal_radio_sw_switch_phyend_delay_compensation_config_clear(uint8_t radio_enable_ #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ - -#endif /* CONFIG_SOC_NRF5340_CPUNET || DPPI_PRESENT */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h index b97b31a926f..74fb56d9b5c 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h @@ -9,9 +9,8 @@ * Enable Radio on Event Timer tick: * wire the EVENT_TIMER EVENTS_COMPARE[0] event to RADIO TASKS_TXEN/RXEN task. */ -#define HAL_RADIO_ENABLE_ON_TICK_PPI 6 -#define HAL_RADIO_ENABLE_TX_ON_TICK_PPI HAL_RADIO_ENABLE_ON_TICK_PPI -#define HAL_RADIO_ENABLE_RX_ON_TICK_PPI HAL_RADIO_ENABLE_ON_TICK_PPI +#define HAL_RADIO_ENABLE_TX_ON_TICK_PPI 6 +#define HAL_RADIO_ENABLE_RX_ON_TICK_PPI 6 /******************************************************************************* * Capture event timer on Address reception: diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h index e725124df6a..866769c95eb 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h @@ -4,11 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_COMPATIBLE_NRF52X) - -#include - -#include "radio_nrf5_ppi_resources.h" static inline void hal_radio_nrf_ppi_channels_enable(uint32_t mask) { @@ -34,28 +29,54 @@ static inline void hal_radio_enable_on_tick_ppi_config_and_enable(uint8_t trx) /* No need to configure anything for the pre-programmed channels. * Just enable and disable them accordingly. */ - nrf_ppi_channels_disable( - NRF_PPI, - trx ? BIT(HAL_RADIO_ENABLE_RX_ON_TICK_PPI) - : BIT(HAL_RADIO_ENABLE_TX_ON_TICK_PPI)); - nrf_ppi_channels_enable( - NRF_PPI, - trx ? BIT(HAL_RADIO_ENABLE_TX_ON_TICK_PPI) - : BIT(HAL_RADIO_ENABLE_RX_ON_TICK_PPI)); + if (trx) { + nrf_ppi_channels_enable(NRF_PPI, + BIT(HAL_RADIO_ENABLE_TX_ON_TICK_PPI)); + } else { + nrf_ppi_channels_enable(NRF_PPI, + BIT(HAL_RADIO_ENABLE_RX_ON_TICK_PPI)); + } } #else static inline void hal_radio_enable_on_tick_ppi_config_and_enable(uint8_t trx) { - uint32_t event_address = (trx ? (uint32_t)&(NRF_RADIO->TASKS_TXEN) - : (uint32_t)&(NRF_RADIO->TASKS_RXEN)); - nrf_ppi_channel_endpoint_setup( - NRF_PPI, - HAL_RADIO_ENABLE_ON_TICK_PPI, - (uint32_t)&(EVENT_TIMER->EVENTS_COMPARE[0]), - event_address); - nrf_ppi_channels_enable(NRF_PPI, BIT(HAL_RADIO_ENABLE_ON_TICK_PPI)); + if (trx) { + nrf_ppi_channel_endpoint_setup(NRF_PPI, + HAL_RADIO_ENABLE_TX_ON_TICK_PPI, + (uint32_t)&(EVENT_TIMER->EVENTS_COMPARE[0]), + (uint32_t)&(NRF_RADIO->TASKS_TXEN)); + +#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) + NRF_PPI->CHG[SW_SWITCH_SINGLE_TIMER_TASK_GROUP_IDX] = + BIT(HAL_RADIO_ENABLE_TX_ON_TICK_PPI); + + nrf_ppi_fork_endpoint_setup(NRF_PPI, + HAL_RADIO_ENABLE_TX_ON_TICK_PPI, + (uint32_t)&(NRF_PPI->TASKS_CHG[SW_SWITCH_SINGLE_TIMER_TASK_GROUP_IDX].DIS)); +#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ + + nrf_ppi_channels_enable(NRF_PPI, + BIT(HAL_RADIO_ENABLE_TX_ON_TICK_PPI)); + } else { + nrf_ppi_channel_endpoint_setup(NRF_PPI, + HAL_RADIO_ENABLE_RX_ON_TICK_PPI, + (uint32_t)&(EVENT_TIMER->EVENTS_COMPARE[0]), + (uint32_t)&(NRF_RADIO->TASKS_RXEN)); + +#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) + NRF_PPI->CHG[SW_SWITCH_SINGLE_TIMER_TASK_GROUP_IDX] = + BIT(HAL_RADIO_ENABLE_RX_ON_TICK_PPI); + + nrf_ppi_fork_endpoint_setup(NRF_PPI, + HAL_RADIO_ENABLE_RX_ON_TICK_PPI, + (uint32_t)&(NRF_PPI->TASKS_CHG[SW_SWITCH_SINGLE_TIMER_TASK_GROUP_IDX].DIS)); +#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ + + nrf_ppi_channels_enable(NRF_PPI, + BIT(HAL_RADIO_ENABLE_RX_ON_TICK_PPI)); + } } #endif /* (EVENT_TIMER_ID == 0) */ @@ -138,7 +159,7 @@ static inline void hal_radio_end_time_capture_ppi_config(void) nrf_ppi_channel_endpoint_setup( NRF_PPI, HAL_RADIO_END_TIME_CAPTURE_PPI, - (uint32_t)&(NRF_RADIO->EVENTS_END), + (uint32_t)&(NRF_RADIO->NRF_RADIO_TXRX_END_EVENT), (uint32_t)&(EVENT_TIMER->TASKS_CAPTURE[2])); } @@ -700,4 +721,3 @@ static inline void hal_radio_sw_switch_ppi_group_setup(void) } #endif /* !CONFIG_BT_CTLR_TIFS_HW */ -#endif /* CONFIG_SOC_SERIES_NRF51X || CONFIG_SOC_COMPATIBLE_NRF52X */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h index df3fbd446f1..5c5093f4b52 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h @@ -3,10 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include "radio_nrf5_fem.h" -#if defined(CONFIG_BT_CTLR_TIFS_HW) || !defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) +#if (EVENT_TIMER_ID == 0) /* PPI channel 20 is pre-programmed with the following fixed settings: * EEP: TIMER0->EVENTS_COMPARE[0] @@ -37,16 +35,15 @@ */ #define HAL_RADIO_END_TIME_CAPTURE_PPI 27 -#else /* CONFIG_BT_CTLR_TIFS_HW || !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#else /* EVENT_TIMER_ID != 0 */ -#define HAL_RADIO_ENABLE_ON_TICK_PPI 2 -#define HAL_RADIO_ENABLE_TX_ON_TICK_PPI HAL_RADIO_ENABLE_ON_TICK_PPI -#define HAL_RADIO_ENABLE_RX_ON_TICK_PPI HAL_RADIO_ENABLE_ON_TICK_PPI +#define HAL_RADIO_ENABLE_TX_ON_TICK_PPI 2 +#define HAL_RADIO_ENABLE_RX_ON_TICK_PPI 2 #define HAL_RADIO_RECV_TIMEOUT_CANCEL_PPI 3 #define HAL_RADIO_DISABLE_ON_HCTO_PPI 4 #define HAL_RADIO_END_TIME_CAPTURE_PPI 5 -#endif /* CONFIG_BT_CTLR_TIFS_HW || !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#endif /* EVENT_TIMER_ID != 0 */ /* Start event timer on RTC tick wire the RTC0 EVENTS_COMPARE[2] event to * EVENT_TIMER TASKS_START task. @@ -92,7 +89,7 @@ #if !defined(CONFIG_BT_CTLR_TIFS_HW) /* PPI setup used for SW-based auto-switching during TIFS. */ -#if !defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) +#if (EVENT_TIMER_ID == 0) /* Clear SW-switch timer on packet end: * wire the RADIO EVENTS_END event to SW_SWITCH_TIMER TASKS_CLEAR task. @@ -101,7 +98,7 @@ */ #define HAL_SW_SWITCH_TIMER_CLEAR_PPI 8 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#else /* EVENT_TIMER_ID != 0 */ /* Clear event timer (sw-switch timer) on Radio end: * wire the RADIO EVENTS_END event to the @@ -112,7 +109,7 @@ */ #define HAL_SW_SWITCH_TIMER_CLEAR_PPI HAL_RADIO_END_TIME_CAPTURE_PPI -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#endif /* EVENT_TIMER_ID != 0 */ /* Wire a SW SWITCH TIMER EVENTS_COMPARE[] event * to a PPI GROUP TASK DISABLE task (PPI group with index ). @@ -193,5 +190,6 @@ /* The 2 adjacent PPI groups used for implementing SW_SWITCH_TIMER-based * auto-switch for TIFS. 'index' must be 0 or 1. */ -#define SW_SWITCH_TIMER_TASK_GROUP_BASE 0 +#define SW_SWITCH_TIMER_TASK_GROUP_BASE 0 +#define SW_SWITCH_SINGLE_TIMER_TASK_GROUP_IDX 2 #endif /* !CONFIG_BT_CTLR_TIFS_HW */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h new file mode 100644 index 00000000000..87acc1896ee --- /dev/null +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Use the timer instance ID, not NRF_TIMERx directly, so that it can be checked + * in radio_nrf5_ppi.h by the preprocessor. + */ +#if defined(CONFIG_BT_CTLR_TIFS_HW) +#define EVENT_TIMER_ID 0 +#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 + +#else /* !CONFIG_BT_CTLR_TIFS_HW */ +#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) +#define EVENT_TIMER_ID 4 +#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) + +#define SW_SWITCH_TIMER EVENT_TIMER + +#if defined(CONFIG_BT_CTLR_PHY_CODED) +#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 +#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 + +#else /* !CONFIG_BT_CTLR_PHY_CODED */ +#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 +#endif /* !CONFIG_BT_CTLR_PHY_CODED */ + +#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#define EVENT_TIMER_ID 0 +#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) + +#define SW_SWITCH_TIMER NRF_TIMER1 +#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 + +#if defined(CONFIG_BT_CTLR_PHY_CODED) +#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 +#endif /* !CONFIG_BT_CTLR_PHY_CODED */ + +#if defined(CONFIG_BT_CTLR_DF) + +#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) +/* Allocate 2 adjacent channels for PHYEND delay compensation. Use the same channels as for + * PHY CODED S2. The CTEINLINE may not be enabled for PHY CODED so PHYEND event is generated + * at the same instant as END event. Hence the channels are uesed interchangeably. + * That saves from use of another timer. + */ +#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 2 +#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + * + * When direction finding is enabled a PDU may include Constant Tone Extension at its end. For PDU + * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in + * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND + +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. + * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. + * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. + * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. + * If there is no CTE, it is generated in the same instant as EVENTS_END. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk + +/* Delay of EVENTS_PHYEND event on receive PDU without CTE inclded when CTEINLINE is enabled */ +#define RADIO_EVENTS_PHYEND_DELAY_US 16 + +/* Delay of CCM TASKS_CRYPT start in number of bits for Radio Bit counter */ +#define CCM_TASKS_CRYPT_DELAY_BITS 3 + +#else /* !CONFIG_BT_CTLR_DF */ +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk +#endif /* !CONFIG_BT_CTLR_DF */ + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 +#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#endif /* !CONFIG_BT_CTLR_TIFS_HW */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h index a49089282f4..2eb772f20cc 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h @@ -18,10 +18,24 @@ #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Pos3dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_PLUS_2) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Pos2dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_PLUS_1) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Pos1dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_0) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_0dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_1) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg1dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_2) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg2dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_3) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg3dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_4) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg4dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_5) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg5dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_6) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg6dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_7) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg7dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_8) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg8dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_12) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h index 317638eeabf..a767fe1ab30 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h @@ -183,18 +183,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER -#define EVENT_TIMER NRF_TIMER0 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* TODO: Add any required setup for each radio event diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c index ae9dd686133..482e48b198b 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c @@ -5,8 +5,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include -#include + #include #include "hal/cntr.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h index a3324ce44e3..972638298f7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - #include "hal/nrf5/radio/radio.h" #include "hal/nrf5/radio/radio_nrf5.h" #include "hal/nrf5/radio/radio_nrf5_txp.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index 0c9dceec3e0..3a23ee8a902 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -470,10 +470,7 @@ uint32_t lll_preempt_calc(struct ull_hdr *ull, uint8_t ticker_id, * duration. * 3. Increase the preempt to start ticks for future events. */ - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(diff)); - - return 1U; + return diff; } return 0U; @@ -758,6 +755,11 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, err = prepare_cb(prepare_param); + if (!IS_ENABLED(CONFIG_BT_CTLR_ASSERT_OVERHEAD_START) && + (err == -ECANCELED)) { + err = 0; + } + #if !defined(CONFIG_BT_CTLR_LOW_LAT) uint32_t ret; @@ -855,6 +857,13 @@ static uint32_t preempt_ticker_start(struct lll_event *first, (preempt_req != preempt_ack)) { uint32_t diff; + /* preempt timeout already started but no role/state in the head + * of prepare pipeline. + */ + if (!prev || prev->is_aborted) { + return TICKER_STATUS_SUCCESS; + } + /* Calc the preempt timeout */ p = &next->prepare_param; ull = HDR_LLL2ULL(p->param); @@ -867,9 +876,9 @@ static uint32_t preempt_ticker_start(struct lll_event *first, ticks_at_preempt_new &= HAL_TICKER_CNTR_MASK; /* Check for short preempt timeouts */ - diff = ticks_at_preempt_new - ticks_at_preempt; - if (!prev || prev->is_aborted || - ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U)) { + diff = ticker_ticks_diff_get(ticks_at_preempt_new, + ticks_at_preempt); + if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) { return TICKER_STATUS_SUCCESS; } @@ -878,15 +887,6 @@ static uint32_t preempt_ticker_start(struct lll_event *first, LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || (ret == TICKER_STATUS_BUSY)); - /* Set early as we get called again through the call to - * abort_cb(). - */ - ticks_at_preempt = ticks_at_preempt_new; - - /* Abort previous prepare that set the preempt timeout */ - prev->is_aborted = 1U; - prev->abort_cb(&prev->prepare_param, prev->prepare_param.param); - /* Schedule short preempt timeout */ first = next; } else { @@ -975,17 +975,11 @@ static void preempt(void *param) return; } - /* Check if any prepare in pipeline */ - idx = UINT8_MAX; - next = ull_prepare_dequeue_iter(&idx); - if (!next) { - return; - } - /* Find a prepare that is ready and not a resume */ - while (next && (next->is_aborted || next->is_resume)) { + idx = UINT8_MAX; + do { next = ull_prepare_dequeue_iter(&idx); - } + } while (next && (next->is_aborted || next->is_resume)); /* No ready prepare */ if (!next) { @@ -994,14 +988,52 @@ static void preempt(void *param) /* Preemptor not in pipeline */ if (next->prepare_param.param != param) { + struct lll_event *next_next = NULL; + struct lll_event *e; uint32_t ret; - /* Start the preempt timeout */ - ret = preempt_ticker_start(next, NULL, next); - LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || - (ret == TICKER_STATUS_BUSY)); + /* Find if a short prepare request in the pipeline */ + do { + e = ull_prepare_dequeue_iter(&idx); + if (!next_next && e && !e->is_aborted && + !e->is_resume) { + next_next = e; + } + } while (e && (e->is_aborted || e->is_resume || + (e->prepare_param.param != param))); - return; + /* No short prepare request in pipeline */ + if (!e) { + /* Start the preempt timeout for next event */ + ret = preempt_ticker_start(next, NULL, next); + LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || + (ret == TICKER_STATUS_BUSY)); + + return; + } + + /* FIXME: Abort all events in pipeline before the short + * prepare event. For now, lets assert when many + * enqueued prepares need aborting. + */ + LL_ASSERT(next_next == e); + + /* Abort the prepare that is present before the short prepare */ + next->is_aborted = 1; + next->abort_cb(&next->prepare_param, next->prepare_param.param); + + /* As the prepare queue has been refreshed due to the call of + * abort_cb which invokes the lll_done, find the latest prepare + */ + idx = UINT8_MAX; + do { + next = ull_prepare_dequeue_iter(&idx); + } while (next && (next->is_aborted || next->is_resume)); + + /* No ready prepare */ + if (!next) { + return; + } } /* Check if current event want to continue */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index 859e024dc44..851c82692b8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -8,9 +8,8 @@ #include #include -#include +#include #include -#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -937,6 +936,7 @@ static int prepare_cb(struct lll_prepare_param *p) struct lll_adv *lll; uint32_t remainder; uint32_t start_us; + uint32_t ret; uint32_t aa; DEBUG_RADIO_START_A(1); @@ -1035,34 +1035,37 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_BASE + ull_adv_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_ADV_BASE + - ull_adv_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_abort, lll); radio_disable(); - } else + + return -ECANCELED; + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; -#if defined(CONFIG_BT_CTLR_ADV_EXT) - if (lll->aux) { - /* fill in aux ptr in pdu */ - ull_adv_aux_lll_auxptr_fill(pdu, lll); - - /* NOTE: as first primary channel PDU does not use remainder, the packet - * timer is started one tick in advance to start the radio with - * microsecond precision, hence compensate for the higher start_us value - * captured at radio start of the first primary channel PDU. - */ - lll->aux->ticks_pri_pdu_offset += 1U; - } -#endif +#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + if (lll->aux) { + /* fill in aux ptr in pdu */ + ull_adv_aux_lll_auxptr_fill(pdu, lll); - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); + /* NOTE: as first primary channel PDU does not use remainder, the packet + * timer is started one tick in advance to start the radio with + * microsecond precision, hence compensate for the higher start_us value + * captured at radio start of the first primary channel PDU. + */ + lll->aux->ticks_pri_pdu_offset += 1U; } +#endif + + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_A(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c index 51c8b9066ba..ca566a04db4 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" @@ -110,10 +110,9 @@ static int init_reset(void) static int prepare_cb(struct lll_prepare_param *p) { - struct pdu_adv_com_ext_adv *com_hdr; uint32_t ticks_at_event, ticks_at_start; - struct ll_adv_aux_set *aux; - struct pdu_adv *pdu; + struct pdu_adv_com_ext_adv *com_hdr; + struct pdu_adv *sec_pdu; struct lll_adv_aux *lll; struct lll_adv *lll_adv; struct ull_hdr *ull; @@ -121,25 +120,83 @@ static int prepare_cb(struct lll_prepare_param *p) uint32_t start_us; uint8_t chan_idx; uint8_t phy_s; + uint32_t ret; uint8_t upd; uint32_t aa; DEBUG_RADIO_START_A(1); lll = p->param; - aux = HDR_LLL2ULL(lll); + lll_adv = lll->adv; /* FIXME: get latest only when primary PDU without Aux PDUs */ upd = 0U; - pdu = lll_adv_aux_data_latest_get(lll, &upd); - LL_ASSERT(pdu); + sec_pdu = lll_adv_aux_data_latest_get(lll, &upd); + LL_ASSERT(sec_pdu); - lll_adv = lll->adv; +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + struct ll_adv_aux_set *aux; + + /* Get reference to extended header */ + com_hdr = (void *)&sec_pdu->adv_ext_ind; + aux = HDR_LLL2ULL(lll); chan_idx = lll_chan_sel_2(lll->data_chan_counter, aux->data_chan_id, aux->chm[aux->chm_first].data_chan_map, aux->chm[aux->chm_first].data_chan_count); +#else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + struct pdu_adv_aux_ptr *aux_ptr; + struct pdu_adv_ext_hdr *pri_hdr; + struct pdu_adv *pri_pdu; + uint8_t *pri_dptr; + + /* Get reference to primary PDU */ + pri_pdu = lll_adv_data_curr_get(lll_adv); + LL_ASSERT(pri_pdu->type == PDU_ADV_TYPE_EXT_IND); + + /* Get reference to extended header */ + com_hdr = (void *)&pri_pdu->adv_ext_ind; + pri_hdr = (void *)com_hdr->ext_hdr_adv_data; + pri_dptr = pri_hdr->data; + + /* NOTE: We shall be here in auxiliary PDU prepare due to + * aux_ptr flag being set in the extended common header + * flags. Hence, ext_hdr_len is non-zero, an explicit check + * is not needed. + */ + LL_ASSERT(com_hdr->ext_hdr_len); + + /* traverse through adv_addr, if present */ + if (pri_hdr->adv_addr) { + pri_dptr += BDADDR_SIZE; + } + + /* traverse through tgt_addr, if present */ + if (pri_hdr->tgt_addr) { + pri_dptr += BDADDR_SIZE; + } + + /* No CTEInfo flag in primary and secondary channel PDU */ + + /* traverse through adi, if present */ + if (pri_hdr->adi) { + pri_dptr += sizeof(struct pdu_adv_adi); + } + + aux_ptr = (void *)pri_dptr; + + /* Abort if no aux_ptr filled */ + if (unlikely(!pri_hdr->aux_ptr || !PDU_ADV_AUX_PTR_OFFSET_GET(aux_ptr))) { + radio_isr_set(lll_isr_early_abort, lll); + radio_disable(); + + return 0; + } + + chan_idx = aux_ptr->chan_idx; +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + /* Increment counter used in ULL for channel index calculation */ lll->data_chan_counter++; @@ -165,14 +222,11 @@ static int prepare_cb(struct lll_prepare_param *p) radio_crc_configure(PDU_CRC_POLYNOMIAL, PDU_AC_CRC_IV); - /* Set the channel index */ + /* Use channel idx calculated or that was in aux_ptr */ lll_chan_set(chan_idx); /* Set the Radio Tx Packet */ - radio_pkt_tx_set(pdu); - - /* Get reference to extended header */ - com_hdr = (void *)&pdu->adv_ext_ind; + radio_pkt_tx_set(sec_pdu); /* Switch to Rx if connectable or scannable */ if (com_hdr->adv_mode & (BT_HCI_LE_ADV_PROP_CONN | @@ -195,7 +249,7 @@ static int prepare_cb(struct lll_prepare_param *p) * into the scan response. */ memcpy(&scan_pdu->adv_ext_ind.ext_hdr.data[ADVA_OFFSET], - &pdu->adv_ext_ind.ext_hdr.data[ADVA_OFFSET], + &sec_pdu->adv_ext_ind.ext_hdr.data[ADVA_OFFSET], BDADDR_SIZE); } @@ -223,9 +277,9 @@ static int prepare_cb(struct lll_prepare_param *p) } #if defined(CONFIG_BT_CTLR_ADV_AUX_PDU_BACK2BACK) - } else if (pdu->adv_ext_ind.ext_hdr_len && - pdu->adv_ext_ind.ext_hdr.aux_ptr) { - lll->last_pdu = pdu; + } else if (sec_pdu->adv_ext_ind.ext_hdr_len && + sec_pdu->adv_ext_ind.ext_hdr.aux_ptr) { + lll->last_pdu = sec_pdu; radio_isr_set(isr_tx_chain, lll); radio_tmr_tifs_set(EVENT_B2B_MAFS_US); @@ -263,27 +317,31 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_AUX_BASE + ull_adv_aux_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_ADV_AUX_BASE + - ull_adv_aux_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) - if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.sync_info) { - ull_adv_sync_lll_syncinfo_fill(pdu, lll); - } -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ + return -ECANCELED; + } +#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); + if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC) && + IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) && + sec_pdu->adv_ext_ind.ext_hdr_len && + sec_pdu->adv_ext_ind.ext_hdr.sync_info) { + ull_adv_sync_lll_syncinfo_fill(sec_pdu, lll); } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); + DEBUG_RADIO_START_A(1); return 0; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c index 545cbfd2a89..87849d0e1fd 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c @@ -188,6 +188,7 @@ static int prepare_cb_common(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint32_t start_us; + uint32_t ret; uint8_t phy; DEBUG_RADIO_START_A(1); @@ -360,7 +361,9 @@ static int prepare_cb_common(struct lll_prepare_param *p) RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (lll->max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_tx_set(radio_ccm_tx_pkt_set(&lll->ccm_tx, pdu)); + radio_pkt_tx_set(radio_ccm_iso_tx_pkt_set(&lll->ccm_tx, + RADIO_PKT_CONF_PDU_TYPE_BIS, + pdu)); } else { uint8_t pkt_flags; @@ -417,23 +420,24 @@ static int prepare_cb_common(struct lll_prepare_param *p) ARG_UNUSED(start_us); #endif /* !HAL_RADIO_GPIO_HAVE_PA_PIN */ - if (0) { #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_ISO_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, (TICKER_ID_ADV_ISO_BASE + lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - } else { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); /* Calculate ahead the next subevent channel index */ next_chan_calc(lll, event_counter, data_chan_id); @@ -689,7 +693,9 @@ static void isr_tx_common(void *param, (void)memcpy(lll->ccm_tx.iv, lll->giv, 4U); mem_xor_32(lll->ccm_tx.iv, lll->ccm_tx.iv, access_addr); - radio_pkt_tx_set(radio_ccm_tx_pkt_set(&lll->ccm_tx, pdu)); + radio_pkt_tx_set(radio_ccm_iso_tx_pkt_set(&lll->ccm_tx, + RADIO_PKT_CONF_PDU_TYPE_BIS, + pdu)); } else { radio_pkt_tx_set(pdu); } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c index 4f77e578963..1e56f70493c 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -120,6 +120,7 @@ static int prepare_cb(struct lll_prepare_param *p) uint32_t remainder; uint32_t start_us; uint8_t phy_s; + uint32_t ret; uint8_t upd; DEBUG_RADIO_START_A(1); @@ -237,26 +238,29 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_SYNC_BASE + + ull_adv_sync_lll_handle_get(lll)), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_ADV_SYNC_BASE + - ull_adv_sync_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; -#if defined(CONFIG_BT_CTLR_ADV_ISO) - if (lll->iso) { - ull_adv_iso_lll_biginfo_fill(pdu, lll); - } -#endif /* CONFIG_BT_CTLR_ADV_ISO */ + return -ECANCELED; + } +#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); +#if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + if (lll->iso) { + ull_adv_iso_lll_biginfo_fill(pdu, lll); } +#endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_A(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c index 9af7d7b95b2..a73364ef410 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c @@ -101,6 +101,7 @@ static int prepare_cb(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint8_t cte_len; + uint32_t ret; DEBUG_RADIO_START_M(1); @@ -240,19 +241,22 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); + return -ECANCELED; } +#endif /* !CONFIG_BT_CTLR_XTAL_ADVANCED */ + + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_M(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c index c1091bd6f12..6135cc9d863 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c @@ -40,6 +40,8 @@ #include "hal/debug.h" static int init_reset(void); +static inline void lll_flush_tx(struct lll_conn_iso_stream *cis_lll); +static inline void lll_flush_rx(struct lll_conn_iso_stream *cis_lll); static int prepare_cb(struct lll_prepare_param *p); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); static void isr_tx(void *param); @@ -47,14 +49,17 @@ static void isr_rx(void *param); static void isr_prepare_subevent(void *param); static void isr_done(void *param); -static uint8_t next_chan_use; -static uint16_t data_chan_id; -static uint16_t data_chan_prn_s; +static uint16_t next_cis_chan_remap_idx; +static uint16_t next_cis_chan_prn_s; static uint16_t data_chan_remap_idx; +static uint16_t data_chan_prn_s; +static uint8_t next_chan_use; +static uint8_t next_cis_chan; + static uint32_t trx_performed_bitmask; +static uint16_t cis_offset_first; +static uint16_t cis_handle_curr; static uint8_t se_curr; -static uint8_t bn_tx; -static uint8_t bn_rx; #if defined(CONFIG_BT_CTLR_LE_ENC) static uint8_t mic_state; @@ -86,12 +91,23 @@ int lll_central_iso_reset(void) void lll_central_iso_prepare(void *param) { + struct lll_conn_iso_group *cig_lll; + struct lll_prepare_param *p; + uint16_t elapsed; int err; /* Initiate HF clock start up */ err = lll_hfclock_on(); LL_ASSERT(err >= 0); + /* Instants elapsed */ + p = param; + elapsed = p->lazy + 1U; + + /* Save the (latency + 1) for use in event and/or supervision timeout */ + cig_lll = p->param; + cig_lll->latency_prepare += elapsed; + /* Invoke common pipeline handling of prepare */ err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0U, param); LL_ASSERT(!err || err == -EINPROGRESS); @@ -102,21 +118,44 @@ static int init_reset(void) return 0; } +static inline void lll_flush_tx(struct lll_conn_iso_stream *cis_lll) +{ + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + uint8_t sn_update = cis_lll->tx.bn + 1U - cis_lll->tx.bn_curr; + + /* we'll re-use sn_update when implementing flush timeout */ + cis_lll->sn += sn_update; +} + +static inline void lll_flush_rx(struct lll_conn_iso_stream *cis_lll) +{ + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + uint8_t nesn_update = cis_lll->rx.bn + 1U - cis_lll->rx.bn_curr; + + /* we'll re-use sn_update when implementing flush timeout */ + cis_lll->nesn += nesn_update; +} + static int prepare_cb(struct lll_prepare_param *p) { struct lll_conn_iso_group *cig_lll = p->param; struct lll_conn_iso_stream *cis_lll; - struct lll_conn *conn_lll; + const struct lll_conn *conn_lll; uint32_t ticks_at_event; uint32_t ticks_at_start; struct pdu_cis *pdu_tx; uint16_t event_counter; uint64_t payload_count; + uint16_t data_chan_id; uint8_t data_chan_use; + uint16_t cis_handle; struct ull_hdr *ull; uint32_t remainder; uint32_t start_us; + uint16_t lazy; + uint32_t ret; uint8_t phy; + int err = 0; DEBUG_RADIO_START_M(1); @@ -127,7 +166,15 @@ static int prepare_cb(struct lll_prepare_param *p) #endif /* CONFIG_BT_CTLR_LE_ENC */ /* Get the first CIS */ - cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, NULL); + cis_handle_curr = UINT16_MAX; + do { + cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle_curr); + } while (cis_lll && !cis_lll->active); + + LL_ASSERT(cis_lll); + + /* Save first active CIS offset */ + cis_offset_first = cis_lll->offset; /* Get reference to ACL context */ conn_lll = ull_conn_lll_get(cis_lll->acl_handle); @@ -143,37 +190,58 @@ static int prepare_cb(struct lll_prepare_param *p) &data_chan_prn_s, &data_chan_remap_idx); + /* Store the current event latency */ + cig_lll->latency_event = cig_lll->latency_prepare; + lazy = cig_lll->latency_prepare - 1U; + + /* Reset accumulated latencies */ + cig_lll->latency_prepare = 0U; + + /* Adjust the SN and NESN for skipped CIG events */ + if (cis_lll->event_count) { + uint16_t cis_lazy; + + if (lazy > cis_lll->event_count) { + cis_lazy = lazy - cis_lll->event_count; + } else { + cis_lazy = lazy; + } + + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + cis_lll->sn += cis_lll->tx.bn * cis_lazy; + cis_lll->nesn += cis_lll->rx.bn * cis_lazy; + } + se_curr = 1U; - bn_tx = 1U; - bn_rx = 1U; + cis_lll->tx.bn_curr = 1U; + cis_lll->rx.bn_curr = 1U; /* Start setting up of Radio h/w */ radio_reset(); #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) radio_tx_power_set(cis_lll->tx_pwr_lvl); -#else +#else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ radio_tx_power_set(RADIO_TXP_DEFAULT); -#endif +#endif /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ phy = cis_lll->tx.phy; radio_phy_set(phy, cis_lll->tx.phy_flags); radio_aa_set(cis_lll->access_addr); - radio_crc_configure(PDU_CRC_POLYNOMIAL, - sys_get_le24(conn_lll->crc_init)); + radio_crc_configure(PDU_CRC_POLYNOMIAL, sys_get_le24(conn_lll->crc_init)); lll_chan_set(data_chan_use); /* Get ISO data PDU */ - if (bn_tx > cis_lll->tx.bn) { + if (cis_lll->tx.bn_curr > cis_lll->tx.bn) { payload_count = 0U; - cis_lll->empty = 1U; + cis_lll->npi = 1U; pdu_tx = radio_pkt_empty_get(); pdu_tx->ll_id = PDU_CIS_LLID_START_CONTINUE; pdu_tx->nesn = cis_lll->nesn; pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ - pdu_tx->cie = (bn_rx > cis_lll->rx.bn); + pdu_tx->cie = (cis_lll->rx.bn_curr > cis_lll->rx.bn); pdu_tx->npi = 1U; pdu_tx->len = 0U; } else { @@ -186,47 +254,42 @@ static int prepare_cb(struct lll_prepare_param *p) link = memq_peek(cis_lll->memq_tx.head, cis_lll->memq_tx.tail, (void **)&node_tx); - if (link) { - if (node_tx->payload_count < payload_count) { - memq_dequeue(cis_lll->memq_tx.tail, - &cis_lll->memq_tx.head, - NULL); + if (!link) { + break; + } - node_tx->next = link; - ull_iso_lll_ack_enqueue(cis_lll->handle, - node_tx); - } else if (node_tx->payload_count >= - (payload_count + cis_lll->tx.bn)) { - link = NULL; - } else { - if (node_tx->payload_count != - payload_count) { - link = NULL; - } + if (node_tx->payload_count < payload_count) { + memq_dequeue(cis_lll->memq_tx.tail, + &cis_lll->memq_tx.head, + NULL); - break; + node_tx->next = link; + ull_iso_lll_ack_enqueue(cis_lll->handle, + node_tx); + } else if (node_tx->payload_count >= (payload_count + cis_lll->tx.bn)) { + link = NULL; + } else { + if (node_tx->payload_count != payload_count) { + link = NULL; } + + break; } } while (link); if (!link) { - cis_lll->empty = 1U; + cis_lll->npi = 1U; pdu_tx = radio_pkt_empty_get(); pdu_tx->ll_id = PDU_CIS_LLID_START_CONTINUE; pdu_tx->nesn = cis_lll->nesn; - pdu_tx->cie = (bn_tx > cis_lll->tx.bn) && - (bn_rx > cis_lll->rx.bn); + pdu_tx->cie = (cis_lll->tx.bn_curr > cis_lll->tx.bn) && + (cis_lll->rx.bn_curr > cis_lll->rx.bn); pdu_tx->len = 0U; - if (bn_tx > cis_lll->tx.bn) { - pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ - pdu_tx->npi = 1U; - } else { - pdu_tx->sn = cis_lll->sn; - pdu_tx->npi = 0U; - } + pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ + pdu_tx->npi = 1U; } else { - cis_lll->empty = 0U; + cis_lll->npi = 0U; pdu_tx = (void *)node_tx->pdu; pdu_tx->nesn = cis_lll->nesn; @@ -249,20 +312,21 @@ static int prepare_cb(struct lll_prepare_param *p) cis_lll->tx.ccm.counter = payload_count; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (cis_lll->tx.max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_tx_set(radio_ccm_tx_pkt_set(&cis_lll->tx.ccm, + radio_pkt_tx_set(radio_ccm_iso_tx_pkt_set(&cis_lll->tx.ccm, + RADIO_PKT_CONF_PDU_TYPE_CIS, pdu_tx)); #endif /* CONFIG_BT_CTLR_LE_ENC */ } else { uint8_t pkt_flags; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, @@ -285,7 +349,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event += lll_event_offset_get(ull); ticks_at_start = ticks_at_event; - ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US); + ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US + + cis_offset_first); remainder = p->remainder; start_us = radio_tmr_start(1U, ticks_at_start, remainder); @@ -312,27 +377,68 @@ static int prepare_cb(struct lll_prepare_param *p) ARG_UNUSED(start_us); #endif /* !HAL_RADIO_GPIO_HAVE_PA_PIN */ - if (false) { - #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), + ticks_at_event); /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, - (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), - ticks_at_event)) { - radio_isr_set(lll_isr_abort, cig_lll); + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + + radio_isr_set(isr_done, cis_lll); radio_disable(); - return -ECANCELED; + err = -ECANCELED; + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - } else { - uint32_t ret; + /* Adjust the SN and NESN for skipped CIG events */ + cis_handle = cis_handle_curr; + do { + cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle); + if (cis_lll && cis_lll->active) { + if (cis_lll->event_count) { + uint16_t cis_lazy; - ret = lll_prepare_done(cig_lll); - LL_ASSERT(!ret); + if (lazy > cis_lll->event_count) { + cis_lazy = lazy - cis_lll->event_count; + } else { + cis_lazy = lazy; + } + + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + cis_lll->sn += cis_lll->tx.bn * cis_lazy; + cis_lll->nesn += cis_lll->rx.bn * cis_lazy; + + /* Adjust sn and nesn for canceled events */ + if (err) { + /* Adjust sn when flushing Tx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + lll_flush_tx(cis_lll); + } + + /* Adjust nesn when flushing Rx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + lll_flush_rx(cis_lll); + } + } + } + } + } while (cis_lll); + + /* Return if prepare callback cancelled */ + if (err) { + return err; } + /* Prepare is done */ + ret = lll_prepare_done(cig_lll); + LL_ASSERT(!ret); + DEBUG_RADIO_START_M(1); return 0; @@ -344,10 +450,9 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) /* NOTE: This is not a prepare being cancelled */ if (!prepare_param) { - struct lll_conn_iso_group *cig_lll = param; struct lll_conn_iso_stream *cis_lll; - cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, NULL); + cis_lll = ull_conn_iso_lll_stream_get(cis_handle_curr); /* Perform event abort here. * After event has been cleanly aborted, clean up resources @@ -372,7 +477,6 @@ static void isr_tx(void *param) { struct lll_conn_iso_stream *cis_lll; struct node_rx_pdu *node_rx; - struct lll_conn *conn_lll; uint32_t hcto; /* Clear radio tx status and events */ @@ -384,8 +488,10 @@ static void isr_tx(void *param) /* Get reference to CIS LLL context */ cis_lll = param; +#if defined(CONFIG_BT_CTLR_LE_ENC) /* Get reference to ACL context */ - conn_lll = ull_conn_lll_get(cis_lll->acl_handle); + const struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); +#endif /* CONFIG_BT_CTLR_LE_ENC */ /* Acquire rx node for reception */ node_rx = ull_iso_pdu_rx_alloc_peek(1U); @@ -400,24 +506,26 @@ static void isr_tx(void *param) uint8_t pkt_flags; payload_count = (cis_lll->event_count * cis_lll->rx.bn) + - (bn_rx - 1U); + (cis_lll->rx.bn_curr - 1U); + cis_lll->rx.ccm.counter = payload_count; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->rx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (cis_lll->rx.max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_rx_set(radio_ccm_rx_pkt_set(&cis_lll->rx.ccm, - cis_lll->rx.phy, - node_rx->pdu)); + radio_pkt_rx_set(radio_ccm_iso_rx_pkt_set(&cis_lll->rx.ccm, + cis_lll->rx.phy, + RADIO_PKT_CONF_PDU_TYPE_CIS, + node_rx->pdu)); #endif /* CONFIG_BT_CTLR_LE_ENC */ } else { uint8_t pkt_flags; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->rx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, @@ -432,6 +540,7 @@ static void isr_tx(void *param) hcto = radio_tmr_tifs_base_get() + EVENT_IFS_US + (EVENT_CLOCK_JITTER_US << 1) + RANGE_DELAY_US + HCTO_START_DELAY_US; + #if defined(CONFIG_BT_CTLR_PHY) hcto += radio_rx_chain_delay_get(cis_lll->rx.phy, PHY_FLAGS_S8); hcto += addr_us_get(cis_lll->rx.phy); @@ -471,25 +580,104 @@ static void isr_tx(void *param) /* Schedule next subevent */ if (se_curr < cis_lll->nse) { - struct lll_conn *conn_lll; + const struct lll_conn *evt_conn_lll; + uint16_t data_chan_id; uint32_t subevent_us; uint32_t start_us; subevent_us = radio_tmr_ready_restore(); - subevent_us += cis_lll->sub_interval * se_curr; + subevent_us += cis_lll->offset - cis_offset_first + + (cis_lll->sub_interval * se_curr); start_us = radio_tmr_start_us(1U, subevent_us); LL_ASSERT(start_us == (subevent_us + 1U)); /* Get reference to ACL context */ - conn_lll = ull_conn_lll_get(cis_lll->acl_handle); + evt_conn_lll = ull_conn_lll_get(cis_lll->acl_handle); /* Calculate the radio channel to use for next subevent */ + data_chan_id = lll_chan_id(cis_lll->access_addr); next_chan_use = lll_chan_iso_subevent(data_chan_id, - conn_lll->data_chan_map, - conn_lll->data_chan_count, + evt_conn_lll->data_chan_map, + evt_conn_lll->data_chan_count, &data_chan_prn_s, &data_chan_remap_idx); + } else { + struct lll_conn_iso_stream *next_cis_lll; + struct lll_conn_iso_group *cig_lll; + struct lll_conn *next_conn_lll; + struct node_tx_iso *node_tx; + uint64_t payload_count; + uint16_t event_counter; + uint16_t data_chan_id; + uint32_t subevent_us; + uint16_t cis_handle; + uint32_t start_us; + memq_link_t *link; + + /* Calculate channel for next CIS */ + cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll); + cis_handle = cis_handle_curr; + do { + next_cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle); + } while (next_cis_lll && !next_cis_lll->active); + + if (!next_cis_lll) { + return; + } + + /* Get reference to ACL context */ + next_conn_lll = ull_conn_lll_get(next_cis_lll->acl_handle); + + /* Event counter value, 0-15 bit of cisEventCounter */ + event_counter = next_cis_lll->event_count; + + /* Calculate the radio channel to use for ISO event */ + data_chan_id = lll_chan_id(next_cis_lll->access_addr); + next_cis_chan = lll_chan_iso_event(event_counter, data_chan_id, + next_conn_lll->data_chan_map, + next_conn_lll->data_chan_count, + &next_cis_chan_prn_s, + &next_cis_chan_remap_idx); + + subevent_us = radio_tmr_ready_restore(); + subevent_us += next_cis_lll->offset - cis_offset_first; + + start_us = radio_tmr_start_us(1U, subevent_us); + LL_ASSERT(start_us == (subevent_us + 1U)); + + cis_lll = next_cis_lll; + + /* Tx Ack stale ISO Data */ + payload_count = cis_lll->event_count * cis_lll->tx.bn; + do { + link = memq_peek(cis_lll->memq_tx.head, + cis_lll->memq_tx.tail, + (void **)&node_tx); + if (!link) { + break; + } + + if (node_tx->payload_count < payload_count) { + memq_dequeue(cis_lll->memq_tx.tail, + &cis_lll->memq_tx.head, + NULL); + + node_tx->next = link; + ull_iso_lll_ack_enqueue(cis_lll->handle, + node_tx); + } else if (node_tx->payload_count >= + (payload_count + cis_lll->tx.bn)) { + link = NULL; + } else { + if (node_tx->payload_count != + payload_count) { + link = NULL; + } + + break; + } + } while (link); } } @@ -529,11 +717,11 @@ static void isr_rx(void *param) /* FIXME: Do not call this for every event/subevent */ ull_conn_iso_lll_cis_established(param); - /* FIXME: set the bit corresponding to CIS index */ - trx_performed_bitmask = 1U; + /* Set the bit corresponding to CIS index */ + trx_performed_bitmask |= (1U << LL_CIS_IDX_FROM_HANDLE(cis_lll->handle)); /* Get reference to received PDU */ - node_rx = ull_iso_pdu_rx_alloc_peek(1); + node_rx = ull_iso_pdu_rx_alloc_peek(1U); LL_ASSERT(node_rx); pdu_rx = (void *)node_rx->pdu; @@ -541,68 +729,35 @@ static void isr_rx(void *param) if (crc_ok) { /* Tx ACK */ if (pdu_rx->nesn != cis_lll->sn) { - struct pdu_cis *pdu_tx; - /* Increment sequence number */ cis_lll->sn++; - /* Get reference to PDU Tx */ - if (cis_lll->empty) { - cis_lll->empty = 0U; - - pdu_tx = radio_pkt_empty_get(); - } else { - struct node_tx_iso *node_tx; - uint8_t payload_index; - memq_link_t *link; - - payload_index = bn_tx - 1U; - link = memq_peek_n(cis_lll->memq_tx.head, - cis_lll->memq_tx.tail, - payload_index, - (void **)&node_tx); - if (link) { - pdu_tx = (void *)node_tx->pdu; - } else { - pdu_tx = radio_pkt_empty_get(); - } - } - -#if defined(CONFIG_BT_CTLR_LE_ENC) - /* Get reference to ACL context */ - struct lll_conn *conn_lll = - ull_conn_lll_get(cis_lll->acl_handle); + /* Increment burst number */ + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { - if (pdu_tx->len) { - /* if encrypted increment tx counter */ - if (conn_lll->enc_tx) { - cis_lll->tx.ccm.counter++; - } - } -#endif /* CONFIG_BT_CTLR_LE_ENC */ + cis_lll->tx.bn_curr++; - /* Increment burst number */ - if (bn_tx <= cis_lll->tx.bn) { - bn_tx++; } - /* TODO: Tx Ack */ + /* TODO: Implement early Tx Ack. Currently Tx Ack + * generated as stale Tx Ack when payload count + * has elapsed. + */ } - /* Rx receive */ + /* Handle valid ISO data Rx */ if (!pdu_rx->npi && - (bn_rx <= cis_lll->rx.bn) && + (cis_lll->rx.bn_curr <= cis_lll->rx.bn) && (pdu_rx->sn == cis_lll->nesn) && - ull_iso_pdu_rx_alloc_peek(2)) { + ull_iso_pdu_rx_alloc_peek(2U)) { struct node_rx_iso_meta *iso_meta; - /* Increment next expected serial number */ + /* Increment next expected sequence number */ cis_lll->nesn++; #if defined(CONFIG_BT_CTLR_LE_ENC) /* Get reference to ACL context */ - struct lll_conn *conn_lll = - ull_conn_lll_get(cis_lll->acl_handle); + const struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); /* If required, wait for CCM to finish */ @@ -619,9 +774,6 @@ static void isr_rx(void *param) goto isr_rx_done; } - /* Increment counter */ - cis_lll->rx.ccm.counter++; - /* Record MIC valid */ mic_state = LLL_CONN_MIC_PASS; } @@ -633,7 +785,7 @@ static void isr_rx(void *param) iso_meta = &node_rx->hdr.rx_iso_meta; iso_meta->payload_number = (cis_lll->event_count * cis_lll->rx.bn) + - (bn_rx - 1U); + (cis_lll->rx.bn_curr - 1U); iso_meta->timestamp = HAL_TICKER_TICKS_TO_US(radio_tmr_start_get()) + radio_tmr_ready_restore(); @@ -649,10 +801,29 @@ static void isr_rx(void *param) #endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ /* Increment burst number */ - bn_rx++; + cis_lll->rx.bn_curr++; /* Need to be acked */ ack_pending = 1U; + + /* Handle NULL PDU indication received */ + } else if (pdu_rx->npi) { + /* Source could not send ISO data, increment NESN as if + * we received and expect to receive the next PDU in the + * burst. + */ + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + /* Increment next expected serial number */ + cis_lll->nesn++; + + /* Increment burst number */ + cis_lll->rx.bn_curr++; + } + + /* Not NPI, or more than the BN, or no free Rx ISO PDU buffers. + */ + } else { + /* Do nothing, ignore the Rx buffer */ } /* Close Isochronous Event */ @@ -660,13 +831,173 @@ static void isr_rx(void *param) } /* Close Isochronous Event */ - cie = cie || ((bn_rx > cis_lll->rx.bn) && - (bn_tx > cis_lll->tx.bn) && + cie = cie || ((cis_lll->rx.bn_curr > cis_lll->rx.bn) && + (cis_lll->tx.bn_curr > cis_lll->tx.bn) && !ack_pending); isr_rx_next_subevent: if (cie || (se_curr == cis_lll->nse)) { - goto isr_rx_done; + struct lll_conn_iso_stream *old_cis_lll; + struct lll_conn_iso_stream *next_cis_lll; + struct lll_conn_iso_group *cig_lll; + struct lll_conn *next_conn_lll; + uint8_t phy; + uint8_t bn; + + /* Fetch next CIS */ + /* TODO: Use a new ull_conn_iso_lll_stream_get_active_by_group() + * in the future. + */ + cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll); + do { + next_cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, + &cis_handle_curr); + } while (next_cis_lll && !next_cis_lll->active); + + if (!next_cis_lll) { + goto isr_rx_done; + } + + /* Adjust sn when flushing Tx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + lll_flush_tx(cis_lll); + } + + /* Adjust nesn when flushing Rx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + lll_flush_rx(cis_lll); + } + + /* Get reference to ACL context */ + next_conn_lll = ull_conn_lll_get(next_cis_lll->acl_handle); + + /* Calculate CIS channel if not already calculated */ + if (se_curr < cis_lll->nse) { + struct node_tx_iso *node_tx; + uint64_t payload_count; + uint16_t event_counter; + uint16_t data_chan_id; + uint32_t subevent_us; + uint32_t start_us; + memq_link_t *link; + + /* Event counter value, 0-15 bit of cisEventCounter */ + event_counter = next_cis_lll->event_count; + + /* Calculate the radio channel to use for ISO event */ + data_chan_id = lll_chan_id(next_cis_lll->access_addr); + next_cis_chan = lll_chan_iso_event(event_counter, data_chan_id, + next_conn_lll->data_chan_map, + next_conn_lll->data_chan_count, + &next_cis_chan_prn_s, + &next_cis_chan_remap_idx); + + subevent_us = radio_tmr_ready_restore(); + subevent_us += next_cis_lll->offset - cis_offset_first; + + start_us = radio_tmr_start_us(1U, subevent_us); + LL_ASSERT(start_us == (subevent_us + 1U)); + + old_cis_lll = cis_lll; + cis_lll = next_cis_lll; + + payload_count = cis_lll->event_count * cis_lll->tx.bn; + + do { + link = memq_peek(cis_lll->memq_tx.head, + cis_lll->memq_tx.tail, + (void **)&node_tx); + if (!link) { + break; + } + + if (node_tx->payload_count < payload_count) { + memq_dequeue(cis_lll->memq_tx.tail, + &cis_lll->memq_tx.head, + NULL); + + node_tx->next = link; + ull_iso_lll_ack_enqueue(cis_lll->handle, + node_tx); + } else if (node_tx->payload_count >= + (payload_count + cis_lll->tx.bn)) { + link = NULL; + } else { + if (node_tx->payload_count != + payload_count) { + link = NULL; + } + + break; + } + } while (link); + + cis_lll = old_cis_lll; + } + + /* Generate ISO Data Invalid Status */ + bn = cis_lll->rx.bn_curr; + while (bn <= cis_lll->rx.bn) { + struct node_rx_iso_meta *iso_meta; + struct node_rx_pdu *status_node_rx; + + /* Ensure there is always one free for reception + * of ISO PDU by the radio h/w DMA, hence peek + * for two available ISO PDU when using one for + * generating invalid ISO data. + */ + status_node_rx = ull_iso_pdu_rx_alloc_peek(2U); + if (!status_node_rx) { + break; + } + + status_node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU; + status_node_rx->hdr.handle = cis_lll->handle; + iso_meta = &status_node_rx->hdr.rx_iso_meta; + iso_meta->payload_number = (cis_lll->event_count * + cis_lll->rx.bn) + (bn - 1U); + iso_meta->timestamp = + HAL_TICKER_TICKS_TO_US(radio_tmr_start_get()) + + radio_tmr_ready_restore(); + iso_meta->timestamp %= + HAL_TICKER_TICKS_TO_US(BIT(HAL_TICKER_CNTR_MSBIT + 1U)); + iso_meta->status = 1U; + + ull_iso_pdu_rx_alloc(); + iso_rx_put(status_node_rx->hdr.link, status_node_rx); + + bn++; + } + +#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) + if (bn != cis_lll->rx.bn_curr) { + iso_rx_sched(); + } +#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ + + /* Reset indices for the next CIS */ + se_curr = 0U; /* isr_prepare_subevent() will increase se_curr */ + next_cis_lll->tx.bn_curr = 1U; + next_cis_lll->rx.bn_curr = 1U; + +#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) + radio_tx_power_set(next_cis_lll->tx_pwr_lvl); +#else + radio_tx_power_set(RADIO_TXP_DEFAULT); +#endif + + phy = next_cis_lll->tx.phy; + radio_phy_set(phy, next_cis_lll->tx.phy_flags); + radio_aa_set(next_cis_lll->access_addr); + radio_crc_configure(PDU_CRC_POLYNOMIAL, + sys_get_le24(next_conn_lll->crc_init)); + + param = next_cis_lll; + next_chan_use = next_cis_chan; + data_chan_prn_s = next_cis_chan_prn_s; + data_chan_remap_idx = next_cis_chan_remap_idx; } isr_prepare_subevent(param); @@ -691,23 +1022,23 @@ static void isr_prepare_subevent(void *param) cis_lll = param; /* Get ISO data PDU */ - if (bn_tx > cis_lll->tx.bn) { + if (cis_lll->tx.bn_curr > cis_lll->tx.bn) { payload_count = 0U; - cis_lll->empty = 1U; + cis_lll->npi = 1U; pdu_tx = radio_pkt_empty_get(); pdu_tx->ll_id = PDU_CIS_LLID_START_CONTINUE; pdu_tx->nesn = cis_lll->nesn; pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ - pdu_tx->cie = (bn_rx > cis_lll->rx.bn); + pdu_tx->cie = (cis_lll->rx.bn_curr > cis_lll->rx.bn); pdu_tx->npi = 1U; pdu_tx->len = 0U; } else { struct node_tx_iso *node_tx; memq_link_t *link; - payload_index = bn_tx - 1U; + payload_index = cis_lll->tx.bn_curr - 1U; payload_count = cis_lll->event_count * cis_lll->tx.bn + payload_index; @@ -726,23 +1057,18 @@ static void isr_prepare_subevent(void *param) } if (!link || (node_tx->payload_count != payload_count)) { - cis_lll->empty = 1U; + cis_lll->npi = 1U; pdu_tx = radio_pkt_empty_get(); pdu_tx->ll_id = PDU_CIS_LLID_START_CONTINUE; pdu_tx->nesn = cis_lll->nesn; - pdu_tx->cie = (bn_tx > cis_lll->tx.bn) && - (bn_rx > cis_lll->rx.bn); + pdu_tx->cie = (cis_lll->tx.bn_curr > cis_lll->tx.bn) && + (cis_lll->rx.bn_curr > cis_lll->rx.bn); pdu_tx->len = 0U; - if (bn_tx > cis_lll->tx.bn) { - pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ - pdu_tx->npi = 1U; - } else { - pdu_tx->sn = cis_lll->sn; - pdu_tx->npi = 0U; - } + pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ + pdu_tx->npi = 1U; } else { - cis_lll->empty = 0U; + cis_lll->npi = 0U; pdu_tx = (void *)node_tx->pdu; pdu_tx->nesn = cis_lll->nesn; @@ -758,7 +1084,7 @@ static void isr_prepare_subevent(void *param) #if defined(CONFIG_BT_CTLR_LE_ENC) /* Get reference to ACL context */ - struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); + const struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); #endif /* CONFIG_BT_CTLR_LE_ENC */ /* Encryption */ @@ -770,19 +1096,20 @@ static void isr_prepare_subevent(void *param) cis_lll->tx.ccm.counter = payload_count; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->tx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (cis_lll->tx.max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_tx_set(radio_ccm_tx_pkt_set(&cis_lll->tx.ccm, + radio_pkt_tx_set(radio_ccm_iso_tx_pkt_set(&cis_lll->tx.ccm, + RADIO_PKT_CONF_PDU_TYPE_CIS, pdu_tx)); #endif /* CONFIG_BT_CTLR_LE_ENC */ } else { uint8_t pkt_flags; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->tx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, @@ -792,15 +1119,9 @@ static void isr_prepare_subevent(void *param) lll_chan_set(next_chan_use); - subevent_us = radio_tmr_ready_restore(); - subevent_us += cis_lll->sub_interval * se_curr; - radio_tmr_rx_disable(); radio_tmr_tx_enable(); - /* Compensate for the 1 us added by radio_tmr_start_us() */ - start_us = subevent_us + 1U; - radio_tmr_tifs_set(EVENT_IFS_US); #if defined(CONFIG_BT_CTLR_PHY) @@ -809,6 +1130,13 @@ static void isr_prepare_subevent(void *param) radio_switch_complete_and_rx(0U); #endif /* !CONFIG_BT_CTLR_PHY */ + subevent_us = radio_tmr_ready_restore(); + subevent_us += cis_lll->offset - cis_offset_first + + (cis_lll->sub_interval * se_curr); + + /* Compensate for the 1 us added by radio_tmr_start_us() */ + start_us = subevent_us + 1U; + /* capture end of Tx-ed PDU, used to calculate HCTO. */ radio_tmr_end_capture(); @@ -851,22 +1179,26 @@ static void isr_done(void *param) /* Adjust sn when flushing Tx */ /* FIXME: When Flush Timeout is implemented */ - if (bn_tx <= cis_lll->tx.bn) { - cis_lll->sn += cis_lll->tx.bn + 1U - bn_tx; + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + lll_flush_tx(cis_lll); } /* Adjust nesn when flushing Rx */ /* FIXME: When Flush Timeout is implemented */ - if (bn_rx <= cis_lll->rx.bn) { - cis_lll->nesn += cis_lll->rx.bn + 1U - bn_rx; + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + lll_flush_rx(cis_lll); } /* Generate ISO Data Invalid Status */ - bn = bn_rx; + bn = cis_lll->rx.bn_curr; while (bn <= cis_lll->rx.bn) { struct node_rx_iso_meta *iso_meta; struct node_rx_pdu *node_rx; + /* Ensure there is always one free for reception of ISO PDU by + * the radio h/w DMA, hence peek for two available ISO PDU when + * using one for generating invalid ISO data. + */ node_rx = ull_iso_pdu_rx_alloc_peek(2U); if (!node_rx) { break; @@ -891,7 +1223,7 @@ static void isr_done(void *param) } #if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) - if (bn != bn_rx) { + if (bn != cis_lll->rx.bn_curr) { iso_rx_sched(); } #endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c index b38ff0ff8dc..1f3cd8a04af 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c @@ -39,7 +39,7 @@ #include "lll_tim_internal.h" #include "lll_prof_internal.h" -#include +#include #include "hal/debug.h" @@ -814,12 +814,12 @@ void lll_conn_pdu_tx_prep(struct lll_conn *lll, struct pdu_data **pdu_data_tx) } #if defined(CONFIG_BT_CTLR_FORCE_MD_AUTO) -uint8_t lll_conn_force_md_cnt_set(uint8_t force_md_cnt) +uint8_t lll_conn_force_md_cnt_set(uint8_t reload_cnt) { uint8_t previous; previous = force_md_cnt_reload; - force_md_cnt_reload = force_md_cnt; + force_md_cnt_reload = reload_cnt; return previous; } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c index d1500d2b29b..1c1f07938e0 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include "util/util.h" #include "util/memq.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c index 977fd15a8c3..14796717885 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c @@ -113,6 +113,7 @@ static int prepare_cb(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint32_t hcto; + uint32_t ret; DEBUG_RADIO_START_S(1); @@ -322,19 +323,22 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); + return -ECANCELED; } +#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ + + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_S(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c index 9053770b8ab..4796696ce73 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c @@ -44,17 +44,23 @@ static int prepare_cb(struct lll_prepare_param *p); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); static void isr_rx(void *param); static void isr_tx(void *param); +static void next_cis_prepare(void *param); static void isr_prepare_subevent(void *param); +static void isr_prepare_subevent_next_cis(void *param); +static void isr_prepare_subevent_common(void *param); static void isr_done(void *param); +static inline void lll_flush_tx(struct lll_conn_iso_stream *cis_lll); +static inline void lll_flush_rx(struct lll_conn_iso_stream *cis_lll); static uint8_t next_chan_use; static uint16_t data_chan_id; static uint16_t data_chan_prn_s; static uint16_t data_chan_remap_idx; + static uint32_t trx_performed_bitmask; +static uint16_t cis_offset_first; +static uint16_t cis_handle_curr; static uint8_t se_curr; -static uint8_t bn_tx; -static uint8_t bn_rx; static uint8_t has_tx; #if defined(CONFIG_BT_CTLR_LE_ENC) @@ -87,17 +93,26 @@ int lll_peripheral_iso_reset(void) void lll_peripheral_iso_prepare(void *param) { - struct lll_prepare_param *p = param; - struct lll_conn_iso_group *cig_lll = p->param; + struct lll_conn_iso_group *cig_lll; + struct lll_prepare_param *p; + uint16_t elapsed; int err; /* Initiate HF clock start up */ err = lll_hfclock_on(); LL_ASSERT(err >= 0); + /* Instants elapsed */ + p = param; + elapsed = p->lazy + 1U; + + /* Save the (latency + 1) for use in event and/or supervision timeout */ + cig_lll = p->param; + cig_lll->latency_prepare += elapsed; + /* Accumulate window widening */ cig_lll->window_widening_prepare_us_frac += - cig_lll->window_widening_periodic_us_frac * (p->lazy + 1); + cig_lll->window_widening_periodic_us_frac * elapsed; if (cig_lll->window_widening_prepare_us_frac > EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us)) { cig_lll->window_widening_prepare_us_frac = @@ -120,12 +135,30 @@ static int init_reset(void) return 0; } +static inline void lll_flush_tx(struct lll_conn_iso_stream *cis_lll) +{ + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + uint8_t sn_update = cis_lll->tx.bn + 1U - cis_lll->tx.bn_curr; + + /* TODO we'll re-use sn_update when implementing flush timeout */ + cis_lll->sn += sn_update; +} + +static inline void lll_flush_rx(struct lll_conn_iso_stream *cis_lll) +{ + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + uint8_t nesn_update = cis_lll->rx.bn + 1U - cis_lll->rx.bn_curr; + + /* TODO we'll re-use nesn_update when implementing flush timeout */ + cis_lll->nesn += nesn_update; +} + static int prepare_cb(struct lll_prepare_param *p) { struct lll_conn_iso_group *cig_lll = p->param; struct lll_conn_iso_stream *cis_lll; + const struct lll_conn *conn_lll; struct node_rx_pdu *node_rx; - struct lll_conn *conn_lll; uint32_t ticks_at_event; uint32_t ticks_at_start; struct node_tx_iso *tx; @@ -137,7 +170,10 @@ static int prepare_cb(struct lll_prepare_param *p) memq_link_t *link; uint32_t start_us; uint32_t hcto; + uint16_t lazy; + uint32_t ret; uint8_t phy; + int err = 0; DEBUG_RADIO_START_S(1); @@ -148,7 +184,15 @@ static int prepare_cb(struct lll_prepare_param *p) #endif /* CONFIG_BT_CTLR_LE_ENC */ /* Get the first CIS */ - cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, NULL); + cis_handle_curr = UINT16_MAX; + do { + cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle_curr); + } while (cis_lll && !cis_lll->active); + + LL_ASSERT(cis_lll); + + /* Save first active CIS offset */ + cis_offset_first = cis_lll->offset; /* Get reference to ACL context */ conn_lll = ull_conn_lll_get(cis_lll->acl_handle); @@ -164,9 +208,12 @@ static int prepare_cb(struct lll_prepare_param *p) &data_chan_prn_s, &data_chan_remap_idx); - se_curr = 1U; - bn_rx = 1U; - has_tx = 0U; + /* Store the current event latency */ + cig_lll->latency_event = cig_lll->latency_prepare; + lazy = cig_lll->latency_prepare - 1U; + + /* Reset accumulated latencies */ + cig_lll->latency_prepare = 0U; /* current window widening */ cig_lll->window_widening_event_us_frac += @@ -178,21 +225,28 @@ static int prepare_cb(struct lll_prepare_param *p) EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us); } + /* Adjust sn and nesn for skipped CIG events */ + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + cis_lll->sn += (cis_lll->tx.bn * lazy); + cis_lll->nesn += cis_lll->rx.bn * lazy; + + se_curr = 1U; + cis_lll->rx.bn_curr = 1U; + has_tx = 0U; + /* Start setting up of Radio h/w */ radio_reset(); #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) - radio_tx_power_set(lll->tx_pwr_lvl); -#else + radio_tx_power_set(cis_lll->tx_pwr_lvl); +#else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ radio_tx_power_set(RADIO_TXP_DEFAULT); -#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ +#endif /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ phy = cis_lll->rx.phy; radio_phy_set(phy, cis_lll->rx.phy_flags); radio_aa_set(cis_lll->access_addr); - conn_lll = ull_conn_lll_get(cis_lll->acl_handle); - radio_crc_configure(PDU_CRC_POLYNOMIAL, - sys_get_le24(conn_lll->crc_init)); + radio_crc_configure(PDU_CRC_POLYNOMIAL, sys_get_le24(conn_lll->crc_init)); lll_chan_set(data_chan_use); node_rx = ull_iso_pdu_rx_alloc_peek(1U); @@ -203,27 +257,28 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_LE_ENC) } else if (conn_lll->enc_rx) { - uint64_t payload_count; + uint64_t payload_cnt; uint8_t pkt_flags; - payload_count = (cis_lll->event_count * cis_lll->rx.bn) + - (bn_rx - 1U); - cis_lll->rx.ccm.counter = payload_count; + payload_cnt = (cis_lll->event_count * cis_lll->rx.bn) + + (cis_lll->rx.bn_curr - 1U); + cis_lll->rx.ccm.counter = payload_cnt; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (cis_lll->rx.max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_rx_set(radio_ccm_rx_pkt_set(&cis_lll->rx.ccm, phy, - node_rx->pdu)); + radio_pkt_rx_set(radio_ccm_iso_rx_pkt_set(&cis_lll->rx.ccm, phy, + RADIO_PKT_CONF_PDU_TYPE_CIS, + node_rx->pdu)); #endif /* CONFIG_BT_CTLR_LE_ENC */ } else { uint8_t pkt_flags; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, @@ -247,7 +302,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event += lll_event_offset_get(ull); ticks_at_start = ticks_at_event; - ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US); + ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US + + cis_offset_first); remainder = p->remainder; start_us = radio_tmr_start(0U, ticks_at_start, remainder); @@ -256,13 +312,18 @@ static int prepare_cb(struct lll_prepare_param *p) radio_tmr_aa_save(0U); radio_tmr_aa_capture(); + /* Header Complete Timeout, use additional EVENT_TICKER_RES_MARGIN_US to + * compensate for possible shift in ACL peripheral's anchor point at + * the instant the CIS is to be established. + * + * FIXME: use a one time value in a window member variable to avoid + * using this additional EVENT_TICKER_RES_MARGIN_US window in + * subsequent events once CIS is established. + */ hcto = start_us + ((EVENT_JITTER_US + EVENT_TICKER_RES_MARGIN_US + EVENT_US_FRAC_TO_US(cig_lll->window_widening_event_us_frac)) << - 1U); - - /* Compensate for unused ticker remainder value starting CIG */ - hcto += EVENT_TICKER_RES_MARGIN_US; + 1U) + EVENT_TICKER_RES_MARGIN_US; #if defined(CONFIG_BT_CTLR_PHY) hcto += radio_rx_ready_delay_get(cis_lll->rx.phy, PHY_FLAGS_S8); @@ -291,47 +352,75 @@ static int prepare_cb(struct lll_prepare_param *p) #endif /* !CONFIG_BT_CTLR_PHY */ #endif /* HAL_RADIO_GPIO_HAVE_LNA_PIN */ - if (false) { - #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) - /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, - (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), - ticks_at_event)) { - radio_isr_set(lll_isr_abort, cig_lll); - radio_disable(); + uint32_t overhead; - return -ECANCELED; -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), + ticks_at_event); + /* check if preempt to start has changed */ + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); - } else { - uint32_t ret; + radio_isr_set(isr_done, cis_lll); + radio_disable(); - ret = lll_prepare_done(cig_lll); - LL_ASSERT(!ret); + err = -ECANCELED; } +#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - /* FIXME: Update below implementation when supporting Flush Timeout */ + /* Adjust the SN and NESN for skipped CIG events */ + uint16_t cis_handle = cis_handle_curr; + + while (true) { + /* FIXME: Update below implementation when supporting Flush Timeout */ + payload_count = cis_lll->event_count * cis_lll->tx.bn; + do { + link = memq_peek(cis_lll->memq_tx.head, + cis_lll->memq_tx.tail, (void **)&tx); + if (link) { + if (tx->payload_count < payload_count) { + memq_dequeue(cis_lll->memq_tx.tail, + &cis_lll->memq_tx.head, + NULL); + + tx->next = link; + ull_iso_lll_ack_enqueue(cis_lll->handle, tx); + } else { + break; + } + } + } while (link); - payload_count = cis_lll->event_count * cis_lll->tx.bn; + cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle); + if (!cis_lll) { + break; + } - do { - link = memq_peek(cis_lll->memq_tx.head, - cis_lll->memq_tx.tail, (void **)&tx); - if (link) { - if (tx->payload_count < payload_count) { - memq_dequeue(cis_lll->memq_tx.tail, - &cis_lll->memq_tx.head, - NULL); - - tx->next = link; - ull_iso_lll_ack_enqueue(cis_lll->handle, tx); - } else { - break; + if (cis_lll->active) { + /* sn and nesn are 1-bit, only Least Significant bit is needed */ + cis_lll->sn += cis_lll->tx.bn * lazy; + cis_lll->nesn += cis_lll->rx.bn * lazy; + + /* Adjust sn and nesn for canceled events */ + if (err) { + /* Adjust nesn when flushing Rx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + lll_flush_rx(cis_lll); + } } } - } while (link); + }; + + /* Return if prepare callback cancelled */ + if (err) { + return err; + } + + /* Prepare is done */ + ret = lll_prepare_done(cig_lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_S(1); @@ -349,6 +438,20 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, NULL); + /* FIXME: Consider Flush Timeout when resetting current burst number */ + if (!has_tx) { + has_tx = 1U; + + /* Adjust nesn when flushing Tx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + lll_flush_tx(cis_lll); + } + + /* Set to last burst number in previous event */ + cis_lll->tx.bn_curr = cis_lll->tx.bn; + } + /* Perform event abort here. * After event has been cleanly aborted, clean up resources * and dispatch event done. @@ -371,9 +474,12 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) static void isr_rx(void *param) { struct lll_conn_iso_stream *cis_lll; + const struct lll_conn *conn_lll; struct pdu_cis *pdu_tx; uint64_t payload_count; uint8_t payload_index; + uint32_t subevent_us; + uint32_t start_us; uint8_t trx_done; uint8_t crc_ok; uint8_t cie; @@ -394,10 +500,24 @@ static void isr_rx(void *param) /* No Rx */ if (!trx_done) { + /* FIXME: Consider Flush Timeout when resetting current burst number */ + if (!has_tx) { + has_tx = 1U; + + /* Adjust nesn when flushing Tx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + lll_flush_tx(cis_lll); + } + + /* Start transmitting new burst */ + cis_lll->tx.bn_curr = cis_lll->tx.bn; + } + if (se_curr < cis_lll->nse) { radio_isr_set(isr_prepare_subevent, param); } else { - radio_isr_set(isr_done, param); + next_cis_prepare(param); } radio_disable(); @@ -419,14 +539,17 @@ static void isr_rx(void *param) radio_tmr_ready_save(radio_tmr_ready_get() - se_offset_us); } + /* Close subevent, one tx-rx chain */ + radio_switch_complete_and_disable(); + /* FIXME: Do not call this for every event/subevent */ ull_conn_iso_lll_cis_established(param); - /* FIXME: set the bit corresponding to CIS index */ - trx_performed_bitmask = 1U; + /* Set the bit corresponding to CIS index */ + trx_performed_bitmask |= (1U << LL_CIS_IDX_FROM_HANDLE(cis_lll->handle)); - /* Close subevent, one tx-rx chain */ - radio_switch_complete_and_disable(); + /* Get reference to ACL context */ + conn_lll = ull_conn_lll_get(cis_lll->acl_handle); if (crc_ok) { struct node_rx_pdu *node_rx; @@ -440,69 +563,29 @@ static void isr_rx(void *param) /* Tx ACK */ if (pdu_rx->nesn != cis_lll->sn) { - struct pdu_cis *pdu_tx; - /* Increment sequence number */ cis_lll->sn++; - /* Get reference to PDU Tx */ - if (cis_lll->empty) { - cis_lll->empty = 0U; - - pdu_tx = radio_pkt_empty_get(); - } else { - struct node_tx_iso *node_tx; - uint8_t payload_index; - memq_link_t *link; - - payload_index = bn_tx - 1U; - link = memq_peek_n(cis_lll->memq_tx.head, - cis_lll->memq_tx.tail, - payload_index, - (void **)&node_tx); - if (link) { - pdu_tx = (void *)node_tx->pdu; - } else { - pdu_tx = radio_pkt_empty_get(); - } - } - -#if defined(CONFIG_BT_CTLR_LE_ENC) - /* Get reference to ACL context */ - struct lll_conn *conn_lll = - ull_conn_lll_get(cis_lll->acl_handle); - - if (pdu_tx->len) { - /* if encrypted increment tx counter */ - if (conn_lll->enc_tx) { - cis_lll->tx.ccm.counter++; - } - } -#endif /* CONFIG_BT_CTLR_LE_ENC */ - /* Increment burst number */ - if (has_tx && (bn_tx <= cis_lll->tx.bn)) { - bn_tx++; + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + cis_lll->tx.bn_curr++; } /* TODO: Tx Ack */ + } - /* Rx receive */ + /* Handle valid ISO data Rx */ if (!pdu_rx->npi && - (bn_rx <= cis_lll->rx.bn) && + (cis_lll->rx.bn_curr <= cis_lll->rx.bn) && (pdu_rx->sn == cis_lll->nesn) && ull_iso_pdu_rx_alloc_peek(2U)) { struct node_rx_iso_meta *iso_meta; - /* Increment next expected serial number */ + /* Increment next expected sequence number */ cis_lll->nesn++; #if defined(CONFIG_BT_CTLR_LE_ENC) - /* Get reference to ACL context */ - struct lll_conn *conn_lll = - ull_conn_lll_get(cis_lll->acl_handle); - /* If required, wait for CCM to finish */ if (pdu_rx->len && conn_lll->enc_rx) { @@ -522,9 +605,6 @@ static void isr_rx(void *param) return; } - /* Increment counter */ - cis_lll->rx.ccm.counter++; - /* Record MIC valid */ mic_state = LLL_CONN_MIC_PASS; } @@ -536,10 +616,10 @@ static void isr_rx(void *param) iso_meta = &node_rx->hdr.rx_iso_meta; iso_meta->payload_number = (cis_lll->event_count * cis_lll->rx.bn) + - (bn_rx - 1U); - iso_meta->timestamp = + (cis_lll->rx.bn_curr - 1U); + iso_meta->timestamp = cis_lll->offset + HAL_TICKER_TICKS_TO_US(radio_tmr_start_get()) + - radio_tmr_aa_restore() - + radio_tmr_aa_restore() - cis_offset_first - addr_us_get(cis_lll->rx.phy); iso_meta->timestamp %= HAL_TICKER_TICKS_TO_US(BIT(HAL_TICKER_CNTR_MSBIT + 1U)); @@ -553,7 +633,26 @@ static void isr_rx(void *param) #endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ /* Increment burst number */ - bn_rx++; + cis_lll->rx.bn_curr++; + + /* Handle NULL PDU indication received */ + } else if (pdu_rx->npi) { + /* Source could not send ISO data, increment NESN as if + * we received and expect to receive the next PDU in the + * burst. + */ + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + /* Increment next expected serial number */ + cis_lll->nesn++; + + /* Increment burst number */ + cis_lll->rx.bn_curr++; + } + + /* Not NPI, or more than the BN, or no free Rx ISO PDU buffers. + */ + } else { + /* Do nothing, ignore the Rx buffer */ } /* Close Isochronous Event */ @@ -564,28 +663,26 @@ static void isr_rx(void *param) if (!has_tx) { has_tx = 1U; - /* Adjust sn when flushing Tx. Stop at sn != nesn, hence - * (bn < cis_lll->tx.bn). - */ + /* Adjust nesn when flushing Tx */ /* FIXME: When Flush Timeout is implemented */ - if (bn_tx < cis_lll->tx.bn) { - cis_lll->sn += cis_lll->tx.bn - bn_tx; + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + lll_flush_tx(cis_lll); } /* Start transmitting new burst */ - bn_tx = 1U; + cis_lll->tx.bn_curr = 1U; } /* Close Isochronous Event */ - cie = cie || ((bn_rx > cis_lll->rx.bn) && - (bn_tx > cis_lll->tx.bn) && + cie = cie || ((cis_lll->rx.bn_curr > cis_lll->rx.bn) && + (cis_lll->tx.bn_curr > cis_lll->tx.bn) && (se_curr < cis_lll->nse)); - /* TODO: Get ISO data PDU */ - if (bn_tx > cis_lll->tx.bn) { + /* Get ISO data PDU */ + if (cis_lll->tx.bn_curr > cis_lll->tx.bn) { payload_count = 0U; - cis_lll->empty = 1U; + cis_lll->npi = 1U; pdu_tx = radio_pkt_empty_get(); pdu_tx->ll_id = PDU_CIS_LLID_START_CONTINUE; @@ -598,7 +695,7 @@ static void isr_rx(void *param) struct node_tx_iso *tx; memq_link_t *link; - payload_index = bn_tx - 1U; + payload_index = cis_lll->tx.bn_curr - 1U; payload_count = cis_lll->event_count * cis_lll->tx.bn + payload_index; @@ -616,23 +713,18 @@ static void isr_rx(void *param) } if (!link || (tx->payload_count != payload_count)) { - cis_lll->empty = 1U; + cis_lll->npi = 1U; pdu_tx = radio_pkt_empty_get(); pdu_tx->ll_id = PDU_CIS_LLID_START_CONTINUE; pdu_tx->nesn = cis_lll->nesn; - pdu_tx->cie = (bn_tx > cis_lll->tx.bn) && - (bn_rx > cis_lll->rx.bn); + pdu_tx->cie = (cis_lll->tx.bn_curr > cis_lll->tx.bn) && + (cis_lll->rx.bn_curr > cis_lll->rx.bn); pdu_tx->len = 0U; - if (bn_tx > cis_lll->tx.bn) { - pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ - pdu_tx->npi = 1U; - } else { - pdu_tx->sn = cis_lll->sn; - pdu_tx->npi = 0U; - } + pdu_tx->sn = 0U; /* reserved RFU for NULL PDU */ + pdu_tx->npi = 1U; } else { - cis_lll->empty = 0U; + cis_lll->npi = 0U; pdu_tx = (void *)tx->pdu; pdu_tx->nesn = cis_lll->nesn; @@ -646,11 +738,6 @@ static void isr_rx(void *param) pdu_tx->rfu0 = 0U; pdu_tx->rfu1 = 0U; -#if defined(CONFIG_BT_CTLR_LE_ENC) - /* Get reference to ACL context */ - struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); -#endif /* CONFIG_BT_CTLR_LE_ENC */ - /* Encryption */ if (false) { @@ -660,20 +747,21 @@ static void isr_rx(void *param) cis_lll->tx.ccm.counter = payload_count; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->tx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (cis_lll->tx.max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_tx_set(radio_ccm_tx_pkt_set(&cis_lll->tx.ccm, + radio_pkt_tx_set(radio_ccm_iso_tx_pkt_set(&cis_lll->tx.ccm, + RADIO_PKT_CONF_PDU_TYPE_CIS, pdu_tx)); #endif /* CONFIG_BT_CTLR_LE_ENC */ } else { uint8_t pkt_flags; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->tx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, @@ -702,32 +790,6 @@ static void isr_rx(void *param) /* Schedule next subevent */ if (!cie && (se_curr < cis_lll->nse)) { - struct lll_conn *conn_lll; - uint32_t subevent_us; - uint32_t start_us; - - subevent_us = radio_tmr_aa_restore(); - subevent_us += cis_lll->sub_interval * se_curr; - subevent_us -= addr_us_get(cis_lll->rx.phy); - -#if defined(CONFIG_BT_CTLR_PHY) - subevent_us -= radio_rx_ready_delay_get(cis_lll->rx.phy, - PHY_FLAGS_S8); - subevent_us -= radio_rx_chain_delay_get(cis_lll->rx.phy, - PHY_FLAGS_S8); -#else /* !CONFIG_BT_CTLR_PHY */ - subevent_us -= radio_rx_ready_delay_get(0U, 0U); - subevent_us -= radio_rx_chain_delay_get(0U, 0U); -#endif /* !CONFIG_BT_CTLR_PHY */ - - start_us = radio_tmr_start_us(0U, subevent_us); - LL_ASSERT(start_us == (subevent_us + 1U)); - - radio_isr_set(isr_tx, param); - - /* Get reference to ACL context */ - conn_lll = ull_conn_lll_get(cis_lll->acl_handle); - /* Calculate the radio channel to use for next subevent */ next_chan_use = lll_chan_iso_subevent(data_chan_id, @@ -736,9 +798,64 @@ static void isr_rx(void *param) &data_chan_prn_s, &data_chan_remap_idx); } else { - /* ISO Event Done */ - radio_isr_set(isr_done, param); + struct lll_conn_iso_group *cig_lll; + uint16_t event_counter; + uint16_t cis_handle; + + /* Check for next active CIS */ + cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll); + cis_handle = cis_handle_curr; + do { + cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle); + } while (cis_lll && !cis_lll->active); + + if (!cis_lll) { + /* ISO Event Done */ + radio_isr_set(isr_done, param); + + return; + } + + cis_handle_curr = cis_handle; + + /* Event counter value, 0-15 bit of cisEventCounter */ + event_counter = cis_lll->event_count; + + /* Calculate the radio channel to use for next CIS ISO event */ + data_chan_id = lll_chan_id(cis_lll->access_addr); + next_chan_use = lll_chan_iso_event(event_counter, data_chan_id, + conn_lll->data_chan_map, + conn_lll->data_chan_count, + &data_chan_prn_s, + &data_chan_remap_idx); + + /* Reset indices for the next CIS */ + se_curr = 0U; /* isr_tx() will increase se_curr */ + cis_lll->tx.bn_curr = 1U; /* FIXME: may be this should be previous event value? */ + cis_lll->rx.bn_curr = 1U; + has_tx = 0U; } + + /* Schedule next subevent reception */ + subevent_us = radio_tmr_aa_restore(); + subevent_us += cis_lll->offset - cis_offset_first + + (cis_lll->sub_interval * se_curr); + subevent_us -= addr_us_get(cis_lll->rx.phy); + +#if defined(CONFIG_BT_CTLR_PHY) + subevent_us -= radio_rx_ready_delay_get(cis_lll->rx.phy, + PHY_FLAGS_S8); + subevent_us -= radio_rx_chain_delay_get(cis_lll->rx.phy, + PHY_FLAGS_S8); +#else /* !CONFIG_BT_CTLR_PHY */ + subevent_us -= radio_rx_ready_delay_get(0U, 0U); + subevent_us -= radio_rx_chain_delay_get(0U, 0U); +#endif /* !CONFIG_BT_CTLR_PHY */ + + start_us = radio_tmr_start_us(0U, subevent_us); + LL_ASSERT(start_us == (subevent_us + 1U)); + + radio_isr_set(isr_tx, cis_lll); } static void isr_tx(void *param) @@ -760,7 +877,7 @@ static void isr_tx(void *param) #if defined(CONFIG_BT_CTLR_LE_ENC) /* Get reference to ACL context */ - struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); + const struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); #endif /* CONFIG_BT_CTLR_LE_ENC */ /* Encryption */ @@ -772,24 +889,25 @@ static void isr_tx(void *param) uint8_t pkt_flags; payload_count = (cis_lll->event_count * cis_lll->rx.bn) + - (bn_rx - 1U); + (cis_lll->rx.bn_curr - 1U); cis_lll->rx.ccm.counter = payload_count; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->rx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (cis_lll->rx.max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_rx_set(radio_ccm_rx_pkt_set(&cis_lll->rx.ccm, - cis_lll->rx.phy, - node_rx->pdu)); + radio_pkt_rx_set(radio_ccm_iso_rx_pkt_set(&cis_lll->rx.ccm, + cis_lll->rx.phy, + RADIO_PKT_CONF_PDU_TYPE_CIS, + node_rx->pdu)); #endif /* CONFIG_BT_CTLR_LE_ENC */ } else { uint8_t pkt_flags; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->rx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, @@ -797,6 +915,8 @@ static void isr_tx(void *param) radio_pkt_rx_set(node_rx->pdu); } + radio_aa_set(cis_lll->access_addr); + lll_chan_set(next_chan_use); radio_tmr_tx_disable(); @@ -814,7 +934,8 @@ static void isr_tx(void *param) cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll); subevent_us = radio_tmr_aa_restore(); - subevent_us += cis_lll->sub_interval * se_curr; + subevent_us += cis_lll->offset - cis_offset_first + + (cis_lll->sub_interval * se_curr); subevent_us -= addr_us_get(cis_lll->rx.phy); #if defined(CONFIG_BT_CTLR_PHY) @@ -867,15 +988,38 @@ static void isr_tx(void *param) se_curr++; } -static void isr_prepare_subevent(void *param) +static void next_cis_prepare(void *param) { struct lll_conn_iso_stream *cis_lll; struct lll_conn_iso_group *cig_lll; - struct node_rx_pdu *node_rx; - struct lll_conn *conn_lll; - uint32_t subevent_us; - uint32_t start_us; - uint32_t hcto; + uint16_t cis_handle; + + /* Get reference to CIS LLL context */ + cis_lll = param; + + /* Check for next active CIS */ + cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll); + cis_handle = cis_handle_curr; + do { + cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle); + } while (cis_lll && !cis_lll->active); + + if (!cis_lll) { + /* ISO Event Done */ + radio_isr_set(isr_done, param); + + return; + } + + cis_handle_curr = cis_handle; + + radio_isr_set(isr_prepare_subevent_next_cis, cis_lll); +} + +static void isr_prepare_subevent(void *param) +{ + struct lll_conn_iso_stream *cis_lll; + const struct lll_conn *conn_lll; lll_isr_status_reset(); @@ -892,11 +1036,64 @@ static void isr_prepare_subevent(void *param) conn_lll->data_chan_count, &data_chan_prn_s, &data_chan_remap_idx); - lll_chan_set(next_chan_use); + + isr_prepare_subevent_common(param); +} + +static void isr_prepare_subevent_next_cis(void *param) +{ + struct lll_conn_iso_stream *cis_lll; + const struct lll_conn *conn_lll; + uint16_t event_counter; + + lll_isr_status_reset(); + + /* Get reference to CIS LLL context */ + cis_lll = param; + + /* Get reference to ACL context */ + conn_lll = ull_conn_lll_get(cis_lll->acl_handle); + + /* Event counter value, 0-15 bit of cisEventCounter */ + event_counter = cis_lll->event_count; + + /* Calculate the radio channel to use for next CIS ISO event */ + data_chan_id = lll_chan_id(cis_lll->access_addr); + next_chan_use = lll_chan_iso_event(event_counter, data_chan_id, + conn_lll->data_chan_map, + conn_lll->data_chan_count, + &data_chan_prn_s, + &data_chan_remap_idx); + + /* Reset indices for the next CIS */ + se_curr = 0U; /* isr_prepare_subevent_common() will increase se_curr */ + cis_lll->tx.bn_curr = 1U; /* FIXME: may be this should be previous event value? */ + cis_lll->rx.bn_curr = 1U; + has_tx = 0U; + + isr_prepare_subevent_common(param); +} + +static void isr_prepare_subevent_common(void *param) +{ + struct lll_conn_iso_stream *cis_lll; + struct lll_conn_iso_group *cig_lll; + struct node_rx_pdu *node_rx; + uint32_t subevent_us; + uint32_t start_us; + uint32_t hcto; + + /* Get reference to CIS LLL context */ + cis_lll = param; node_rx = ull_iso_pdu_rx_alloc_peek(1U); LL_ASSERT(node_rx); +#if defined(CONFIG_BT_CTLR_LE_ENC) + /* Get reference to ACL context */ + const struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle); +#endif /* CONFIG_BT_CTLR_LE_ENC */ + /* Encryption */ if (false) { @@ -906,24 +1103,25 @@ static void isr_prepare_subevent(void *param) uint8_t pkt_flags; payload_count = (cis_lll->event_count * cis_lll->rx.bn) + - (bn_rx - 1U); + (cis_lll->rx.bn_curr - 1U); cis_lll->rx.ccm.counter = payload_count; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->rx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (cis_lll->rx.max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_rx_set(radio_ccm_rx_pkt_set(&cis_lll->rx.ccm, - cis_lll->rx.phy, - node_rx->pdu)); + radio_pkt_rx_set(radio_ccm_iso_rx_pkt_set(&cis_lll->rx.ccm, + cis_lll->rx.phy, + RADIO_PKT_CONF_PDU_TYPE_CIS, + node_rx->pdu)); #endif /* CONFIG_BT_CTLR_LE_ENC */ } else { uint8_t pkt_flags; - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_DC, + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_CIS, cis_lll->rx.phy, RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, @@ -931,6 +1129,10 @@ static void isr_prepare_subevent(void *param) radio_pkt_rx_set(node_rx->pdu); } + radio_aa_set(cis_lll->access_addr); + + lll_chan_set(next_chan_use); + radio_tmr_tx_disable(); radio_tmr_rx_enable(); @@ -946,7 +1148,8 @@ static void isr_prepare_subevent(void *param) /* Anchor point sync-ed */ if (trx_performed_bitmask) { subevent_us = radio_tmr_aa_restore(); - subevent_us += cis_lll->sub_interval * se_curr; + subevent_us += cis_lll->offset - cis_offset_first + + (cis_lll->sub_interval * se_curr); subevent_us -= addr_us_get(cis_lll->rx.phy); #if defined(CONFIG_BT_CTLR_PHY) @@ -960,7 +1163,8 @@ static void isr_prepare_subevent(void *param) #endif /* !CONFIG_BT_CTLR_PHY */ } else { subevent_us = radio_tmr_ready_restore(); - subevent_us += cis_lll->sub_interval * se_curr; + subevent_us += cis_lll->offset - cis_offset_first + + (cis_lll->sub_interval * se_curr); } start_us = radio_tmr_start_us(0U, subevent_us); @@ -1025,12 +1229,12 @@ static void isr_done(void *param) /* Adjust nesn when flushing Rx */ /* FIXME: When Flush Timeout is implemented */ - if (bn_rx <= cis_lll->rx.bn) { - cis_lll->nesn += cis_lll->rx.bn + 1U - bn_rx; + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + lll_flush_rx(cis_lll); } /* Generate ISO Data Invalid Status */ - bn = bn_rx; + bn = cis_lll->rx.bn_curr; while (bn <= cis_lll->rx.bn) { struct node_rx_iso_meta *iso_meta; struct node_rx_pdu *node_rx; @@ -1046,14 +1250,14 @@ static void isr_done(void *param) iso_meta->payload_number = (cis_lll->event_count * cis_lll->rx.bn) + (bn - 1U); if (trx_performed_bitmask) { - iso_meta->timestamp = + iso_meta->timestamp = cis_lll->offset + HAL_TICKER_TICKS_TO_US(radio_tmr_start_get()) + - radio_tmr_aa_restore() - + radio_tmr_aa_restore() - cis_offset_first - addr_us_get(cis_lll->rx.phy); } else { - iso_meta->timestamp = + iso_meta->timestamp = cis_lll->offset + HAL_TICKER_TICKS_TO_US(radio_tmr_start_get()) + - radio_tmr_ready_restore(); + radio_tmr_ready_restore() - cis_offset_first; } iso_meta->timestamp %= HAL_TICKER_TICKS_TO_US(BIT(HAL_TICKER_CNTR_MSBIT + 1U)); @@ -1066,7 +1270,7 @@ static void isr_done(void *param) } #if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) - if (bn != bn_rx) { + if (bn != cis_lll->rx.bn_curr) { iso_rx_sched(); } #endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ @@ -1076,7 +1280,6 @@ static void isr_done(void *param) e->type = EVENT_DONE_EXTRA_TYPE_CIS; e->trx_performed_bitmask = trx_performed_bitmask; - e->crc_valid = 1U; #if defined(CONFIG_BT_CTLR_LE_ENC) e->mic_state = mic_state; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c index b5c12ab537c..0fa44d1447d 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -5,13 +5,11 @@ */ #include - -#include - -#include +#include +#include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -345,6 +343,7 @@ static int common_prepare_cb(struct lll_prepare_param *p, bool is_resume) struct lll_scan *lll; struct ull_hdr *ull; uint32_t remainder; + uint32_t ret; uint32_t aa; DEBUG_RADIO_START_O(1); @@ -477,58 +476,51 @@ static int common_prepare_cb(struct lll_prepare_param *p, bool is_resume) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_BASE + ull_scan_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_SCAN_BASE + - ull_scan_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_abort, lll); radio_disable(); - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED && - * (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) - */ - { - uint32_t ret; - - if (!is_resume && lll->ticks_window) { - /* start window close timeout */ - ret = ticker_start(TICKER_INSTANCE_ID_CTLR, - TICKER_USER_ID_LLL, - TICKER_ID_SCAN_STOP, - ticks_at_event, lll->ticks_window, - TICKER_NULL_PERIOD, - TICKER_NULL_REMAINDER, - TICKER_NULL_LAZY, TICKER_NULL_SLOT, - ticker_stop_cb, lll, - ticker_op_start_cb, - (void *)__LINE__); - LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || - (ret == TICKER_STATUS_BUSY)); - } + + return -ECANCELED; + } +#endif /* !CONFIG_BT_CTLR_XTAL_ADVANCED */ + + if (!is_resume && lll->ticks_window) { + /* start window close timeout */ + ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, TICKER_ID_SCAN_STOP, + ticks_at_event, lll->ticks_window, TICKER_NULL_PERIOD, + TICKER_NULL_REMAINDER, TICKER_NULL_LAZY, TICKER_NULL_SLOT, + ticker_stop_cb, lll, ticker_op_start_cb, (void *)__LINE__); + LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || + (ret == TICKER_STATUS_BUSY)); + } #if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED) - /* calc next group in us for the anchor where first connection - * event to be placed. - */ - if (lll->conn) { - static memq_link_t link; - static struct mayfly mfy_after_cen_offset_get = { - 0, 0, &link, NULL, - ull_sched_mfy_after_cen_offset_get}; - uint32_t retval; - - mfy_after_cen_offset_get.param = p; - - retval = mayfly_enqueue(TICKER_USER_ID_LLL, - TICKER_USER_ID_ULL_LOW, 1, - &mfy_after_cen_offset_get); - LL_ASSERT(!retval); - } -#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + /* calc next group in us for the anchor where first connection + * event to be placed. + */ + if (lll->conn) { + static memq_link_t link; + static struct mayfly mfy_after_cen_offset_get = { + 0U, 0U, &link, NULL, ull_sched_mfy_after_cen_offset_get}; + uint32_t retval; + + mfy_after_cen_offset_get.param = p; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); + retval = mayfly_enqueue(TICKER_USER_ID_LLL, TICKER_USER_ID_ULL_LOW, 1U, + &mfy_after_cen_offset_get); + LL_ASSERT(!retval); } +#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_O(1); @@ -1039,8 +1031,8 @@ static void isr_done_cleanup(void *param) * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, - TICKER_ID_SCAN_STOP, NULL, NULL); + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, + TICKER_ID_SCAN_STOP, NULL, NULL); #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) struct node_rx_hdr *node_rx; @@ -1091,18 +1083,18 @@ static void isr_done_cleanup(void *param) } if (lll->is_aux_sched) { - struct node_rx_pdu *node_rx; + struct node_rx_pdu *node_rx2; lll->is_aux_sched = 0U; - node_rx = ull_pdu_rx_alloc(); - LL_ASSERT(node_rx); + node_rx2 = ull_pdu_rx_alloc(); + LL_ASSERT(node_rx2); - node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; + node_rx2->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - node_rx->hdr.rx_ftr.param = lll; + node_rx2->hdr.rx_ftr.param = lll; - ull_rx_put_sched(node_rx->hdr.link, node_rx); + ull_rx_put_sched(node_rx2->hdr.link, node_rx2); } #endif /* CONFIG_BT_CTLR_ADV_EXT */ @@ -1275,6 +1267,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx, /* Active scanner */ } else if (((pdu_adv_rx->type == PDU_ADV_TYPE_ADV_IND) || (pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_IND)) && + (pdu_adv_rx->len >= offsetof(struct pdu_adv_adv_ind, data)) && (pdu_adv_rx->len <= sizeof(struct pdu_adv_adv_ind)) && lll->type && !lll->state && #if defined(CONFIG_BT_CENTRAL) @@ -1367,6 +1360,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx, else if (((((pdu_adv_rx->type == PDU_ADV_TYPE_ADV_IND) || (pdu_adv_rx->type == PDU_ADV_TYPE_NONCONN_IND) || (pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_IND)) && + (pdu_adv_rx->len >= offsetof(struct pdu_adv_adv_ind, data)) && (pdu_adv_rx->len <= sizeof(struct pdu_adv_adv_ind))) || ((pdu_adv_rx->type == PDU_ADV_TYPE_DIRECT_IND) && (pdu_adv_rx->len == sizeof(struct pdu_adv_direct_ind)) && @@ -1381,6 +1375,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx, &dir_report)) || #endif /* CONFIG_BT_CTLR_ADV_EXT */ ((pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_RSP) && + (pdu_adv_rx->len >= offsetof(struct pdu_adv_scan_rsp, data)) && (pdu_adv_rx->len <= sizeof(struct pdu_adv_scan_rsp)) && (lll->state != 0U) && isr_scan_rsp_adva_matches(pdu_adv_rx))) && @@ -1431,6 +1426,7 @@ static inline bool isr_scan_init_check(const struct lll_scan *lll, lll_scan_adva_check(lll, pdu->tx_addr, pdu->adv_ind.addr, rl_idx)) && (((pdu->type == PDU_ADV_TYPE_ADV_IND) && + (pdu->len >= offsetof(struct pdu_adv_adv_ind, data)) && (pdu->len <= sizeof(struct pdu_adv_adv_ind))) || ((pdu->type == PDU_ADV_TYPE_DIRECT_IND) && (pdu->len == sizeof(struct pdu_adv_direct_ind)) && diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index 652facac9e4..df9b8fd75ca 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -5,11 +5,12 @@ */ #include +#include #include #include -#include +#include #include "hal/ccm.h" #include "hal/radio.h" @@ -427,6 +428,7 @@ static int prepare_cb(struct lll_prepare_param *p) uint8_t is_lll_scan; uint32_t remainder; uint32_t hcto; + uint32_t ret; uint32_t aa; DEBUG_RADIO_START_O(1); @@ -559,43 +561,44 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_AUX_BASE + + ull_scan_aux_lll_handle_get(lll_aux)), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_SCAN_AUX_BASE + - ull_scan_aux_lll_handle_get(lll_aux)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_done, lll_aux); radio_disable(); - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; + + return -ECANCELED; + } +#endif /* !CONFIG_BT_CTLR_XTAL_ADVANCED */ #if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED) - /* calc end of group in us for the anchor where next connection - * event to be placed. - */ - if (lll && lll->conn) { - static memq_link_t link; - static struct mayfly mfy_after_cen_offset_get = { - 0, 0, &link, NULL, - ull_sched_mfy_after_cen_offset_get}; - - /* NOTE: LLL scan instance passed, as done when - * establishing legacy connections. - */ - p->param = lll; - mfy_after_cen_offset_get.param = p; + /* calc end of group in us for the anchor where next connection + * event to be placed. + */ + if (lll && lll->conn) { + static memq_link_t link; + static struct mayfly mfy_after_cen_offset_get = { + 0U, 0U, &link, NULL, ull_sched_mfy_after_cen_offset_get}; - ret = mayfly_enqueue(TICKER_USER_ID_LLL, - TICKER_USER_ID_ULL_LOW, 1, - &mfy_after_cen_offset_get); - LL_ASSERT(!ret); - } -#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + /* NOTE: LLL scan instance passed, as done when + * establishing legacy connections. + */ + p->param = lll; + mfy_after_cen_offset_get.param = p; - ret = lll_prepare_done(lll_aux); + ret = mayfly_enqueue(TICKER_USER_ID_LLL, TICKER_USER_ID_ULL_LOW, 1U, + &mfy_after_cen_offset_get); LL_ASSERT(!ret); } +#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + + ret = lll_prepare_done(lll_aux); + LL_ASSERT(!ret); DEBUG_RADIO_START_O(1); @@ -844,12 +847,12 @@ static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, } else { /* Send message to flush Auxiliary PDU list */ if (lll->is_aux_sched && err != -ECANCELED) { - struct node_rx_pdu *node_rx; + struct node_rx_pdu *node_rx2; - node_rx = ull_pdu_rx_alloc(); - LL_ASSERT(node_rx); + node_rx2 = ull_pdu_rx_alloc(); + LL_ASSERT(node_rx2); - node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; + node_rx2->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; /* Use LLL scan context pointer which will be resolved * to LLL aux context in the `ull_scan_aux_release` @@ -860,9 +863,9 @@ static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, * under race, if ULL execution did assign one, it will * free it. */ - node_rx->hdr.rx_ftr.param = lll; + node_rx2->hdr.rx_ftr.param = lll; - ull_rx_put_sched(node_rx->hdr.link, node_rx); + ull_rx_put_sched(node_rx2->hdr.link, node_rx2); } /* Check if LLL scheduled auxiliary PDU reception by scan @@ -900,7 +903,6 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, lll_scan_ext_tgta_check(lll, false, true, pdu, rl_idx, NULL)) { struct lll_scan_aux *lll_aux_to_use; - struct node_rx_ftr *ftr; struct node_rx_pdu *rx; struct pdu_adv *pdu_tx; uint32_t conn_space_us; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 0136692d58c..1ecec8d0f60 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -40,7 +40,7 @@ #include "ll_feat.h" -#include +#include #include #include "hal/debug.h" @@ -301,8 +301,6 @@ static int create_prepare_cb(struct lll_prepare_param *p) if (false) { #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) } else if (cfg->is_enabled) { - int err; - /* In case of call in create_prepare_cb, new sync event starts hence discard * previous incomplete state. */ @@ -312,8 +310,8 @@ static int create_prepare_cb(struct lll_prepare_param *p) err = lll_df_iq_report_no_resources_prepare(lll); if (!err) { err = lll_df_conf_cte_rx_enable(cfg->slot_durations, cfg->ant_sw_len, - cfg->ant_ids, chan_idx, CTE_INFO_IN_PAYLOAD, - lll->phy); + cfg->ant_ids, chan_idx, + CTE_INFO_IN_PAYLOAD, lll->phy); if (err) { lll->is_cte_incomplete = true; } @@ -388,8 +386,6 @@ static int prepare_cb(struct lll_prepare_param *p) cfg = lll_df_sync_cfg_latest_get(&lll->df_cfg, NULL); if (cfg->is_enabled) { - int err; - /* In case of call in prepare, new sync event starts hence discard previous * incomplete state. */ @@ -399,8 +395,8 @@ static int prepare_cb(struct lll_prepare_param *p) err = lll_df_iq_report_no_resources_prepare(lll); if (!err) { err = lll_df_conf_cte_rx_enable(cfg->slot_durations, cfg->ant_sw_len, - cfg->ant_ids, chan_idx, CTE_INFO_IN_PAYLOAD, - lll->phy); + cfg->ant_ids, chan_idx, + CTE_INFO_IN_PAYLOAD, lll->phy); if (err) { lll->is_cte_incomplete = true; } @@ -440,6 +436,7 @@ static int prepare_cb_common(struct lll_prepare_param *p, uint8_t chan_idx) struct ull_hdr *ull; uint32_t remainder; uint32_t hcto; + uint32_t ret; lll = p->param; @@ -507,22 +504,23 @@ static int prepare_cb_common(struct lll_prepare_param *p, uint8_t chan_idx) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_BASE + ull_sync_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_BASE + - ull_sync_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_done, lll); radio_disable(); return -ECANCELED; - } else + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_O(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index 22d4a6e7521..5089c6ccde7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -201,6 +201,7 @@ static int prepare_cb_common(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint32_t hcto; + uint32_t ret; uint8_t phy; DEBUG_RADIO_START_O(1); @@ -319,8 +320,9 @@ static int prepare_cb_common(struct lll_prepare_param *p) RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (lll->max_pdu + PDU_MIC_SIZE), pkt_flags); - radio_pkt_rx_set(radio_ccm_rx_pkt_set(&lll->ccm_rx, phy, - node_rx->pdu)); + radio_pkt_rx_set(radio_ccm_iso_rx_pkt_set(&lll->ccm_rx, phy, + RADIO_PKT_CONF_PDU_TYPE_BIS, + node_rx->pdu)); } else { uint8_t pkt_flags; @@ -368,24 +370,25 @@ static int prepare_cb_common(struct lll_prepare_param *p) HAL_RADIO_GPIO_LNA_OFFSET); #endif /* HAL_RADIO_GPIO_HAVE_LNA_PIN */ - if (0) { #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_ISO_BASE + + ull_sync_iso_lll_handle_get(lll)), ticks_at_event); /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_ISO_BASE + - ull_sync_iso_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - } else { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); /* Calculate ahead the next subevent channel index */ next_chan_calc(lll, event_counter, data_chan_id); @@ -527,14 +530,14 @@ static void isr_rx(void *param) /* Save the AA captured for the first anchor point sync */ if (!radio_tmr_aa_restore()) { - const struct lll_sync_iso_stream *stream; + const struct lll_sync_iso_stream *sync_stream; uint32_t se_offset_us; uint8_t se; crc_ok_anchor = crc_ok; - stream = ull_sync_iso_lll_stream_get(lll->stream_handle[0]); - se = ((lll->bis_curr - stream->bis_index) * + sync_stream = ull_sync_iso_lll_stream_get(lll->stream_handle[0]); + se = ((lll->bis_curr - sync_stream->bis_index) * ((lll->bn * lll->irc) + lll->ptc)) + ((lll->irc_curr - 1U) * lll->bn) + (lll->bn_curr - 1U) + lll->ptc_curr + lll->ctrl; @@ -551,7 +554,7 @@ static void isr_rx(void *param) /* Check CRC and generate ISO Data PDU */ if (crc_ok) { - struct lll_sync_iso_stream *stream; + struct lll_sync_iso_stream *sync_stream; uint16_t stream_handle; struct pdu_bis *pdu; @@ -598,10 +601,10 @@ static void isr_rx(void *param) } stream_handle = lll->stream_handle[lll->stream_curr]; - stream = ull_sync_iso_lll_stream_get(stream_handle); + sync_stream = ull_sync_iso_lll_stream_get(stream_handle); /* store the received PDU */ - if ((lll->bis_curr == stream->bis_index) && pdu->len && + if ((lll->bis_curr == sync_stream->bis_index) && pdu->len && !lll->payload[bis_idx][payload_index] && ((payload_index >= lll->payload_tail) || (payload_index < lll->payload_head))) { @@ -721,18 +724,18 @@ static void isr_rx(void *param) /* Next BIS */ if (lll->bis_curr < lll->num_bis) { const uint8_t stream_curr = lll->stream_curr + 1U; - struct lll_sync_iso_stream *stream; + struct lll_sync_iso_stream *sync_stream; uint16_t stream_handle; /* Next selected stream */ if (stream_curr < lll->stream_count) { lll->stream_curr = stream_curr; stream_handle = lll->stream_handle[lll->stream_curr]; - stream = ull_sync_iso_lll_stream_get(stream_handle); - if (stream->bis_index <= lll->num_bis) { + sync_stream = ull_sync_iso_lll_stream_get(stream_handle); + if (sync_stream->bis_index <= lll->num_bis) { uint8_t bis_idx_new; - lll->bis_curr = stream->bis_index; + lll->bis_curr = sync_stream->bis_index; lll->ptc_curr = 0U; lll->irc_curr = 1U; lll->bn_curr = 1U; @@ -903,7 +906,9 @@ static void isr_rx(void *param) (void)memcpy(lll->ccm_rx.iv, lll->giv, 4U); mem_xor_32(lll->ccm_rx.iv, lll->ccm_rx.iv, access_addr); - radio_pkt_rx_set(radio_ccm_rx_pkt_set(&lll->ccm_rx, lll->phy, pdu)); + radio_pkt_rx_set(radio_ccm_iso_rx_pkt_set(&lll->ccm_rx, lll->phy, + RADIO_PKT_CONF_PDU_TYPE_BIS, + pdu)); } else { struct pdu_bis *pdu; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c index 400c113b63c..90d00e624d4 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c @@ -41,7 +41,7 @@ #include "ull_df_internal.h" #endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */ -#include +#include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_vendor.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_vendor.h index 5ee063e4d53..92f0306ea79 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_vendor.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_vendor.h @@ -21,22 +21,22 @@ /* Active connection in peripheral role with extended scanning on 1M and Coded * PHY, scheduling and receiving auxiliary PDUs. */ -#define EVENT_OVERHEAD_START_US 458 +#define EVENT_OVERHEAD_START_US 733 /* 24 RTC ticks */ #else /* !CONFIG_BT_CTLR_PHY_CODED */ /* Active connection in peripheral role with extended scanning on 1M only, * scheduling and receiving auxiliary PDUs. */ -#define EVENT_OVERHEAD_START_US 428 +#define EVENT_OVERHEAD_START_US 428 /* 14 RTC ticks */ #endif /* !CONFIG_BT_CTLR_PHY_CODED */ #else /* !CONFIG_BT_OBSERVER */ /* Active connection in peripheral role with legacy scanning on 1M. */ -#define EVENT_OVERHEAD_START_US 275 +#define EVENT_OVERHEAD_START_US 275 /* 9 RTC ticks */ #endif /* !CONFIG_BT_OBSERVER */ #else /* !CONFIG_BT_CTLR_ADV_EXT */ /* Active connection in peripheral role with additional advertising state. */ -#define EVENT_OVERHEAD_START_US 275 +#define EVENT_OVERHEAD_START_US 275 /* 9 RTC ticks */ #endif /* !CONFIG_BT_CTLR_ADV_EXT */ /* Worst-case time margin needed after event end-time in the air diff --git a/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c b/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c index ffe57d1b2c1..a8727318cc0 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include "isoal.h" #include "ull_iso_types.h" diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c index edbb1b7d431..e3e2496b1a4 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c @@ -6,14 +6,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include "hal/cntr.h" +#include +#include "hal/cntr.h" #include "hal/debug.h" -#include -#include "ll_irqs.h" +#include "ll_irqs.h" #define PCS_SOURCE_RTC 2 diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h index f1f87c2efe0..45469ddeecd 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h @@ -85,6 +85,21 @@ extern const struct device *vega_debug_portd; vega_debug_portc = DEVICE_DT_GET(DT_NODELABEL(gpioc)); \ vega_debug_portd = DEVICE_DT_GET(DT_NODELABEL(gpiod)); \ \ + __ASSERT_NO_MSG(device_is_ready(vega_debug_portb)); \ + __ASSERT_NO_MSG(device_is_ready(vega_debug_portc)); \ + __ASSERT_NO_MSG(device_is_ready(vega_debug_portd)); \ + \ + gpio_pin_configure(DEBUG0_PORT, DEBUG0_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG1_PORT, DEBUG1_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG2_PORT, DEBUG2_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG3_PORT, DEBUG3_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG4_PORT, DEBUG4_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG5_PORT, DEBUG5_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG6_PORT, DEBUG6_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG7_PORT, DEBUG7_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG8_PORT, DEBUG8_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG9_PORT, DEBUG9_PIN, GPIO_OUTPUT); \ + \ gpio_pin_set(DEBUG0_PORT, DEBUG0_PIN, 1); \ gpio_pin_set(DEBUG0_PORT, DEBUG0_PIN, 0); \ } while (0) diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c index 8613c094528..2d6f7bb86cb 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c @@ -8,11 +8,10 @@ #include -#include - -#include #include +#include + #include "hal/ecb.h" #include diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c index 0ed3c6f348b..6107bfc9c68 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c index fea28ce18a9..aaa881fccd0 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c @@ -5,8 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include -#include #include "hal/cntr.h" diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll.c index f534e4c0105..c77e39e00f9 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll.c @@ -661,7 +661,7 @@ static void ticker_start_next_op_cb(uint32_t status, void *param) LL_ASSERT(status == TICKER_STATUS_SUCCESS); } -static uint32_t preempt_ticker_start(struct lll_event *event, +static uint32_t preempt_ticker_start(struct lll_event *evt, ticker_op_func op_cb) { struct lll_prepare_param *p; @@ -671,7 +671,7 @@ static uint32_t preempt_ticker_start(struct lll_event *event, uint32_t ret; /* Calc the preempt timeout */ - p = &event->prepare_param; + p = &evt->prepare_param; ull = HDR_LLL2ULL(p->param); preempt_anchor = p->ticks_at_expire; preempt_to = MAX(ull->ticks_active_to_start, @@ -688,8 +688,8 @@ static uint32_t preempt_ticker_start(struct lll_event *event, TICKER_NULL_REMAINDER, TICKER_NULL_LAZY, TICKER_NULL_SLOT, - preempt_ticker_cb, event, - op_cb, event); + preempt_ticker_cb, evt, + op_cb, evt); return ret; } diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c index 0988a606e12..df51202fdbc 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include +#include -#include -#include -#include +#include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c index 618be26ab5e..ddb74fef652 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c @@ -5,9 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include +#include +#include +#include +#include + +#include #include #include "hal/ccm.h" @@ -576,8 +579,8 @@ static void isr_abort(void *param) * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, - TICKER_ID_SCAN_STOP, NULL, NULL); + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, + TICKER_ID_SCAN_STOP, NULL, NULL); /* Under race conditions, radio could get started while entering ISR */ radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index b37a6b6030e..ceeb9ca12e7 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -251,6 +251,9 @@ #define PDU_ADV_DATA_HEADER_TYPE_OFFSET 1U #define PDU_ADV_DATA_HEADER_DATA_OFFSET 2U +/* Advertising Data Types in ACAD */ +#define PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND 0x28 + /* * Macros to return correct Data Channel PDU time * Note: formula is valid for 1M, 2M and Coded S8 @@ -265,6 +268,18 @@ #define PHY_FLAGS_S2 0 #define PHY_FLAGS_S8 BIT(0) +/* Macros for getting/setting did/sid from pdu_adv_adi */ +#define PDU_ADV_ADI_DID_GET(adi) ((adi)->did_sid_packed[0] | \ + (((adi)->did_sid_packed[1] & 0x0F) << 8)) +#define PDU_ADV_ADI_SID_GET(adi) (((adi)->did_sid_packed[1] >> 4) & 0x0F) +#define PDU_ADV_ADI_SID_SET(adi, sid) (adi)->did_sid_packed[1] = (((sid) << 4) + \ + ((adi)->did_sid_packed[1] & 0x0F)) +#define PDU_ADV_ADI_DID_SID_SET(adi, did, sid) \ + do { \ + (adi)->did_sid_packed[0] = (did) & 0xFF; \ + (adi)->did_sid_packed[1] = (((did) >> 8) & 0x0F) + ((sid) << 4); \ + } while (0) + #if defined(CONFIG_BT_CTLR_PHY_CODED) #define CODED_PHY_PREAMBLE_TIME_US 80 #define CODED_PHY_ACCESS_ADDRESS_TIME_US 256 @@ -339,6 +354,7 @@ ((enc) ? \ (PDU_MIC_SIZE) : 0), \ (phy)) +#define PDU_CIS_OFFSET_MIN_US 500U struct pdu_adv_adv_ind { uint8_t addr[BDADDR_SIZE]; @@ -429,13 +445,12 @@ enum pdu_adv_mode { #define PDU_ADV_SID_COUNT 16 struct pdu_adv_adi { -#ifdef CONFIG_LITTLE_ENDIAN - uint16_t did:12; - uint16_t sid:4; -#else - uint16_t sid:4; - uint16_t did:12; -#endif /* CONFIG_LITTLE_ENDIAN */ + /* did:12 + * sid:4 + * NOTE: This layout as bitfields is not portable for BE using + * endianness conversion macros. + */ + uint8_t did_sid_packed[2]; } __packed; struct pdu_adv_aux_ptr { diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 55f86966b9d..3f60290dba3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -248,6 +248,10 @@ #define TICKER_USER_ULL_HIGH_VENDOR_OPS 0 #endif /* TICKER_USER_ULL_HIGH_VENDOR_OPS */ +#if !defined(TICKER_USER_ULL_LOW_VENDOR_OPS) +#define TICKER_USER_ULL_LOW_VENDOR_OPS 0 +#endif /* TICKER_USER_ULL_LOW_VENDOR_OPS */ + #if !defined(TICKER_USER_THREAD_VENDOR_OPS) #define TICKER_USER_THREAD_VENDOR_OPS 0 #endif /* TICKER_USER_THREAD_VENDOR_OPS */ @@ -271,7 +275,7 @@ #define TICKER_USER_THREAD_OPS (1 + TICKER_USER_THREAD_VENDOR_OPS + 1) #endif /* !CONFIG_BT_CTLR_LOW_LAT */ -#define TICKER_USER_ULL_LOW_OPS (1 + 1) +#define TICKER_USER_ULL_LOW_OPS (1 + TICKER_USER_ULL_LOW_VENDOR_OPS + 1) /* NOTE: When ULL_LOW priority is configured to lower than ULL_HIGH, then extra * ULL_HIGH operations queue elements are required to buffer the @@ -323,8 +327,6 @@ static MFIFO_DEFINE(prep, sizeof(struct lll_event), EVENT_PIPELINE_MAX); * - mem_done: Backing data pool for struct node_rx_event_done elements * - mem_link_done: Pool of memq_link_t elements * - * An extra link may be reserved for use by the ull_done memq (EVENT_DONE_LINK_CNT). - * * Queue of pointers to struct node_rx_event_done. * The actual backing behind these pointers is mem_done. * @@ -362,8 +364,13 @@ static MFIFO_DEFINE(prep, sizeof(struct lll_event), EVENT_PIPELINE_MAX); #define EVENT_DONE_MAX VENDOR_EVENT_DONE_MAX #endif +/* Maximum time allowed for comleting synchronous LLL disabling via + * ull_disable. + */ +#define ULL_DISABLE_TIMEOUT K_MSEC(1000) + static RXFIFO_DEFINE(done, sizeof(struct node_rx_event_done), - EVENT_DONE_MAX, EVENT_DONE_LINK_CNT); + EVENT_DONE_MAX, 0U); /* Minimum number of node rx for ULL to LL/HCI thread per connection. * Increasing this by times the max. simultaneous connection count will permit @@ -494,9 +501,6 @@ static struct { static MEMQ_DECLARE(ull_rx); static MEMQ_DECLARE(ll_rx); -#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) -static MEMQ_DECLARE(ull_done); -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ #if defined(CONFIG_BT_CONN) static MFIFO_DEFINE(ll_pdu_rx_free, sizeof(void *), LL_PDU_RX_CNT); @@ -544,15 +548,12 @@ static inline void rx_demux_conn_tx_ack(uint8_t ack_last, uint16_t handle, memq_link_t *link, struct node_tx *node_tx); #endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO */ -static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx); +static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx); static inline void rx_demux_event_done(memq_link_t *link, struct node_rx_hdr *rx); static void ll_rx_link_quota_inc(void); static void ll_rx_link_quota_dec(void); static void disabled_cb(void *param); -#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) -static void ull_done(void *param); -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ int ll_init(struct k_sem *sem_rx) { @@ -1099,11 +1100,11 @@ void ll_rx_dequeue(void) LL_ASSERT(!lll_conn->link_tx_free); - memq_link_t *link = memq_deinit(&lll_conn->memq_tx.head, - &lll_conn->memq_tx.tail); - LL_ASSERT(link); + memq_link_t *memq_link = memq_deinit(&lll_conn->memq_tx.head, + &lll_conn->memq_tx.tail); + LL_ASSERT(memq_link); - lll_conn->link_tx_free = link; + lll_conn->link_tx_free = memq_link; struct ll_conn *conn = HDR_LLL2ULL(lll_conn); @@ -1143,17 +1144,17 @@ void ll_rx_dequeue(void) if (cc->status == BT_HCI_ERR_ADV_TIMEOUT) { struct lll_conn *conn_lll; struct ll_conn *conn; - memq_link_t *link; + memq_link_t *memq_link; conn_lll = lll->conn; LL_ASSERT(conn_lll); lll->conn = NULL; LL_ASSERT(!conn_lll->link_tx_free); - link = memq_deinit(&conn_lll->memq_tx.head, - &conn_lll->memq_tx.tail); - LL_ASSERT(link); - conn_lll->link_tx_free = link; + memq_link = memq_deinit(&conn_lll->memq_tx.head, + &conn_lll->memq_tx.tail); + LL_ASSERT(memq_link); + conn_lll->link_tx_free = memq_link; conn = HDR_LLL2ULL(conn_lll); ll_conn_release(conn); @@ -1804,26 +1805,54 @@ void ull_ticker_status_give(uint32_t status, void *param) k_sem_give(&sem_ticker_api_cb); } +/** + * @brief Take the ticker API semaphore (if applicable) and wait for operation + * complete. + * + * Waits for ticker operation to complete by taking ticker API semaphore, + * unless the operation was executed inline due to same-priority caller/ + * callee id. + * + * In case of asynchronous ticker operation (caller priority != + * callee priority), the function grabs the semaphore and waits for + * ull_ticker_status_give, which assigns the ret_cb variable and releases + * the semaphore. + * + * In case of synchronous ticker operation, the result is already known at + * entry, and semaphore is only taken if ret_cb has been updated. This is done + * to balance take/give counts. If *ret_cb is still TICKER_STATUS_BUSY, but + * ret is not, the ticker operation has failed early, and no callback will be + * invoked. In this case the semaphore shall not be taken. + * + * @param ret Return value from ticker API call: + * TICKER_STATUS_BUSY: Ticker operation is queued + * TICKER_STATUS_SUCCESS: Operation completed OK + * TICKER_STATUS_FAILURE: Operation failed + * + * @param ret_cb Pointer to user data passed to ticker operation + * callback, which holds the operation result. Value + * upon entry: + * TICKER_STATUS_BUSY: Ticker has not yet called CB + * TICKER_STATUS_SUCCESS: Operation completed OK via CB + * TICKER_STATUS_FAILURE: Operation failed via CB + * + * NOTE: For correct operation, *ret_cb must be initialized + * to TICKER_STATUS_BUSY before initiating the ticker API call. + * + * @return uint32_t Returns result of completed ticker operation + */ uint32_t ull_ticker_status_take(uint32_t ret, uint32_t volatile *ret_cb) { - if (ret == TICKER_STATUS_BUSY) { - /* TODO: Enable ticker job in case of CONFIG_BT_CTLR_LOW_LAT */ - } else { - /* Check for ticker operation enqueue failed, in which case - * function return value (ret) will be TICKER_STATUS_FAILURE - * and callback return value (ret_cb) will remain as - * TICKER_STATUS_BUSY. - * This assert check will avoid waiting forever to take the - * semaphore that will never be given when the ticker operation - * callback does not get called due to enqueue failure. + if ((ret == TICKER_STATUS_BUSY) || (*ret_cb != TICKER_STATUS_BUSY)) { + /* Operation is either pending of completed via callback + * prior to this function call. Take the sempaphore and wait, + * or take it to balance take/give counting. */ - LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || - (*ret_cb != TICKER_STATUS_BUSY)); + k_sem_take(&sem_ticker_api_cb, K_FOREVER); + return *ret_cb; } - k_sem_take(&sem_ticker_api_cb, K_FOREVER); - - return *ret_cb; + return ret; } void *ull_disable_mark(void *param) @@ -1944,7 +1973,7 @@ int ull_disable(void *lll) &mfy); LL_ASSERT(!ret); - return k_sem_take(&sem, K_FOREVER); + return k_sem_take(&sem, ULL_DISABLE_TIMEOUT); } void *ull_pdu_rx_alloc_peek(uint8_t count) @@ -1996,23 +2025,6 @@ void ull_rx_put_sched(memq_link_t *link, void *rx) ull_rx_sched(); } -#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) -void ull_rx_put_done(memq_link_t *link, void *done) -{ - /* Enqueue the done object */ - memq_enqueue(link, done, &memq_ull_done.tail); -} - -void ull_rx_sched_done(void) -{ - static memq_link_t link; - static struct mayfly mfy = {0, 0, &link, NULL, ull_done}; - - /* Kick the ULL (using the mayfly, tailchain it) */ - mayfly_enqueue(TICKER_USER_ID_LLL, TICKER_USER_ID_ULL_HIGH, 1, &mfy); -} -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ - struct lll_event *ull_prepare_enqueue(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, struct lll_prepare_param *prepare_param, @@ -2051,8 +2063,6 @@ void *ull_prepare_dequeue_iter(uint8_t *idx) void ull_prepare_dequeue(uint8_t caller_id) { - void *param_normal_head = NULL; - void *param_normal_next = NULL; void *param_resume_head = NULL; void *param_resume_next = NULL; struct lll_event *next; @@ -2093,41 +2103,31 @@ void ull_prepare_dequeue(uint8_t caller_id) /* The prepare element was not a resume event, it would * use the radio or was enqueued back into prepare * pipeline with a preempt timeout being set. - * - * Remember the first encountered and the next element - * in the prepare pipeline so that we do not infinitely - * loop through the resume events in prepare pipeline. */ if (!is_resume) { - if (!param_normal_head) { - param_normal_head = param; - } else if (!param_normal_next) { - param_normal_next = param; - } - } else { - if (!param_resume_head) { - param_resume_head = param; - } else if (!param_resume_next) { - param_resume_next = param; - } + break; + } + + /* Remember the first encountered resume and the next + * resume element in the prepare pipeline so that we do + * not infinitely loop through the resume events in + * prepare pipeline. + */ + if (!param_resume_head) { + param_resume_head = param; + } else if (!param_resume_next) { + param_resume_next = param; } /* Stop traversing the prepare pipeline when we reach - * back to the first or next event where we + * back to the first or next resume event where we * initially started processing the prepare pipeline. */ - if (!next->is_aborted && - ((!next->is_resume && - ((next->prepare_param.param == - param_normal_head) || - (next->prepare_param.param == - param_normal_next))) || - (next->is_resume && - !param_normal_next && - ((next->prepare_param.param == - param_resume_head) || - (next->prepare_param.param == - param_resume_next))))) { + if (next->is_resume && + ((next->prepare_param.param == + param_resume_head) || + (next->prepare_param.param == + param_resume_next))) { break; } } @@ -2185,12 +2185,7 @@ void *ull_event_done(void *param) evdone->hdr.type = NODE_RX_TYPE_EVENT_DONE; evdone->param = param; -#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) - ull_rx_put_done(link, evdone); - ull_rx_sched_done(); -#else ull_rx_put_sched(link, evdone); -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ return evdone; } @@ -2265,15 +2260,6 @@ static inline int init_reset(void) /* Initialize ull rx memq */ MEMQ_INIT(ull_rx, link); -#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) - /* Acquire a link to initialize ull done memq */ - link = mem_acquire(&mem_link_done.free); - LL_ASSERT(link); - - /* Initialize ull done memq */ - MEMQ_INIT(ull_done, link); -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ - /* Acquire a link to initialize ll rx memq */ link = mem_acquire(&mem_link_rx.free); LL_ASSERT(link); @@ -2466,7 +2452,6 @@ static void rx_demux(void *param) memq_link_t *link_tx; uint16_t handle; /* Handle to Ack TX */ #endif /* CONFIG_BT_CONN */ - int nack = 0; LL_ASSERT(rx); @@ -2479,17 +2464,11 @@ static void rx_demux(void *param) } else #endif /* CONFIG_BT_CONN */ { - nack = rx_demux_rx(link, rx); + rx_demux_rx(link, rx); } #if defined(CONFIG_BT_CTLR_LOW_LAT_ULL) - if (!nack) { - rx_demux_yield(); - } -#else /* !CONFIG_BT_CTLR_LOW_LAT_ULL */ - if (nack) { - break; - } + rx_demux_yield(); #endif /* !CONFIG_BT_CTLR_LOW_LAT_ULL */ #if defined(CONFIG_BT_CONN) @@ -2718,43 +2697,21 @@ static inline void rx_demux_conn_tx_ack(uint8_t ack_last, uint16_t handle, } #endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO */ -#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) -static void ull_done(void *param) -{ - memq_link_t *link; - struct node_rx_hdr *done; - - do { - link = memq_peek(memq_ull_done.head, memq_ull_done.tail, - (void **)&done); - - if (link) { - /* Process done event */ - (void)memq_dequeue(memq_ull_done.tail, - &memq_ull_done.head, NULL); - rx_demux_event_done(link, done); - } - } while (link); -} -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ - /** * @brief Dispatch rx objects * @details Rx objects are only peeked, not dequeued yet. * Execution context: ULL high priority Mayfly */ -static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) +static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) { /* Demux Rx objects */ switch (rx->type) { -#if defined(CONFIG_BT_CTLR_LOW_LAT_ULL) case NODE_RX_TYPE_EVENT_DONE: { (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); rx_demux_event_done(link, rx); } break; -#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ #if defined(CONFIG_BT_OBSERVER) #if defined(CONFIG_BT_CTLR_ADV_EXT) @@ -2796,7 +2753,7 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_OBSERVER */ -#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) +#if defined(CONFIG_BT_CTLR_CONN_ISO) case NODE_RX_TYPE_CIS_ESTABLISHED: { struct ll_conn *conn; @@ -2812,7 +2769,7 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) ll_rx_put_sched(link, rx); } break; -#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO */ +#endif /* CONFIG_BT_CTLR_CONN_ISO */ #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \ defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT) @@ -2837,16 +2794,12 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) case NODE_RX_TYPE_DC_PDU: { - int nack; - - nack = ull_conn_rx(link, (void *)&rx); - if (nack) { - return nack; - } + ull_conn_rx(link, (void *)&rx); (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); - if (rx) { + /* Only schedule node if not marked as retain by LLCP */ + if (rx && rx->type != NODE_RX_TYPE_RETAIN) { ll_rx_put_sched(link, rx); } } @@ -2921,8 +2874,6 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) } break; } - - return 0; } static inline void rx_demux_event_done(memq_link_t *link, diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index 01e84245923..3797acdc541 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" @@ -79,7 +79,6 @@ static uint16_t adv_time_get(struct pdu_adv *pdu, struct pdu_adv *pdu_scan, static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param); - static void ticker_update_op_cb(uint32_t status, void *param); #if defined(CONFIG_BT_PERIPHERAL) @@ -607,7 +606,7 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type, sizeof(struct pdu_adv_adi)); adi = (void *)pri_dptr; - adi->sid = sid; + PDU_ADV_ADI_SID_SET(adi, sid); } adv->sid = sid; @@ -1278,17 +1277,21 @@ uint8_t ll_adv_enable(uint8_t enable) lll->is_hdcd = !interval && (pdu_adv->type == PDU_ADV_TYPE_DIRECT_IND); if (lll->is_hdcd) { ret_cb = TICKER_STATUS_BUSY; + #if defined(CONFIG_BT_TICKER_EXT) #if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) ll_adv_ticker_ext[handle].ticks_slot_window = 0; #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ - ll_adv_ticker_ext[handle].ext_timeout_func = ticker_cb; + +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) ll_adv_ticker_ext[handle].expire_info_id = TICKER_NULL; + ll_adv_ticker_ext[handle].ext_timeout_func = ticker_cb; +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ ret = ticker_start_ext( -#else +#else /* !CONFIG_BT_TICKER_EXT */ ret = ticker_start( -#endif +#endif /* !CONFIG_BT_TICKER_EXT */ TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, (TICKER_ID_ADV_BASE + handle), @@ -1296,12 +1299,7 @@ uint8_t ll_adv_enable(uint8_t enable) (adv->ull.ticks_slot + ticks_slot_overhead), TICKER_NULL_REMAINDER, TICKER_NULL_LAZY, (adv->ull.ticks_slot + ticks_slot_overhead), -#if defined(CONFIG_BT_TICKER_EXT) - NULL, -#else - ticker_cb, -#endif /* CONFIG_BT_TICKER_EXT */ - adv, + ticker_cb, adv, ull_ticker_status_give, (void *)&ret_cb #if defined(CONFIG_BT_TICKER_EXT) , @@ -1394,7 +1392,7 @@ uint8_t ll_adv_enable(uint8_t enable) * started. */ if (sync) { - uint32_t ticks_slot_overhead; + uint32_t ticks_slot_overhead2; uint32_t ticks_slot_aux; #if defined(CONFIG_BT_CTLR_ADV_RESERVE_MAX) @@ -1438,10 +1436,10 @@ uint8_t ll_adv_enable(uint8_t enable) #endif /* CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET */ - ticks_slot_overhead = ull_adv_sync_evt_init(adv, sync, NULL); + ticks_slot_overhead2 = ull_adv_sync_evt_init(adv, sync, NULL); ret = ull_adv_sync_start(adv, sync, ticks_anchor_sync, - ticks_slot_overhead); + ticks_slot_overhead2); if (ret) { goto failure_cleanup; } @@ -1492,26 +1490,25 @@ uint8_t ll_adv_enable(uint8_t enable) #if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) ll_adv_ticker_ext[handle].ticks_slot_window = ULL_ADV_RANDOM_DELAY + ticks_slot; -#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ - ll_adv_ticker_ext[handle].ext_timeout_func = ticker_cb; - -#if defined(CONFIG_BT_CTLR_ADV_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (lll->aux) { uint8_t aux_handle = ull_adv_aux_handle_get(aux); ll_adv_ticker_ext[handle].expire_info_id = TICKER_ID_ADV_AUX_BASE + aux_handle; - } else -#endif /* CONFIG_BT_CTLR_ADV_EXT */ - { + ll_adv_ticker_ext[handle].ext_timeout_func = ticker_cb; + } else { ll_adv_ticker_ext[handle].expire_info_id = TICKER_NULL; + ll_adv_ticker_ext[handle].ext_timeout_func = ticker_cb; } +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ ret = ticker_start_ext( -#else +#else /* !CONFIG_BT_TICKER_EXT */ ret = ticker_start( -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* !CONFIG_BT_TICKER_EXT */ TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, (TICKER_ID_ADV_BASE + handle), @@ -1527,14 +1524,8 @@ uint8_t ll_adv_enable(uint8_t enable) TICKER_NULL_LAZY, #endif /* !CONFIG_BT_TICKER_LOW_LAT && !CONFIG_BT_CTLR_LOW_LAT */ ticks_slot, -#if defined(CONFIG_BT_TICKER_EXT) - NULL, -#else - ticker_cb, -#endif /* CONFIG_BT_TICKER_EXT */ - adv, - ull_ticker_status_give, - (void *)&ret_cb + ticker_cb, adv, + ull_ticker_status_give, (void *)&ret_cb #if defined(CONFIG_BT_TICKER_EXT) , &ll_adv_ticker_ext[handle] @@ -1629,7 +1620,7 @@ int ull_adv_init(void) return 0; } -int ull_adv_reset(void) +uint8_t ll_adv_disable_all(void) { uint8_t handle; @@ -1637,6 +1628,13 @@ int ull_adv_reset(void) (void)disable(handle); } + return 0U; +} + +int ull_adv_reset(void) +{ + (void)ll_adv_disable_all(); + #if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_HCI_RAW) ll_adv_cmds = LL_ADV_CMDS_ANY; @@ -1766,6 +1764,7 @@ struct ll_adv_set *ull_adv_is_created_get(uint8_t handle) return adv; } +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) void ull_adv_aux_created(struct ll_adv_set *adv) { if (adv->lll.aux && adv->is_enabled) { @@ -1778,6 +1777,7 @@ void ull_adv_aux_created(struct ll_adv_set *adv) TICKER_ID_ADV_AUX_BASE + aux_handle); } } +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ #endif /* CONFIG_BT_CTLR_ADV_EXT */ uint8_t ull_adv_data_set(struct ll_adv_set *adv, uint8_t len, @@ -2124,16 +2124,12 @@ const uint8_t *ull_adv_pdu_update_addrs(struct ll_adv_set *adv, uint8_t ull_adv_time_update(struct ll_adv_set *adv, struct pdu_adv *pdu, struct pdu_adv *pdu_scan) { - uint32_t volatile ret_cb; - uint32_t ticks_minus; - uint32_t ticks_plus; struct lll_adv *lll; uint32_t time_ticks; uint8_t phy_flags; uint16_t time_us; uint8_t chan_map; uint8_t chan_cnt; - uint32_t ret; uint8_t phy; lll = &adv->lll; @@ -2150,6 +2146,13 @@ uint8_t ull_adv_time_update(struct ll_adv_set *adv, struct pdu_adv *pdu, chan_cnt = util_ones_count_get(&chan_map, sizeof(chan_map)); time_us = adv_time_get(pdu, pdu_scan, chan_cnt, phy, phy_flags); time_ticks = HAL_TICKER_US_TO_TICKS(time_us); + +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + uint32_t volatile ret_cb; + uint32_t ticks_minus; + uint32_t ticks_plus; + uint32_t ret; + if (adv->ull.ticks_slot > time_ticks) { ticks_minus = adv->ull.ticks_slot - time_ticks; ticks_plus = 0U; @@ -2171,6 +2174,7 @@ uint8_t ull_adv_time_update(struct ll_adv_set *adv, struct pdu_adv *pdu, if (ret != TICKER_STATUS_SUCCESS) { return BT_HCI_ERR_CMD_DISALLOWED; } +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ adv->ull.ticks_slot = time_ticks; @@ -2295,12 +2299,12 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static memq_link_t link; static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_prepare}; static struct lll_prepare_param p; -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) struct ticker_ext_context *context = param; struct ll_adv_set *adv = context->context; -#else +#else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ struct ll_adv_set *adv = param; -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ uint32_t random_delay; struct lll_adv *lll; uint32_t ret; @@ -2333,15 +2337,8 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, ref = ull_ref_inc(&adv->ull); LL_ASSERT(ref); - /* Append timing parameters */ - p.ticks_at_expire = ticks_at_expire; - p.remainder = remainder; - p.lazy = lazy; - p.force = force; - p.param = lll; - mfy.param = &p; - -#if defined(CONFIG_BT_CTLR_ADV_EXT) && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) +#if defined(CONFIG_BT_CTLR_ADV_EXT) && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (adv->lll.aux) { uint32_t ticks_to_expire; uint32_t other_remainder; @@ -2357,13 +2354,32 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, adv->lll.aux->ticks_pri_pdu_offset = ticks_to_expire; adv->lll.aux->us_pri_pdu_offset = other_remainder; } -#endif /* CONFIG_BT_CTLR_ADV_EXT && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */ +#endif /* CONFIG_BT_CTLR_ADV_EXT && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && + * CONFIG_BT_TICKER_EXT_EXPIRE_INFO + */ + + /* Append timing parameters */ + p.ticks_at_expire = ticks_at_expire; + p.remainder = remainder; + p.lazy = lazy; + p.force = force; + p.param = lll; + mfy.param = &p; /* Kick LLL prepare */ ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 0, &mfy); LL_ASSERT(!ret); +#if defined(CONFIG_BT_CTLR_ADV_EXT) && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && \ + !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + if (adv->lll.aux) { + ull_adv_aux_offset_get(adv); + } +#endif /* CONFIG_BT_CTLR_ADV_EXT && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) + * !CONFIG_BT_TICKER_EXT_EXPIRE_INFO + */ + #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) adv->ticks_at_expire = ticks_at_expire; adv->delay_at_expire = adv->delay; @@ -2407,8 +2423,25 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static void ticker_update_op_cb(uint32_t status, void *param) { +#if defined(CONFIG_BT_PERIPHERAL) && (defined(CONFIG_BT_ASSERT) || defined(CONFIG_ASSERT)) + struct ll_adv_set *adv = param; + struct pdu_adv *pdu = lll_adv_data_peek(&adv->lll); + bool connectable = (pdu->type == PDU_ADV_TYPE_ADV_IND) || + (pdu->type == PDU_ADV_TYPE_DIRECT_IND) || +#if defined(CONFIG_BT_CTLR_ADV_EXT) + ((pdu->type == PDU_ADV_TYPE_EXT_IND) && + (pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_CONN)) || +#endif /* CONFIG_BT_CTLR_ADV_EXT */ + 0; +#endif /* CONFIG_BT_PERIPHERAL && (CONFIG_BT_ASSERT || CONFIG_ASSERT) */ + LL_ASSERT(status == TICKER_STATUS_SUCCESS || - param == ull_disable_mark_get()); + param == ull_disable_mark_get() || +#if defined(CONFIG_BT_PERIPHERAL) + /* if using connectable adv and lll.conn is 0 -> a connection is underway */ + (connectable && !adv->lll.conn) || +#endif /* CONFIG_BT_PERIPHERAL */ + 0); } #if defined(CONFIG_BT_PERIPHERAL) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index 337823a0bda..907a69b05c7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" @@ -58,6 +58,12 @@ static uint32_t aux_time_get(const struct ll_adv_aux_set *aux, static uint32_t aux_time_min_get(const struct ll_adv_aux_set *aux); static uint8_t aux_time_update(struct ll_adv_aux_set *aux, struct pdu_adv *pdu, struct pdu_adv *pdu_scan); + +#if !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +static void mfy_aux_offset_get(void *param); +static void ticker_op_cb(uint32_t status, void *param); +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param); @@ -65,9 +71,11 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static struct ll_adv_aux_set ll_adv_aux_pool[CONFIG_BT_CTLR_ADV_AUX_SET]; static void *adv_aux_free; -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +static void ticker_update_op_cb(uint32_t status, void *param); + static struct ticker_ext ll_adv_aux_ticker_ext[CONFIG_BT_CTLR_ADV_AUX_SET]; -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ +#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ #endif /* (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */ static uint16_t did_unique[PDU_ADV_SID_COUNT]; @@ -502,9 +510,9 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, /* Reduce the AD data in the previous PDU */ err = ull_adv_aux_pdu_set_clear(adv, pdu_prev, pdu, - (ULL_ADV_PDU_HDR_FIELD_AD_DATA | - ULL_ADV_PDU_HDR_FIELD_AUX_PTR), - 0, hdr_data); + (ULL_ADV_PDU_HDR_FIELD_AD_DATA | + ULL_ADV_PDU_HDR_FIELD_AUX_PTR), + 0U, hdr_data); if (err) { /* NOTE: latest PDU was not consumed by LLL and * as ull_adv_sync_pdu_alloc() has reverted back @@ -574,7 +582,7 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, if (adv->is_enabled) { struct ll_adv_aux_set *aux; - struct pdu_adv *pdu; + struct pdu_adv *chan_res_pdu; uint8_t tmp_idx; aux = HDR_LLL2ULL(adv->lll.aux); @@ -626,8 +634,8 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, } /* Update primary channel reservation */ - pdu = lll_adv_data_alloc(&adv->lll, &tmp_idx); - err = ull_adv_time_update(adv, pdu, NULL); + chan_res_pdu = lll_adv_data_alloc(&adv->lll, &tmp_idx); + err = ull_adv_time_update(adv, chan_res_pdu, NULL); if (err) { return err; } @@ -825,7 +833,7 @@ uint8_t ll_adv_aux_sr_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ULL_ADV_PDU_HDR_FIELD_AD_DATA_APPEND; err = ull_adv_aux_pdu_set_clear(adv, sr_pdu_prev, sr_pdu, hdr_add_fields, - 0, + 0U, hdr_data); } else { /* Add AD Data and remove any prior presence of Aux Ptr */ @@ -1400,7 +1408,7 @@ uint8_t ull_adv_aux_chm_update(void) ull_chan_map_get(aux->chm[chm_last].data_chan_map); aux->chm_last = chm_last; - if (!aux->is_started) { + if (IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) && !aux->is_started) { /* Ticker not started yet, apply new channel map now * Note that it should be safe to modify chm_first here * since advertising is not active @@ -1504,7 +1512,10 @@ uint8_t ull_adv_aux_hdr_set_clear(struct ll_adv_set *adv, } lll_aux = &aux->lll; - ull_adv_aux_created(adv); + + if (IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) { + ull_adv_aux_created(adv); + } is_aux_new = 1U; } else { @@ -1892,19 +1903,17 @@ uint8_t ull_adv_aux_hdr_set_clear(struct ll_adv_set *adv, pri_adi = (void *)pri_dptr; sec_adi = (void *)sec_dptr; - pri_adi->sid = adv->sid; - sec_adi->sid = adv->sid; - if (!adi) { /* The DID for a specific SID shall be unique. */ did = ull_adv_aux_did_next_unique_get(adv->sid); } else { - did = adi->did; + did = PDU_ADV_ADI_DID_GET(adi); } - pri_adi->did = sys_cpu_to_le16(did); - sec_adi->did = sys_cpu_to_le16(did); + did = sys_cpu_to_le16(did); + PDU_ADV_ADI_DID_SID_SET(pri_adi, did, adv->sid); + PDU_ADV_ADI_DID_SID_SET(sec_adi, did, adv->sid); /* No CTEInfo field in primary channel PDU */ @@ -2335,16 +2344,14 @@ uint8_t ull_adv_aux_pdu_set_clear(struct ll_adv_set *adv, adi_pdu = (void *)dptr; if (!adi) { - adi_pdu->sid = adv->sid; - /* The DID for a specific SID shall be unique. */ const uint16_t did = - ull_adv_aux_did_next_unique_get(adv->sid); - adi_pdu->did = sys_cpu_to_le16(did); + sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid)); + PDU_ADV_ADI_DID_SID_SET(adi_pdu, did, adv->sid); } else { - adi_pdu->sid = adi->sid; - adi_pdu->did = adi->did; + adi_pdu->did_sid_packed[0] = adi->did_sid_packed[0]; + adi_pdu->did_sid_packed[1] = adi->did_sid_packed[1]; } } @@ -2469,10 +2476,9 @@ uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux, ticks_slot = aux->ull.ticks_slot; #endif - err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD, - (ticks_slot + - ticks_slot_overhead), - &ticks_anchor_aux); + err = ull_sched_adv_aux_sync_free_anchor_get((ticks_slot + + ticks_slot_overhead), + &ticks_anchor_aux); if (!err) { *ticks_anchor = ticks_anchor_aux; *ticks_anchor += HAL_TICKER_US_TO_TICKS( @@ -2486,13 +2492,7 @@ uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux, return ticks_slot_overhead; } -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) -static void ticker_update_op_cb(uint32_t status, void *param) -{ - LL_ASSERT(status == TICKER_STATUS_SUCCESS || - param == ull_disable_mark_get()); -} - +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) void ull_adv_sync_started_stopped(struct ll_adv_aux_set *aux) { if (aux->is_started) { @@ -2520,7 +2520,7 @@ void ull_adv_sync_started_stopped(struct ll_adv_aux_set *aux) } } } -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, uint32_t ticks_slot_overhead) @@ -2534,10 +2534,9 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, aux_handle = ull_adv_aux_handle_get(aux); interval_us = aux->interval * PERIODIC_INT_UNIT_US; -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) - ll_adv_aux_ticker_ext[aux_handle].ext_timeout_func = ticker_cb; +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (aux->lll.adv->sync) { - struct ll_adv_sync_set *sync = HDR_LLL2ULL(aux->lll.adv->sync); + const struct ll_adv_sync_set *sync = HDR_LLL2ULL(aux->lll.adv->sync); uint8_t sync_handle = ull_adv_sync_handle_get(sync); ll_adv_aux_ticker_ext[aux_handle].expire_info_id = TICKER_ID_ADV_SYNC_BASE + @@ -2545,29 +2544,29 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, } else { ll_adv_aux_ticker_ext[aux_handle].expire_info_id = TICKER_NULL; } -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ + + ll_adv_aux_ticker_ext[aux_handle].ext_timeout_func = ticker_cb; ret_cb = TICKER_STATUS_BUSY; ret = ticker_start_ext( +#else /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_start( +#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, (TICKER_ID_ADV_AUX_BASE + aux_handle), ticks_anchor, 0U, HAL_TICKER_US_TO_TICKS(interval_us), HAL_TICKER_REMAINDER(interval_us), TICKER_NULL_LAZY, (aux->ull.ticks_slot + ticks_slot_overhead), -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) - NULL, -#else - ticker_cb, -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ - aux, - ull_ticker_status_give, (void *)&ret_cb, -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) - &ll_adv_aux_ticker_ext[aux_handle]); -#else - NULL); -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ - + ticker_cb, aux, + ull_ticker_status_give, (void *)&ret_cb +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + , + &ll_adv_aux_ticker_ext[aux_handle] +#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + ); ret = ull_ticker_status_take(ret, &ret_cb); return ret; @@ -2659,6 +2658,25 @@ uint32_t ull_adv_aux_time_get(const struct ll_adv_aux_set *aux, uint8_t pdu_len, return aux_time_get(aux, pdu, pdu_len, pdu_scan_len); } +#if !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +void ull_adv_aux_offset_get(struct ll_adv_set *adv) +{ + static memq_link_t link; + static struct mayfly mfy = {0, 0, &link, NULL, mfy_aux_offset_get}; + uint32_t ret; + + /* NOTE: Single mayfly instance is sufficient as primary channel PDUs + * use time reservation, and this mayfly shall complete within + * the radio event. Multiple advertising sets do not need + * independent mayfly allocations. + */ + mfy.param = adv; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1, + &mfy); + LL_ASSERT(!ret); +} +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + struct pdu_adv_aux_ptr *ull_adv_aux_lll_offset_fill(struct pdu_adv *pdu, uint32_t ticks_offset, uint32_t remainder_us, @@ -2840,10 +2858,11 @@ void ull_adv_aux_chain_pdu_duplicate(struct pdu_adv *pdu_prev, if (hdr_chain->adi) { struct pdu_adv_adi *adi; - /* update DID to superior PDU DID */ + /* update ADI to superior PDU ADI */ adi = (void *)dptr_chain; if (adi_parent) { - adi->did = adi_parent->did; + adi->did_sid_packed[0] = adi_parent->did_sid_packed[0]; + adi->did_sid_packed[1] = adi_parent->did_sid_packed[1]; } dptr_chain += sizeof(struct pdu_adv_adi); @@ -2974,15 +2993,18 @@ static uint32_t aux_time_min_get(const struct ll_adv_aux_set *aux) static uint8_t aux_time_update(struct ll_adv_aux_set *aux, struct pdu_adv *pdu, struct pdu_adv *pdu_scan) { - uint32_t volatile ret_cb; - uint32_t ticks_minus; - uint32_t ticks_plus; uint32_t time_ticks; uint32_t time_us; - uint32_t ret; time_us = aux_time_min_get(aux); time_ticks = HAL_TICKER_US_TO_TICKS(time_us); + +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + uint32_t volatile ret_cb; + uint32_t ticks_minus; + uint32_t ticks_plus; + uint32_t ret; + if (aux->ull.ticks_slot > time_ticks) { ticks_minus = aux->ull.ticks_slot - time_ticks; ticks_plus = 0U; @@ -3004,12 +3026,14 @@ static uint8_t aux_time_update(struct ll_adv_aux_set *aux, struct pdu_adv *pdu, if (ret != TICKER_STATUS_SUCCESS) { return BT_HCI_ERR_CMD_DISALLOWED; } +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ aux->ull.ticks_slot = time_ticks; return BT_HCI_ERR_SUCCESS; } +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) void ull_adv_aux_lll_auxptr_fill(struct pdu_adv *pdu, struct lll_adv *adv) { struct lll_adv_aux *lll_aux = adv->aux; @@ -3033,7 +3057,6 @@ void ull_adv_aux_lll_auxptr_fill(struct pdu_adv *pdu, struct lll_adv *adv) offset_us = HAL_TICKER_TICKS_TO_US(lll_aux->ticks_pri_pdu_offset) + lll_aux->us_pri_pdu_offset; if ((offset_us/OFFS_UNIT_30_US)*OFFS_UNIT_30_US < EVENT_MAFS_US + pdu_us) { - struct ll_adv_aux_set *aux = HDR_LLL2ULL(lll_aux); uint32_t interval_us; /* Offset too small, point to next aux packet instead */ @@ -3058,6 +3081,108 @@ void ull_adv_aux_lll_auxptr_fill(struct pdu_adv *pdu, struct lll_adv *adv) data_chan_map, data_chan_count); } +#else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +static void mfy_aux_offset_get(void *param) +{ + struct pdu_adv_aux_ptr *aux_ptr; + struct lll_adv_aux *lll_aux; + struct ll_adv_aux_set *aux; + uint32_t ticks_to_expire; + uint8_t data_chan_count; + uint8_t *data_chan_map; + uint32_t ticks_current; + struct ll_adv_set *adv; + struct pdu_adv *pdu; + uint32_t remainder; + uint8_t ticker_id; + uint8_t retry; + uint8_t id; + + adv = param; + lll_aux = adv->lll.aux; + aux = HDR_LLL2ULL(lll_aux); + ticker_id = TICKER_ID_ADV_AUX_BASE + ull_adv_aux_handle_get(aux); + + id = TICKER_NULL; + ticks_to_expire = 0U; + ticks_current = 0U; + retry = 4U; + do { + uint32_t volatile ret_cb; + uint32_t ticks_previous; + uint32_t ret; + bool success; + + ticks_previous = ticks_current; + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW, + &id, &ticks_current, + &ticks_to_expire, &remainder, + NULL, NULL, NULL, + ticker_op_cb, (void *)&ret_cb); + if (ret == TICKER_STATUS_BUSY) { + while (ret_cb == TICKER_STATUS_BUSY) { + ticker_job_sched(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW); + } + } + + success = (ret_cb == TICKER_STATUS_SUCCESS); + LL_ASSERT(success); + + LL_ASSERT((ticks_current == ticks_previous) || retry--); + + LL_ASSERT(id != TICKER_NULL); + } while (id != ticker_id); + + /* Adjust ticks to expire based on remainder value */ + hal_ticker_remove_jitter(&ticks_to_expire, &remainder); + + /* Store the ticks offset for population in other advertising primary + * channel PDUs. + */ + lll_aux->ticks_pri_pdu_offset = ticks_to_expire; + + /* NOTE: as first primary channel PDU does not use remainder, the packet + * timer is started one tick in advance to start the radio with + * microsecond precision, hence compensate for the higher start_us value + * captured at radio start of the first primary channel PDU. + */ + lll_aux->ticks_pri_pdu_offset += 1U; + + /* Store the microsecond remainder offset for population in other + * advertising primary channel PDUs. + */ + lll_aux->us_pri_pdu_offset = remainder; + + /* Fill the aux offset in the first Primary channel PDU */ + /* FIXME: we are in ULL_LOW context, fill offset in LLL context? */ + pdu = lll_adv_data_latest_peek(&adv->lll); + aux_ptr = ull_adv_aux_lll_offset_fill(pdu, ticks_to_expire, remainder, + 0U); + + /* Process channel map update, if any */ + if (aux->chm_first != aux->chm_last) { + /* Use channelMapNew */ + aux->chm_first = aux->chm_last; + } + + /* Calculate the radio channel to use */ + data_chan_map = aux->chm[aux->chm_first].data_chan_map; + data_chan_count = aux->chm[aux->chm_first].data_chan_count; + aux_ptr->chan_idx = lll_chan_sel_2(lll_aux->data_chan_counter, + aux->data_chan_id, + data_chan_map, data_chan_count); +} + +static void ticker_op_cb(uint32_t status, void *param) +{ + *((uint32_t volatile *)param) = status; +} +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param) @@ -3065,12 +3190,12 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static memq_link_t link; static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_aux_prepare}; static struct lll_prepare_param p; -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) struct ticker_ext_context *context = param; struct ll_adv_aux_set *aux = context->context; -#else +#else /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ struct ll_adv_aux_set *aux = param; -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ +#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ struct lll_adv_aux *lll; uint32_t ret; uint8_t ref; @@ -3083,14 +3208,7 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, ref = ull_ref_inc(&aux->ull); LL_ASSERT(ref); - /* Append timing parameters */ - p.ticks_at_expire = ticks_at_expire; - p.remainder = remainder; - p.lazy = lazy; - p.force = force; - p.param = lll; - mfy.param = &p; - +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) struct ll_adv_set *adv; @@ -3133,15 +3251,47 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, /* Use channelMapNew */ aux->chm_first = aux->chm_last; } +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + + /* Append timing parameters */ + p.ticks_at_expire = ticks_at_expire; + p.remainder = remainder; + p.lazy = lazy; + p.force = force; + p.param = lll; + mfy.param = &p; /* Kick LLL prepare */ ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 0, &mfy); LL_ASSERT(!ret); +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + struct ll_adv_set *adv; + + adv = HDR_LLL2ULL(lll->adv); + if (adv->lll.sync) { + struct ll_adv_sync_set *sync; + + sync = HDR_LLL2ULL(adv->lll.sync); + if (sync->is_started) { + sync->aux_remainder = remainder; + ull_adv_sync_offset_get(adv); + } + } +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC && !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + DEBUG_RADIO_PREPARE_A(1); } +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +static void ticker_update_op_cb(uint32_t status, void *param) +{ + LL_ASSERT(status == TICKER_STATUS_SUCCESS || + param == ull_disable_mark_get()); +} +#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + #else /* !(CONFIG_BT_CTLR_ADV_AUX_SET > 0) */ static int init_reset(void) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h index 341f010adeb..00bf3c126df 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h @@ -107,6 +107,9 @@ struct ll_adv_aux_set *ull_adv_aux_get(uint8_t handle); uint32_t ull_adv_aux_time_get(const struct ll_adv_aux_set *aux, uint8_t pdu_len, uint8_t pdu_scan_len); +/* helper function to schedule a mayfly to get aux offset */ +void ull_adv_aux_offset_get(struct ll_adv_set *adv); + /* Below are BT Spec v5.2, Vol 6, Part B Section 2.3.4 Table 2.12 defined */ #define ULL_ADV_PDU_HDR_FIELD_NONE 0 #define ULL_ADV_PDU_HDR_FIELD_ADVA BIT(0) @@ -229,8 +232,8 @@ int ull_adv_sync_reset_finalize(void); /* Return ll_adv_sync_set context (unconditional) */ struct ll_adv_sync_set *ull_adv_sync_get(uint8_t handle); -/* Return the sync set handle given the sync set instance */ -uint16_t ull_adv_sync_handle_get(struct ll_adv_sync_set *sync); +/* Return the aux set handle given the sync set instance */ +uint16_t ull_adv_sync_handle_get(const struct ll_adv_sync_set *sync); /* helper function to release periodic advertising instance */ void ull_adv_sync_release(struct ll_adv_sync_set *sync); @@ -286,6 +289,9 @@ void ull_adv_sync_extra_data_set_clear(void *extra_data_prev, uint16_t hdr_rem_fields, void *data); +/* helper function to schedule a mayfly to get sync offset */ +void ull_adv_sync_offset_get(struct ll_adv_set *adv); + int ull_adv_iso_init(void); int ull_adv_iso_reset(void); @@ -298,6 +304,9 @@ uint8_t ull_adv_iso_chm_update(void); /* helper function to cleanup after channel map update complete */ void ull_adv_iso_chm_complete(struct node_rx_hdr *rx); +/* helper function to schedule a mayfly to get BIG offset */ +void ull_adv_iso_offset_get(struct ll_adv_sync_set *sync); + /* helper function to handle adv ISO done BIG complete events */ void ull_adv_iso_done_complete(struct node_rx_event_done *done); diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 0b1eb155032..765e911b208 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -7,8 +7,7 @@ #include #include #include -#include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -62,6 +61,7 @@ static uint32_t adv_iso_start(struct ll_adv_iso_set *adv_iso, uint32_t iso_interval_us); static uint8_t adv_iso_chm_update(uint8_t big_handle); static void adv_iso_chm_complete_commit(struct lll_adv_iso *lll_iso); +static void mfy_iso_offset_get(void *param); static void pdu_big_info_chan_map_phy_set(uint8_t *chm_phy, uint8_t *chan_map, uint8_t phy); static inline struct pdu_big_info *big_info_get(struct pdu_adv *pdu); @@ -71,6 +71,7 @@ static inline void big_info_offset_fill(struct pdu_big_info *bi, static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param); +static void ticker_op_cb(uint32_t status, void *param); static void ticker_stop_op_cb(uint32_t status, void *param); static void adv_iso_disable(void *param); static void disabled_cb(void *param); @@ -250,7 +251,7 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, */ iso_interval_us = ((sdu_interval * lll_adv_iso->bn * sdu_per_event) / (bn * PERIODIC_INT_UNIT_US)) * PERIODIC_INT_UNIT_US; - lll_adv_iso->iso_interval = iso_interval_us; + lll_adv_iso->iso_interval = iso_interval_us / PERIODIC_INT_UNIT_US; /* Immediate Repetition Count (IRC), Mandatory IRC = 1 */ lll_adv_iso->irc = rtn + 1U; @@ -408,6 +409,7 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, pdu_big_info_chan_map_phy_set(big_info->chm_phy, lll_adv_iso->data_chan_map, phy); + /* Assign the 39-bit payload count, and 1-bit framing */ big_info->payload_count_framing[0] = lll_adv_iso->payload_count; big_info->payload_count_framing[1] = lll_adv_iso->payload_count >> 8; big_info->payload_count_framing[2] = lll_adv_iso->payload_count >> 16; @@ -483,8 +485,10 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, /* Associate the ISO instance with a Periodic Advertising */ lll_adv_sync->iso = lll_adv_iso; +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) /* Notify the sync instance */ ull_adv_iso_created(HDR_LLL2ULL(lll_adv_sync)); +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /* Commit the BIGInfo in the ACAD field of Periodic Advertising */ lll_adv_sync_data_enqueue(lll_adv_sync, ter_idx); @@ -556,7 +560,7 @@ uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason) stream_handle = lll_adv_iso->stream_handle[num_bis]; handle = LL_BIS_ADV_HANDLE_FROM_IDX(stream_handle); err = ll_remove_iso_path(handle, - BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); + BIT(BT_HCI_DATAPATH_DIR_HOST_TO_CTLR)); if (err) { return err; } @@ -710,6 +714,64 @@ uint8_t ll_adv_iso_by_hci_handle_new(uint8_t hci_handle, uint8_t *handle) } #endif /* CONFIG_BT_CTLR_HCI_ADV_HANDLE_MAPPING */ +void ull_adv_iso_offset_get(struct ll_adv_sync_set *sync) +{ + static memq_link_t link; + static struct mayfly mfy = {0U, 0U, &link, NULL, mfy_iso_offset_get}; + uint32_t ret; + + mfy.param = sync; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1, + &mfy); + LL_ASSERT(!ret); +} + +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +void ull_adv_iso_lll_biginfo_fill(struct pdu_adv *pdu, struct lll_adv_sync *lll_sync) +{ + struct lll_adv_iso *lll_iso; + uint16_t latency_prepare; + struct pdu_big_info *bi; + uint64_t payload_count; + + lll_iso = lll_sync->iso; + + /* Calculate current payload count. If refcount is non-zero, we have called + * prepare and the LLL implementation has incremented latency_prepare already. + * In this case we need to subtract lazy + 1 from latency_prepare + */ + latency_prepare = lll_iso->latency_prepare; + if (ull_ref_get(HDR_LLL2ULL(lll_iso))) { + /* We are in post-prepare. latency_prepare is already + * incremented by lazy + 1 for next event + */ + latency_prepare -= lll_iso->iso_lazy + 1; + } + + payload_count = lll_iso->payload_count + ((latency_prepare + + lll_iso->iso_lazy) * lll_iso->bn); + + bi = big_info_get(pdu); + big_info_offset_fill(bi, lll_iso->ticks_sync_pdu_offset, 0U); + /* Assign the 39-bit payload count, retaining the 1 MS bit framing value */ + bi->payload_count_framing[0] = payload_count; + bi->payload_count_framing[1] = payload_count >> 8; + bi->payload_count_framing[2] = payload_count >> 16; + bi->payload_count_framing[3] = payload_count >> 24; + bi->payload_count_framing[4] &= ~0x7F; + bi->payload_count_framing[4] |= (payload_count >> 32) & 0x7F; + + /* Update Channel Map in the BIGInfo until Thread context gets a + * chance to update the PDU with new Channel Map. + */ + if (lll_sync->iso_chm_done_req != lll_sync->iso_chm_done_ack) { + pdu_big_info_chan_map_phy_set(bi->chm_phy, + lll_iso->data_chan_map, + lll_iso->phy); + } +} +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + void ull_adv_iso_done_complete(struct node_rx_event_done *done) { struct ll_adv_iso_set *adv_iso; @@ -929,8 +991,7 @@ static uint32_t adv_iso_start(struct ll_adv_iso_set *adv_iso, /* Find the slot after Periodic Advertisings events */ ticks_anchor = ticker_ticks_now_get() + HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US); - err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD, - ticks_slot, &ticks_anchor); + err = ull_sched_adv_aux_sync_free_anchor_get(ticks_slot, &ticks_anchor); if (!err) { ticks_anchor += HAL_TICKER_US_TO_TICKS( MAX(EVENT_MAFS_US, @@ -1052,37 +1113,76 @@ static void adv_iso_chm_complete_commit(struct lll_adv_iso *lll_iso) lll_adv_sync_data_enqueue(lll_sync, ter_idx); } -void ull_adv_iso_lll_biginfo_fill(struct pdu_adv *pdu, struct lll_adv_sync *lll_sync) +static void mfy_iso_offset_get(void *param) { + struct lll_adv_sync *lll_sync; + struct ll_adv_sync_set *sync; struct lll_adv_iso *lll_iso; - uint16_t latency_prepare; + uint32_t ticks_to_expire; struct pdu_big_info *bi; + uint32_t ticks_current; uint64_t payload_count; - + struct pdu_adv *pdu; + uint8_t ticker_id; + uint16_t lazy; + uint8_t retry; + uint8_t id; + + sync = param; + lll_sync = &sync->lll; lll_iso = lll_sync->iso; + ticker_id = TICKER_ID_ADV_ISO_BASE + lll_iso->handle; - /* Calculate current payload count. If refcount is non-zero, we have called - * prepare and the LLL implementation has incremented latency_prepare already. - * In this case we need to subtract lazy + 1 from latency_prepare - */ - latency_prepare = lll_iso->latency_prepare; - if (ull_ref_get(HDR_LLL2ULL(lll_iso))) { - /* We are in post-prepare. latency_prepare is already - * incremented by lazy + 1 for next event - */ - latency_prepare -= lll_iso->iso_lazy + 1; - } + id = TICKER_NULL; + ticks_to_expire = 0U; + ticks_current = 0U; + retry = 4U; + do { + uint32_t volatile ret_cb; + uint32_t ticks_previous; + uint32_t ret; + bool success; + + ticks_previous = ticks_current; + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW, + &id, &ticks_current, + &ticks_to_expire, NULL, &lazy, + NULL, NULL, + ticker_op_cb, (void *)&ret_cb); + if (ret == TICKER_STATUS_BUSY) { + /* Busy wait until Ticker Job is enabled after any Radio + * event is done using the Radio hardware. Ticker Job + * ISR is disabled during Radio events in LOW_LAT + * feature to avoid Radio ISR latencies. + */ + while (ret_cb == TICKER_STATUS_BUSY) { + ticker_job_sched(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW); + } + } - payload_count = lll_iso->payload_count + ((latency_prepare + - lll_iso->iso_lazy) * lll_iso->bn); + success = (ret_cb == TICKER_STATUS_SUCCESS); + LL_ASSERT(success); + + LL_ASSERT((ticks_current == ticks_previous) || retry--); + + LL_ASSERT(id != TICKER_NULL); + } while (id != ticker_id); + payload_count = lll_iso->payload_count + + (((uint64_t)lll_iso->latency_prepare + lazy) * lll_iso->bn); + + pdu = lll_adv_sync_data_latest_peek(lll_sync); bi = big_info_get(pdu); - big_info_offset_fill(bi, lll_iso->ticks_sync_pdu_offset, 0U); + big_info_offset_fill(bi, ticks_to_expire, 0U); + /* Assign the 39-bit payload count, retaining the 1 MS bit framing value */ bi->payload_count_framing[0] = payload_count; bi->payload_count_framing[1] = payload_count >> 8; bi->payload_count_framing[2] = payload_count >> 16; bi->payload_count_framing[3] = payload_count >> 24; - bi->payload_count_framing[4] = payload_count >> 32; bi->payload_count_framing[4] &= ~0x7F; bi->payload_count_framing[4] |= (payload_count >> 32) & 0x7F; @@ -1168,6 +1268,7 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, { static struct lll_prepare_param p; struct ll_adv_iso_set *adv_iso = param; + uint32_t remainder_us; uint32_t ret; uint8_t ref; @@ -1190,9 +1291,22 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, &mfy_lll_prepare); LL_ASSERT(!ret); + /* Calculate the BIG reference point of current BIG event */ + remainder_us = remainder; + hal_ticker_remove_jitter(&ticks_at_expire, &remainder_us); + ticks_at_expire &= HAL_TICKER_CNTR_MASK; + adv_iso->big_ref_point = isoal_get_wrapped_time_us(HAL_TICKER_TICKS_TO_US(ticks_at_expire), + (remainder_us + + EVENT_OVERHEAD_START_US)); + DEBUG_RADIO_PREPARE_A(1); } +static void ticker_op_cb(uint32_t status, void *param) +{ + *((uint32_t volatile *)param) = status; +} + static void ticker_stop_op_cb(uint32_t status, void *param) { static memq_link_t link; @@ -1269,20 +1383,20 @@ static void tx_lll_flush(void *param) struct lll_adv_iso_stream *stream; struct node_tx_iso *tx; uint16_t stream_handle; - memq_link_t *link; + memq_link_t *link2; uint16_t handle; stream_handle = lll->stream_handle[num_bis]; handle = LL_BIS_ADV_HANDLE_FROM_IDX(stream_handle); stream = ull_adv_iso_stream_get(stream_handle); - link = memq_dequeue(stream->memq_tx.tail, &stream->memq_tx.head, - (void **)&tx); - while (link) { - tx->next = link; + link2 = memq_dequeue(stream->memq_tx.tail, &stream->memq_tx.head, + (void **)&tx); + while (link2) { + tx->next = link2; ull_iso_lll_ack_enqueue(handle, tx); - link = memq_dequeue(stream->memq_tx.tail, + link2 = memq_dequeue(stream->memq_tx.tail, &stream->memq_tx.head, (void **)&tx); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index c45a545fc51..178116a54ec 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" @@ -51,22 +51,36 @@ static int init_reset(void); static uint8_t adv_type_check(struct ll_adv_set *adv); static inline struct ll_adv_sync_set *sync_acquire(void); static inline void sync_release(struct ll_adv_sync_set *sync); +static inline uint16_t sync_handle_get(const struct ll_adv_sync_set *sync); static uint32_t sync_time_get(const struct ll_adv_sync_set *sync, const struct pdu_adv *pdu); static inline uint8_t sync_remove(struct ll_adv_sync_set *sync, struct ll_adv_set *adv, uint8_t enable); static uint8_t sync_chm_update(uint8_t handle); -static inline struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu); -static inline void sync_info_offset_fill(struct pdu_adv_sync_info *si, - uint32_t offs); -#if defined(CONFIG_BT_CTLR_ADV_ISO) -static struct ticker_ext ll_adv_sync_ticker_ext[CONFIG_BT_CTLR_ADV_SYNC_SET]; -#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +static void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs); + +#else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +static void mfy_sync_offset_get(void *param); +static void sync_info_offset_fill(struct pdu_adv_sync_info *si, + uint32_t ticks_offset, + uint32_t remainder_us, + uint32_t start_us); +static void ticker_op_cb(uint32_t status, void *param); +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + +static struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu); static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param); +#if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +static void ticker_update_op_cb(uint32_t status, void *param); + +static struct ticker_ext ll_adv_sync_ticker_ext[CONFIG_BT_CTLR_ADV_SYNC_SET]; +#endif /* !CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + static struct ll_adv_sync_set ll_adv_sync_pool[CONFIG_BT_CTLR_ADV_SYNC_SET]; static void *adv_sync_free; @@ -85,8 +99,6 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags) } if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) { - uint8_t err; - err = adv_type_check(adv); if (err) { return err; @@ -98,7 +110,6 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags) struct pdu_adv *ter_pdu; struct lll_adv *lll; uint8_t chm_last; - int err; sync = sync_acquire(); if (!sync) { @@ -210,25 +221,19 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags) return 0; } -#if defined(CONFIG_BT_CTLR_ADV_ISO) -static void ticker_update_op_cb(uint32_t status, void *param) -{ - LL_ASSERT(status == TICKER_STATUS_SUCCESS || - param == ull_disable_mark_get()); -} - +#if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) void ull_adv_iso_created(struct ll_adv_sync_set *sync) { if (sync->lll.iso && sync->is_started) { uint8_t iso_handle = sync->lll.iso->handle; - uint8_t handle = ull_adv_sync_handle_get(sync); + uint8_t handle = sync_handle_get(sync); ticker_update_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, (TICKER_ID_ADV_SYNC_BASE + handle), 0, 0, 0, 0, 0, 0, ticker_update_op_cb, sync, 0, TICKER_ID_ADV_ISO_BASE + iso_handle); } } -#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, uint8_t const *const data) @@ -260,8 +265,6 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, /* Check for advertising set type */ if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) { - uint8_t err; - err = adv_type_check(adv); if (err) { return err; @@ -749,8 +752,6 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable) /* Check for advertising set type */ if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) { - uint8_t err; - err = adv_type_check(adv); if (err) { return BT_HCI_ERR_CMD_DISALLOWED; @@ -907,9 +908,8 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable) HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US); #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED) - err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD, - sync->ull.ticks_slot, - &ticks_anchor_sync); + err = ull_sched_adv_aux_sync_free_anchor_get(sync->ull.ticks_slot, + &ticks_anchor_sync); if (!err) { ticks_anchor_sync += HAL_TICKER_US_TO_TICKS( MAX(EVENT_MAFS_US, @@ -979,7 +979,8 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable) } aux->is_started = 1U; - } else { + + } else if (IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) { /* notify the auxiliary set */ ull_adv_sync_started_stopped(HDR_LLL2ULL(lll_aux)); } @@ -1068,14 +1069,14 @@ struct ll_adv_sync_set *ull_adv_sync_get(uint8_t handle) return &ll_adv_sync_pool[handle]; } -uint16_t ull_adv_sync_handle_get(struct ll_adv_sync_set *sync) +uint16_t ull_adv_sync_handle_get(const struct ll_adv_sync_set *sync) { - return mem_index_get(sync, ll_adv_sync_pool, sizeof(struct ll_adv_sync_set)); + return sync_handle_get(sync); } -uint16_t ull_adv_sync_lll_handle_get(struct lll_adv_sync *lll) +uint16_t ull_adv_sync_lll_handle_get(const struct lll_adv_sync *lll) { - return ull_adv_sync_handle_get((void *)lll->hdr.parent); + return sync_handle_get((void *)lll->hdr.parent); } void ull_adv_sync_release(struct ll_adv_sync_set *sync) @@ -1160,37 +1161,39 @@ uint32_t ull_adv_sync_start(struct ll_adv_set *adv, interval_us = (uint32_t)sync->interval * PERIODIC_INT_UNIT_US; - sync_handle = ull_adv_sync_handle_get(sync); + sync_handle = sync_handle_get(sync); -#if defined(CONFIG_BT_CTLR_ADV_ISO) - ll_adv_sync_ticker_ext[sync_handle].ext_timeout_func = ticker_cb; +#if defined(CONFIG_BT_CTLR_ADV_ISO) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (sync->lll.iso) { ll_adv_sync_ticker_ext[sync_handle].expire_info_id = TICKER_ID_ADV_ISO_BASE + sync->lll.iso->handle; } else { ll_adv_sync_ticker_ext[sync_handle].expire_info_id = TICKER_NULL; } -#endif /* CONFIG_BT_CTLR_ADV_ISO */ + + ll_adv_sync_ticker_ext[sync_handle].ext_timeout_func = ticker_cb; ret_cb = TICKER_STATUS_BUSY; - ret = ticker_start_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, + ret = ticker_start_ext( +#else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_start( +#endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, (TICKER_ID_ADV_SYNC_BASE + sync_handle), ticks_anchor, 0U, HAL_TICKER_US_TO_TICKS(interval_us), HAL_TICKER_REMAINDER(interval_us), TICKER_NULL_LAZY, (sync->ull.ticks_slot + ticks_slot_overhead), -#if defined(CONFIG_BT_CTLR_ADV_ISO) - NULL, -#else - ticker_cb, -#endif /* CONFIG_BT_CTLR_ADV_ISO */ - sync, - ull_ticker_status_give, (void *)&ret_cb, -#if defined(CONFIG_BT_CTLR_ADV_ISO) + ticker_cb, sync, + ull_ticker_status_give, (void *)&ret_cb +#if defined(CONFIG_BT_CTLR_ADV_ISO) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + , &ll_adv_sync_ticker_ext[sync_handle] -#else - NULL -#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ ); ret = ull_ticker_status_take(ret, &ret_cb); @@ -1200,15 +1203,18 @@ uint32_t ull_adv_sync_start(struct ll_adv_set *adv, uint8_t ull_adv_sync_time_update(struct ll_adv_sync_set *sync, struct pdu_adv *pdu) { - uint32_t volatile ret_cb; - uint32_t ticks_minus; - uint32_t ticks_plus; uint32_t time_ticks; uint32_t time_us; - uint32_t ret; time_us = sync_time_get(sync, pdu); time_ticks = HAL_TICKER_US_TO_TICKS(time_us); + +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + uint32_t volatile ret_cb; + uint32_t ticks_minus; + uint32_t ticks_plus; + uint32_t ret; + if (sync->ull.ticks_slot > time_ticks) { ticks_minus = sync->ull.ticks_slot - time_ticks; ticks_plus = 0U; @@ -1222,13 +1228,14 @@ uint8_t ull_adv_sync_time_update(struct ll_adv_sync_set *sync, ret_cb = TICKER_STATUS_BUSY; ret = ticker_update(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, - (TICKER_ID_ADV_SYNC_BASE + ull_adv_sync_handle_get(sync)), + (TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync)), 0, 0, ticks_plus, ticks_minus, 0, 0, ull_ticker_status_give, (void *)&ret_cb); ret = ull_ticker_status_take(ret, &ret_cb); if (ret != TICKER_STATUS_SUCCESS) { return BT_HCI_ERR_CMD_DISALLOWED; } +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ sync->ull.ticks_slot = time_ticks; @@ -1258,7 +1265,6 @@ void ull_adv_sync_chm_complete(struct node_rx_hdr *rx) struct pdu_adv *pdu_prev; struct ll_adv_set *adv; struct pdu_adv *pdu; - uint8_t others_len; uint8_t acad_len; uint8_t *others; uint8_t ter_idx; @@ -1289,12 +1295,6 @@ void ull_adv_sync_chm_complete(struct node_rx_hdr *rx) /* Dev assert if ACAD empty */ LL_ASSERT(hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET]); - /* Get the pointer, prev content and size of current ACAD */ - err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, - ULL_ADV_PDU_HDR_FIELD_ACAD, 0U, - &hdr_data); - LL_ASSERT(!err); - /* Find the Channel Map Update Indication */ acad_len = hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET]; len = acad_len; @@ -1305,7 +1305,7 @@ void ull_adv_sync_chm_complete(struct node_rx_hdr *rx) ad_len = ad[PDU_ADV_DATA_HEADER_LEN_OFFSET]; if (ad_len && (ad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] == - BT_DATA_CHANNEL_MAP_UPDATE_IND)) { + PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND)) { break; } @@ -1324,8 +1324,7 @@ void ull_adv_sync_chm_complete(struct node_rx_hdr *rx) ad_len += 1U; others = ad + ad_len; acad_len -= ad_len; - others_len = acad_len - (ad - acad); - (void)memmove(ad, others, others_len); + (void)memmove(ad, others, acad_len); /* Adjust the next PDU for ACAD length, this is done by using the next * PDU to copy ACAD into same next PDU. @@ -1363,6 +1362,20 @@ void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync, si->evt_cntr = 0U; } +#if !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +void ull_adv_sync_offset_get(struct ll_adv_set *adv) +{ + static memq_link_t link; + static struct mayfly mfy = {0, 0, &link, NULL, mfy_sync_offset_get}; + uint32_t ret; + + mfy.param = adv; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1, + &mfy); + LL_ASSERT(!ret); +} +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags, uint8_t phy_s, uint8_t phy_flags, struct pdu_cte_info *cte_info) @@ -1705,19 +1718,22 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, /* Add/Retain/Remove ACAD */ if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_ACAD) { + /* remember the new acad data len */ acad_len = *(uint8_t *)hdr_data; - /* If zero length ACAD then do not reduce ACAD but return - * return previous ACAD length. - */ - if (!acad_len) { - acad_len = acad_len_prev; - } + /* return prev ACAD length */ *(uint8_t *)hdr_data = acad_len_prev; - hdr_data = (uint8_t *)hdr_data + 1; + hdr_data = (uint8_t *)hdr_data + sizeof(acad_len); + /* return the pointer to ACAD offset */ (void)memcpy(hdr_data, &ter_dptr, sizeof(ter_dptr)); hdr_data = (uint8_t *)hdr_data + sizeof(ter_dptr); + + /* unchanged acad */ + if (!acad_len) { + acad_len = acad_len_prev; + } + ter_dptr += acad_len; } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_ACAD)) { acad_len = acad_len_prev; @@ -1778,6 +1794,8 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, return BT_HCI_ERR_PACKET_TOO_LONG; } + LL_ASSERT(ter_len <= (PDU_AC_EXT_HEADER_SIZE_MIN + PDU_AC_EXT_HEADER_SIZE_MAX)); + /* set the tertiary extended header and PDU length */ ull_adv_aux_hdr_len_fill(ter_com_hdr, ter_len); ter_pdu->len = ter_len + ad_len; @@ -1834,16 +1852,14 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, adv = HDR_LLL2ULL(lll_sync->adv); - adi_pdu->sid = adv->sid; - /* The DID for a specific SID shall be unique. */ const uint16_t did = - ull_adv_aux_did_next_unique_get(adv->sid); - adi_pdu->did = sys_cpu_to_le16(did); + sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid)); + PDU_ADV_ADI_DID_SID_SET(adi_pdu, did, adv->sid); } else { - adi_pdu->sid = adi->sid; - adi_pdu->did = adi->did; + adi_pdu->did_sid_packed[0] = adi->did_sid_packed[0]; + adi_pdu->did_sid_packed[1] = adi->did_sid_packed[1]; } } @@ -1959,6 +1975,12 @@ static inline void sync_release(struct ll_adv_sync_set *sync) mem_release(sync, &adv_sync_free); } +static inline uint16_t sync_handle_get(const struct ll_adv_sync_set *sync) +{ + return mem_index_get(sync, ll_adv_sync_pool, + sizeof(struct ll_adv_sync_set)); +} + static uint32_t sync_time_get(const struct ll_adv_sync_set *sync, const struct pdu_adv *pdu) { @@ -1981,7 +2003,7 @@ static uint8_t sync_stop(struct ll_adv_sync_set *sync) uint8_t sync_handle; int err; - sync_handle = ull_adv_sync_handle_get(sync); + sync_handle = sync_handle_get(sync); err = ull_ticker_stop_with_mark(TICKER_ID_ADV_SYNC_BASE + sync_handle, sync, &sync->lll); @@ -2022,10 +2044,12 @@ static inline uint8_t sync_remove(struct ll_adv_sync_set *sync, sync->is_started = 0U; +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (adv->lll.aux) { /* notify the auxiliary set */ ull_adv_sync_started_stopped(HDR_LLL2ULL(adv->lll.aux)); } +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ } if (!enable) { @@ -2041,7 +2065,6 @@ static uint8_t sync_chm_update(uint8_t handle) ULL_ADV_HDR_DATA_ACAD_PTR_SIZE]; struct pdu_adv_sync_chm_upd_ind *chm_upd_ind; struct lll_adv_sync *lll_sync; - struct ll_adv_sync_set *sync; struct pdu_adv *pdu_prev; struct ll_adv_set *adv; uint8_t acad_len_prev; @@ -2079,7 +2102,7 @@ static uint8_t sync_chm_update(uint8_t handle) /* Try to allocate ACAD for channel map update indication, previous * ACAD length with be returned back. */ - hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = sizeof(*chm_upd_ind) + 2U; + hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = 0U; err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, ULL_ADV_PDU_HDR_FIELD_ACAD, 0U, &hdr_data); @@ -2087,20 +2110,18 @@ static uint8_t sync_chm_update(uint8_t handle) return err; } - /* Check if there are other ACAD data previously */ + /* Check if there are other ACAD data previously and append to end of + * other ACAD already present. + */ acad_len_prev = hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET]; - if (acad_len_prev) { - /* Append to end of other ACAD already present */ - hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = acad_len_prev + - sizeof(*chm_upd_ind) + - 2U; - - err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, - ULL_ADV_PDU_HDR_FIELD_ACAD, 0U, - &hdr_data); - if (err) { - return err; - } + hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = acad_len_prev + + sizeof(*chm_upd_ind) + + 2U; + err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, + ULL_ADV_PDU_HDR_FIELD_ACAD, 0U, + &hdr_data); + if (err) { + return err; } /* Populate the AD data length and opcode */ @@ -2108,7 +2129,8 @@ static uint8_t sync_chm_update(uint8_t handle) sizeof(acad)); acad += acad_len_prev; acad[PDU_ADV_DATA_HEADER_LEN_OFFSET] = sizeof(*chm_upd_ind) + 1U; - acad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] = BT_DATA_CHANNEL_MAP_UPDATE_IND; + acad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] = + PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND; /* Populate the Channel Map Indication structure */ chm_upd_ind = (void *)&acad[PDU_ADV_DATA_HEADER_DATA_OFFSET]; @@ -2125,25 +2147,27 @@ static uint8_t sync_chm_update(uint8_t handle) ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map); lll_sync->chm_instant = instant; - sync = HDR_LLL2ULL(lll_sync); - if (sync->is_started) { - /* Commit the Channel Map Indication in the ACAD field of Periodic - * Advertising - */ - lll_adv_sync_data_enqueue(lll_sync, ter_idx); - } + /* Commit the Channel Map Indication in the ACAD field of Periodic + * Advertising + */ + lll_adv_sync_data_enqueue(lll_sync, ter_idx); /* Initiate the Channel Map Indication */ lll_sync->chm_last = chm_last; +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + struct ll_adv_sync_set *sync = HDR_LLL2ULL(lll_sync); + if (!sync->is_started) { /* Sync not started yet, apply new channel map now */ lll_sync->chm_first = lll_sync->chm_last; } +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ return 0; } +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) void ull_adv_sync_lll_syncinfo_fill(struct pdu_adv *pdu, struct lll_adv_aux *lll_aux) { struct lll_adv_sync *lll_sync; @@ -2181,7 +2205,155 @@ void ull_adv_sync_lll_syncinfo_fill(struct pdu_adv *pdu, struct lll_adv_aux *lll PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK); } -static inline struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu) +static void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs) +{ + if (offs >= OFFS_ADJUST_US) { + offs -= OFFS_ADJUST_US; + si->offs_adjust = 1U; + } + + offs = offs / OFFS_UNIT_30_US; + if (!!(offs >> OFFS_UNIT_BITS)) { + si->offs = sys_cpu_to_le16(offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US)); + si->offs_units = OFFS_UNIT_VALUE_300_US; + } else { + si->offs = sys_cpu_to_le16(offs); + si->offs_units = OFFS_UNIT_VALUE_30_US; + } +} + +#else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +static void mfy_sync_offset_get(void *param) +{ + struct ll_adv_set *adv = param; + struct lll_adv_sync *lll_sync; + struct ll_adv_sync_set *sync; + struct pdu_adv_sync_info *si; + uint32_t sync_remainder_us; + uint32_t aux_remainder_us; + uint32_t ticks_to_expire; + uint32_t ticks_current; + struct pdu_adv *pdu; + uint32_t remainder; + uint8_t chm_first; + uint8_t ticker_id; + uint16_t lazy; + uint8_t retry; + uint8_t id; + + lll_sync = adv->lll.sync; + sync = HDR_LLL2ULL(lll_sync); + ticker_id = TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync); + + id = TICKER_NULL; + ticks_to_expire = 0U; + ticks_current = 0U; + retry = 4U; + do { + uint32_t volatile ret_cb; + uint32_t ticks_previous; + uint32_t ret; + bool success; + + ticks_previous = ticks_current; + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW, + &id, &ticks_current, + &ticks_to_expire, &remainder, + &lazy, NULL, NULL, + ticker_op_cb, (void *)&ret_cb); + if (ret == TICKER_STATUS_BUSY) { + while (ret_cb == TICKER_STATUS_BUSY) { + ticker_job_sched(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW); + } + } + + success = (ret_cb == TICKER_STATUS_SUCCESS); + LL_ASSERT(success); + + LL_ASSERT((ticks_current == ticks_previous) || retry--); + + LL_ASSERT(id != TICKER_NULL); + } while (id != ticker_id); + + /* Reduced a tick for negative remainder and return positive remainder + * value. + */ + hal_ticker_remove_jitter(&ticks_to_expire, &remainder); + sync_remainder_us = remainder; + + /* Add a tick for negative remainder and return positive remainder + * value. + */ + remainder = sync->aux_remainder; + hal_ticker_add_jitter(&ticks_to_expire, &remainder); + aux_remainder_us = remainder; + + pdu = lll_adv_aux_data_latest_peek(adv->lll.aux); + si = sync_info_get(pdu); + sync_info_offset_fill(si, ticks_to_expire, sync_remainder_us, + aux_remainder_us); + si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare + + lazy; + + /* Fill the correct channel map to use if at or past the instant */ + if (lll_sync->chm_first != lll_sync->chm_last) { + uint16_t instant_latency; + + instant_latency = (si->evt_cntr - lll_sync->chm_instant) & + EVENT_INSTANT_MAX; + if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) { + chm_first = lll_sync->chm_last; + } else { + chm_first = lll_sync->chm_first; + } + } else { + chm_first = lll_sync->chm_first; + } + (void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map, + sizeof(si->sca_chm)); + si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &= + ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK; + si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |= + ((lll_clock_sca_local_get() << + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) & + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK); +} + +static void sync_info_offset_fill(struct pdu_adv_sync_info *si, + uint32_t ticks_offset, + uint32_t remainder_us, + uint32_t start_us) +{ + uint32_t offs; + + offs = HAL_TICKER_TICKS_TO_US(ticks_offset) + remainder_us - start_us; + + if (offs >= OFFS_ADJUST_US) { + offs -= OFFS_ADJUST_US; + si->offs_adjust = 1U; + } + + offs = offs / OFFS_UNIT_30_US; + if (!!(offs >> OFFS_UNIT_BITS)) { + si->offs = sys_cpu_to_le16(offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US)); + si->offs_units = OFFS_UNIT_VALUE_300_US; + } else { + si->offs = sys_cpu_to_le16(offs); + si->offs_units = OFFS_UNIT_VALUE_30_US; + } +} + +static void ticker_op_cb(uint32_t status, void *param) +{ + *((uint32_t volatile *)param) = status; +} +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + +static struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu) { struct pdu_adv_com_ext_adv *p; struct pdu_adv_ext_hdr *h; @@ -2217,25 +2389,6 @@ static inline struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu) return (void *)ptr; } -static inline void sync_info_offset_fill(struct pdu_adv_sync_info *si, - uint32_t offs) -{ - if (offs >= OFFS_ADJUST_US) { - offs -= OFFS_ADJUST_US; - si->offs_adjust = 1U; - } - - offs = offs / OFFS_UNIT_30_US; - if (!!(offs >> OFFS_UNIT_BITS)) { - si->offs = sys_cpu_to_le16(offs / (OFFS_UNIT_300_US / - OFFS_UNIT_30_US)); - si->offs_units = OFFS_UNIT_VALUE_300_US; - } else { - si->offs = sys_cpu_to_le16(offs); - si->offs_units = OFFS_UNIT_VALUE_30_US; - } -} - static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param) @@ -2243,12 +2396,13 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static memq_link_t link; static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_sync_prepare}; static struct lll_prepare_param p; -#if defined(CONFIG_BT_CTLR_ADV_ISO) +#if defined(CONFIG_BT_CTLR_ADV_ISO) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) struct ticker_ext_context *context = param; struct ll_adv_sync_set *sync = context->context; -#else +#else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ struct ll_adv_sync_set *sync = param; -#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ struct lll_adv_sync *lll; uint32_t ret; uint8_t ref; @@ -2261,15 +2415,8 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, ref = ull_ref_inc(&sync->ull); LL_ASSERT(ref); - /* Append timing parameters */ - p.ticks_at_expire = ticks_at_expire; - p.remainder = remainder; - p.lazy = lazy; - p.force = force; - p.param = lll; - mfy.param = &p; - -#if defined(CONFIG_BT_CTLR_ADV_ISO) +#if defined(CONFIG_BT_CTLR_ADV_ISO) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (lll->iso) { struct lll_adv_iso *lll_iso = lll->iso; @@ -2279,12 +2426,36 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, lll_iso->ticks_sync_pdu_offset = context->other_expire_info->ticks_to_expire; lll_iso->iso_lazy = context->other_expire_info->lazy; } -#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + + /* Append timing parameters */ + p.ticks_at_expire = ticks_at_expire; + p.remainder = remainder; + p.lazy = lazy; + p.force = force; + p.param = lll; + mfy.param = &p; /* Kick LLL prepare */ ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 0, &mfy); LL_ASSERT(!ret); +#if defined(CONFIG_BT_CTLR_ADV_ISO) && \ + !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + if (lll->iso) { + ull_adv_iso_offset_get(sync); + } +#endif /* CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + DEBUG_RADIO_PREPARE_A(1); } + +#if defined(CONFIG_BT_CTLR_ADV_ISO) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +static void ticker_update_op_cb(uint32_t status, void *param) +{ + LL_ASSERT(status == TICKER_STATUS_SUCCESS || + param == ull_disable_mark_get()); +} +#endif /* !CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h index 9a1475dbf6f..de0e4908b6f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h @@ -91,12 +91,21 @@ struct ll_adv_sync_set { uint8_t is_enabled:1; uint8_t is_started:1; uint8_t is_data_cmplt:1; + +#if !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + uint32_t aux_remainder; +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ }; struct ll_adv_iso_set { struct ull_hdr ull; struct lll_adv_iso lll; + uint32_t big_ref_point; /* Previously elapsed BIG reference point in + * microseconds of the free running Controller + * clock. + */ + struct { struct node_rx_hdr hdr; } node_rx_complete; diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index db32d639614..5effe2ae676 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "util/util.h" @@ -60,6 +60,7 @@ #include "ll_sw/isoal.h" #include "ll_sw/ull_iso_types.h" #include "ll_sw/ull_conn_iso_types.h" +#include "ll_sw/ull_conn_iso_internal.h" #include "ll_sw/ull_llcp.h" @@ -555,6 +556,14 @@ uint8_t ll_enc_req_send(uint16_t handle, uint8_t const *const rand_num, return BT_HCI_ERR_UNKNOWN_CONN_ID; } +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) + struct ll_conn_iso_stream *cis = ll_conn_iso_stream_get_by_acl(conn, NULL); + + if (cis || ull_lp_cc_is_enqueued(conn)) { + return BT_HCI_ERR_CMD_DISALLOWED; + } +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ + if (!conn->lll.enc_tx && !conn->lll.enc_rx) { /* Encryption is fully disabled */ return ull_cp_encryption_start(conn, rand_num, ediv, ltk); @@ -793,7 +802,6 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, conn_interval_us = lll->interval * CONN_INT_UNIT_US; conn_offset_us = ftr->radio_end_us; - conn_offset_us += EVENT_TICKER_RES_MARGIN_US; #if defined(CONFIG_BT_CTLR_PHY) conn_offset_us -= lll_radio_tx_ready_delay_get(lll->phy_tx, @@ -851,23 +859,23 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, - TICKER_ID_SCAN_STOP, NULL, NULL); + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, + TICKER_ID_SCAN_STOP, NULL, NULL); /* Start central */ ticker_id_conn = TICKER_ID_CONN_BASE + ll_conn_handle_get(conn); - ticker_status = ticker_start(TICKER_INSTANCE_ID_CTLR, - TICKER_USER_ID_ULL_HIGH, - ticker_id_conn, - ftr->ticks_anchor - ticks_slot_offset, - HAL_TICKER_US_TO_TICKS(conn_offset_us), - HAL_TICKER_US_TO_TICKS(conn_interval_us), - HAL_TICKER_REMAINDER(conn_interval_us), - TICKER_NULL_LAZY, - (conn->ull.ticks_slot + - ticks_slot_overhead), - ull_central_ticker_cb, conn, ticker_op_cb, - (void *)__LINE__); + ticker_status = ticker_start_us(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_HIGH, + ticker_id_conn, + ftr->ticks_anchor - ticks_slot_offset, + HAL_TICKER_US_TO_TICKS(conn_offset_us), + HAL_TICKER_REMAINDER(conn_offset_us), + HAL_TICKER_US_TO_TICKS(conn_interval_us), + HAL_TICKER_REMAINDER(conn_interval_us), + TICKER_NULL_LAZY, + (conn->ull.ticks_slot + ticks_slot_overhead), + ull_central_ticker_cb, conn, + ticker_op_cb, (void *)__LINE__); LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) || (ticker_status == TICKER_STATUS_BUSY)); @@ -912,7 +920,7 @@ void ull_central_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, int ret; /* Handle any LL Control Procedures */ - ret = ull_conn_llcp(conn, ticks_at_expire, lazy); + ret = ull_conn_llcp(conn, ticks_at_expire, remainder, lazy); if (ret) { /* NOTE: Under BT_CTLR_LOW_LAT, ULL_LOW context is * disabled inside radio events, hence, abort any diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index f29958b3433..0c7a8e5ef35 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -5,8 +5,9 @@ */ #include -#include #include + +#include #include #include "util/util.h" @@ -42,21 +43,48 @@ #include "ull_llcp.h" #include "ull_internal.h" +#include "ull_sched_internal.h" #include "ull_conn_internal.h" #include "ull_conn_iso_internal.h" #include "ll.h" #include "ll_feat.h" -#include +#include #include "hal/debug.h" #define SDU_MAX_DRIFT_PPM 100 +#define SUB_INTERVAL_MIN 400 + +#define STREAMS_PER_GROUP CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP + +#if defined(CONFIG_BT_CTLR_PHY_CODED) +#define PHY_VALID_MASK (BT_HCI_ISO_PHY_VALID_MASK) +#else +#define PHY_VALID_MASK (BT_HCI_ISO_PHY_VALID_MASK & ~BIT(2)) +#endif + +#if (CONFIG_BT_CTLR_CENTRAL_SPACING == 0) +static void cig_offset_get(struct ll_conn_iso_stream *cis); +static void mfy_cig_offset_get(void *param); +static void cis_offset_get(struct ll_conn_iso_stream *cis); +static void mfy_cis_offset_get(void *param); +static void ticker_op_cb(uint32_t status, void *param); +#endif /* CONFIG_BT_CTLR_CENTRAL_SPACING == 0 */ static void set_bn_max_pdu(bool framed, uint32_t iso_interval, uint32_t sdu_interval, uint16_t max_sdu, uint8_t *bn, uint8_t *max_pdu); +static uint8_t ll_cig_parameters_validate(void); +static uint8_t ll_cis_parameters_validate(uint8_t cis_idx, uint8_t cis_id, + uint16_t c_sdu, uint16_t p_sdu, + uint16_t c_phy, uint16_t p_phy); + +#if defined(CONFIG_BT_CTLR_CONN_ISO_RELIABILITY_POLICY) +static uint8_t ll_cis_calculate_ft(uint32_t cig_sync_delay, uint32_t iso_interval_us, + uint32_t sdu_interval, uint32_t latency, uint8_t framed); +#endif /* CONFIG_BT_CTLR_CONN_ISO_RELIABILITY_POLICY */ /* Setup cache for CIG commit transaction */ static struct { @@ -79,14 +107,14 @@ uint8_t ll_cig_parameters_open(uint8_t cig_id, ll_iso_setup.group.cig_id = cig_id; ll_iso_setup.group.c_sdu_interval = c_interval; ll_iso_setup.group.p_sdu_interval = p_interval; - ll_iso_setup.group.c_latency = c_latency * 1000; - ll_iso_setup.group.p_latency = p_latency * 1000; + ll_iso_setup.group.c_latency = c_latency * USEC_PER_MSEC; + ll_iso_setup.group.p_latency = p_latency * USEC_PER_MSEC; ll_iso_setup.group.central.sca = sca; ll_iso_setup.group.central.packing = packing; ll_iso_setup.group.central.framing = framing; ll_iso_setup.cis_count = num_cis; - return BT_HCI_ERR_SUCCESS; + return ll_cig_parameters_validate(); } uint8_t ll_cis_parameters_set(uint8_t cis_id, @@ -95,9 +123,11 @@ uint8_t ll_cis_parameters_set(uint8_t cis_id, uint8_t c_rtn, uint8_t p_rtn) { uint8_t cis_idx = ll_iso_setup.cis_idx; + uint8_t status; - if (cis_idx >= CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP) { - return BT_HCI_ERR_INSUFFICIENT_RESOURCES; + status = ll_cis_parameters_validate(cis_idx, cis_id, c_sdu, p_sdu, c_phy, p_phy); + if (status) { + return status; } memset(&ll_iso_setup.stream[cis_idx], 0, sizeof(struct ll_conn_iso_stream)); @@ -118,8 +148,9 @@ uint8_t ll_cis_parameters_set(uint8_t cis_id, * - Drop retransmissions to stay within Max_Transmission_Latency instead of asserting * - Calculate ISO_Interval to allow SDU_Interval < ISO_Interval */ -uint8_t ll_cig_parameters_commit(uint8_t cig_id) +uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) { + uint16_t cis_created_handles[STREAMS_PER_GROUP]; struct ll_conn_iso_stream *cis; struct ll_conn_iso_group *cig; uint32_t iso_interval_us; @@ -128,36 +159,57 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) uint32_t c_max_latency; uint32_t p_max_latency; uint16_t handle_iter; - uint8_t cis_count; + uint32_t total_time; + bool force_framed; + bool cig_created; + uint8_t num_cis; + uint8_t err; /* Intermediate subevent data */ struct { uint32_t length; uint8_t total_count; - } se[CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP]; + } se[STREAMS_PER_GROUP]; - /* If CIG already exists, controller and host are not in sync */ - cig = ll_conn_iso_group_get_by_id(cig_id); - LL_ASSERT(!cig); + for (uint8_t i = 0U; i < STREAMS_PER_GROUP; i++) { + cis_created_handles[i] = LLL_HANDLE_INVALID; + }; - /* CIG does not exist - create it */ - cig = ll_conn_iso_group_acquire(); + cig_created = false; + + /* If CIG already exists, this is a reconfigure */ + cig = ll_conn_iso_group_get_by_id(cig_id); if (!cig) { - ll_iso_setup.cis_idx = 0U; + /* CIG does not exist - create it */ + cig = ll_conn_iso_group_acquire(); + if (!cig) { + ll_iso_setup.cis_idx = 0U; + + /* No space for new CIG */ + return BT_HCI_ERR_INSUFFICIENT_RESOURCES; + } + cig->lll.num_cis = 0U; + cig_created = true; - /* No space for new CIG */ - return BT_HCI_ERR_INSUFFICIENT_RESOURCES; + } else if (cig->state != CIG_STATE_CONFIGURABLE) { + /* CIG is not in configurable state */ + return BT_HCI_ERR_CMD_DISALLOWED; } - /* Transfer parameters from update cache and clear LLL fields */ + /* Store currently configured number of CISes before cache transfer */ + num_cis = cig->lll.num_cis; + + /* Transfer parameters from configuration cache and clear LLL fields */ memcpy(cig, &ll_iso_setup.group, sizeof(struct ll_conn_iso_group)); - cis_count = ll_iso_setup.cis_count; + + cig->state = CIG_STATE_CONFIGURABLE; /* Setup LLL parameters */ cig->lll.handle = ll_conn_iso_group_handle_get(cig); cig->lll.role = BT_HCI_ROLE_CENTRAL; cig->lll.resume_cis = LLL_HANDLE_INVALID; - cig->lll.num_cis = cis_count; + cig->lll.num_cis = num_cis; + force_framed = false; if (!cig->central.test) { /* TODO: Calculate ISO_Interval based on SDU_Interval and Max_SDU vs Max_PDU, @@ -170,14 +222,84 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) * 10 ms 10 ms 40 40 100% * 10 ms 12.5 ms 40 50 25% */ - iso_interval_us = cig->c_sdu_interval; - cig->iso_interval = DIV_ROUND_UP(iso_interval_us, ISO_INT_UNIT_US); - } else { - iso_interval_us = cig->iso_interval * ISO_INT_UNIT_US; + + /* Set ISO_Interval to the closest lower value of SDU_Interval to be able to + * handle the throughput. For unframed these must be divisible, if they're not, + * framed mode must be forced. + */ + cig->iso_interval = cig->c_sdu_interval / ISO_INT_UNIT_US; + + if (cig->iso_interval < BT_HCI_ISO_INTERVAL_MIN) { + /* ISO_Interval is below minimum (5 ms) */ + cig->iso_interval = BT_HCI_ISO_INTERVAL_MIN; + } + + if (!cig->central.framing && (cig->c_sdu_interval % ISO_INT_UNIT_US)) { + /* Framing not requested but requirement for unframed is not met. Force + * CIG into framed mode. + */ + force_framed = true; + } } + iso_interval_us = cig->iso_interval * ISO_INT_UNIT_US; + lll_hdr_init(&cig->lll, cig); - max_se_length = 0; + max_se_length = 0U; + + /* Create all configurable CISes */ + for (uint8_t i = 0U; i < ll_iso_setup.cis_count; i++) { + memq_link_t *link_tx_free; + memq_link_t link_tx; + + cis = ll_conn_iso_stream_get_by_id(ll_iso_setup.stream[i].cis_id); + if (cis) { + /* Check if Max_SDU reconfigure violates datapath by changing + * non-zero Max_SDU with associated datapath, to zero. + */ + if ((cis->c_max_sdu && cis->hdr.datapath_in && + !ll_iso_setup.stream[i].c_max_sdu) || + (cis->p_max_sdu && cis->hdr.datapath_out && + !ll_iso_setup.stream[i].p_max_sdu)) { + /* Reconfiguring CIS with datapath to wrong direction is + * not allowed. + */ + err = BT_HCI_ERR_CMD_DISALLOWED; + goto ll_cig_parameters_commit_cleanup; + } + } else { + /* Acquire new CIS */ + cis = ll_conn_iso_stream_acquire(); + if (!cis) { + /* No space for new CIS */ + ll_iso_setup.cis_idx = 0U; + + err = BT_HCI_ERR_CONN_LIMIT_EXCEEDED; + goto ll_cig_parameters_commit_cleanup; + } + + cis_created_handles[i] = ll_conn_iso_stream_handle_get(cis); + cig->lll.num_cis++; + } + + /* Store TX link and free link before transfer */ + link_tx_free = cis->lll.link_tx_free; + link_tx = cis->lll.link_tx; + + /* Transfer parameters from configuration cache */ + memcpy(cis, &ll_iso_setup.stream[i], sizeof(struct ll_conn_iso_stream)); + + cis->group = cig; + cis->framed = cig->central.framing || force_framed; + + cis->lll.link_tx_free = link_tx_free; + cis->lll.link_tx = link_tx; + cis->lll.handle = ll_conn_iso_stream_handle_get(cis); + handles[i] = cis->lll.handle; + } + + num_cis = cig->lll.num_cis; + handle_iter = UINT16_MAX; /* 1) Acquire CIS instances and initialize instance data. * 2) Calculate SE_Length for each CIS and store the largest @@ -193,27 +315,13 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) * CIS_Sync_Delay 1 |......| |..........| * ISO_Interval |.................|.. |.................|.. */ - for (uint8_t i = 0; i < cis_count; i++) { + for (uint8_t i = 0U; i < num_cis; i++) { uint32_t mpt_c; uint32_t mpt_p; bool tx; bool rx; - /* Acquire new CIS */ - cis = ll_conn_iso_stream_acquire(); - if (cis == NULL) { - ll_iso_setup.cis_idx = 0U; - - /* No space for new CIS */ - return BT_HCI_ERR_INSUFFICIENT_RESOURCES; - } - - /* Transfer parameters from update cache */ - memcpy(cis, &ll_iso_setup.stream[i], sizeof(struct ll_conn_iso_stream)); - cis->group = cig; - cis->framed = cig->central.framing; - - cis->lll.handle = ll_conn_iso_stream_handle_get(cis); + cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); if (cig->central.test) { cis->lll.tx.ft = ll_iso_setup.c_ft; @@ -222,7 +330,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) tx = cis->lll.tx.bn && cis->lll.tx.max_pdu; rx = cis->lll.rx.bn && cis->lll.rx.max_pdu; } else { - LL_ASSERT(iso_interval_us >= cig->c_sdu_interval); + LL_ASSERT(cis->framed || iso_interval_us >= cig->c_sdu_interval); tx = cig->c_sdu_interval && cis->c_max_sdu; rx = cig->p_sdu_interval && cis->p_max_sdu; @@ -250,7 +358,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) cis->lll.tx.bn = bn; cis->lll.tx.max_pdu = max_pdu; } else { - cis->lll.tx.bn = 0; + cis->lll.tx.bn = 0U; } if (rx) { @@ -265,7 +373,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) cis->lll.rx.bn = bn; cis->lll.rx.max_pdu = max_pdu; } else { - cis->lll.rx.bn = 0; + cis->lll.rx.bn = 0U; } } @@ -282,31 +390,20 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) } handle_iter = UINT16_MAX; - uint32_t total_time = 0; + total_time = 0U; /* 1) Prepare calculation of the flush timeout by adding up the total time needed to * transfer all payloads, including retransmissions. */ - for (uint8_t i = 0; i < cis_count; i++) { - cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); - - if (cig->central.packing == BT_ISO_PACKING_SEQUENTIAL) { - /* Sequential CISes - add up the duration and set individual - * subinterval. - */ + if (cig->central.packing == BT_ISO_PACKING_SEQUENTIAL) { + /* Sequential CISes - add up the total duration */ + for (uint8_t i = 0U; i < num_cis; i++) { total_time += se[i].total_count * se[i].length; - } else { - /* Interleaved CISes - find the largest total duration and - * set all subintervals to the largest SE_Length of any CIS x - * the number of interleaved CISes. - */ - total_time = MAX(total_time, se[i].total_count * cis->lll.sub_interval + - (i * cis->lll.sub_interval / cis_count)); } } handle_iter = UINT16_MAX; - cig_sync_delay = 0; + cig_sync_delay = 0U; /* 1) Calculate the flush timeout either by dividing the total time needed to transfer all, * payloads including retransmissions, and divide by the ISO_Interval (low latency @@ -318,70 +415,73 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) * largest SE_Length times number of CISes (interleaved). Min. subinterval is 400 us. * 4) Calculate CIG_Sync_Delay */ - for (uint8_t i = 0; i < cis_count; i++) { + for (uint8_t i = 0U; i < num_cis; i++) { cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); if (!cig->central.test) { #if defined(CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY) + /* TODO: Only implemented for sequential packing */ + LL_ASSERT(cig->central.packing == BT_ISO_PACKING_SEQUENTIAL); + /* Use symmetric flush timeout */ cis->lll.tx.ft = DIV_ROUND_UP(total_time, iso_interval_us); cis->lll.rx.ft = cis->lll.tx.ft; #elif defined(CONFIG_BT_CTLR_CONN_ISO_RELIABILITY_POLICY) - /* Utilize Max_Transmission_latency */ - if (cis->framed) { - /* TL = CIG_Sync_Delay + FT x ISO_Interval + SDU_Interval. - * SDU_Interval <= CIG_Sync_Delay - */ - cis->lll.tx.ft = - DIV_ROUND_UP(cig->c_latency - cig->c_sdu_interval - - iso_interval_us, iso_interval_us); - cis->lll.rx.ft = - DIV_ROUND_UP(cig->p_latency - cig->p_sdu_interval - - iso_interval_us, iso_interval_us); - } else { - /* TL = CIG_Sync_Delay + FT x ISO_Interval - SDU_Interval. - * SDU_Interval <= CIG_Sync_Delay - */ - cis->lll.tx.ft = - DIV_ROUND_UP(cig->c_latency + cig->c_sdu_interval - - iso_interval_us, iso_interval_us); - cis->lll.rx.ft = - DIV_ROUND_UP(cig->p_latency + cig->p_sdu_interval - - iso_interval_us, iso_interval_us); + /* Utilize Max_Transport_latency */ + + /* + * Set CIG_Sync_Delay = ISO_Interval as largest possible CIG_Sync_Delay. + * This favors utilizing as much as possible of the Max_Transport_latency, + * and spreads out payloads over multiple CIS events (if necessary). + */ + uint32_t cig_sync_delay_us_max = iso_interval_us; + + cis->lll.tx.ft = ll_cis_calculate_ft(cig_sync_delay_us_max, iso_interval_us, + cig->c_sdu_interval, cig->c_latency, + cis->framed); + + cis->lll.rx.ft = ll_cis_calculate_ft(cig_sync_delay_us_max, iso_interval_us, + cig->p_sdu_interval, cig->p_latency, + cis->framed); + + if ((cis->lll.tx.ft == 0U) || (cis->lll.rx.ft == 0U)) { + /* Invalid FT caused by invalid combination of parameters */ + err = BT_HCI_ERR_INVALID_PARAM; + goto ll_cig_parameters_commit_cleanup; } + #else LL_ASSERT(0); #endif - cis->lll.nse = DIV_ROUND_UP(se[i].total_count, - cis->lll.tx.ft); + cis->lll.nse = DIV_ROUND_UP(se[i].total_count, cis->lll.tx.ft); } if (cig->central.packing == BT_ISO_PACKING_SEQUENTIAL) { /* Accumulate CIG sync delay for sequential CISes */ - cis->lll.sub_interval = MAX(400, se[i].length); + cis->lll.sub_interval = MAX(SUB_INTERVAL_MIN, se[i].length); cig_sync_delay += cis->lll.nse * cis->lll.sub_interval; } else { /* For interleaved CISes, offset each CIS by a fraction of a subinterval, * positioning them evenly within the subinterval. */ - cis->lll.sub_interval = MAX(400, cis_count * max_se_length); + cis->lll.sub_interval = MAX(SUB_INTERVAL_MIN, num_cis * max_se_length); cig_sync_delay = MAX(cig_sync_delay, (cis->lll.nse * cis->lll.sub_interval) + - (i * cis->lll.sub_interval / cis_count)); + (i * cis->lll.sub_interval / num_cis)); } } cig->sync_delay = cig_sync_delay; handle_iter = UINT16_MAX; - c_max_latency = 0; - p_max_latency = 0; + c_max_latency = 0U; + p_max_latency = 0U; /* 1) Calculate transport latencies for each CIS and validate against Max_Transport_Latency. * 2) Lay out CISes by updating CIS_Sync_Delay, distributing according to the packing. */ - for (uint8_t i = 0; i < cis_count; i++) { + for (uint8_t i = 0U; i < num_cis; i++) { uint32_t c_latency; uint32_t p_latency; @@ -422,11 +522,11 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) } else { /* Distribute CISes interleaved */ cis->sync_delay = cig_sync_delay; - cig_sync_delay -= (cis->lll.sub_interval / cis_count); + cig_sync_delay -= (cis->lll.sub_interval / num_cis); } if (cis->lll.nse <= 1) { - cis->lll.sub_interval = 0; + cis->lll.sub_interval = 0U; } } @@ -434,9 +534,48 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) cig->c_latency = c_max_latency; cig->p_latency = p_max_latency; +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + uint32_t slot_us; + + /* CIG sync_delay has been calculated considering the configured + * packing. + */ + slot_us = cig->sync_delay; + + slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + + /* Populate the ULL hdr with event timings overheads */ + cig->ull.ticks_active_to_start = 0U; + cig->ull.ticks_prepare_to_start = + HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US); + cig->ull.ticks_preempt_to_start = + HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US); + cig->ull.ticks_slot = HAL_TICKER_US_TO_TICKS(slot_us); +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + + /* Reset params cache */ ll_iso_setup.cis_idx = 0U; return BT_HCI_ERR_SUCCESS; + +ll_cig_parameters_commit_cleanup: + /* Late configuration failure - clean up */ + for (uint8_t i = 0U; i < ll_iso_setup.cis_count; i++) { + if (cis_created_handles[i] != LLL_HANDLE_INVALID) { + /* Release CIS instance created in failing configuration */ + cis = ll_conn_iso_stream_get(cis_created_handles[i]); + ll_conn_iso_stream_release(cis); + } else { + break; + } + } + + /* If CIG was created in this failed configuration - release it */ + if (cig_created) { + ll_conn_iso_group_release(cig); + } + + return err; } uint8_t ll_cig_parameters_test_open(uint8_t cig_id, uint32_t c_interval, @@ -461,7 +600,7 @@ uint8_t ll_cig_parameters_test_open(uint8_t cig_id, uint32_t c_interval, ll_iso_setup.c_ft = c_ft; ll_iso_setup.p_ft = p_ft; - return BT_HCI_ERR_SUCCESS; + return ll_cig_parameters_validate(); } uint8_t ll_cis_parameters_test_set(uint8_t cis_id, uint8_t nse, @@ -471,9 +610,11 @@ uint8_t ll_cis_parameters_test_set(uint8_t cis_id, uint8_t nse, uint8_t c_bn, uint8_t p_bn) { uint8_t cis_idx = ll_iso_setup.cis_idx; + uint8_t status; - if (cis_idx >= CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP) { - return BT_HCI_ERR_INSUFFICIENT_RESOURCES; + status = ll_cis_parameters_validate(cis_idx, cis_id, c_sdu, p_sdu, c_phy, p_phy); + if (status) { + return status; } memset(&ll_iso_setup.stream[cis_idx], 0, sizeof(struct ll_conn_iso_stream)); @@ -482,8 +623,8 @@ uint8_t ll_cis_parameters_test_set(uint8_t cis_id, uint8_t nse, ll_iso_setup.stream[cis_idx].c_max_sdu = c_sdu; ll_iso_setup.stream[cis_idx].p_max_sdu = p_sdu; ll_iso_setup.stream[cis_idx].lll.nse = nse; - ll_iso_setup.stream[cis_idx].lll.tx.max_pdu = c_bn ? c_pdu : 0; - ll_iso_setup.stream[cis_idx].lll.rx.max_pdu = p_bn ? p_pdu : 0; + ll_iso_setup.stream[cis_idx].lll.tx.max_pdu = c_bn ? c_pdu : 0U; + ll_iso_setup.stream[cis_idx].lll.rx.max_pdu = p_bn ? p_pdu : 0U; ll_iso_setup.stream[cis_idx].lll.tx.phy = c_phy; ll_iso_setup.stream[cis_idx].lll.rx.phy = p_phy; ll_iso_setup.stream[cis_idx].lll.tx.bn = c_bn; @@ -501,14 +642,25 @@ uint8_t ll_cis_create_check(uint16_t cis_handle, uint16_t acl_handle) if (conn) { struct ll_conn_iso_stream *cis; + /* Verify conn refers to a device acting as central */ + if (conn->lll.role != BT_HCI_ROLE_CENTRAL) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + /* Verify handle validity and association */ cis = ll_conn_iso_stream_get(cis_handle); - if (cis->lll.handle == cis_handle) { + + if (cis->group && (cis->lll.handle == cis_handle)) { + if (cis->established) { + /* CIS is already created */ + return BT_HCI_ERR_CONN_ALREADY_EXISTS; + } + return BT_HCI_ERR_SUCCESS; } } - return BT_HCI_ERR_CMD_DISALLOWED; + return BT_HCI_ERR_UNKNOWN_CONN_ID; } void ll_cis_create(uint16_t cis_handle, uint16_t acl_handle) @@ -529,13 +681,15 @@ void ll_cis_create(uint16_t cis_handle, uint16_t acl_handle) /* Initialize stream states */ cis->established = 0; cis->teardown = 0; - cis->lll.event_count = 0; + cis->lll.event_count = LLL_CONN_ISO_EVENT_COUNT_MAX; cis->lll.sn = 0; cis->lll.nesn = 0; cis->lll.cie = 0; - cis->lll.flushed = 0; + cis->lll.flush = LLL_CIS_FLUSH_NONE; cis->lll.active = 0; cis->lll.datapath_ready_rx = 0; + cis->lll.tx.bn_curr = 1U; + cis->lll.rx.bn_curr = 1U; (void)memset(&cis->hdr, 0U, sizeof(cis->hdr)); @@ -548,7 +702,14 @@ void ll_cis_create(uint16_t cis_handle, uint16_t acl_handle) cis->lll.link_tx_free = NULL; /* Initiate CIS Request Control Procedure */ - (void)ull_cp_cis_create(conn, cis); + if (ull_cp_cis_create(conn, cis) == BT_HCI_ERR_SUCCESS) { + LL_ASSERT(cis->group); + + if (cis->group->state == CIG_STATE_CONFIGURABLE) { + /* This CIG is now initiating an ISO connection */ + cis->group->state = CIG_STATE_INITIATING; + } + } } /* Core 5.3 Vol 6, Part B section 7.8.100: @@ -571,13 +732,13 @@ uint8_t ll_cig_remove(uint8_t cig_id) return BT_HCI_ERR_UNKNOWN_CONN_ID; } - if (cig->started) { - /* CIG is in active state */ + if ((cig->state == CIG_STATE_INITIATING) || (cig->state == CIG_STATE_ACTIVE)) { + /* CIG is in initiating- or active state */ return BT_HCI_ERR_CMD_DISALLOWED; } handle_iter = UINT16_MAX; - for (int i = 0; i < cig->lll.num_cis; i++) { + for (uint8_t i = 0U; i < cig->lll.num_cis; i++) { struct ll_conn *conn; cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); @@ -634,8 +795,6 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle, struct ll_conn_iso_group *cig; uint16_t event_counter; struct ll_conn *conn; - uint16_t handle_iter; - uint32_t cis_offset; uint16_t instant; cis = ll_conn_iso_stream_get(cis_handle); @@ -648,33 +807,35 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle, return BT_HCI_ERR_UNSPECIFIED; } + /* ACL connection of the new CIS */ conn = ll_conn_get(cis->lll.acl_handle); event_counter = ull_conn_event_counter(conn); instant = MAX(*conn_event_count, event_counter + 1); - handle_iter = UINT16_MAX; - #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) - cis_offset = *cis_offset_min; - -#else /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ - cis_offset = MAX((HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) + - (EVENT_TICKER_RES_MARGIN_US << 1U)), *cis_offset_min); + uint32_t cis_offset; -#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + cis_offset = *cis_offset_min; /* Calculate offset for CIS */ - if (cig->started) { + if (cig->state == CIG_STATE_ACTIVE) { uint32_t time_of_intant; uint32_t cig_ref_point; /* CIG is started. Use the CIG reference point and latest ticks_at_expire * for associated ACL, to calculate the offset. + * NOTE: The following calculations are done in a 32-bit time + * range with full consideration and expectation that the + * controller clock does not support the full 32-bit range in + * microseconds. However it is valid as the purpose is to + * calculate the difference and the spare higher order bits will + * ensure that no wrapping can occur before the termination + * condition of the while loop is met. Using time wrapping will + * complicate this. */ - time_of_intant = isoal_get_wrapped_time_us( - HAL_TICKER_TICKS_TO_US(conn->llcp.prep.ticks_at_expire), - EVENT_OVERHEAD_START_US + - (instant - event_counter) * conn->lll.interval * CONN_INT_UNIT_US); + time_of_intant = HAL_TICKER_TICKS_TO_US(conn->llcp.prep.ticks_at_expire) + + EVENT_OVERHEAD_START_US + + ((instant - event_counter) * conn->lll.interval * CONN_INT_UNIT_US); cig_ref_point = cig->cig_ref_point; while (cig_ref_point < time_of_intant) { @@ -690,18 +851,35 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle, } cis->offset = cis_offset; + +#else /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + if (IS_ENABLED(CONFIG_BT_CTLR_CENTRAL_SPACING) && (CONFIG_BT_CTLR_CENTRAL_SPACING > 0)) { + uint32_t cis_offset; + + cis_offset = MAX((HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) + + (EVENT_TICKER_RES_MARGIN_US << 1U) + cig->sync_delay - + cis->sync_delay), *cis_offset_min); + cis->offset = cis_offset; + } else { + cis->offset = *cis_offset_min; + } +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + cis->central.instant = instant; - cis->lll.event_count = -1; cis->lll.next_subevent = 0U; cis->lll.sn = 0U; cis->lll.nesn = 0U; cis->lll.cie = 0U; - cis->lll.flushed = 0U; + cis->lll.npi = 0U; + cis->lll.flush = LLL_CIS_FLUSH_NONE; cis->lll.active = 0U; cis->lll.datapath_ready_rx = 0U; cis->lll.tx.payload_count = 0U; cis->lll.rx.payload_count = 0U; + cis->lll.tx.bn_curr = 1U; + cis->lll.rx.bn_curr = 1U; + /* Transfer to caller */ *cig_sync_delay = cig->sync_delay; *cis_sync_delay = cis->sync_delay; @@ -710,13 +888,16 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle, *conn_event_count = instant; - return 0; + return 0U; } -uint16_t ull_central_iso_cis_offset_get(uint16_t cis_handle, uint32_t *cis_offset_min, - uint32_t *cis_offset_max) +int ull_central_iso_cis_offset_get(uint16_t cis_handle, + uint32_t *cis_offset_min, + uint32_t *cis_offset_max, + uint16_t *conn_event_count) { struct ll_conn_iso_stream *cis; + struct ll_conn_iso_group *cig; struct ll_conn *conn; cis = ll_conn_iso_stream_get(cis_handle); @@ -724,22 +905,227 @@ uint16_t ull_central_iso_cis_offset_get(uint16_t cis_handle, uint32_t *cis_offse conn = ll_conn_get(cis->lll.acl_handle); - if (cis_offset_min && cis_offset_max) { - struct ll_conn_iso_group *cig; + cis->central.instant = ull_conn_event_counter(conn) + 3U; + *conn_event_count = cis->central.instant; + + /* Provide CIS offset range + * CIS_Offset_Max < (connInterval - (CIG_Sync_Delay + T_MSS)) + */ + cig = cis->group; + *cis_offset_max = (conn->lll.interval * CONN_INT_UNIT_US) - + cig->sync_delay; - cig = cis->group; + if (IS_ENABLED(CONFIG_BT_CTLR_JIT_SCHEDULING)) { + *cis_offset_min = MAX(CIS_MIN_OFFSET_MIN, EVENT_OVERHEAD_CIS_SETUP_US); + return 0; + } - /* Provide CIS offset range - * CIS_Offset_Max < (connInterval - (CIG_Sync_Delay + T_MSS)) - */ - *cis_offset_max = (conn->lll.interval * CONN_INT_UNIT_US) - cig->sync_delay; - *cis_offset_min = MAX(400, EVENT_OVERHEAD_CIS_SETUP_US); +#if (CONFIG_BT_CTLR_CENTRAL_SPACING == 0) + if (cig->state == CIG_STATE_ACTIVE) { + cis_offset_get(cis); + } else { + cig_offset_get(cis); + } + + return -EBUSY; +#endif /* CONFIG_BT_CTLR_CENTRAL_SPACING != 0 */ + + *cis_offset_min = HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) + + (EVENT_TICKER_RES_MARGIN_US << 1U) + + cig->sync_delay - cis->sync_delay; + + return 0; +} + +#if (CONFIG_BT_CTLR_CENTRAL_SPACING == 0) +static void cig_offset_get(struct ll_conn_iso_stream *cis) +{ + static memq_link_t link; + static struct mayfly mfy = {0, 0, &link, NULL, mfy_cig_offset_get}; + uint32_t ret; + + mfy.param = cis; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1, + &mfy); + LL_ASSERT(!ret); +} + +static void mfy_cig_offset_get(void *param) +{ + struct ll_conn_iso_stream *cis; + struct ll_conn_iso_group *cig; + uint32_t conn_interval_us; + uint32_t ticks_to_expire; + uint32_t offset_max_us; + uint32_t offset_min_us; + struct ll_conn *conn; + int err; + + cis = param; + cig = cis->group; + + err = ull_sched_conn_iso_free_offset_get(cig->ull.ticks_slot, + &ticks_to_expire); + LL_ASSERT(!err); + + offset_min_us = HAL_TICKER_TICKS_TO_US(ticks_to_expire) + + (EVENT_TICKER_RES_MARGIN_US << 2U); + offset_min_us += cig->sync_delay - cis->sync_delay; + + conn = ll_conn_get(cis->lll.acl_handle); + + conn_interval_us = (uint32_t)conn->lll.interval * CONN_INT_UNIT_US; + while (offset_min_us >= (conn_interval_us + PDU_CIS_OFFSET_MIN_US)) { + offset_min_us -= conn_interval_us; + } + + offset_max_us = conn_interval_us - cig->sync_delay; + + ull_cp_cc_offset_calc_reply(conn, offset_min_us, offset_max_us); +} + +static void cis_offset_get(struct ll_conn_iso_stream *cis) +{ + static memq_link_t link; + static struct mayfly mfy = {0, 0, &link, NULL, mfy_cis_offset_get}; + uint32_t ret; + + mfy.param = cis; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1, + &mfy); + LL_ASSERT(!ret); +} + +static void mfy_cis_offset_get(void *param) +{ + uint32_t elapsed_acl_us, elapsed_cig_us; + uint16_t latency_acl, latency_cig; + struct ll_conn_iso_stream *cis; + struct ll_conn_iso_group *cig; + uint32_t cig_remainder_us; + uint32_t acl_remainder_us; + uint32_t cig_interval_us; + uint32_t ticks_to_expire; + uint32_t ticks_current; + uint32_t offset_min_us; + struct ll_conn *conn; + uint32_t remainder; + uint8_t ticker_id; + uint16_t lazy; + uint8_t retry; + uint8_t id; + + cis = param; + cig = cis->group; + ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig); + + id = TICKER_NULL; + ticks_to_expire = 0U; + ticks_current = 0U; + + /* In the first iteration the actual ticks_current value is returned + * which will be different from the initial value of 0 that is set. + * Subsequent iterations should return the same ticks_current as the + * reference tick. + * In order to avoid infinite updates to ticker's reference due to any + * race condition due to expiring tickers, we try upto 3 more times. + * Hence, first iteration to get an actual ticks_current and 3 more as + * retries when there could be race conditions that changes the value + * of ticks_current. + * + * ticker_next_slot_get_ext() restarts iterating when updated value of + * ticks_current is returned. + */ + retry = 4U; + do { + uint32_t volatile ret_cb; + uint32_t ticks_previous; + uint32_t ret; + bool success; + + ticks_previous = ticks_current; + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW, + &id, &ticks_current, + &ticks_to_expire, &remainder, + &lazy, NULL, NULL, + ticker_op_cb, (void *)&ret_cb); + if (ret == TICKER_STATUS_BUSY) { + /* Busy wait until Ticker Job is enabled after any Radio + * event is done using the Radio hardware. Ticker Job + * ISR is disabled during Radio events in LOW_LAT + * feature to avoid Radio ISR latencies. + */ + while (ret_cb == TICKER_STATUS_BUSY) { + ticker_job_sched(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW); + } + } + + success = (ret_cb == TICKER_STATUS_SUCCESS); + LL_ASSERT(success); + + LL_ASSERT((ticks_current == ticks_previous) || retry--); + + LL_ASSERT(id != TICKER_NULL); + } while (id != ticker_id); + + /* Reduced a tick for negative remainder and return positive remainder + * value. + */ + hal_ticker_remove_jitter(&ticks_to_expire, &remainder); + cig_remainder_us = remainder; + + /* Add a tick for negative remainder and return positive remainder + * value. + */ + conn = ll_conn_get(cis->lll.acl_handle); + remainder = conn->llcp.prep.remainder; + hal_ticker_add_jitter(&ticks_to_expire, &remainder); + acl_remainder_us = remainder; + + /* Calculate the CIS offset in the CIG */ + offset_min_us = HAL_TICKER_TICKS_TO_US(ticks_to_expire) + + cig_remainder_us + cig->sync_delay - + acl_remainder_us - cis->sync_delay; + + /* Calculate instant latency */ + /* 32-bits are sufficient as maximum connection interval is 4 seconds, + * and latency counts (typically 3) is low enough to avoid 32-bit + * overflow. Refer to ull_central_iso_cis_offset_get(). + */ + latency_acl = cis->central.instant - ull_conn_event_counter(conn); + elapsed_acl_us = latency_acl * conn->lll.interval * CONN_INT_UNIT_US; + + /* Calculate elapsed CIG intervals until the instant */ + cig_interval_us = cig->iso_interval * ISO_INT_UNIT_US; + latency_cig = DIV_ROUND_UP(elapsed_acl_us, cig_interval_us); + elapsed_cig_us = latency_cig * cig_interval_us; + + /* Compensate for the difference between ACL elapsed vs CIG elapsed */ + offset_min_us += elapsed_cig_us - elapsed_acl_us; + while (offset_min_us >= (cig_interval_us + PDU_CIS_OFFSET_MIN_US)) { + offset_min_us -= cig_interval_us; } - cis->central.instant = ull_conn_event_counter(conn) + 3; - return cis->central.instant; + /* Decrement event_count to compensate for offset_min_us greater than + * CIG interval due to offset being atleast PDU_CIS_OFFSET_MIN_US. + */ + if (offset_min_us > cig_interval_us) { + cis->lll.event_count--; + } + + ull_cp_cc_offset_calc_reply(conn, offset_min_us, offset_min_us); } +static void ticker_op_cb(uint32_t status, void *param) +{ + *((uint32_t volatile *)param) = status; +} +#endif /* CONFIG_BT_CTLR_CENTRAL_SPACING == 0 */ + static void set_bn_max_pdu(bool framed, uint32_t iso_interval, uint32_t sdu_interval, uint16_t max_sdu, uint8_t *bn, uint8_t *max_pdu) @@ -778,3 +1164,109 @@ static void set_bn_max_pdu(bool framed, uint32_t iso_interval, *bn = DIV_ROUND_UP(max_sdu * iso_interval, (*max_pdu) * sdu_interval); } } + +static uint8_t ll_cig_parameters_validate(void) +{ + if (ll_iso_setup.cis_count > BT_HCI_ISO_CIS_COUNT_MAX) { + /* Invalid CIS_Count */ + return BT_HCI_ERR_INVALID_PARAM; + } + + if (ll_iso_setup.group.cig_id > BT_HCI_ISO_CIG_ID_MAX) { + /* Invalid CIG_ID */ + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(ll_iso_setup.group.c_sdu_interval, BT_HCI_ISO_SDU_INTERVAL_MIN, + BT_HCI_ISO_SDU_INTERVAL_MAX) || + !IN_RANGE(ll_iso_setup.group.p_sdu_interval, BT_HCI_ISO_SDU_INTERVAL_MIN, + BT_HCI_ISO_SDU_INTERVAL_MAX)) { + /* Parameter out of range */ + return BT_HCI_ERR_INVALID_PARAM; + } + + if (ll_iso_setup.group.central.test) { + if (!IN_RANGE(ll_iso_setup.group.iso_interval, + BT_HCI_ISO_INTERVAL_MIN, BT_HCI_ISO_INTERVAL_MAX)) { + /* Parameter out of range */ + return BT_HCI_ERR_INVALID_PARAM; + } + } else { + if (!IN_RANGE(ll_iso_setup.group.c_latency, + BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MIN * USEC_PER_MSEC, + BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MAX * USEC_PER_MSEC) || + !IN_RANGE(ll_iso_setup.group.p_latency, + BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MIN * USEC_PER_MSEC, + BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MAX * USEC_PER_MSEC)) { + /* Parameter out of range */ + return BT_HCI_ERR_INVALID_PARAM; + } + } + + if (((ll_iso_setup.group.central.sca & ~BT_HCI_ISO_WORST_CASE_SCA_VALID_MASK) != 0U) || + ((ll_iso_setup.group.central.packing & ~BT_HCI_ISO_PACKING_VALID_MASK) != 0U) || + ((ll_iso_setup.group.central.framing & ~BT_HCI_ISO_FRAMING_VALID_MASK) != 0U)) { + /* Worst_Case_SCA, Packing or Framing sets RFU value */ + return BT_HCI_ERR_INVALID_PARAM; + } + + if (ll_iso_setup.cis_count > STREAMS_PER_GROUP) { + /* Requested number of CISes not available by configuration. Check as last + * to avoid interfering with qualification parameter checks. + */ + return BT_HCI_ERR_CONN_LIMIT_EXCEEDED; + } + + return BT_HCI_ERR_SUCCESS; +} + +static uint8_t ll_cis_parameters_validate(uint8_t cis_idx, uint8_t cis_id, + uint16_t c_sdu, uint16_t p_sdu, + uint16_t c_phy, uint16_t p_phy) +{ + if ((cis_id > BT_HCI_ISO_CIS_ID_VALID_MAX) || + ((c_sdu & ~BT_HCI_ISO_MAX_SDU_VALID_MASK) != 0U) || + ((p_sdu & ~BT_HCI_ISO_MAX_SDU_VALID_MASK) != 0U)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!c_phy || ((c_phy & ~PHY_VALID_MASK) != 0U) || + !p_phy || ((p_phy & ~PHY_VALID_MASK) != 0U)) { + return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL; + } + + if (cis_idx >= STREAMS_PER_GROUP) { + return BT_HCI_ERR_CONN_LIMIT_EXCEEDED; + } + + return BT_HCI_ERR_SUCCESS; +} + +#if defined(CONFIG_BT_CTLR_CONN_ISO_RELIABILITY_POLICY) +static uint8_t ll_cis_calculate_ft(uint32_t cig_sync_delay, uint32_t iso_interval_us, + uint32_t sdu_interval, uint32_t latency, uint8_t framed) +{ + uint32_t tl; + + /* Framed: + * TL = CIG_Sync_Delay + FT x ISO_Interval + SDU_Interval + * + * Unframed: + * TL = CIG_Sync_Delay + FT x ISO_Interval - SDU_Interval + */ + for (uint16_t ft = 1U; ft <= CONFIG_BT_CTLR_CONN_ISO_STREAMS_MAX_FT; ft++) { + if (framed) { + tl = cig_sync_delay + ft * iso_interval_us + sdu_interval; + } else { + tl = cig_sync_delay + ft * iso_interval_us - sdu_interval; + } + + if (tl > latency) { + /* Latency exceeded - use one less */ + return ft - 1U; + } + } + + return 0; +} +#endif /* CONFIG_BT_CTLR_CONN_ISO_RELIABILITY_POLICY */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h b/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h index 8c929d58f3b..fea89a0992e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h @@ -8,8 +8,10 @@ int ull_central_iso_init(void); int ull_central_iso_reset(void); -uint16_t ull_central_iso_cis_offset_get(uint16_t cis_handle, uint32_t *cis_offset_min, - uint32_t *cis_offset_max); +int ull_central_iso_cis_offset_get(uint16_t cis_handle, + uint32_t *cis_offset_min, + uint32_t *cis_offset_max, + uint16_t *conn_event_count); uint8_t ull_central_iso_setup(uint16_t cis_handle, uint32_t *cig_sync_delay, uint32_t *cis_sync_delay, diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 7f4d9685a34..0b54a5dee79 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -7,8 +7,7 @@ #include #include #include -#include -#include +#include #include #include "hal/cpu.h" @@ -417,8 +416,52 @@ uint8_t ll_terminate_ind_send(uint16_t handle, uint8_t reason) #if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) || defined(CONFIG_BT_CTLR_CENTRAL_ISO) if (IS_CIS_HANDLE(handle)) { cis = ll_iso_stream_connected_get(handle); - /* Disallow if CIS is not connected */ if (!cis) { +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) + /* CIS is not connected - get the unconnected instance */ + cis = ll_conn_iso_stream_get(handle); + + /* Sanity-check instance to make sure it's created but not connected */ + if (cis->group && cis->lll.handle == handle && !cis->established) { + if (cis->group->state == CIG_STATE_CONFIGURABLE) { + /* Disallow if CIG is still in configurable state */ + return BT_HCI_ERR_CMD_DISALLOWED; + + } else if (cis->group->state == CIG_STATE_INITIATING) { + conn = ll_connected_get(cis->lll.acl_handle); + + /* CIS is not yet established - try to cancel procedure */ + if (ull_cp_cc_cancel(conn)) { + /* Successfully canceled - complete disconnect */ + struct node_rx_pdu *node_terminate; + + node_terminate = ull_pdu_rx_alloc(); + LL_ASSERT(node_terminate); + + node_terminate->hdr.handle = handle; + node_terminate->hdr.type = NODE_RX_TYPE_TERMINATE; + *((uint8_t *)node_terminate->pdu) = + BT_HCI_ERR_LOCALHOST_TERM_CONN; + + ll_rx_put_sched(node_terminate->hdr.link, + node_terminate); + + /* We're no longer initiating a connection */ + cis->group->state = CIG_STATE_CONFIGURABLE; + + /* This is now a successful disconnection */ + return BT_HCI_ERR_SUCCESS; + } + + /* Procedure could not be canceled in the current + * state - let it run its course and enqueue a + * terminate procedure. + */ + return ull_cp_cis_terminate(conn, cis, reason); + } + } +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ + /* Disallow if CIS is not connected */ return BT_HCI_ERR_CMD_DISALLOWED; } @@ -447,7 +490,7 @@ uint8_t ll_feature_req_send(uint16_t handle) uint8_t err; - err = ull_cp_feature_exchange(conn); + err = ull_cp_feature_exchange(conn, 1U); if (err) { return err; } @@ -804,7 +847,7 @@ void ull_conn_setup(memq_link_t *rx_link, struct node_rx_hdr *rx) } } -int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx) +void ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx) { struct pdu_data *pdu_rx; struct ll_conn *conn; @@ -814,7 +857,7 @@ int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx) /* Mark for buffer for release */ (*rx)->hdr.type = NODE_RX_TYPE_RELEASE; - return 0; + return; } ull_cp_tx_ntf(conn); @@ -824,14 +867,12 @@ int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx) switch (pdu_rx->ll_id) { case PDU_DATA_LLID_CTRL: { - ARG_UNUSED(link); - ARG_UNUSED(pdu_rx); - - ull_cp_rx(conn, *rx); - /* Mark buffer for release */ (*rx)->hdr.type = NODE_RX_TYPE_RELEASE; - return 0; + + ull_cp_rx(conn, link, *rx); + + return; } case PDU_DATA_LLID_DATA_CONTINUE: @@ -863,16 +904,15 @@ int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx) break; } - - - return 0; } -int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, uint16_t lazy) +int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, + uint32_t remainder, uint16_t lazy) { LL_ASSERT(conn->lll.handle != LLL_HANDLE_INVALID); conn->llcp.prep.ticks_at_expire = ticks_at_expire; + conn->llcp.prep.remainder = remainder; conn->llcp.prep.lazy = lazy; ull_cp_run(conn); @@ -1241,7 +1281,7 @@ void ull_conn_done(struct node_rx_event_done *done) ticks_slot_plus || ticks_slot_minus || lazy || force) { uint8_t ticker_id = TICKER_ID_CONN_BASE + lll->handle; - struct ll_conn *conn = lll->hdr.parent; + struct ll_conn *conn_ll = lll->hdr.parent; uint32_t ticker_status; /* Call to ticker_update can fail under the race @@ -1257,10 +1297,10 @@ void ull_conn_done(struct node_rx_event_done *done) ticks_slot_plus, ticks_slot_minus, lazy, force, ticker_update_conn_op_cb, - conn); + conn_ll); LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) || (ticker_status == TICKER_STATUS_BUSY) || - ((void *)conn == ull_disable_mark_get())); + ((void *)conn_ll == ull_disable_mark_get())); } } @@ -1727,6 +1767,7 @@ static void conn_cleanup_finalize(struct ll_conn *conn) #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) ull_cp_update_tx_buffer_queue(conn); #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ + ull_cp_release_nodes(conn); /* flush demux-ed Tx buffer still in ULL context */ tx_ull_flush(conn); @@ -1936,10 +1977,6 @@ static int empty_data_start_release(struct ll_conn *conn, struct node_tx *tx) } #endif /* CONFIG_BT_CTLR_LLID_DATA_START_EMPTY */ -/* - * TODO: struct lll_conn *lll_conn gives a CI error that tag names - * must be unique. This may be a false positive - */ #if defined(CONFIG_BT_CTLR_FORCE_MD_AUTO) static uint8_t force_md_cnt_calc(struct lll_conn *lll_connection, uint32_t tx_rate) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h index 0cd64423f90..e047a114008 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h @@ -22,8 +22,9 @@ bool ull_conn_peer_connected(uint8_t const own_id_addr_type, uint8_t const peer_id_addr_type, uint8_t const *const peer_id_addr); void ull_conn_setup(memq_link_t *rx_link, struct node_rx_hdr *rx); -int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx); -int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, uint16_t lazy); +void ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx); +int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, + uint32_t remainder, uint16_t lazy); void ull_conn_done(struct node_rx_event_done *done); void ull_conn_tx_demux(uint8_t count); void ull_conn_tx_lll_enqueue(struct ll_conn *conn, uint8_t count); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index 1ac92b2fa3f..8b79100d942 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -6,8 +6,7 @@ #include #include -#include -#include +#include #include "util/util.h" #include "util/mem.h" @@ -66,6 +65,12 @@ static int init_reset(void); +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) +static void cis_lazy_fill(struct ll_conn_iso_stream *cis); +static void mfy_cis_lazy_fill(void *param); +static void ticker_next_slot_get_op_cb(uint32_t status, void *param); +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ +static void ticker_start_op_cb(uint32_t status, void *param); static void ticker_update_cig_op_cb(uint32_t status, void *param); static void ticker_resume_op_cb(uint32_t status, void *param); static void ticker_resume_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, @@ -97,8 +102,9 @@ struct ll_conn_iso_group *ll_conn_iso_group_acquire(void) void ll_conn_iso_group_release(struct ll_conn_iso_group *cig) { - cig->cig_id = 0xFF; - cig->started = 0; + cig->cig_id = 0xFF; + cig->state = CIG_STATE_NO_CIG; + cig->lll.num_cis = 0U; mem_release(cig, &cig_free); } @@ -159,6 +165,18 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_get(uint16_t handle) LL_CIS_HANDLE_BASE); } +struct lll_conn_iso_stream *ull_conn_iso_lll_stream_get(uint16_t handle) +{ + struct ll_conn_iso_stream *cis; + + cis = ll_conn_iso_stream_get(handle); + if (!cis) { + return NULL; + } + + return &cis->lll; +} + struct ll_conn_iso_stream *ll_iso_stream_connected_get(uint16_t handle) { struct ll_conn_iso_stream *cis; @@ -198,25 +216,28 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_acl(struct ll_conn *conn, u handle_iter = UINT16_MAX; - for (cis_idx = 0; cis_idx < cig->lll.num_cis; cis_idx++) { + /* Find next connected CIS in the group */ + for (cis_idx = 0; cis_idx < CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP; cis_idx++) { cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); - LL_ASSERT(cis); + if (cis) { + uint16_t cis_handle = cis->lll.handle; - uint16_t cis_handle = cis->lll.handle; + cis = ll_iso_stream_connected_get(cis_handle); + if (!cis) { + /* CIS is not connected */ + continue; + } - cis = ll_iso_stream_connected_get(cis_handle); - if (!cis) { - continue; - } + if (!cis_iter_start) { + /* Look for iterator start handle */ + cis_iter_start = cis_handle == (*cis_iter); + } else if (cis->lll.acl_handle == conn->lll.handle) { + if (cis_iter) { + (*cis_iter) = cis_handle; + } - if (!cis_iter_start) { - /* Look for iterator start handle */ - cis_iter_start = cis_handle == (*cis_iter); - } else if (cis->lll.acl_handle == conn->lll.handle) { - if (cis_iter) { - (*cis_iter) = cis_handle; + return cis; } - return cis; } } } @@ -247,6 +268,21 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_group(struct ll_conn_iso_gr return NULL; } +struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_id(uint8_t cis_id) +{ + struct ll_conn_iso_stream *cis; + uint16_t handle; + + for (handle = LL_CIS_HANDLE_BASE; handle <= LL_CIS_HANDLE_LAST; handle++) { + cis = ll_conn_iso_stream_get(handle); + if (cis->group && (cis->cis_id == cis_id)) { + return cis; + } + } + + return NULL; +} + struct lll_conn_iso_stream * ull_conn_iso_lll_stream_get_by_group(struct lll_conn_iso_group *cig_lll, uint16_t *handle_iter) @@ -256,6 +292,9 @@ ull_conn_iso_lll_stream_get_by_group(struct lll_conn_iso_group *cig_lll, cig = HDR_LLL2ULL(cig_lll); cis = ll_conn_iso_stream_get_by_group(cig, handle_iter); + if (!cis) { + return NULL; + } return &cis->lll; } @@ -295,11 +334,25 @@ void ull_conn_iso_lll_cis_established(struct lll_conn_iso_stream *cis_lll) { struct ll_conn_iso_stream *cis = ll_conn_iso_stream_get(cis_lll->handle); + struct node_rx_pdu *node_rx; if (cis->established) { return; } + node_rx = ull_pdu_rx_alloc(); + if (!node_rx) { + /* No node available - try again later */ + return; + } + + node_rx->hdr.type = NODE_RX_TYPE_CIS_ESTABLISHED; + + /* Send node to ULL RX demuxer for triggering LLCP state machine */ + node_rx->hdr.handle = cis->lll.acl_handle; + + ull_rx_put_sched(node_rx->hdr.link, node_rx); + cis->established = 1; } @@ -332,26 +385,36 @@ void ull_conn_iso_done(struct node_rx_event_done *done) cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); LL_ASSERT(cis); - if (cis->lll.handle != LLL_HANDLE_INVALID) { + if (cis->lll.active && cis->lll.handle != LLL_HANDLE_INVALID) { /* CIS was setup and is now expected to be going */ - if (done->extra.mic_state == LLL_CONN_MIC_FAIL) { - /* MIC failure - stop CIS and defer cleanup to after teardown. */ - ull_conn_iso_cis_stop(cis, NULL, BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL); - } else if (!(done->extra.trx_performed_bitmask & - (1U << LL_CIS_IDX_FROM_HANDLE(cis->lll.handle)))) { + if (done->extra.trx_performed_bitmask & + (1U << LL_CIS_IDX_FROM_HANDLE(cis->lll.handle))) { + if (done->extra.mic_state == LLL_CONN_MIC_FAIL) { + /* MIC failure - stop CIS and defer cleanup to after + * teardown. + */ + ull_conn_iso_cis_stop(cis, NULL, + BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL); + } else { + cis->event_expire = 0U; + } + } else { /* We did NOT have successful transaction on established CIS, * or CIS was not yet established, so handle timeout */ if (!cis->event_expire) { struct ll_conn *conn = ll_conn_get(cis->lll.acl_handle); - cis->event_expire = - RADIO_CONN_EVENTS( + cis->event_expire = RADIO_CONN_EVENTS( conn->supervision_timeout * 10U * 1000U, - cig->iso_interval * CONN_INT_UNIT_US) + 1; - } + cig->iso_interval * CONN_INT_UNIT_US); + + } else if (cis->event_expire > cig->lll.latency_event) { + cis->event_expire -= cig->lll.latency_event; + + } else { + cis->event_expire = 0U; - if (--cis->event_expire == 0) { /* Stop CIS and defer cleanup to after teardown. This will * only generate a terminate event to the host if CIS has * been established. If CIS was not established, the @@ -363,8 +426,6 @@ void ull_conn_iso_done(struct node_rx_event_done *done) BT_HCI_ERR_CONN_FAIL_TO_ESTAB); } - } else { - cis->event_expire = 0; } } } @@ -419,6 +480,13 @@ void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis, if (cis->teardown) { /* Teardown already started */ + LL_ASSERT(!cis->released_cb || !cis_released_cb || + (cis->released_cb == cis_released_cb)); + + if (cis_released_cb) { + cis->released_cb = cis_released_cb; + } + return; } @@ -564,8 +632,8 @@ static int init_reset(void) for (handle = 0; handle < CONFIG_BT_CTLR_CONN_ISO_GROUPS; handle++) { cig = ll_conn_iso_group_get(handle); - cig->cig_id = 0xFF; - cig->started = 0; + cig->cig_id = 0xFF; + cig->state = CIG_STATE_NO_CIG; cig->lll.num_cis = 0; } @@ -627,6 +695,11 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, if (cis->lll.handle != 0xFFFF && cis->lll.active) { cis->lll.event_count += (lazy + 1U); +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + cis->lll.event_count -= cis->lll.lazy_active; + cis->lll.lazy_active = 0U; +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + leading_event_count = MAX(leading_event_count, cis->lll.event_count); @@ -701,15 +774,9 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, ull_conn_iso_transmit_test_cig_interval(cig->lll.handle, ticks_at_expire); } -static void ticker_op_cb(uint32_t status, void *param) -{ - ARG_UNUSED(param); - - LL_ASSERT(status == TICKER_STATUS_SUCCESS); -} - -void ull_conn_iso_start(struct ll_conn *conn, uint32_t ticks_at_expire, - uint16_t cis_handle, uint16_t instant_latency) +void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, + uint32_t ticks_at_expire, uint32_t remainder, + uint16_t instant_latency) { struct ll_conn_iso_group *cig; struct ll_conn_iso_stream *cis; @@ -718,6 +785,7 @@ void ull_conn_iso_start(struct ll_conn *conn, uint32_t ticks_at_expire, uint32_t ticks_remainder; uint32_t ticks_periodic; uint32_t ticker_status; + uint32_t remainder_us; int32_t cig_offset_us; uint32_t ticks_slot; uint8_t ticker_id; @@ -729,7 +797,6 @@ void ull_conn_iso_start(struct ll_conn *conn, uint32_t ticks_at_expire, cis->lll.offset = cis_offs_to_cig_ref; cis->lll.handle = cis_handle; - cis->lll.active = 1U; #if defined(CONFIG_BT_CTLR_LE_ENC) if (conn->lll.enc_tx) { @@ -782,28 +849,39 @@ void ull_conn_iso_start(struct ll_conn *conn, uint32_t ticks_at_expire, * running. If so, we just return with updated offset and * validated handle. */ - if (cig->started) { + if (cig->state == CIG_STATE_ACTIVE) { +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + cis_lazy_fill(cis); +#else /* CONFIG_BT_CTLR_JIT_SCHEDULING */ + /* Set CIS active in already active CIG */ + cis->lll.active = 1U; +#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ + /* We're done */ return; } ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig); + remainder_us = remainder; + hal_ticker_remove_jitter(&ticks_at_expire, &remainder_us); + /* Establish the CIG reference point by adjusting ACL-to-CIS offset * (cis->offset) by the difference between CIG- and CIS sync delays. */ acl_to_cig_ref_point = cis->offset - cis_offs_to_cig_ref; /* Calculate initial ticker offset */ - cig_offset_us = acl_to_cig_ref_point; + cig_offset_us = remainder_us + acl_to_cig_ref_point; /* Calculate the CIG reference point of first CIG event. This * calculation is inaccurate. However it is the best estimate available * until the first anchor point for the leading CIS is available. */ cig->cig_ref_point = isoal_get_wrapped_time_us(HAL_TICKER_TICKS_TO_US(ticks_at_expire), - EVENT_OVERHEAD_START_US + - acl_to_cig_ref_point); + remainder_us + + EVENT_OVERHEAD_START_US + + acl_to_cig_ref_point); if (false) { @@ -856,12 +934,6 @@ void ull_conn_iso_start(struct ll_conn *conn, uint32_t ticks_at_expire, ticks_periodic = HAL_TICKER_US_TO_TICKS(iso_interval_us); ticks_remainder = HAL_TICKER_REMAINDER(iso_interval_us); - /* Compensate for unused ticker remainder value starting CIG */ - cig_offset_us += EVENT_TICKER_RES_MARGIN_US; - - /* Compensate for missing remainder scheduling first expire */ - cig_offset_us += EVENT_TICKER_RES_MARGIN_US; - /* FIXME: Handle latency due to skipped ACL events around the * instant to start CIG */ @@ -885,30 +957,34 @@ void ull_conn_iso_start(struct ll_conn *conn, uint32_t ticks_at_expire, #else /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ uint32_t ticks_slot_overhead; uint32_t ticks_slot_offset; - uint32_t slot_us; /* Calculate time reservations for sequential and interleaved packing as * configured. */ - if (IS_CENTRAL(cig)) { - /* CIG sync_delay has been calculated considering the configured - * packing. - */ - slot_us = cig->sync_delay; - } else { + if (IS_PERIPHERAL(cig)) { + uint32_t slot_us; + /* FIXME: Time reservation for interleaved packing */ /* Below is time reservation for sequential packing */ slot_us = cis->lll.sub_interval * cis->lll.nse; - } - slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; - /* Populate the ULL hdr with event timings overheads */ - cig->ull.ticks_active_to_start = 0U; - cig->ull.ticks_prepare_to_start = - HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US); - cig->ull.ticks_preempt_to_start = - HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US); - cig->ull.ticks_slot = HAL_TICKER_US_TO_TICKS(slot_us); + slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + + /* FIXME: How to use ready_delay_us in the time reservation? + * i.e. when CISes use different PHYs? Is that even + * allowed? + * + * Missing code here, i.e. slot_us += ready_delay_us; + */ + + /* Populate the ULL hdr with event timings overheads */ + cig->ull.ticks_active_to_start = 0U; + cig->ull.ticks_prepare_to_start = + HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US); + cig->ull.ticks_preempt_to_start = + HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US); + cig->ull.ticks_slot = HAL_TICKER_US_TO_TICKS(slot_us); + } ticks_slot_offset = MAX(cig->ull.ticks_active_to_start, cig->ull.ticks_prepare_to_start); @@ -923,22 +999,126 @@ void ull_conn_iso_start(struct ll_conn *conn, uint32_t ticks_at_expire, #endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ /* Start CIS peripheral CIG ticker */ - ticker_status = ticker_start(TICKER_INSTANCE_ID_CTLR, - TICKER_USER_ID_ULL_HIGH, - ticker_id, - ticks_at_expire, - HAL_TICKER_US_TO_TICKS(cig_offset_us), - ticks_periodic, - ticks_remainder, - TICKER_NULL_LAZY, - ticks_slot, - ull_conn_iso_ticker_cb, cig, - ticker_op_cb, NULL); - + ticker_status = ticker_start_us(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_HIGH, + ticker_id, ticks_at_expire, + HAL_TICKER_US_TO_TICKS(cig_offset_us), + HAL_TICKER_REMAINDER(cig_offset_us), + ticks_periodic, ticks_remainder, + TICKER_NULL_LAZY, ticks_slot, + ull_conn_iso_ticker_cb, cig, + ticker_start_op_cb, NULL); LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) || (ticker_status == TICKER_STATUS_BUSY)); - cig->started = 1; + /* Set CIG and the first CIS state as active */ + cig->state = CIG_STATE_ACTIVE; + cis->lll.active = 1U; + +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + /* CIS event lazy at CIS create */ + cis->lll.lazy_active = 0U; +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ +} + +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) +static void cis_lazy_fill(struct ll_conn_iso_stream *cis) +{ + static memq_link_t link; + static struct mayfly mfy = {0U, 0U, &link, NULL, mfy_cis_lazy_fill}; + uint32_t ret; + + mfy.param = cis; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1U, &mfy); + LL_ASSERT(!ret); +} + +static void mfy_cis_lazy_fill(void *param) +{ + struct ll_conn_iso_stream *cis; + struct ll_conn_iso_group *cig; + uint32_t ticks_to_expire; + uint32_t ticks_current; + uint32_t remainder; + uint8_t ticker_id; + uint16_t lazy; + uint8_t retry; + uint8_t id; + + cis = param; + cig = cis->group; + ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig); + + id = TICKER_NULL; + ticks_to_expire = 0U; + ticks_current = 0U; + + /* In the first iteration the actual ticks_current value is returned + * which will be different from the initial value of 0 that is set. + * Subsequent iterations should return the same ticks_current as the + * reference tick. + * In order to avoid infinite updates to ticker's reference due to any + * race condition due to expiring tickers, we try upto 3 more times. + * Hence, first iteration to get an actual ticks_current and 3 more as + * retries when there could be race conditions that changes the value + * of ticks_current. + * + * ticker_next_slot_get_ext() restarts iterating when updated value of + * ticks_current is returned. + */ + retry = 4U; + do { + uint32_t volatile ret_cb; + uint32_t ticks_previous; + uint32_t ret; + bool success; + + ticks_previous = ticks_current; + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_LOW, &id, + &ticks_current, &ticks_to_expire, &remainder, &lazy, + NULL, NULL, ticker_next_slot_get_op_cb, + (void *)&ret_cb); + if (ret == TICKER_STATUS_BUSY) { + /* Busy wait until Ticker Job is enabled after any Radio + * event is done using the Radio hardware. Ticker Job + * ISR is disabled during Radio events in LOW_LAT + * feature to avoid Radio ISR latencies. + */ + while (ret_cb == TICKER_STATUS_BUSY) { + ticker_job_sched(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW); + } + } + + success = (ret_cb == TICKER_STATUS_SUCCESS); + LL_ASSERT(success); + + LL_ASSERT((ticks_current == ticks_previous) || retry--); + + LL_ASSERT(id != TICKER_NULL); + } while (id != ticker_id); + + /* Set CIS active in already active CIG and any previous laziness in + * CIG before the CIS gets active that be decremented when event_count + * is incremented in ull_conn_iso_ticker_cb(). + */ + cis->lll.active = 1U; + cis->lll.lazy_active = lazy; +} + +static void ticker_next_slot_get_op_cb(uint32_t status, void *param) +{ + *((uint32_t volatile *)param) = status; +} +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + +static void ticker_start_op_cb(uint32_t status, void *param) +{ + ARG_UNUSED(param); + + LL_ASSERT(status == TICKER_STATUS_SUCCESS); } static void ticker_update_cig_op_cb(uint32_t status, void *param) @@ -998,46 +1178,65 @@ static void cis_disabled_cb(void *param) struct ll_conn_iso_stream *cis; uint32_t ticker_status; struct ll_conn *conn; + uint8_t active_cises; uint16_t handle_iter; uint8_t cis_idx; - uint8_t active_cises; + uint8_t num_cis; cig = HDR_LLL2ULL(param); handle_iter = UINT16_MAX; active_cises = 0; /* Remove all CISes marked for teardown */ - for (cis_idx = 0; cis_idx < cig->lll.num_cis; cis_idx++) { + num_cis = cig->lll.num_cis; + for (cis_idx = 0; cis_idx < num_cis; cis_idx++) { cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); LL_ASSERT(cis); - if (!cis->lll.active && !cis->lll.flushed) { - /* CIS is not active and not being flushed - skip it */ + if (!cis->lll.active && (cis->lll.flush != LLL_CIS_FLUSH_COMPLETE)) { + /* CIS is not active and did not just complete LLL flush - skip it */ continue; } + active_cises++; - if (cis->lll.flushed) { + if (cis->lll.flush == LLL_CIS_FLUSH_PENDING) { + /* CIS has LLL flush pending - wait for completion */ + continue; + } else if (cis->lll.flush == LLL_CIS_FLUSH_COMPLETE) { ll_iso_stream_released_cb_t cis_released_cb; conn = ll_conn_get(cis->lll.acl_handle); cis_released_cb = cis->released_cb; + cis->released_cb = NULL; if (IS_PERIPHERAL(cig)) { /* Remove data path and ISOAL sink/source associated with this - * CIS for both directions. + * CIS for both directions. Disable them one at a time to make sure + * both are removed, even if only one is set. */ ll_remove_iso_path(cis->lll.handle, - BT_HCI_DATAPATH_DIR_CTLR_TO_HOST); + BIT(BT_HCI_DATAPATH_DIR_HOST_TO_CTLR)); ll_remove_iso_path(cis->lll.handle, - BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); + BIT(BT_HCI_DATAPATH_DIR_CTLR_TO_HOST)); ll_conn_iso_stream_release(cis); + cig->lll.num_cis--; + + } else if (IS_CENTRAL(cig)) { + cis->established = 0U; + cis->teardown = 0U; + + /* Prevent referencing inactive CIS */ + cis->lll.flush = LLL_CIS_FLUSH_NONE; + cis->lll.acl_handle = LLL_HANDLE_INVALID; + + } else { + LL_ASSERT(0); } /* CIS is no longer active */ - cis->lll.active = 0U; active_cises--; /* CIS terminated, triggers completion of CIS_TERMINATE_IND procedure */ @@ -1054,10 +1253,11 @@ static void cis_disabled_cb(void *param) } else if (cis->teardown) { DECLARE_MAYFLY_ARRAY(mfys, cis_tx_lll_flush, CONFIG_BT_CTLR_CONN_ISO_GROUPS); - struct node_rx_pdu *node_terminate; uint32_t ret; if (cis->established) { + struct node_rx_pdu *node_terminate; + /* Create and enqueue termination node. This shall prevent * further enqueuing of TX nodes for terminating CIS. */ @@ -1092,6 +1292,8 @@ static void cis_disabled_cb(void *param) * More than one CIG may be terminating at the same time, so * enqueue a mayfly instance for this CIG. */ + cis->lll.flush = LLL_CIS_FLUSH_PENDING; + mfys[cig->lll.handle].param = &cis->lll; ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 1, &mfys[cig->lll.handle]); @@ -1101,11 +1303,11 @@ static void cis_disabled_cb(void *param) } } - if (cig->started && !active_cises) { + if ((cig->state == CIG_STATE_ACTIVE) && !active_cises) { /* This was the last active CIS of the CIG. Initiate CIG teardown by * stopping ticker. */ - cig->started = 0; + cig->state = CIG_STATE_INACTIVE; ticker_status = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, @@ -1128,10 +1330,8 @@ static void cis_tx_lll_flush(void *param) struct ll_conn_iso_group *cig; struct node_tx_iso *tx; memq_link_t *link; - uint32_t ret; lll = param; - lll->flushed = 1U; lll->active = 0U; cis = ll_conn_iso_stream_get(lll->handle); @@ -1155,11 +1355,12 @@ static void cis_tx_lll_flush(void *param) LL_ASSERT(link); lll->link_tx_free = link; + lll->flush = LLL_CIS_FLUSH_COMPLETE; + /* Resume CIS teardown in ULL_HIGH context */ mfys[cig->lll.handle].param = &cig->lll; - ret = mayfly_enqueue(TICKER_USER_ID_LLL, + (void)mayfly_enqueue(TICKER_USER_ID_LLL, TICKER_USER_ID_ULL_HIGH, 1, &mfys[cig->lll.handle]); - LL_ASSERT(!ret); } static void ticker_stop_op_cb(uint32_t status, void *param) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h index 5726ec76ff7..fe19f73b172 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h @@ -12,6 +12,9 @@ (IS_ENABLED(CONFIG_BT_CTLR_CENTRAL_ISO) && \ (cig->lll.role == BT_HCI_ROLE_CENTRAL)) +/* BT Core 5.4, Vol 6, Part B, section 2.4.2.29 */ +#define CIS_MIN_OFFSET_MIN 500U + /* Helper functions to initialize and reset ull_conn_iso module */ int ull_conn_iso_init(void); int ull_conn_iso_reset(void); @@ -31,9 +34,11 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_acl(struct ll_conn *conn, uint16_t *cis_iter); struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_group(struct ll_conn_iso_group *cig, uint16_t *handle_iter); +struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_id(uint8_t cis_id); -void ull_conn_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, - uint16_t cis_handle, uint16_t instant_latency); +void ull_conn_iso_start(struct ll_conn *acl, uint16_t cis_handle, + uint32_t ticks_at_expire, uint32_t remainder, + uint16_t instant_latency); void ull_conn_iso_done(struct node_rx_event_done *done); void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis, ll_iso_stream_released_cb_t cis_released_cb, diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h index 6c0d73bd040..e8ca29da7af 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h @@ -8,6 +8,11 @@ struct ll_conn; typedef void (*ll_iso_stream_released_cb_t)(struct ll_conn *conn); +#define CIG_STATE_NO_CIG 0 +#define CIG_STATE_CONFIGURABLE 1 /* Central only */ +#define CIG_STATE_INITIATING 2 /* Central only */ +#define CIG_STATE_ACTIVE 3 +#define CIG_STATE_INACTIVE 4 struct ll_conn_iso_stream { struct ll_iso_stream_hdr hdr; @@ -67,7 +72,10 @@ struct ll_conn_iso_group { uint16_t iso_interval; uint8_t cig_id; - uint8_t started:1; /* 1 if CIG started and ticker is running */ + uint8_t state:3; /* CIG_STATE_NO_CIG, CIG_STATE_CONFIGURABLE (central only), + * CIG_STATE_INITIATING (central only), CIG_STATE_ACTIVE or + * CIG_STATE_INACTIVE. + */ uint8_t sca_update:4; /* (new SCA)+1 to trigger restart of ticker */ union { diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index ad1faccdf54..12e16488f38 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -66,8 +66,9 @@ struct llcp_struct { /* Prepare parameters */ struct { - uint32_t ticks_at_expire; - uint16_t lazy; + uint32_t ticks_at_expire; /* Vendor specific tick units */ + uint32_t remainder; /* Vendor specific remainder fraction of a tick unit */ + uint16_t lazy; /* Previous skipped radio event count */ } prep; /* Version Exchange Procedure State */ @@ -147,6 +148,10 @@ struct llcp_struct { uint8_t tx_buffer_alloc; uint8_t tx_q_pause_data_mask; + + struct node_rx_pdu *rx_node_release; + struct node_tx *tx_node_release; + }; /* struct llcp_struct */ struct ll_conn { diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 70de3e28f36..8be711539da 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_filter.c b/subsys/bluetooth/controller/ll_sw/ull_filter.c index 3be6f80950d..341b7296515 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_filter.c +++ b/subsys/bluetooth/controller/ll_sw/ull_filter.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" @@ -74,6 +74,10 @@ static uint8_t rl_enable; static uint8_t newest_prpa; static struct lll_prpa_cache prpa_cache[CONFIG_BT_CTLR_RPA_CACHE_SIZE]; +/* Cache of known unknown target RPAs */ +static uint8_t newest_trpa; +static struct lll_trpa_cache trpa_cache[CONFIG_BT_CTLR_TRPA_CACHE_SIZE]; + struct prpa_resolve_work { struct k_work prpa_work; bt_addr_t rpa; @@ -99,6 +103,7 @@ static struct prpa_resolve_work resolve_work; static struct target_resolve_work t_work; BUILD_ASSERT(ARRAY_SIZE(prpa_cache) < FILTER_IDX_NONE); +BUILD_ASSERT(ARRAY_SIZE(trpa_cache) < FILTER_IDX_NONE); #endif /* CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY */ BUILD_ASSERT(ARRAY_SIZE(fal) < FILTER_IDX_NONE); BUILD_ASSERT(ARRAY_SIZE(rl) < FILTER_IDX_NONE); @@ -158,6 +163,9 @@ static void prpa_cache_add(bt_addr_t *prpa_cache_addr); static uint8_t prpa_cache_try_resolve(bt_addr_t *rpa); static void prpa_cache_resolve(struct k_work *work); static void target_resolve(struct k_work *work); +static void trpa_cache_clear(void); +static uint8_t trpa_cache_find(bt_addr_t *prpa_cache_addr, uint8_t rl_idx); +static void trpa_cache_add(bt_addr_t *prpa_cache_addr, uint8_t rl_idx); #endif /* CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY */ #endif /* CONFIG_BT_CTLR_FILTER_ACCEPT_LIST */ @@ -326,6 +334,7 @@ uint8_t ll_rl_add(bt_addr_le_t *id_addr, const uint8_t pirk[IRK_SIZE], #if defined(CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY) /* a new key was added, invalidate the known/unknown list */ prpa_cache_clear(); + trpa_cache_clear(); #endif } if (rl[i].lirk) { @@ -629,6 +638,7 @@ void ull_filter_reset(bool init) rl_clear(); #if defined(CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY) prpa_cache_clear(); + trpa_cache_clear(); #endif if (init) { k_work_init_delayable(&rpa_work, rpa_timeout); @@ -748,6 +758,7 @@ void ull_filter_rpa_update(bool timeout) * invalidate the known/unknown peer RPA cache */ prpa_cache_clear(); + trpa_cache_clear(); #endif } @@ -1493,15 +1504,28 @@ static void target_resolve(struct k_work *work) idx = twork->idx; search_rpa = &(twork->rpa); - if (rl[idx].taken && !bt_addr_cmp(&(rl[idx].target_rpa), search_rpa)) { + if (rl[idx].taken && bt_addr_eq(&(rl[idx].target_rpa), search_rpa)) { j = idx; } else { - /* No match - so not in list Need to see if we can resolve */ - if (bt_rpa_irk_matches(rl[idx].local_irk, search_rpa)) { + uint8_t i; + + /* No match - so not in list; Need to see if we can resolve */ + + i = trpa_cache_find(search_rpa, idx); + if (i != FILTER_IDX_NONE) { + /* Found a known unknown - do nothing */ + j = FILTER_IDX_NONE; + } else if (bt_rpa_irk_matches(rl[idx].local_irk, search_rpa)) { /* Could resolve, store RPA */ (void)memcpy(rl[idx].target_rpa.val, search_rpa->val, sizeof(bt_addr_t)); j = idx; + } else if (rl[idx].taken) { + /* No match - thus cannot resolve, we have an unknown + * so insert in known unknown list + */ + trpa_cache_add(search_rpa, idx); + j = FILTER_IDX_NONE; } else { /* Could not resolve, and not in table */ j = FILTER_IDX_NONE; @@ -1618,7 +1642,7 @@ static uint8_t prpa_cache_find(bt_addr_t *rpa) { for (uint8_t i = 0; i < CONFIG_BT_CTLR_RPA_CACHE_SIZE; i++) { if (prpa_cache[i].taken && - !bt_addr_cmp(&(prpa_cache[i].rpa), rpa)) { + bt_addr_eq(&(prpa_cache[i].rpa), rpa)) { return i; } } @@ -1629,4 +1653,45 @@ const struct lll_prpa_cache *ull_filter_lll_prpa_cache_get(void) { return prpa_cache; } + +static void trpa_cache_clear(void) +{ + /* Note the first element will not be in use before wrap around + * is reached. + * The first element in actual use will be at index 1. + * There is no element waisted with this implementation, as + * element 0 will eventually be allocated. + */ + newest_trpa = 0U; + + for (uint8_t i = 0; i < CONFIG_BT_CTLR_TRPA_CACHE_SIZE; i++) { + trpa_cache[i].rl_idx = FILTER_IDX_NONE; + } +} + +static void trpa_cache_add(bt_addr_t *rpa, uint8_t rl_idx) +{ + newest_trpa = (newest_trpa + 1) % CONFIG_BT_CTLR_TRPA_CACHE_SIZE; + + (void)memcpy(trpa_cache[newest_trpa].rpa.val, rpa->val, + sizeof(bt_addr_t)); + trpa_cache[newest_trpa].rl_idx = rl_idx; +} + +static uint8_t trpa_cache_find(bt_addr_t *rpa, uint8_t rl_idx) +{ + for (uint8_t i = 0; i < CONFIG_BT_CTLR_TRPA_CACHE_SIZE; i++) { + if (trpa_cache[i].rl_idx == rl_idx && + bt_addr_eq(&(trpa_cache[i].rpa), rpa)) { + return i; + } + } + return FILTER_IDX_NONE; +} + +const struct lll_trpa_cache *ull_filter_lll_trpa_cache_get(void) +{ + return trpa_cache; +} + #endif /* !CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_internal.h b/subsys/bluetooth/controller/ll_sw/ull_internal.h index f4ad4c40d2a..a0f6b7a6a0d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_internal.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - /** * User CPR Interval */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index ed370b49b67..1520bd76963 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -4,10 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include +#include #include -#include +#include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -176,9 +177,18 @@ uint8_t ll_read_iso_tx_sync(uint16_t handle, uint16_t *seq, return BT_HCI_ERR_CMD_DISALLOWED; } else if (IS_ADV_ISO_HANDLE(handle)) { - /* FIXME: Do something similar to connected */ + const struct lll_adv_iso_stream *adv_stream; + uint16_t stream_handle; - return BT_HCI_ERR_CMD_DISALLOWED; + stream_handle = LL_BIS_ADV_IDX_FROM_HANDLE(handle); + adv_stream = ull_adv_iso_stream_get(stream_handle); + if (!adv_stream || !adv_stream->dp || + isoal_tx_get_sync_info(adv_stream->dp->source_hdl, seq, + timestamp, offset) != ISOAL_STATUS_OK) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + return BT_HCI_ERR_SUCCESS; } return BT_HCI_ERR_UNKNOWN_CONN_ID; @@ -225,7 +235,7 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, * Identifier (0x02) */ cis = ll_conn_iso_stream_get(handle); - if (!cis->group) { + if (!cis || !cis->group) { /* CIS does not belong to a CIG */ return BT_HCI_ERR_UNKNOWN_CONN_ID; } @@ -303,7 +313,7 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, adv_iso = ull_adv_iso_by_stream_get(stream_handle); lll_iso = &adv_iso->lll; - role = 0U; /* FIXME: Set role from LLL struct */ + role = ISOAL_ROLE_BROADCAST_SOURCE; iso_interval = lll_iso->iso_interval; sdu_interval = lll_iso->sdu_interval; burst_number = lll_iso->bn; @@ -329,7 +339,7 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, sync_iso = ull_sync_iso_by_stream_get(stream_handle); lll_iso = &sync_iso->lll; - role = 1U; /* FIXME: Is this correct role value? */ + role = ISOAL_ROLE_BROADCAST_SINK; iso_interval = lll_iso->iso_interval; sdu_interval = lll_iso->sdu_interval; burst_number = lll_iso->bn; @@ -510,26 +520,22 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, uint8_t ll_remove_iso_path(uint16_t handle, uint8_t path_dir) { + /* If the Host issues this command with a Connection_Handle that does + * not exist or is not for a CIS or a BIS, the Controller shall return + * the error code Unknown Connection Identifier (0x02). + */ if (false) { #if defined(CONFIG_BT_CTLR_CONN_ISO) } else if (IS_CIS_HANDLE(handle)) { struct ll_conn_iso_stream *cis; + struct ll_iso_stream_hdr *hdr; + struct ll_iso_datapath *dp; - /* If the Host issues this command with a Connection_Handle that does - * not exist or is not for a CIS or a BIS, the Controller shall return - * the error code Unknown Connection Identifier (0x02). - */ cis = ll_conn_iso_stream_get(handle); - if (!cis) { - return BT_HCI_ERR_UNKNOWN_CONN_ID; - } - - if (path_dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) { - struct ll_iso_stream_hdr *hdr; - struct ll_iso_datapath *dp; + hdr = &cis->hdr; - hdr = &cis->hdr; + if (path_dir & BIT(BT_HCI_DATAPATH_DIR_HOST_TO_CTLR)) { dp = hdr->datapath_in; if (dp) { isoal_source_destroy(dp->source_hdl); @@ -540,11 +546,9 @@ uint8_t ll_remove_iso_path(uint16_t handle, uint8_t path_dir) /* Datapath was not previously set up */ return BT_HCI_ERR_CMD_DISALLOWED; } - } else if (path_dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { - struct ll_iso_stream_hdr *hdr; - struct ll_iso_datapath *dp; + } - hdr = &cis->hdr; + if (path_dir & BIT(BT_HCI_DATAPATH_DIR_CTLR_TO_HOST)) { dp = hdr->datapath_out; if (dp) { isoal_sink_destroy(dp->sink_hdl); @@ -555,9 +559,6 @@ uint8_t ll_remove_iso_path(uint16_t handle, uint8_t path_dir) /* Datapath was not previously set up */ return BT_HCI_ERR_CMD_DISALLOWED; } - } else { - /* Reserved for future use */ - return BT_HCI_ERR_CMD_DISALLOWED; } #endif /* CONFIG_BT_CTLR_CONN_ISO */ @@ -567,7 +568,7 @@ uint8_t ll_remove_iso_path(uint16_t handle, uint8_t path_dir) struct ll_iso_datapath *dp; uint16_t stream_handle; - if (path_dir != BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) { + if (!(path_dir & BIT(BT_HCI_DATAPATH_DIR_HOST_TO_CTLR))) { return BT_HCI_ERR_CMD_DISALLOWED; } @@ -594,7 +595,7 @@ uint8_t ll_remove_iso_path(uint16_t handle, uint8_t path_dir) struct ll_iso_datapath *dp; uint16_t stream_handle; - if (path_dir != BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { + if (!(path_dir & BIT(BT_HCI_DATAPATH_DIR_CTLR_TO_HOST))) { return BT_HCI_ERR_CMD_DISALLOWED; } @@ -908,16 +909,45 @@ uint8_t ll_read_iso_link_quality(uint16_t handle, uint32_t *rx_unreceived_packets, uint32_t *duplicate_packets) { - ARG_UNUSED(handle); - ARG_UNUSED(tx_unacked_packets); - ARG_UNUSED(tx_flushed_packets); - ARG_UNUSED(tx_last_subevent_packets); - ARG_UNUSED(retransmitted_packets); - ARG_UNUSED(crc_error_packets); - ARG_UNUSED(rx_unreceived_packets); - ARG_UNUSED(duplicate_packets); - - return BT_HCI_ERR_CMD_DISALLOWED; + uint8_t status; + + *tx_unacked_packets = 0; + *tx_flushed_packets = 0; + *tx_last_subevent_packets = 0; + *retransmitted_packets = 0; + *crc_error_packets = 0; + *rx_unreceived_packets = 0; + *duplicate_packets = 0; + + status = BT_HCI_ERR_SUCCESS; + + if (IS_CIS_HANDLE(handle)) { + struct ll_conn_iso_stream *cis; + + cis = ll_iso_stream_connected_get(handle); + + if (!cis) { + /* CIS is not connected */ + return BT_HCI_ERR_UNKNOWN_CONN_ID; + } + + *tx_unacked_packets = cis->hdr.link_quality.tx_unacked_packets; + *tx_flushed_packets = cis->hdr.link_quality.tx_flushed_packets; + *tx_last_subevent_packets = cis->hdr.link_quality.tx_last_subevent_packets; + *retransmitted_packets = cis->hdr.link_quality.retransmitted_packets; + *crc_error_packets = cis->hdr.link_quality.crc_error_packets; + *rx_unreceived_packets = cis->hdr.link_quality.rx_unreceived_packets; + *duplicate_packets = cis->hdr.link_quality.duplicate_packets; + + } else if (IS_SYNC_ISO_HANDLE(handle)) { + /* FIXME: Implement for sync receiver */ + status = BT_HCI_ERR_CMD_DISALLOWED; + } else { + /* Handle is out of range */ + status = BT_HCI_ERR_UNKNOWN_CONN_ID; + } + + return status; } #endif /* CONFIG_BT_CTLR_READ_ISO_LINK_QUALITY */ @@ -953,6 +983,7 @@ void ll_iso_transmit_test_send_sdu(uint16_t handle, uint32_t ticks_at_expire) struct ll_conn_iso_group *cig; uint32_t rand_max_sdu; uint8_t event_offset; + uint8_t max_sdu; uint8_t rand_8; cis = ll_iso_stream_connected_get(handle); @@ -966,21 +997,23 @@ void ll_iso_transmit_test_send_sdu(uint16_t handle, uint32_t ticks_at_expire) cig = cis->group; source_handle = cis->hdr.datapath_in->source_hdl; + max_sdu = IS_PERIPHERAL(cig) ? cis->p_max_sdu : cis->c_max_sdu; + switch (cis->hdr.test_mode.tx_payload_type) { case BT_HCI_ISO_TEST_ZERO_SIZE_SDU: remaining_tx = 0; break; case BT_HCI_ISO_TEST_VARIABLE_SIZE_SDU: - /* Randomize the length [4..p_max_sdu] */ + /* Randomize the length [4..max_sdu] */ lll_rand_get(&rand_8, sizeof(rand_8)); - rand_max_sdu = rand_8 * (cis->p_max_sdu - ISO_TEST_PACKET_COUNTER_SIZE); + rand_max_sdu = rand_8 * (max_sdu - ISO_TEST_PACKET_COUNTER_SIZE); remaining_tx = ISO_TEST_PACKET_COUNTER_SIZE + (rand_max_sdu >> 8); break; case BT_HCI_ISO_TEST_MAX_SIZE_SDU: - LL_ASSERT(cis->p_max_sdu > ISO_TEST_PACKET_COUNTER_SIZE); - remaining_tx = cis->p_max_sdu; + LL_ASSERT(max_sdu > ISO_TEST_PACKET_COUNTER_SIZE); + remaining_tx = max_sdu; break; default: @@ -1121,18 +1154,12 @@ uint8_t ll_iso_transmit_test(uint16_t handle, uint8_t payload_type) cis->hdr.datapath_in = dp; cig = cis->group; - if (cig->lll.role == BT_HCI_ROLE_PERIPHERAL) { - /* peripheral */ - sdu_interval = cig->c_sdu_interval; - } else { - /* central */ - sdu_interval = cig->p_sdu_interval; - } + sdu_interval = IS_PERIPHERAL(cig) ? cig->p_sdu_interval : cig->c_sdu_interval; /* Setup the test source */ err = isoal_source_create(handle, cig->lll.role, cis->framed, - cis->lll.rx.bn, cis->lll.rx.ft, - cis->lll.rx.max_pdu, sdu_interval, + cis->lll.tx.bn, cis->lll.tx.ft, + cis->lll.tx.max_pdu, sdu_interval, cig->iso_interval, cis->sync_delay, cig->sync_delay, ll_iso_pdu_alloc, ll_iso_pdu_write, ll_iso_pdu_emit, @@ -1419,8 +1446,8 @@ static void iso_rx_cig_ref_point_update(struct ll_conn_iso_group *cig, /* Update the CIG reference point based on the CIS * anchor point */ - cig->cig_ref_point = meta->timestamp + cis_sync_delay - - cig_sync_delay; + cig->cig_ref_point = isoal_get_wrapped_time_us(meta->timestamp, + cis_sync_delay - cig_sync_delay); } } } diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso_types.h b/subsys/bluetooth/controller/ll_sw/ull_iso_types.h index 495c778f22a..18d9a0f7bfe 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_iso_types.h @@ -34,9 +34,6 @@ /* CIS */ #if defined(CONFIG_BT_CTLR_CONN_ISO) -#define LL_CIS_HANDLE_BASE (BT_CTLR_CONN_ISO_STREAM_HANDLE_BASE) -#define LL_CIS_IDX_FROM_HANDLE(_handle) \ - ((_handle) - LL_CIS_HANDLE_BASE) #define LL_CIS_HANDLE_LAST \ (CONFIG_BT_CTLR_CONN_ISO_STREAMS + LL_CIS_HANDLE_BASE - 1) #define IS_CIS_HANDLE(_handle) \ @@ -58,13 +55,27 @@ struct ll_iso_test_mode_data { uint64_t rx_payload_type:4; }; +struct ll_iso_link_quality { + uint32_t tx_unacked_packets; + uint32_t tx_flushed_packets; + uint32_t tx_last_subevent_packets; + uint32_t retransmitted_packets; + uint32_t crc_error_packets; + uint32_t rx_unreceived_packets; + uint32_t duplicate_packets; +}; + /* Common members for ll_conn_iso_stream and ll_broadcast_iso_stream */ struct ll_iso_stream_hdr { struct ll_iso_test_mode_data test_mode; struct ll_iso_datapath *datapath_in; struct ll_iso_datapath *datapath_out; +#if defined(CONFIG_BT_CTLR_READ_ISO_LINK_QUALITY) + struct ll_iso_link_quality link_quality; +#endif /* CONFIG_BT_CTLR_READ_ISO_LINK_QUALITY */ }; + struct ll_iso_datapath { uint8_t path_dir; uint8_t path_id; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index 410ada80ac0..2b93c17a201 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" @@ -279,6 +280,38 @@ void llcp_tx_resume_data(struct ll_conn *conn, enum llcp_tx_q_pause_data_mask re } } +void llcp_rx_node_retain(struct proc_ctx *ctx) +{ + LL_ASSERT(ctx->node_ref.rx); + + /* Mark RX node to NOT release */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; + + /* store link element reference to use once this node is moved up */ + ctx->node_ref.rx->hdr.link = ctx->node_ref.link; +} + +void llcp_nodes_release(struct ll_conn *conn, struct proc_ctx *ctx) +{ + if (ctx->node_ref.rx && ctx->node_ref.rx->hdr.type == NODE_RX_TYPE_RETAIN) { + /* RX node retained, so release */ + ctx->node_ref.rx->hdr.link->mem = conn->llcp.rx_node_release; + conn->llcp.rx_node_release = ctx->node_ref.rx; + } +#if defined(CONFIG_BT_CTLR_PHY) && defined(CONFIG_BT_CTLR_DATA_LENGTH) + if (ctx->proc == PROC_PHY_UPDATE && ctx->data.pu.ntf_dle_node) { + /* RX node retained, so release */ + ctx->data.pu.ntf_dle_node->hdr.link->mem = conn->llcp.rx_node_release; + conn->llcp.rx_node_release = ctx->data.pu.ntf_dle_node; + } +#endif + + if (ctx->node_ref.tx) { + ctx->node_ref.tx->next = conn->llcp.tx_node_release; + conn->llcp.tx_node_release = ctx->node_ref.tx; + } +} + /* * LLCP Procedure Creation */ @@ -296,7 +329,8 @@ static struct proc_ctx *create_procedure(enum llcp_proc proc, struct llcp_mem_po ctx->collision = 0U; ctx->done = 0U; ctx->rx_greedy = 0U; - ctx->tx_ack = NULL; + ctx->node_ref.rx = NULL; + ctx->node_ref.tx_ack = NULL; /* Clear procedure data */ memset((void *)&ctx->data, 0, sizeof(ctx->data)); @@ -557,6 +591,9 @@ void ull_llcp_init(struct ll_conn *conn) conn->llcp.tx_q_pause_data_mask = 0; conn->lll.event_counter = 0; + + conn->llcp.tx_node_release = NULL; + conn->llcp.rx_node_release = NULL; } void ull_cp_release_tx(struct ll_conn *conn, struct node_tx *tx) @@ -575,12 +612,6 @@ void ull_cp_release_tx(struct ll_conn *conn, struct node_tx *tx) tx_release(tx); } -void ull_cp_release_ntf(struct node_rx_pdu *ntf) -{ - ntf->hdr.next = NULL; - ll_rx_mem_release((void **)&ntf); -} - static int prt_elapse(uint16_t *expire, uint16_t elapsed_event) { if (*expire != 0U) { @@ -661,6 +692,41 @@ void ull_cp_state_set(struct ll_conn *conn, uint8_t state) } } +void ull_cp_release_nodes(struct ll_conn *conn) +{ + struct node_rx_pdu *rx; + struct node_tx *tx; + + /* release any llcp retained rx nodes */ + rx = conn->llcp.rx_node_release; + while (rx) { + struct node_rx_hdr *hdr; + + /* traverse to next rx node */ + hdr = &rx->hdr; + rx = hdr->link->mem; + + /* Mark for buffer for release */ + hdr->type = NODE_RX_TYPE_RELEASE; + + /* enqueue rx node towards Thread */ + ll_rx_put(hdr->link, hdr); + } + conn->llcp.rx_node_release = NULL; + + /* release any llcp pre-allocated tx nodes */ + tx = conn->llcp.tx_node_release; + while (tx) { + struct node_tx *tx_release; + + tx_release = tx; + tx = tx->next; + + ull_cp_release_tx(conn, tx_release); + } + conn->llcp.tx_node_release = NULL; +} + #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) uint8_t ull_cp_min_used_chans(struct ll_conn *conn, uint8_t phys, uint8_t min_used_chans) { @@ -701,7 +767,7 @@ uint8_t ull_cp_le_ping(struct ll_conn *conn) #endif /* CONFIG_BT_CTLR_LE_PING */ #if defined(CONFIG_BT_CENTRAL) || defined(CONFIG_BT_CTLR_PER_INIT_FEAT_XCHG) -uint8_t ull_cp_feature_exchange(struct ll_conn *conn) +uint8_t ull_cp_feature_exchange(struct ll_conn *conn, uint8_t host_initiated) { struct proc_ctx *ctx; @@ -710,6 +776,8 @@ uint8_t ull_cp_feature_exchange(struct ll_conn *conn) return BT_HCI_ERR_CMD_DISALLOWED; } + ctx->data.fex.host_initiated = host_initiated; + llcp_lr_enqueue(conn, ctx); return BT_HCI_ERR_SUCCESS; @@ -829,7 +897,8 @@ uint8_t ull_cp_terminate(struct ll_conn *conn, uint8_t error_code) { struct proc_ctx *ctx; - llcp_lr_abort(conn); + llcp_lr_terminate(conn); + llcp_rr_terminate(conn); ctx = llcp_create_local_procedure(PROC_TERMINATE); if (!ctx) { @@ -874,8 +943,11 @@ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis) struct ll_conn_iso_group *cig; struct proc_ctx *ctx; - if (conn->lll.handle != cis->lll.acl_handle) { - return BT_HCI_ERR_CMD_DISALLOWED; + if (!conn->llcp.fex.valid) { + /* No feature exchange was performed so initiate before CIS Create */ + if (ull_cp_feature_exchange(conn, 0U) != BT_HCI_ERR_SUCCESS) { + return BT_HCI_ERR_CMD_DISALLOWED; + } } ctx = llcp_create_local_procedure(PROC_CIS_CREATE); @@ -905,10 +977,9 @@ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis) ctx->data.cis_create.c_ft = cis->lll.tx.ft; ctx->data.cis_create.p_ft = cis->lll.rx.ft; - ctx->data.cis_create.conn_event_count = - ull_central_iso_cis_offset_get(cis->lll.handle, - &ctx->data.cis_create.cis_offset_min, - &ctx->data.cis_create.cis_offset_max); + /* ctx->data.cis_create.conn_event_count will be filled when Tx PDU is + * enqueued. + */ llcp_lr_enqueue(conn, ctx); @@ -1234,6 +1305,20 @@ void ull_cp_cte_req_set_disable(struct ll_conn *conn) } #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +void ull_cp_cc_offset_calc_reply(struct ll_conn *conn, uint32_t cis_offset_min, + uint32_t cis_offset_max) +{ + struct proc_ctx *ctx; + + ctx = llcp_lr_peek(conn); + if (ctx && ctx->proc == PROC_CIS_CREATE) { + ctx->data.cis_create.cis_offset_min = cis_offset_min; + ctx->data.cis_create.cis_offset_max = cis_offset_max; + + llcp_lp_cc_offset_calc_reply(conn, ctx); + } +} + #if defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) bool ull_cp_cc_awaiting_reply(struct ll_conn *conn) { @@ -1245,7 +1330,6 @@ bool ull_cp_cc_awaiting_reply(struct ll_conn *conn) } return false; - } uint16_t ull_cp_cc_ongoing_handle(struct ll_conn *conn) @@ -1260,12 +1344,23 @@ uint16_t ull_cp_cc_ongoing_handle(struct ll_conn *conn) return 0xFFFF; } -void ull_cp_cc_accept(struct ll_conn *conn) +void ull_cp_cc_accept(struct ll_conn *conn, uint32_t cis_offset_min) { struct proc_ctx *ctx; ctx = llcp_rr_peek(conn); if (ctx && ctx->proc == PROC_CIS_CREATE) { + if (cis_offset_min > ctx->data.cis_create.cis_offset_min) { + if (cis_offset_min > ctx->data.cis_create.cis_offset_max) { + ctx->data.cis_create.error = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL; + llcp_rp_cc_reject(conn, ctx); + + return; + } + + ctx->data.cis_create.cis_offset_min = cis_offset_min; + } + llcp_rp_cc_accept(conn, ctx); } } @@ -1303,6 +1398,20 @@ bool ull_cp_cc_awaiting_established(struct ll_conn *conn) return false; } +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) +bool ull_cp_cc_cancel(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + ctx = llcp_lr_peek(conn); + if (ctx && ctx->proc == PROC_CIS_CREATE) { + return llcp_lp_cc_cancel(conn, ctx); + } + + return false; +} +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ + void ull_cp_cc_established(struct ll_conn *conn, uint8_t error_code) { struct proc_ctx *ctx; @@ -1338,6 +1447,15 @@ bool ull_lp_cc_is_active(struct ll_conn *conn) } return false; } + +bool ull_lp_cc_is_enqueued(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + ctx = llcp_lr_peek_proc(conn, PROC_CIS_CREATE); + + return (ctx != NULL); +} #endif /* defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_CENTRAL_ISO) */ static bool pdu_is_expected(struct pdu_data *pdu, struct proc_ctx *ctx) @@ -1662,13 +1780,13 @@ void ull_cp_tx_ack(struct ll_conn *conn, struct node_tx *tx) struct proc_ctx *ctx; ctx = llcp_lr_peek(conn); - if (ctx && ctx->tx_ack == tx) { + if (ctx && ctx->node_ref.tx_ack == tx) { /* TX ack re. local request */ llcp_lr_tx_ack(conn, ctx, tx); } ctx = llcp_rr_peek(conn); - if (ctx && ctx->tx_ack == tx) { + if (ctx && ctx->node_ref.tx_ack == tx) { /* TX ack re. remote response */ llcp_rr_tx_ack(conn, ctx, tx); } @@ -1691,7 +1809,7 @@ void ull_cp_tx_ntf(struct ll_conn *conn) } } -void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx) +void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx) { struct proc_ctx *ctx_l; struct proc_ctx *ctx_r; @@ -1765,7 +1883,7 @@ void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx) */ /* Process PDU in remote procedure */ - llcp_rr_rx(conn, ctx_r, rx); + llcp_rr_rx(conn, ctx_r, link, rx); } else if (unexpected_r) { /* Local active procedure * Expected local procedure PDU @@ -1774,7 +1892,7 @@ void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx) */ /* Process PDU in local procedure */ - llcp_lr_rx(conn, ctx_l, rx); + llcp_lr_rx(conn, ctx_l, link, rx); } /* no else clause as this cannot occur with the logic above: * if they are not identical then one must be true @@ -1796,7 +1914,7 @@ void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx) /* Process PDU as a new remote request */ LL_ASSERT(pdu_valid); - llcp_rr_new(conn, rx, true); + llcp_rr_new(conn, link, rx, true); } else { /* Local active procedure * Expected local procedure PDU @@ -1804,7 +1922,7 @@ void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx) */ /* Process PDU in local procedure */ - llcp_lr_rx(conn, ctx_l, rx); + llcp_lr_rx(conn, ctx_l, link, rx); } } } else if (ctx_r) { @@ -1813,14 +1931,14 @@ void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx) */ /* Process PDU in remote procedure */ - llcp_rr_rx(conn, ctx_r, rx); + llcp_rr_rx(conn, ctx_r, link, rx); } else { /* No local active procedure * No remote active procedure */ /* Process PDU as a new remote request */ - llcp_rr_new(conn, rx, pdu_valid); + llcp_rr_new(conn, link, rx, pdu_valid); } } diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.h b/subsys/bluetooth/controller/ll_sw/ull_llcp.h index a264e0297f3..ca0ea2c8ed0 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.h @@ -25,6 +25,8 @@ void ull_llcp_init(struct ll_conn *conn); */ void ull_cp_state_set(struct ll_conn *conn, uint8_t state); +void ull_cp_release_nodes(struct ll_conn *conn); + /* * @brief Update 'global' tx buffer allowance */ @@ -35,11 +37,6 @@ void ull_cp_update_tx_buffer_queue(struct ll_conn *conn); */ void ull_cp_release_tx(struct ll_conn *conn, struct node_tx *tx); -/** - * - */ -void ull_cp_release_ntf(struct node_rx_pdu *ntf); - /** * @brief Procedure Response Timeout Check * @param elapsed_event The number of elapsed events. @@ -68,7 +65,7 @@ void ull_cp_tx_ntf(struct ll_conn *conn); /** * @brief Handle received LL Control PDU. */ -void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx); +void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx); #if defined(CONFIG_BT_CTLR_LE_PING) /** @@ -85,7 +82,7 @@ uint8_t ull_cp_version_exchange(struct ll_conn *conn); /** * @brief Initiate a Feature Exchange Procedure. */ -uint8_t ull_cp_feature_exchange(struct ll_conn *conn); +uint8_t ull_cp_feature_exchange(struct ll_conn *conn, uint8_t host_initiated); #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) /** @@ -186,6 +183,12 @@ uint8_t ull_cp_cis_terminate(struct ll_conn *conn, struct ll_conn_iso_stream *ci */ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis); +/** + * @brief Resume CIS create after CIS offset calculation. + */ +void ull_cp_cc_offset_calc_reply(struct ll_conn *conn, uint32_t cis_offset_min, + uint32_t cis_offset_max); + /** * @brief Is ongoing create cis procedure expecting a reply? */ @@ -196,6 +199,11 @@ bool ull_cp_cc_awaiting_reply(struct ll_conn *conn); */ bool ull_cp_cc_awaiting_established(struct ll_conn *conn); +/** + * @brief Cancel ongoing create cis procedure + */ +bool ull_cp_cc_cancel(struct ll_conn *conn); + /** * @brief Get handle of ongoing create cis procedure. * @return 0xFFFF if none @@ -205,7 +213,7 @@ uint16_t ull_cp_cc_ongoing_handle(struct ll_conn *conn); /** * @brief Accept the remote device’s request to create cis. */ -void ull_cp_cc_accept(struct ll_conn *conn); +void ull_cp_cc_accept(struct ll_conn *conn, uint32_t cis_offset_min); /** * @brief Reject the remote device’s request to create cis. @@ -222,6 +230,11 @@ void ull_cp_cc_established(struct ll_conn *conn, uint8_t error_code); */ bool ull_lp_cc_is_active(struct ll_conn *conn); +/** + * @brief CIS creation ongoing or enqueued. + */ +bool ull_lp_cc_is_enqueued(struct ll_conn *conn); + /** * @brief Initiate a Channel Map Update Procedure. */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c index 6421f144ea5..387cc884dea 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ecb.h" #include "hal/ccm.h" @@ -52,31 +53,18 @@ #include #include "hal/debug.h" -static bool cc_check_cis_established_or_timeout_lll(struct proc_ctx *ctx) -{ - const struct ll_conn_iso_stream *cis = - ll_conn_iso_stream_get(ctx->data.cis_create.cis_handle); - - if (cis->established) { - return true; - } - - if (!cis->event_expire) { - ctx->data.cis_create.error = BT_HCI_ERR_CONN_FAIL_TO_ESTAB; - return true; - } - - return false; -} - static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx) { - struct node_rx_pdu *ntf; struct node_rx_conn_iso_estab *pdu; + struct node_rx_pdu *ntf; + uint8_t piggy_back; /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + ntf = ctx->node_ref.rx; LL_ASSERT(ntf); + ctx->node_ref.rx = NULL; + + piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN); ntf->hdr.type = NODE_RX_TYPE_CIS_ESTABLISHED; ntf->hdr.handle = conn->lll.handle; @@ -87,8 +75,10 @@ static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx) pdu->cis_handle = ctx->data.cis_create.cis_handle; pdu->status = ctx->data.cis_create.error; - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); + if (!piggy_back) { + /* Enqueue notification towards LL */ + ll_rx_put_sched(ntf->hdr.link, ntf); + } } #if defined(CONFIG_BT_PERIPHERAL) @@ -97,14 +87,13 @@ enum { /* Establish Procedure */ RP_CC_STATE_IDLE, RP_CC_STATE_WAIT_RX_CIS_REQ, - RP_CC_STATE_WAIT_NTF_CIS_CREATE, RP_CC_STATE_WAIT_REPLY, RP_CC_STATE_WAIT_TX_CIS_RSP, RP_CC_STATE_WAIT_TX_REJECT_IND, RP_CC_STATE_WAIT_RX_CIS_IND, RP_CC_STATE_WAIT_INSTANT, RP_CC_STATE_WAIT_CIS_ESTABLISHED, - RP_CC_STATE_WAIT_NTF, + RP_CC_STATE_WAIT_NTF_AVAIL, }; /* LLCP Remote Procedure FSM events */ @@ -176,14 +165,19 @@ static void llcp_rp_cc_tx_rsp(struct ll_conn *conn, struct proc_ctx *ctx) * start times is an integer multiple of ISO_Interval for the CIS. * * The offset shall compensate for the relation between ISO- and connection interval. The - * offset translates to what is additionally needed to move the window by an integer number - * of ISO intervals. I.e.: - * offset = (delayed * CONN_interval) MOD ISO_interval + * offset translates to what is additionally needed to move the window up to an integer + * number of ISO intervals. */ if (delay_conn_events) { - uint32_t conn_interval_us = conn->lll.interval * CONN_INT_UNIT_US; - uint32_t iso_interval_us = ctx->data.cis_create.iso_interval * ISO_INT_UNIT_US; - uint32_t offset_us = (delay_conn_events * conn_interval_us) % iso_interval_us; + uint32_t conn_interval_us = conn->lll.interval * CONN_INT_UNIT_US; + uint32_t iso_interval_us = ctx->data.cis_create.iso_interval * ISO_INT_UNIT_US; + uint8_t iso_intervals; + uint32_t offset_us; + + iso_intervals = DIV_ROUND_UP(delay_conn_events * conn_interval_us, + iso_interval_us); + offset_us = (iso_intervals * iso_interval_us) - + (delay_conn_events * conn_interval_us); ctx->data.cis_create.cis_offset_min += offset_us; ctx->data.cis_create.cis_offset_max += offset_us; @@ -202,8 +196,9 @@ static void llcp_rp_cc_tx_reject(struct ll_conn *conn, struct proc_ctx *ctx, uin struct pdu_data *pdu; /* Allocate tx node */ - tx = llcp_tx_alloc(conn, ctx); + tx = ctx->node_ref.tx; LL_ASSERT(tx); + ctx->node_ref.tx = NULL; pdu = (struct pdu_data *)tx->pdu; @@ -220,8 +215,8 @@ static void rp_cc_ntf_create(struct ll_conn *conn, struct proc_ctx *ctx) struct node_rx_pdu *ntf; struct node_rx_conn_iso_req *pdu; - /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); ntf->hdr.type = NODE_RX_TYPE_CIS_REQUEST; @@ -233,20 +228,13 @@ static void rp_cc_ntf_create(struct ll_conn *conn, struct proc_ctx *ctx) pdu->cis_handle = ctx->data.cis_create.cis_handle; ctx->data.cis_create.host_request_to = 0U; - - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); } static void rp_cc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_ntf_alloc_is_available()) { - ctx->state = RP_CC_STATE_WAIT_NTF; - } else { - cc_ntf_established(conn, ctx); - llcp_rr_complete(conn); - ctx->state = RP_CC_STATE_IDLE; - } + cc_ntf_established(conn, ctx); + llcp_rr_complete(conn); + ctx->state = RP_CC_STATE_IDLE; } static void rp_cc_send_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, @@ -263,23 +251,28 @@ static void rp_cc_send_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8 } } -static void rp_cc_send_create_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) -{ - if (!llcp_ntf_alloc_is_available()) { - ctx->state = RP_CC_STATE_WAIT_NTF_CIS_CREATE; - } else { - rp_cc_ntf_create(conn, ctx); - ctx->state = RP_CC_STATE_WAIT_REPLY; - } -} - static void rp_cc_send_reject_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = RP_CC_STATE_WAIT_TX_REJECT_IND; } else { + /* Allocate TX node to use, store in case we need to wait for NTF node */ + ctx->node_ref.tx = llcp_tx_alloc(conn, ctx); + if (ctx->data.cis_create.error == BT_HCI_ERR_CONN_ACCEPT_TIMEOUT) { + /* We complete with error, so we must generate NTF, thus we must make sure + * we have a node to use for NTF before TX'ing + */ + if (!llcp_ntf_alloc_is_available()) { + ctx->state = RP_CC_STATE_WAIT_NTF_AVAIL; + return; + } + ctx->node_ref.rx = llcp_ntf_alloc(); + + /* Mark node as RETAIN to trigger put/sched */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; + } + llcp_rp_cc_tx_reject(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ); if (ctx->data.cis_create.error == BT_HCI_ERR_CONN_ACCEPT_TIMEOUT) { @@ -357,7 +350,8 @@ static void rp_cc_state_wait_rx_cis_req(struct ll_conn *conn, struct proc_ctx *c if (ctx->data.cis_create.error == BT_HCI_ERR_SUCCESS) { /* Now controller accepts, so go ask the host to accept or decline */ - rp_cc_send_create_ntf(conn, ctx, evt, param); + rp_cc_ntf_create(conn, ctx); + ctx->state = RP_CC_STATE_WAIT_REPLY; } else { /* Now controller rejects, right out */ rp_cc_send_reject_ind(conn, ctx, evt, param); @@ -410,6 +404,9 @@ static void rp_cc_state_wait_rx_cis_ind(struct ll_conn *conn, struct proc_ctx *c /* CIS has been setup, go wait for 'instant' before starting */ ctx->state = RP_CC_STATE_WAIT_INSTANT; + /* Mark node as RETAIN to keep until we need for NTF */ + llcp_rx_node_retain(ctx); + /* Check if this connection event is where we need to start the CIS */ rp_cc_check_instant(conn, ctx, evt, param); break; @@ -427,25 +424,20 @@ static void rp_cc_state_wait_rx_cis_ind(struct ll_conn *conn, struct proc_ctx *c } } -static void rp_cc_state_wait_ntf_cis_create(struct ll_conn *conn, struct proc_ctx *ctx, - uint8_t evt, void *param) -{ - switch (evt) { - case RP_CC_EVT_RUN: - rp_cc_send_create_ntf(conn, ctx, evt, param); - break; - default: - /* Ignore other evts */ - break; - } -} - -static void rp_cc_state_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, +static void rp_cc_state_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (evt) { case RP_CC_EVT_RUN: - rp_cc_complete(conn, ctx, evt, param); + if (llcp_ntf_alloc_is_available()) { + ctx->node_ref.rx = llcp_ntf_alloc(); + /* Mark node as RETAIN to trigger put/sched */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; + + /* Now we're good to TX reject and complete procedure*/ + llcp_rp_cc_tx_reject(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ); + rp_cc_complete(conn, ctx, evt, param); + } break; default: /* Ignore other evts */ @@ -453,6 +445,7 @@ static void rp_cc_state_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uin } } + static void rp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -466,8 +459,9 @@ static void rp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint uint16_t instant_latency = (event_counter - start_event_count) & 0xffff; /* Start CIS */ - ull_conn_iso_start(conn, conn->llcp.prep.ticks_at_expire, - ctx->data.cis_create.cis_handle, + ull_conn_iso_start(conn, ctx->data.cis_create.cis_handle, + conn->llcp.prep.ticks_at_expire, + conn->llcp.prep.remainder, instant_latency); /* Now we can wait for CIS to become established */ @@ -524,18 +518,7 @@ static void rp_cc_state_wait_cis_established(struct ll_conn *conn, struct proc_c uint8_t evt, void *param) { switch (evt) { - case RP_CC_EVT_RUN: - /* Check for CIS state */ - if (cc_check_cis_established_or_timeout_lll(ctx)) { - /* CIS was established or establishement timed out, - * In either case complete procedure and generate - * notification - */ - rp_cc_complete(conn, ctx, evt, param); - } - break; case RP_CC_EVT_CIS_ESTABLISHED: - /* CIS was established, so let's go ahead and complete procedure */ rp_cc_complete(conn, ctx, evt, param); break; default: @@ -555,9 +538,6 @@ static void rp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ case RP_CC_STATE_WAIT_RX_CIS_REQ: rp_cc_state_wait_rx_cis_req(conn, ctx, evt, param); break; - case RP_CC_STATE_WAIT_NTF_CIS_CREATE: - rp_cc_state_wait_ntf_cis_create(conn, ctx, evt, param); - break; case RP_CC_STATE_WAIT_TX_REJECT_IND: rp_cc_state_wait_tx_reject_ind(conn, ctx, evt, param); break; @@ -576,8 +556,8 @@ static void rp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ case RP_CC_STATE_WAIT_CIS_ESTABLISHED: rp_cc_state_wait_cis_established(conn, ctx, evt, param); break; - case RP_CC_STATE_WAIT_NTF: - rp_cc_state_wait_ntf(conn, ctx, evt, param); + case RP_CC_STATE_WAIT_NTF_AVAIL: + rp_cc_state_wait_ntf_avail(conn, ctx, evt, param); break; default: /* Unknown state */ @@ -663,12 +643,15 @@ static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ /* LLCP Local Procedure FSM states */ enum { LP_CC_STATE_IDLE, + LP_CC_STATE_WAIT_OFFSET_CALC, + LP_CC_STATE_WAIT_OFFSET_CALC_TX_REQ, LP_CC_STATE_WAIT_TX_CIS_REQ, LP_CC_STATE_WAIT_RX_CIS_RSP, + LP_CC_STATE_WAIT_NOTIFY_CANCEL, + LP_CC_STATE_WAIT_RX_CIS_RSP_CANCEL, LP_CC_STATE_WAIT_TX_CIS_IND, LP_CC_STATE_WAIT_INSTANT, LP_CC_STATE_WAIT_ESTABLISHED, - LP_CC_STATE_WAIT_NTF, }; /* LLCP Local Procedure CIS Creation FSM events */ @@ -676,6 +659,9 @@ enum { /* Procedure run */ LP_CC_EVT_RUN, + /* Offset calculation reply received */ + LP_CC_EVT_OFFSET_CALC_REPLY, + /* Response received */ LP_CC_EVT_CIS_RSP, @@ -742,16 +728,76 @@ void llcp_lp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd } } +void llcp_lp_cc_offset_calc_reply(struct ll_conn *conn, struct proc_ctx *ctx) +{ + lp_cc_execute_fsm(conn, ctx, LP_CC_EVT_OFFSET_CALC_REPLY, NULL); +} + +static void lp_cc_offset_calc_req(struct ll_conn *conn, struct proc_ctx *ctx, + uint8_t evt, void *param) +{ + if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { + ctx->state = LP_CC_STATE_WAIT_OFFSET_CALC_TX_REQ; + } else { + int err; + + /* Update conn_event_count */ + err = ull_central_iso_cis_offset_get(ctx->data.cis_create.cis_handle, + &ctx->data.cis_create.cis_offset_min, + &ctx->data.cis_create.cis_offset_max, + &ctx->data.cis_create.conn_event_count); + if (err) { + ctx->state = LP_CC_STATE_WAIT_OFFSET_CALC; + + return; + } + + lp_cc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ); + + ctx->state = LP_CC_STATE_WAIT_RX_CIS_RSP; + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_CIS_RSP; + } +} + +static void lp_cc_st_wait_offset_calc_tx_req(struct ll_conn *conn, + struct proc_ctx *ctx, + uint8_t evt, void *param) +{ + switch (evt) { + case LP_CC_EVT_RUN: + lp_cc_offset_calc_req(conn, ctx, evt, param); + break; + default: + /* Ignore other evts */ + break; + } +} + +static void lp_cc_st_wait_offset_calc(struct ll_conn *conn, + struct proc_ctx *ctx, + uint8_t evt, void *param) +{ + switch (evt) { + case LP_CC_EVT_RUN: + /* TODO: May be have a timeout calculating the CIS offset? + * otherwise, ignore + */ + break; + case LP_CC_EVT_OFFSET_CALC_REPLY: + ctx->state = LP_CC_STATE_WAIT_TX_CIS_REQ; + break; + default: + /* Ignore other evts */ + break; + } +} + static void lp_cc_send_cis_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_CC_STATE_WAIT_TX_CIS_REQ; } else { - /* Update conn_event_count */ - ctx->data.cis_create.conn_event_count = - ull_central_iso_cis_offset_get(ctx->data.cis_create.cis_handle, NULL, NULL); - lp_cc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ); ctx->state = LP_CC_STATE_WAIT_RX_CIS_RSP; @@ -772,13 +818,29 @@ static void lp_cc_st_wait_tx_cis_req(struct ll_conn *conn, struct proc_ctx *ctx, } } +static void lp_cc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) +{ + cc_ntf_established(conn, ctx); + llcp_lr_complete(conn); + ctx->state = LP_CC_STATE_IDLE; +} + static void lp_cc_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (evt) { case LP_CC_EVT_RUN: switch (ctx->proc) { case PROC_CIS_CREATE: - lp_cc_send_cis_req(conn, ctx, evt, param); + /* In case feature exchange completed after CIS create was enqueued + * peer CIS peripheral support should be confirmed + */ + if (feature_peer_iso_peripheral(conn)) { + lp_cc_offset_calc_req(conn, ctx, evt, param); + } else { + /* Peer doesn't support CIS Peripheral so report unsupported */ + ctx->data.cis_create.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; + lp_cc_complete(conn, ctx, evt, param); + } break; default: /* Unknown procedure */ @@ -821,17 +883,6 @@ static void lp_cc_send_cis_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8 } } -static void lp_cc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) -{ - if (!llcp_ntf_alloc_is_available()) { - ctx->state = LP_CC_STATE_WAIT_NTF; - } else { - cc_ntf_established(conn, ctx); - llcp_lr_complete(conn); - ctx->state = LP_CC_STATE_IDLE; - } -} - static void lp_cc_st_wait_rx_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -841,6 +892,10 @@ static void lp_cc_st_wait_rx_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, case LP_CC_EVT_CIS_RSP: /* TODO: Reject response if outside offset range? */ llcp_pdu_decode_cis_rsp(ctx, param); + + /* Mark RX node to NOT release */ + llcp_rx_node_retain(ctx); + lp_cc_send_cis_ind(conn, ctx, evt, param); break; case LP_CC_EVT_UNKNOWN: @@ -863,6 +918,59 @@ static void lp_cc_st_wait_rx_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, } } +static void lp_cc_st_wait_notify_cancel(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + switch (evt) { + case LP_CC_EVT_RUN: + if (llcp_ntf_alloc_is_available()) { + ctx->node_ref.rx = llcp_ntf_alloc(); + + /* Mark node as RETAIN to trigger put/sched */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; + ctx->state = LP_CC_STATE_WAIT_ESTABLISHED; + + llcp_lp_cc_established(conn, ctx); + } + break; + default: + /* Ignore other evts */ + break; + } +} + +static void lp_cc_st_wait_rx_cis_rsp_cancel(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + struct pdu_data *pdu; + struct node_tx *tx; + + switch (evt) { + case LP_CC_EVT_CIS_RSP: + /* Allocate tx node */ + tx = llcp_tx_alloc(conn, ctx); + LL_ASSERT(tx); + + pdu = (struct pdu_data *)tx->pdu; + + /* Encode LL Control PDU */ + llcp_pdu_encode_reject_ext_ind(pdu, PDU_DATA_LLCTRL_TYPE_CIS_RSP, + ctx->data.cis_create.error); + + /* Enqueue LL Control PDU towards LLL */ + llcp_tx_enqueue(conn, tx); + lp_cc_complete(conn, ctx, evt, param); + break; + case LP_CC_EVT_UNKNOWN: + case LP_CC_EVT_REJECT: + lp_cc_complete(conn, ctx, evt, param); + break; + default: + /* Ignore other evts */ + break; + } +} + static void lp_cc_st_wait_tx_cis_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -889,8 +997,9 @@ static void lp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint instant_latency = (event_counter - start_event_count) & 0xffff; if (instant_latency <= 0x7fff) { /* Start CIS */ - ull_conn_iso_start(conn, conn->llcp.prep.ticks_at_expire, - ctx->data.cis_create.cis_handle, + ull_conn_iso_start(conn, ctx->data.cis_create.cis_handle, + conn->llcp.prep.ticks_at_expire, + conn->llcp.prep.remainder, instant_latency); /* Now we can wait for CIS to become established */ @@ -915,12 +1024,6 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx void *param) { switch (evt) { - case LP_CC_EVT_RUN: - if (cc_check_cis_established_or_timeout_lll(ctx)) { - /* CIS was established, so let's got ahead and complete procedure */ - lp_cc_complete(conn, ctx, evt, param); - } - break; case LP_CC_EVT_ESTABLISHED: /* CIS was established, so let's go ahead and complete procedure */ lp_cc_complete(conn, ctx, evt, param); @@ -931,30 +1034,30 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx } } -static void lp_cc_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) -{ - switch (evt) { - case LP_CC_EVT_RUN: - lp_cc_complete(conn, ctx, evt, param); - break; - default: - /* Ignore other evts */ - break; - } -} - static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (ctx->state) { case LP_CC_STATE_IDLE: lp_cc_st_idle(conn, ctx, evt, param); break; + case LP_CC_STATE_WAIT_OFFSET_CALC_TX_REQ: + lp_cc_st_wait_offset_calc_tx_req(conn, ctx, evt, param); + break; + case LP_CC_STATE_WAIT_OFFSET_CALC: + lp_cc_st_wait_offset_calc(conn, ctx, evt, param); + break; case LP_CC_STATE_WAIT_TX_CIS_REQ: lp_cc_st_wait_tx_cis_req(conn, ctx, evt, param); break; case LP_CC_STATE_WAIT_RX_CIS_RSP: lp_cc_st_wait_rx_cis_rsp(conn, ctx, evt, param); break; + case LP_CC_STATE_WAIT_NOTIFY_CANCEL: + lp_cc_st_wait_notify_cancel(conn, ctx, evt, param); + break; + case LP_CC_STATE_WAIT_RX_CIS_RSP_CANCEL: + lp_cc_st_wait_rx_cis_rsp_cancel(conn, ctx, evt, param); + break; case LP_CC_STATE_WAIT_TX_CIS_IND: lp_cc_st_wait_tx_cis_ind(conn, ctx, evt, param); break; @@ -964,9 +1067,6 @@ static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ case LP_CC_STATE_WAIT_ESTABLISHED: lp_cc_st_wait_established(conn, ctx, evt, param); break; - case LP_CC_STATE_WAIT_NTF: - lp_cc_st_wait_ntf(conn, ctx, evt, param); - break; default: /* Unknown state */ LL_ASSERT(0); @@ -993,4 +1093,25 @@ void llcp_lp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx) { lp_cc_execute_fsm(conn, ctx, LP_CC_EVT_ESTABLISHED, NULL); } + +bool llcp_lp_cc_cancel(struct ll_conn *conn, struct proc_ctx *ctx) +{ + ctx->data.cis_create.error = BT_HCI_ERR_OP_CANCELLED_BY_HOST; + + switch (ctx->state) { + case LP_CC_STATE_IDLE: + case LP_CC_STATE_WAIT_OFFSET_CALC: + case LP_CC_STATE_WAIT_OFFSET_CALC_TX_REQ: + case LP_CC_STATE_WAIT_TX_CIS_REQ: + ctx->state = LP_CC_STATE_WAIT_NOTIFY_CANCEL; + return true; + case LP_CC_STATE_WAIT_RX_CIS_RSP: + ctx->state = LP_CC_STATE_WAIT_RX_CIS_RSP_CANCEL; + return true; + default: + break; + } + + return false; +} #endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c index d52da932529..d1de4e87edb 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index 4bb887e8053..b4cfb881f3f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" @@ -57,7 +58,7 @@ enum { LP_COMMON_STATE_WAIT_TX, LP_COMMON_STATE_WAIT_TX_ACK, LP_COMMON_STATE_WAIT_RX, - LP_COMMON_STATE_WAIT_NTF, + LP_COMMON_STATE_WAIT_NTF_AVAIL, }; /* LLCP Local Procedure Common FSM events */ @@ -88,7 +89,6 @@ enum { RP_COMMON_STATE_POSTPONE_TERMINATE, RP_COMMON_STATE_WAIT_TX, RP_COMMON_STATE_WAIT_TX_ACK, - RP_COMMON_STATE_WAIT_NTF, }; /* LLCP Remote Procedure Common FSM events */ enum { @@ -166,7 +166,7 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) case PROC_MIN_USED_CHANS: llcp_pdu_encode_min_used_chans_ind(ctx, pdu); - ctx->tx_ack = tx; + ctx->node_ref.tx_ack = tx; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; break; #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ @@ -176,13 +176,13 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) break; case PROC_TERMINATE: llcp_pdu_encode_terminate_ind(ctx, pdu); - ctx->tx_ack = tx; + ctx->node_ref.tx_ack = tx; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; break; #if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) case PROC_CIS_TERMINATE: llcp_pdu_encode_cis_terminate_ind(ctx, pdu); - ctx->tx_ack = tx; + ctx->node_ref.tx_ack = tx; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; break; #endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */ @@ -299,13 +299,9 @@ static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, stru static void lp_comm_ntf_cte_req_tx(struct ll_conn *conn, struct proc_ctx *ctx) { - if (llcp_ntf_alloc_is_available()) { - lp_comm_ntf(conn, ctx); - ull_cp_cte_req_set_disable(conn); - ctx->state = LP_COMMON_STATE_IDLE; - } else { - ctx->state = LP_COMMON_STATE_WAIT_NTF; - } + lp_comm_ntf(conn, ctx); + ull_cp_cte_req_set_disable(conn); + ctx->state = LP_COMMON_STATE_IDLE; } static void lp_comm_complete_cte_req(struct ll_conn *conn, struct proc_ctx *ctx) @@ -376,12 +372,18 @@ static void lp_comm_ntf_sca(struct node_rx_pdu *ntf, struct proc_ctx *ctx, struc static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx) { + uint8_t piggy_back = 1U; struct node_rx_pdu *ntf; struct pdu_data *pdu; - /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); - LL_ASSERT(ntf); + ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; + if (!ntf) { + /* Allocate ntf node */ + ntf = llcp_ntf_alloc(); + LL_ASSERT(ntf); + piggy_back = 0U; + } ntf->hdr.type = NODE_RX_TYPE_DC_PDU; ntf->hdr.handle = conn->lll.handle; @@ -414,8 +416,14 @@ static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx) break; } - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); + if (!piggy_back) { + /* Enqueue notification towards LL, unless we re-use RX node, + * in which case it is handled on the ull_cp_rx return path + */ + ll_rx_put_sched(ntf->hdr.link, ntf); + } + + } static void lp_comm_terminate_invalid_pdu(struct ll_conn *conn, struct proc_ctx *ctx) @@ -427,23 +435,6 @@ static void lp_comm_terminate_invalid_pdu(struct ll_conn *conn, struct proc_ctx ctx->state = LP_COMMON_STATE_IDLE; } -static void lp_comm_ntf_complete_proxy(struct ll_conn *conn, struct proc_ctx *ctx, - const bool valid_pdu) -{ - if (valid_pdu) { - if (!llcp_ntf_alloc_is_available()) { - ctx->state = LP_COMMON_STATE_WAIT_NTF; - } else { - lp_comm_ntf(conn, ctx); - llcp_lr_complete(conn); - ctx->state = LP_COMMON_STATE_IDLE; - } - } else { - /* Illegal response opcode */ - lp_comm_terminate_invalid_pdu(conn, ctx); - } -} - static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (ctx->proc) { @@ -460,9 +451,17 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t break; #endif /* CONFIG_BT_CTLR_LE_PING */ case PROC_FEATURE_EXCHANGE: - lp_comm_ntf_complete_proxy(conn, ctx, - (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP || - ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_FEATURE_RSP)); + if ((ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP || + ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_FEATURE_RSP)) { + if (ctx->data.fex.host_initiated) { + lp_comm_ntf(conn, ctx); + } + llcp_lr_complete(conn); + ctx->state = LP_COMMON_STATE_IDLE; + } else { + /* Illegal response opcode */ + lp_comm_terminate_invalid_pdu(conn, ctx); + } break; #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) case PROC_MIN_USED_CHANS: @@ -471,8 +470,25 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t break; #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ case PROC_VERSION_EXCHANGE: - lp_comm_ntf_complete_proxy(conn, ctx, - (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_VERSION_IND)); + if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_VERSION_IND) { + if (ctx->node_ref.rx || llcp_ntf_alloc_is_available()) { + /* Either this is a piggy-back or there is a NTF node avail */ + lp_comm_ntf(conn, ctx); + llcp_lr_complete(conn); + ctx->state = LP_COMMON_STATE_IDLE; + } else { + /* Handle procedure TO, in case we end up waiting 'forever' for + * NTF buffer. This is a simple way to implement mechanism to + * trigger disconnect in case NTF buffer 'never' becomes avail + * see elaborate note in lp_comm_st_wait_ntf_avail() + */ + llcp_lr_prt_restart(conn); + ctx->state = LP_COMMON_STATE_WAIT_NTF_AVAIL; + } + } else { + /* Illegal response opcode */ + lp_comm_terminate_invalid_pdu(conn, ctx); + } break; case PROC_TERMINATE: /* No notification */ @@ -495,16 +511,11 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t /* Apply changes in data lengths/times */ uint8_t dle_changed = ull_dle_update_eff(conn); - if (dle_changed && !llcp_ntf_alloc_is_available()) { - /* We need to generate NTF but no buffers avail so wait for one */ - ctx->state = LP_COMMON_STATE_WAIT_NTF; - } else { - if (dle_changed) { - lp_comm_ntf(conn, ctx); - } - llcp_lr_complete(conn); - ctx->state = LP_COMMON_STATE_IDLE; + if (dle_changed) { + lp_comm_ntf(conn, ctx); } + llcp_lr_complete(conn); + ctx->state = LP_COMMON_STATE_IDLE; } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP) { /* Peer does not accept DLU, so disable on current connection */ feature_unmask_features(conn, LL_FEAT_BIT_DLE); @@ -550,13 +561,9 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t #endif /* defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */ } #endif /* CONFIG_BT_PERIPHERAL */ - if (!llcp_ntf_alloc_is_available()) { - ctx->state = LP_COMMON_STATE_WAIT_NTF; - } else { - lp_comm_ntf(conn, ctx); - llcp_lr_complete(conn); - ctx->state = LP_COMMON_STATE_IDLE; - } + lp_comm_ntf(conn, ctx); + llcp_lr_complete(conn); + ctx->state = LP_COMMON_STATE_IDLE; break; default: /* Illegal response opcode */ @@ -585,7 +592,8 @@ static bool lp_comm_tx_proxy(struct ll_conn *conn, struct proc_ctx *ctx, const b lp_comm_tx(conn, ctx); /* Select correct state, depending on TX ack handling 'request' */ - ctx->state = ctx->tx_ack ? LP_COMMON_STATE_WAIT_TX_ACK : LP_COMMON_STATE_WAIT_RX; + ctx->state = ctx->node_ref.tx_ack ? + LP_COMMON_STATE_WAIT_TX_ACK : LP_COMMON_STATE_WAIT_RX; return true; } return false; @@ -617,6 +625,8 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t } } else { ctx->response_opcode = PDU_DATA_LLCTRL_TYPE_VERSION_IND; + /* Clear node_ref to signal no NTF piggy-backing */ + ctx->node_ref.rx = NULL; lp_comm_complete(conn, ctx, evt, param); } break; @@ -667,7 +677,7 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t 1) { #endif /* CONFIG_BT_CTLR_PHY */ lp_comm_tx_proxy(conn, ctx, - (llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ)); + llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ); } else { /* The PHY was changed to CODED when the request was waiting in a local * request queue. @@ -706,14 +716,10 @@ static void lp_comm_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t /* Clear terminate ack flag, used to signal CIS Terminated */ conn->llcp.cis.terminate_ack = 0U; llcp_cis_stop_by_id(ctx->data.cis_term.cig_id, ctx->data.cis_term.cis_id, - ctx->data.cis_term.error_code); + BT_HCI_ERR_LOCALHOST_TERM_CONN); } #endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */ - if (llcp_lr_ispaused(conn)) { - ctx->state = LP_COMMON_STATE_WAIT_TX; - } else { - lp_comm_send_req(conn, ctx, evt, param); - } + lp_comm_send_req(conn, ctx, evt, param); break; default: /* Ignore other evts */ @@ -742,17 +748,14 @@ static void lp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u switch (ctx->proc) { #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) case PROC_MIN_USED_CHANS: - ctx->tx_ack = NULL; lp_comm_complete(conn, ctx, evt, param); break; #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ case PROC_TERMINATE: - ctx->tx_ack = NULL; lp_comm_complete(conn, ctx, evt, param); break; #if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) case PROC_CIS_TERMINATE: - ctx->tx_ack = NULL; lp_comm_complete(conn, ctx, evt, param); break; #endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */ @@ -843,36 +846,34 @@ static void lp_comm_st_wait_rx(struct ll_conn *conn, struct proc_ctx *ctx, uint8 } } -static void lp_comm_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, +static void lp_comm_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (evt) { case LP_COMMON_EVT_RUN: switch (ctx->proc) { - case PROC_FEATURE_EXCHANGE: case PROC_VERSION_EXCHANGE: -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - case PROC_DATA_LENGTH_UPDATE: -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_SCA_UPDATE) - case PROC_SCA_UPDATE: -#endif /* CONFIG_BT_CTLR_SCA_UPDATE) */ + /* Note re. procedure timeout handling: + * Procedure TO is specifically NOT reset while in wait state, since + * the mechanism is being 'hi-jacked' to implement a TO on the NTF wait + * This to catch the very unlikely case: + * local VERSION IND started after a VERSION IND had already been TX'ed + * in which case the local procedure should complete with NTF without + * prior TX (ie no procedure TO handling initiated). IF this NTF never + * finds buffer avail it would wait forever, but not with proc TO active + */ if (llcp_ntf_alloc_is_available()) { lp_comm_ntf(conn, ctx); llcp_lr_complete(conn); ctx->state = LP_COMMON_STATE_IDLE; } break; -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) - case PROC_CTE_REQ: - if (llcp_ntf_alloc_is_available()) { - lp_comm_ntf(conn, ctx); - ctx->state = LP_COMMON_STATE_IDLE; - lp_comm_complete_cte_req_finalize(conn); - } - break; -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ default: + /* If we get here it is not good since only VERSION EXCHANGE procedure + * out of the ones handled in ull_llcp_common should end up waiting for + * non-piggy-back'ed NTF + */ + LL_ASSERT(0); break; } break; @@ -897,8 +898,8 @@ static void lp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint case LP_COMMON_STATE_WAIT_RX: lp_comm_st_wait_rx(conn, ctx, evt, param); break; - case LP_COMMON_STATE_WAIT_NTF: - lp_comm_st_wait_ntf(conn, ctx, evt, param); + case LP_COMMON_STATE_WAIT_NTF_AVAIL: + lp_comm_st_wait_ntf_avail(conn, ctx, evt, param); break; default: /* Unknown state */ @@ -1005,6 +1006,9 @@ static void rp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct */ llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_DATA_LENGTH); ctx->data.dle.ntf_dle = ull_dle_update_eff_rx(conn); + + /* Mark RX pdu to be removed from RX queue, but NOT be released */ + llcp_rx_node_retain(ctx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) @@ -1053,7 +1057,7 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) #if defined(CONFIG_BT_CTLR_DATA_LENGTH) case PROC_DATA_LENGTH_UPDATE: llcp_pdu_encode_length_rsp(conn, pdu); - ctx->tx_ack = tx; + ctx->node_ref.tx_ack = tx; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ @@ -1086,7 +1090,7 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; } - ctx->tx_ack = tx; + ctx->node_ref.tx_ack = tx; break; } @@ -1094,7 +1098,7 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) #if defined(CONFIG_BT_CTLR_SCA_UPDATE) case PROC_SCA_UPDATE: llcp_pdu_encode_clock_accuracy_rsp(ctx, pdu); - ctx->tx_ack = tx; + ctx->node_ref.tx_ack = tx; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; break; #endif /* CONFIG_BT_CTLR_SCA_UPDATE */ @@ -1124,40 +1128,30 @@ static void rp_comm_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t } } #if defined(CONFIG_BT_CTLR_DATA_LENGTH) -static void rp_comm_ntf_length_change(struct ll_conn *conn, struct proc_ctx *ctx, - struct pdu_data *pdu) -{ - llcp_ntf_encode_length_change(conn, pdu); -} - -static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx) +static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t generate_ntf) { struct node_rx_pdu *ntf; struct pdu_data *pdu; - ARG_UNUSED(pdu); /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + ntf = ctx->node_ref.rx; LL_ASSERT(ntf); - ntf->hdr.type = NODE_RX_TYPE_DC_PDU; - ntf->hdr.handle = conn->lll.handle; - pdu = (struct pdu_data *)ntf->pdu; - switch (ctx->proc) { -/* Note: the 'double' ifdef in case this switch case expands - * in the future and the function is re-instated - */ -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - case PROC_DATA_LENGTH_UPDATE: - rp_comm_ntf_length_change(conn, ctx, pdu); - break; -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ - default: - LL_ASSERT(0); - break; + /* This should be an 'old' RX node, so put/sched when done */ + LL_ASSERT(ntf->hdr.type == NODE_RX_TYPE_RETAIN); + + /* And release memory if no NTF to be generated */ + ntf->hdr.type = NODE_RX_TYPE_RELEASE; + + if (generate_ntf) { + ntf->hdr.type = NODE_RX_TYPE_DC_PDU; + ntf->hdr.handle = conn->lll.handle; + pdu = (struct pdu_data *)ntf->pdu; + LL_ASSERT(ctx->proc == PROC_DATA_LENGTH_UPDATE); + llcp_ntf_encode_length_change(conn, pdu); } - /* Enqueue notification towards LL */ + /* Enqueue notification towards LL - releases mem if no ntf */ ll_rx_put_sched(ntf->hdr.link, ntf); } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ @@ -1266,7 +1260,8 @@ static void rp_comm_send_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: - if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx) || + if (llcp_rr_ispaused(conn) || + !llcp_tx_alloc_peek(conn, ctx) || (llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ)) { ctx->state = RP_COMMON_STATE_WAIT_TX; } else { @@ -1347,22 +1342,15 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u dle_changed |= ctx->data.dle.ntf_dle; llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_DATA_LENGTH); - if (dle_changed && !llcp_ntf_alloc_is_available()) { - ctx->state = RP_COMMON_STATE_WAIT_NTF; - } else { - if (dle_changed) { - rp_comm_ntf(conn, ctx); - } - llcp_rr_complete(conn); - ctx->state = RP_COMMON_STATE_IDLE; - } + rp_comm_ntf(conn, ctx, dle_changed); + llcp_rr_complete(conn); + ctx->state = RP_COMMON_STATE_IDLE; break; } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: { /* add PHY update pause = false here */ - ctx->tx_ack = NULL; llcp_rr_set_paused_cmd(conn, PROC_NONE); llcp_rr_complete(conn); ctx->state = RP_COMMON_STATE_IDLE; @@ -1370,7 +1358,6 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ #if defined(CONFIG_BT_CTLR_SCA_UPDATE) case PROC_SCA_UPDATE: { - ctx->tx_ack = NULL; #if defined(CONFIG_BT_PERIPHERAL) if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) { conn->periph.sca = ctx->data.sca_update.sca; @@ -1395,18 +1382,6 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u } } -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) -static void rp_comm_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) -{ - if (llcp_ntf_alloc_is_available()) { - rp_comm_ntf(conn, ctx); - llcp_rr_complete(conn); - ctx->state = RP_COMMON_STATE_IDLE; - } -} -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ - static void rp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -1426,11 +1401,6 @@ static void rp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint case RP_COMMON_STATE_WAIT_TX_ACK: rp_comm_st_wait_tx_ack(conn, ctx, evt, param); break; -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - case RP_COMMON_STATE_WAIT_NTF: - rp_comm_st_wait_ntf(conn, ctx, evt, param); - break; -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ default: /* Unknown state */ LL_ASSERT(0); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c index a3d037e0537..e922901f67d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" @@ -85,7 +86,7 @@ enum { LP_CU_STATE_WAIT_RX_CONN_UPDATE_IND, LP_CU_STATE_WAIT_TX_REJECT_EXT_IND, LP_CU_STATE_WAIT_INSTANT, - LP_CU_STATE_WAIT_NTF, + LP_CU_STATE_WAIT_NTF_AVAIL, }; /* LLCP Local Procedure Connection Update FSM events */ @@ -120,7 +121,7 @@ enum { RP_CU_STATE_WAIT_TX_CONN_UPDATE_IND, RP_CU_STATE_WAIT_RX_CONN_UPDATE_IND, RP_CU_STATE_WAIT_INSTANT, - RP_CU_STATE_WAIT_NTF, + RP_CU_STATE_WAIT_NTF_AVAIL, RP_CU_STATE_WAIT_TX_UNKNOWN_RSP }; @@ -238,11 +239,15 @@ static void cu_ntf(struct ll_conn *conn, struct proc_ctx *ctx) { struct node_rx_pdu *ntf; struct node_rx_cu *pdu; + uint8_t piggy_back; /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); + piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN); + ntf->hdr.type = NODE_RX_TYPE_CONN_UPDATE; ntf->hdr.handle = conn->lll.handle; pdu = (struct node_rx_cu *)ntf->pdu; @@ -258,8 +263,12 @@ static void cu_ntf(struct ll_conn *conn, struct proc_ctx *ctx) pdu->timeout = conn->supervision_timeout; } - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); + if (!piggy_back) { + /* Enqueue notification towards LL, unless piggy-backing, + * in which case this is done on the rx return path + */ + ll_rx_put_sched(ntf->hdr.link, ntf); + } } #if defined(CONFIG_BT_CENTRAL) || defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) @@ -268,9 +277,15 @@ static void lp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode) struct node_tx *tx; struct pdu_data *pdu; - /* Allocate tx node */ - tx = llcp_tx_alloc(conn, ctx); - LL_ASSERT(tx); + /* Get pre-allocated tx node */ + tx = ctx->node_ref.tx; + ctx->node_ref.tx = NULL; + + if (!tx) { + /* Allocate tx node if non pre-alloc'ed */ + tx = llcp_tx_alloc(conn, ctx); + LL_ASSERT(tx); + } pdu = (struct pdu_data *)tx->pdu; @@ -323,15 +338,11 @@ static void lp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx) ctx->state = LP_CU_STATE_IDLE; } -static void lp_cu_wait_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, +static void lp_cu_ntf_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_ntf_alloc_is_available()) { - ctx->state = LP_CU_STATE_WAIT_NTF; - } else { - cu_ntf(conn, ctx); - lp_cu_complete(conn, ctx); - } + cu_ntf(conn, ctx); + lp_cu_complete(conn, ctx); } #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) @@ -389,16 +400,54 @@ static void lp_cu_send_conn_param_req(struct ll_conn *conn, struct proc_ctx *ctx #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #if defined(CONFIG_BT_CENTRAL) +static void lp_cu_send_conn_update_ind_finalize(struct ll_conn *conn, struct proc_ctx *ctx, + uint8_t evt, void *param) +{ + if (ctx->node_ref.rx == NULL) { + /* If we get here without RX node we know one is avail to be allocated, + * so pre-alloc NTF node + */ + ctx->node_ref.rx = llcp_ntf_alloc(); + } + + /* Signal put/sched on NTF - ie non-RX node piggy */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; + + cu_prepare_update_ind(conn, ctx); + lp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND); + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; + ctx->state = LP_CU_STATE_WAIT_INSTANT; +} + static void lp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND; } else { - cu_prepare_update_ind(conn, ctx); - lp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND); - ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; - ctx->state = LP_CU_STATE_WAIT_INSTANT; + /* ensure alloc of TX node, before possibly waiting for NTF node */ + ctx->node_ref.tx = llcp_tx_alloc(conn, ctx); + if (ctx->node_ref.rx == NULL && !llcp_ntf_alloc_is_available()) { + /* No RX node piggy, and no NTF avail, so go wait for one, before TX'ing */ + ctx->state = LP_CU_STATE_WAIT_NTF_AVAIL; + } else { + lp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param); + } + } +} + +static void lp_cu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + switch (evt) { + case LP_CU_EVT_RUN: + if (llcp_ntf_alloc_is_available()) { + lp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param); + } + break; + default: + /* Ignore other evts */ + break; } } #endif /* CONFIG_BT_CENTRAL */ @@ -415,6 +464,8 @@ static void lp_cu_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t ev #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #if defined(CONFIG_BT_CENTRAL) case PROC_CONN_UPDATE: + /* Ensure the non-piggy-back'ing is signaled */ + ctx->node_ref.rx = NULL; lp_cu_send_conn_update_ind(conn, ctx, evt, param); break; #endif /* CONFIG_BT_CENTRAL */ @@ -477,12 +528,16 @@ static void lp_cu_st_wait_rx_conn_param_rsp(struct ll_conn *conn, struct proc_ct lp_cu_send_reject_ext_ind(conn, ctx, evt, param); break; } + /* Keep RX node to use for NTF */ + llcp_rx_node_retain(ctx); lp_cu_send_conn_update_ind(conn, ctx, evt, param); break; case LP_CU_EVT_UNKNOWN: llcp_rr_set_incompat(conn, INCOMPAT_RESERVED); /* Unsupported in peer, so disable locally for this connection */ feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ); + /* Keep RX node to use for NTF */ + llcp_rx_node_retain(ctx); lp_cu_send_conn_update_ind(conn, ctx, evt, param); break; case LP_CU_EVT_REJECT: @@ -491,11 +546,13 @@ static void lp_cu_st_wait_rx_conn_param_rsp(struct ll_conn *conn, struct proc_ct llcp_rr_set_incompat(conn, INCOMPAT_RESERVED); /* Unsupported in peer, so disable locally for this connection */ feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ); + /* Keep RX node to use for NTF */ + llcp_rx_node_retain(ctx); lp_cu_send_conn_update_ind(conn, ctx, evt, param); } else { llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code; - lp_cu_wait_complete(conn, ctx, evt, param); + lp_cu_ntf_complete(conn, ctx, evt, param); } break; default: @@ -528,17 +585,19 @@ static void lp_cu_st_wait_rx_conn_update_ind(struct ll_conn *conn, struct proc_c switch (evt) { case LP_CU_EVT_CONN_UPDATE_IND: llcp_pdu_decode_conn_update_ind(ctx, param); + /* Keep RX node to use for NTF */ + llcp_rx_node_retain(ctx); ctx->state = LP_CU_STATE_WAIT_INSTANT; break; case LP_CU_EVT_UNKNOWN: /* Unsupported in peer, so disable locally for this connection */ feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ); ctx->data.cu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; - lp_cu_wait_complete(conn, ctx, evt, param); + lp_cu_ntf_complete(conn, ctx, evt, param); break; case LP_CU_EVT_REJECT: ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code; - lp_cu_wait_complete(conn, ctx, evt, param); + lp_cu_ntf_complete(conn, ctx, evt, param); break; default: /* Ignore other evts */ @@ -571,8 +630,13 @@ static void lp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint notify = cu_should_notify_host(ctx); if (notify) { ctx->data.cu.error = BT_HCI_ERR_SUCCESS; - lp_cu_wait_complete(conn, ctx, evt, param); + lp_cu_ntf_complete(conn, ctx, evt, param); } else { + /* Release RX node kept for NTF */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE; + ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx); + ctx->node_ref.rx = NULL; + lp_cu_complete(conn, ctx); } } @@ -591,18 +655,6 @@ static void lp_cu_st_wait_instant(struct ll_conn *conn, struct proc_ctx *ctx, ui } } -static void lp_cu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) -{ - switch (evt) { - case LP_CU_EVT_RUN: - lp_cu_wait_complete(conn, ctx, evt, param); - break; - default: - /* Ignore other evts */ - break; - } -} - static void lp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (ctx->state) { @@ -623,6 +675,9 @@ static void lp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ case LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND: lp_cu_st_wait_tx_conn_update_ind(conn, ctx, evt, param); break; + case LP_CU_STATE_WAIT_NTF_AVAIL: + lp_cu_st_wait_ntf_avail(conn, ctx, evt, param); + break; #endif /* CONFIG_BT_CENTRAL */ #if defined(CONFIG_BT_PERIPHERAL) case LP_CU_STATE_WAIT_RX_CONN_UPDATE_IND: @@ -637,9 +692,6 @@ static void lp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ case LP_CU_STATE_WAIT_INSTANT: lp_cu_st_wait_instant(conn, ctx, evt, param); break; - case LP_CU_STATE_WAIT_NTF: - lp_cu_st_wait_ntf(conn, ctx, evt, param); - break; default: /* Unknown state */ LL_ASSERT(0); @@ -694,9 +746,15 @@ static void rp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode) struct node_tx *tx; struct pdu_data *pdu; - /* Allocate tx node */ - tx = llcp_tx_alloc(conn, ctx); - LL_ASSERT(tx); + /* Get pre-allocated tx node */ + tx = ctx->node_ref.tx; + ctx->node_ref.tx = NULL; + + if (!tx) { + /* Allocate tx node if non pre-alloc'ed */ + tx = llcp_tx_alloc(conn, ctx); + LL_ASSERT(tx); + } pdu = (struct pdu_data *)tx->pdu; @@ -743,19 +801,28 @@ static void rp_cu_conn_param_req_ntf(struct ll_conn *conn, struct proc_ctx *ctx) { struct node_rx_pdu *ntf; struct pdu_data *pdu; + uint8_t piggy_back; + /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); + piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN); + ntf->hdr.type = NODE_RX_TYPE_DC_PDU; ntf->hdr.handle = conn->lll.handle; pdu = (struct pdu_data *)ntf->pdu; llcp_pdu_encode_conn_param_req(ctx, pdu); - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); + if (!piggy_back) { + /* Enqueue notification towards LL, unless piggy-backing, + * in which case this is done on the rx return path + */ + ll_rx_put_sched(ntf->hdr.link, ntf); + } } #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ @@ -770,15 +837,21 @@ static void rp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx) ctx->state = RP_CU_STATE_IDLE; } -static void rp_cu_wait_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) +static void rp_cu_send_conn_update_ind_finalize(struct ll_conn *conn, struct proc_ctx *ctx, + uint8_t evt, void *param) { - if (!llcp_ntf_alloc_is_available()) { - ctx->state = RP_CU_STATE_WAIT_NTF; - } else { - cu_ntf(conn, ctx); - rp_cu_complete(conn, ctx); - } + /* Central role path, should not get here with !=NULL rx-node reference */ + LL_ASSERT(ctx->node_ref.rx == NULL); + /* We pre-alloc NTF node */ + ctx->node_ref.rx = llcp_ntf_alloc(); + + /* Signal put/sched on NTF - ie non-RX node piggy */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; + + cu_prepare_update_ind(conn, ctx); + rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND); + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; + ctx->state = RP_CU_STATE_WAIT_INSTANT; } static void rp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, @@ -787,10 +860,30 @@ static void rp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ct if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = RP_CU_STATE_WAIT_TX_CONN_UPDATE_IND; } else { - cu_prepare_update_ind(conn, ctx); - rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND); - ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; - ctx->state = RP_CU_STATE_WAIT_INSTANT; + /* ensure alloc of TX node, before possibly waiting for NTF node */ + ctx->node_ref.tx = llcp_tx_alloc(conn, ctx); + if (!llcp_ntf_alloc_is_available()) { + /* No RX node piggy, and no NTF avail, so go wait for one, before TX'ing */ + ctx->state = RP_CU_STATE_WAIT_NTF_AVAIL; + } else { + rp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param); + } + } +} + +static void rp_cu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + switch (evt) { + case RP_CU_EVT_RUN: + if (llcp_ntf_alloc_is_available()) { + /* If NTF node is now avail, so pick it up and continue */ + rp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param); + } + break; + default: + /* Ignore other evts */ + break; } } @@ -886,6 +979,8 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct ctx->data.cu.error = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL; rp_cu_send_reject_ext_ind(conn, ctx, evt, param); } + /* In case we have to defer NTF */ + llcp_rx_node_retain(ctx); } else { cpr_active_set(conn); const bool params_changed = @@ -894,7 +989,8 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct /* notify Host if conn parameters changed, else respond */ if (params_changed) { - rp_cu_send_conn_param_req_ntf(conn, ctx, evt, param); + rp_cu_conn_param_req_ntf(conn, ctx); + ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY; } else { #if defined(CONFIG_BT_CTLR_USER_CPR_ANCHOR_POINT_MOVE) /* Handle APM as a vendor specific user extension */ @@ -977,6 +1073,8 @@ static void rp_cu_state_wait_conn_param_req_reply_continue(struct ll_conn *conn, switch (evt) { case RP_CU_EVT_RUN: if (conn->lll.role == BT_HCI_ROLE_CENTRAL) { + /* Ensure that node_ref does not indicate RX node for piggyback */ + ctx->node_ref.rx = NULL; rp_cu_send_conn_update_ind(conn, ctx, evt, param); } else if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) { if (!ctx->data.cu.error) { @@ -1076,10 +1174,14 @@ static void rp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint notify = cu_should_notify_host(ctx); if (notify) { ctx->data.cu.error = BT_HCI_ERR_SUCCESS; - rp_cu_wait_complete(conn, ctx, evt, param); + cu_ntf(conn, ctx); } else { - rp_cu_complete(conn, ctx); + /* Release RX node kept for NTF */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE; + ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx); + ctx->node_ref.rx = NULL; } + rp_cu_complete(conn, ctx); } } @@ -1099,6 +1201,8 @@ static void rp_cu_st_wait_rx_conn_update_ind(struct ll_conn *conn, struct proc_c if (is_instant_not_passed(ctx->data.cu.instant, ull_conn_event_counter(conn))) { + llcp_rx_node_retain(ctx); + ctx->state = RP_CU_STATE_WAIT_INSTANT; /* In case we only just received it in time */ rp_cu_check_instant(conn, ctx, evt, param); @@ -1131,18 +1235,6 @@ static void rp_cu_st_wait_instant(struct ll_conn *conn, struct proc_ctx *ctx, ui } } -static void rp_cu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) -{ - switch (evt) { - case RP_CU_EVT_RUN: - rp_cu_wait_complete(conn, ctx, evt, param); - break; - default: - /* Ignore other evts */ - break; - } -} - static void rp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (ctx->state) { @@ -1186,8 +1278,8 @@ static void rp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ case RP_CU_STATE_WAIT_INSTANT: rp_cu_st_wait_instant(conn, ctx, evt, param); break; - case RP_CU_STATE_WAIT_NTF: - rp_cu_st_wait_ntf(conn, ctx, evt, param); + case RP_CU_STATE_WAIT_NTF_AVAIL: + rp_cu_st_wait_ntf_avail(conn, ctx, evt, param); break; default: /* Unknown state */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c index 690e63d07a3..10fc39d86a5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c @@ -4,9 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include +#include #include #include #include @@ -59,7 +59,6 @@ enum { LP_ENC_STATE_WAIT_RX_START_ENC_REQ, LP_ENC_STATE_WAIT_TX_START_ENC_RSP, LP_ENC_STATE_WAIT_RX_START_ENC_RSP, - LP_ENC_STATE_WAIT_NTF, /* Pause Procedure */ LP_ENC_STATE_ENCRYPTED, LP_ENC_STATE_WAIT_TX_PAUSE_ENC_REQ, @@ -99,12 +98,11 @@ enum { RP_ENC_STATE_UNENCRYPTED, RP_ENC_STATE_WAIT_RX_ENC_REQ, RP_ENC_STATE_WAIT_TX_ENC_RSP, - RP_ENC_STATE_WAIT_NTF_LTK_REQ, RP_ENC_STATE_WAIT_LTK_REPLY, + RP_ENC_STATE_WAIT_LTK_REPLY_CONTINUE, RP_ENC_STATE_WAIT_TX_START_ENC_REQ, RP_ENC_STATE_WAIT_TX_REJECT_IND, RP_ENC_STATE_WAIT_RX_START_ENC_RSP, - RP_ENC_STATE_WAIT_NTF, RP_ENC_STATE_WAIT_TX_START_ENC_RSP, /* Pause Procedure */ RP_ENC_STATE_ENCRYPTED, @@ -225,8 +223,8 @@ static void lp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx) struct node_rx_pdu *ntf; struct pdu_data *pdu; - /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + /* Piggy-back on RX node */ + ntf = ctx->node_ref.rx; LL_ASSERT(ntf); ntf->hdr.type = NODE_RX_TYPE_DC_PDU; @@ -248,20 +246,13 @@ static void lp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx) } else { llcp_pdu_encode_reject_ind(pdu, ctx->data.enc.error); } - - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); } static void lp_enc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_ntf_alloc_is_available()) { - ctx->state = LP_ENC_STATE_WAIT_NTF; - } else { - lp_enc_ntf(conn, ctx); - llcp_lr_complete(conn); - ctx->state = LP_ENC_STATE_UNENCRYPTED; - } + lp_enc_ntf(conn, ctx); + llcp_lr_complete(conn); + ctx->state = LP_ENC_STATE_UNENCRYPTED; } static void lp_enc_store_m(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu) @@ -519,18 +510,6 @@ static void lp_enc_st_wait_rx_start_enc_rsp(struct ll_conn *conn, struct proc_ct } } -static void lp_enc_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) -{ - switch (evt) { - case LP_ENC_EVT_RUN: - lp_enc_complete(conn, ctx, evt, param); - break; - default: - /* Ignore other evts */ - break; - } -} - static void lp_enc_state_encrypted(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -612,9 +591,6 @@ static void lp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8 case LP_ENC_STATE_WAIT_RX_START_ENC_RSP: lp_enc_st_wait_rx_start_enc_rsp(conn, ctx, evt, param); break; - case LP_ENC_STATE_WAIT_NTF: - lp_enc_st_wait_ntf(conn, ctx, evt, param); - break; /* Pause Procedure */ case LP_ENC_STATE_ENCRYPTED: lp_enc_state_encrypted(conn, ctx, evt, param); @@ -730,10 +706,10 @@ static struct node_tx *llcp_rp_enc_tx(struct ll_conn *conn, struct proc_ctx *ctx break; case PDU_DATA_LLCTRL_TYPE_REJECT_IND: if (conn->llcp.fex.valid && feature_ext_rej_ind(conn)) { - llcp_pdu_encode_reject_ext_ind(pdu, PDU_DATA_LLCTRL_TYPE_ENC_REQ, - BT_HCI_ERR_PIN_OR_KEY_MISSING); + llcp_pdu_encode_reject_ext_ind(pdu, ctx->reject_ext_ind.reject_opcode, + ctx->reject_ext_ind.error_code); } else { - llcp_pdu_encode_reject_ind(pdu, BT_HCI_ERR_PIN_OR_KEY_MISSING); + llcp_pdu_encode_reject_ind(pdu, ctx->reject_ext_ind.error_code); } break; default: @@ -755,19 +731,26 @@ static void rp_enc_ntf_ltk(struct ll_conn *conn, struct proc_ctx *ctx) { struct node_rx_pdu *ntf; struct pdu_data *pdu; + uint8_t piggy_back; - /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + /* Piggy-back on RX node */ + ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); + piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN); + ntf->hdr.type = NODE_RX_TYPE_DC_PDU; ntf->hdr.handle = conn->lll.handle; pdu = (struct pdu_data *)ntf->pdu; llcp_ntf_encode_enc_req(ctx, pdu); - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); + if (!piggy_back) { + /* Enqueue notification towards LL unless it's piggybacked */ + ll_rx_put_sched(ntf->hdr.link, ntf); + } + } static void rp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx) @@ -775,8 +758,9 @@ static void rp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx) struct node_rx_pdu *ntf; struct pdu_data *pdu; - /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + /* Piggy-back on RX node */ + ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); ntf->hdr.type = NODE_RX_TYPE_DC_PDU; @@ -794,9 +778,6 @@ static void rp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx) /* Should never happen */ LL_ASSERT(0); } - - /* Enqueue notification towards LL */ - ll_rx_put_sched(ntf->hdr.link, ntf); } static void rp_enc_send_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, @@ -804,23 +785,8 @@ static void rp_enc_send_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx static void rp_enc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_ntf_alloc_is_available()) { - ctx->state = RP_ENC_STATE_WAIT_NTF; - } else { - rp_enc_ntf(conn, ctx); - rp_enc_send_start_enc_rsp(conn, ctx, evt, param); - } -} - -static void rp_enc_send_ltk_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) -{ - if (!llcp_ntf_alloc_is_available()) { - ctx->state = RP_ENC_STATE_WAIT_NTF_LTK_REQ; - } else { - rp_enc_ntf_ltk(conn, ctx); - ctx->state = RP_ENC_STATE_WAIT_LTK_REPLY; - } + rp_enc_ntf(conn, ctx); + rp_enc_send_start_enc_rsp(conn, ctx, evt, param); } static void rp_enc_store_s(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu) @@ -840,11 +806,15 @@ static void rp_enc_send_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint struct node_tx *tx; if (!llcp_tx_alloc_peek(conn, ctx)) { + /* Mark RX node to not release, needed for LTK NTF */ + llcp_rx_node_retain(ctx); ctx->state = RP_ENC_STATE_WAIT_TX_ENC_RSP; } else { tx = llcp_rp_enc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_ENC_RSP); rp_enc_store_s(conn, ctx, (struct pdu_data *)tx->pdu); - rp_enc_send_ltk_ntf(conn, ctx, evt, param); + + rp_enc_ntf_ltk(conn, ctx); + ctx->state = RP_ENC_STATE_WAIT_LTK_REPLY; } } @@ -873,14 +843,30 @@ static void rp_enc_send_reject_ind(struct ll_conn *conn, struct proc_ctx *ctx, u } else { llcp_rp_enc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_REJECT_IND); llcp_rr_complete(conn); - ctx->state = RP_ENC_STATE_UNENCRYPTED; - /* Resume Tx data */ - llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION); - /* Resume Rx data */ - ull_conn_resume_rx_data(conn); - /* Resume possibly paused local procedure */ - llcp_lr_resume(conn); + if (ctx->data.enc.error == BT_HCI_ERR_PIN_OR_KEY_MISSING) { + /* Start encryption rejected due to missing key. + * + * Resume paused data and local procedures. + */ + + ctx->state = RP_ENC_STATE_UNENCRYPTED; + + /* Resume Tx data */ + llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION); + /* Resume Rx data */ + ull_conn_resume_rx_data(conn); + /* Resume possibly paused local procedure */ + llcp_lr_resume(conn); + } else if (ctx->data.enc.error == BT_HCI_ERR_LMP_PDU_NOT_ALLOWED) { + /* Pause encryption rejected due to invalid behaviour. + * + * Nothing special needs to be done. + */ + } else { + /* Shouldn't happen */ + LL_ASSERT(0); + } } } @@ -969,6 +955,7 @@ static void rp_enc_state_wait_rx_enc_req(struct ll_conn *conn, struct proc_ctx * llcp_lr_pause(conn); rp_enc_store_m(conn, ctx, param); + rp_enc_send_enc_rsp(conn, ctx, evt, param); break; default: @@ -990,12 +977,20 @@ static void rp_enc_state_wait_tx_enc_rsp(struct ll_conn *conn, struct proc_ctx * } } -static void rp_enc_state_wait_ntf_ltk_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) +static void rp_enc_state_wait_ltk_reply(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) { switch (evt) { - case RP_ENC_EVT_RUN: - rp_enc_send_ltk_ntf(conn, ctx, evt, param); + case RP_ENC_EVT_LTK_REQ_REPLY: + /* Continue procedure in next prepare run */ + ctx->state = RP_ENC_STATE_WAIT_LTK_REPLY_CONTINUE; + break; + case RP_ENC_EVT_LTK_REQ_NEG_REPLY: + ctx->data.enc.error = BT_HCI_ERR_PIN_OR_KEY_MISSING; + ctx->reject_ext_ind.reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ; + ctx->reject_ext_ind.error_code = BT_HCI_ERR_PIN_OR_KEY_MISSING; + /* Send reject in next prepare run */ + ctx->state = RP_ENC_STATE_WAIT_TX_REJECT_IND; break; default: /* Ignore other evts */ @@ -1003,16 +998,13 @@ static void rp_enc_state_wait_ntf_ltk_req(struct ll_conn *conn, struct proc_ctx } } -static void rp_enc_state_wait_ltk_reply(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) +static void rp_enc_state_wait_ltk_reply_continue(struct ll_conn *conn, struct proc_ctx *ctx, + uint8_t evt, void *param) { switch (evt) { - case RP_ENC_EVT_LTK_REQ_REPLY: + case RP_ENC_EVT_RUN: rp_enc_send_start_enc_req(conn, ctx, evt, param); break; - case RP_ENC_EVT_LTK_REQ_NEG_REPLY: - rp_enc_send_reject_ind(conn, ctx, evt, param); - break; default: /* Ignore other evts */ break; @@ -1058,19 +1050,6 @@ static void rp_enc_state_wait_rx_start_enc_rsp(struct ll_conn *conn, struct proc } } -static void rp_enc_state_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) -{ - switch (evt) { - case RP_ENC_EVT_RUN: - rp_enc_complete(conn, ctx, evt, param); - break; - default: - /* Ignore other evts */ - break; - } -} - static void rp_enc_state_wait_tx_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -1102,6 +1081,26 @@ static void rp_enc_state_wait_rx_pause_enc_req(struct ll_conn *conn, struct proc { switch (evt) { case RP_ENC_EVT_PAUSE_ENC_REQ: +#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) + { + /* Central is not allowed to send a LL_PAUSE_ENC_REQ while the ACL is + * associated with a CIS that has been created. + * + * Handle this invalid case, by rejecting. + */ + struct ll_conn_iso_stream *cis = ll_conn_iso_stream_get_by_acl(conn, NULL); + + if (cis) { + ctx->data.enc.error = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED; + ctx->reject_ext_ind.reject_opcode = + PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ; + ctx->reject_ext_ind.error_code = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED; + rp_enc_send_reject_ind(conn, ctx, evt, param); + break; + } + } +#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO */ + /* Pause Tx data */ llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION); /* @@ -1162,12 +1161,12 @@ static void rp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8 case RP_ENC_STATE_WAIT_TX_ENC_RSP: rp_enc_state_wait_tx_enc_rsp(conn, ctx, evt, param); break; - case RP_ENC_STATE_WAIT_NTF_LTK_REQ: - rp_enc_state_wait_ntf_ltk_req(conn, ctx, evt, param); - break; case RP_ENC_STATE_WAIT_LTK_REPLY: rp_enc_state_wait_ltk_reply(conn, ctx, evt, param); break; + case RP_ENC_STATE_WAIT_LTK_REPLY_CONTINUE: + rp_enc_state_wait_ltk_reply_continue(conn, ctx, evt, param); + break; case RP_ENC_STATE_WAIT_TX_START_ENC_REQ: rp_enc_state_wait_tx_start_enc_req(conn, ctx, evt, param); break; @@ -1177,9 +1176,6 @@ static void rp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8 case RP_ENC_STATE_WAIT_RX_START_ENC_RSP: rp_enc_state_wait_rx_start_enc_rsp(conn, ctx, evt, param); break; - case RP_ENC_STATE_WAIT_NTF: - rp_enc_state_wait_ntf(conn, ctx, evt, param); - break; case RP_ENC_STATE_WAIT_TX_START_ENC_RSP: rp_enc_state_wait_tx_start_enc_rsp(conn, ctx, evt, param); break; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h index a8673057eb3..ac60206bc70 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h @@ -161,7 +161,7 @@ static inline bool feature_peer_smi_tx(struct ll_conn *conn) static inline bool feature_peer_iso_central(struct ll_conn *conn) { - return (conn->llcp.fex.features_peer & LL_FEAT_BIT_CIS_CENTRAL) != 0; + return (conn->llcp.fex.features_peer & BIT64(BT_LE_FEAT_BIT_CIS_CENTRAL)) != 0; } static inline bool feature_iso_central(struct ll_conn *conn) @@ -171,7 +171,7 @@ static inline bool feature_iso_central(struct ll_conn *conn) static inline bool feature_peer_iso_peripheral(struct ll_conn *conn) { - return (conn->llcp.fex.features_peer & LL_FEAT_BIT_CIS_PERIPHERAL) != 0; + return (conn->llcp.fex.features_peer & BIT64(BT_LE_FEAT_BIT_CIS_PERIPHERAL)) != 0; } static inline bool feature_iso_peripheral(struct ll_conn *conn) diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index 39904f8f15a..0e1afb9ff1d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -156,9 +156,16 @@ struct proc_ctx { enum llcp_wait_reason wait_reason; #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ - /* TX node awaiting ack */ - struct node_tx *tx_ack; - + struct { + /* Rx node link element */ + memq_link_t *link; + /* TX node awaiting ack */ + struct node_tx *tx_ack; + /* most recent RX node */ + struct node_rx_pdu *rx; + /* pre-allocated TX node */ + struct node_tx *tx; + } node_ref; /* * This flag is set to 1 when we are finished with the control * procedure and it is safe to release the context ctx @@ -167,6 +174,10 @@ struct proc_ctx { /* Procedure data */ union { + /* Feature Exchange Procedure */ + struct { + uint8_t host_initiated:1; + } fex; /* Used by Minimum Used Channels Procedure */ #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) struct { @@ -190,6 +201,7 @@ struct proc_ctx { uint8_t ntf_pu:1; #if defined(CONFIG_BT_CTLR_DATA_LENGTH) uint8_t ntf_dle:1; + struct node_rx_pdu *ntf_dle_node; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ uint8_t error; uint16_t instant; @@ -392,10 +404,15 @@ bool llcp_ntf_alloc_num_available(uint8_t count); struct node_rx_pdu *llcp_ntf_alloc(void); struct proc_ctx *llcp_create_local_procedure(enum llcp_proc proc); struct proc_ctx *llcp_create_remote_procedure(enum llcp_proc proc); +void llcp_nodes_release(struct ll_conn *conn, struct proc_ctx *ctx); bool llcp_tx_alloc_peek(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_tx_alloc_unpeek(struct proc_ctx *ctx); struct node_tx *llcp_tx_alloc(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_proc_ctx_release(struct proc_ctx *ctx); +void llcp_ntf_set_pending(struct ll_conn *conn); +void llcp_ntf_clear_pending(struct ll_conn *conn); +bool llcp_ntf_pending(struct ll_conn *conn); +void llcp_rx_node_retain(struct proc_ctx *ctx); /* * ULL -> LLL Interface @@ -511,19 +528,21 @@ void llcp_pdu_decode_terminate_ind(struct proc_ctx *ctx, struct pdu_data *pdu); * LLCP Local Request */ struct proc_ctx *llcp_lr_peek(struct ll_conn *conn); +struct proc_ctx *llcp_lr_peek_proc(struct ll_conn *conn, uint8_t proc); bool llcp_lr_ispaused(struct ll_conn *conn); void llcp_lr_pause(struct ll_conn *conn); void llcp_lr_resume(struct ll_conn *conn); void llcp_lr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx); void llcp_lr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx); -void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); +void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, + struct node_rx_pdu *rx); void llcp_lr_enqueue(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_lr_init(struct ll_conn *conn); void llcp_lr_run(struct ll_conn *conn); void llcp_lr_complete(struct ll_conn *conn); void llcp_lr_connect(struct ll_conn *conn); void llcp_lr_disconnect(struct ll_conn *conn); -void llcp_lr_abort(struct ll_conn *conn); +void llcp_lr_terminate(struct ll_conn *conn); void llcp_lr_check_done(struct ll_conn *conn, struct proc_ctx *ctx); /* @@ -539,14 +558,17 @@ void llcp_rr_pause(struct ll_conn *conn); void llcp_rr_resume(struct ll_conn *conn); void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx); void llcp_rr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx); -void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); +void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, + struct node_rx_pdu *rx); void llcp_rr_init(struct ll_conn *conn); void llcp_rr_prepare(struct ll_conn *conn, struct node_rx_pdu *rx); void llcp_rr_run(struct ll_conn *conn); void llcp_rr_complete(struct ll_conn *conn); void llcp_rr_connect(struct ll_conn *conn); void llcp_rr_disconnect(struct ll_conn *conn); -void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu); +void llcp_rr_terminate(struct ll_conn *conn); +void llcp_rr_new(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx, + bool valid_pdu); void llcp_rr_check_done(struct ll_conn *conn, struct proc_ctx *ctx); #if defined(CONFIG_BT_CTLR_LE_PING) @@ -710,11 +732,13 @@ void llcp_pdu_encode_cte_rsp(const struct proc_ctx *ctx, struct pdu_data *pdu); #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ void llcp_lp_cc_init_proc(struct proc_ctx *ctx); +void llcp_lp_cc_offset_calc_reply(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_lp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); void llcp_lp_cc_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param); bool llcp_lp_cc_is_active(struct proc_ctx *ctx); bool llcp_lp_cc_awaiting_established(struct proc_ctx *ctx); void llcp_lp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx); +bool llcp_lp_cc_cancel(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_rp_cc_init_proc(struct proc_ctx *ctx); void llcp_rp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c index 8136576cf39..793e33934bc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" @@ -34,6 +35,7 @@ #include "ull_tx_queue.h" #include "isoal.h" +#include "ull_internal.h" #include "ull_iso_types.h" #include "ull_conn_iso_types.h" #include "ull_conn_iso_internal.h" @@ -157,7 +159,6 @@ struct proc_ctx *llcp_lr_peek(struct ll_conn *conn) /* This function is called from both Thread and Mayfly (ISR), * make sure only a single context have access at a time. */ - struct proc_ctx *ctx; bool key = shared_data_access_lock(); @@ -169,6 +170,27 @@ struct proc_ctx *llcp_lr_peek(struct ll_conn *conn) return ctx; } +struct proc_ctx *llcp_lr_peek_proc(struct ll_conn *conn, uint8_t proc) +{ + /* This function is called from both Thread and Mayfly (ISR), + * make sure only a single context have access at a time. + */ + + struct proc_ctx *ctx, *tmp; + + bool key = shared_data_access_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&conn->llcp.local.pend_proc_list, ctx, tmp, node) { + if (ctx->proc == proc) { + break; + } + } + + shared_data_access_unlock(key); + + return ctx; +} + bool llcp_lr_ispaused(struct ll_conn *conn) { return conn->llcp.local.pause == 1U; @@ -199,8 +221,26 @@ void llcp_lr_prt_stop(struct ll_conn *conn) conn->llcp.local.prt_expire = 0U; } -void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx) +void llcp_lr_flush_procedures(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + /* Flush all pending procedures */ + ctx = lr_dequeue(conn); + while (ctx) { + llcp_nodes_release(conn, ctx); + llcp_proc_ctx_release(ctx); + ctx = lr_dequeue(conn); + } +} + +void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, + struct node_rx_pdu *rx) { + /* Store RX node and link */ + ctx->node_ref.rx = rx; + ctx->node_ref.link = link; + switch (ctx->proc) { #if defined(CONFIG_BT_CTLR_LE_PING) case PROC_LE_PING: @@ -305,6 +345,10 @@ void llcp_lr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx * break; /* Ignore tx_ack */ } + + /* Clear TX node reference */ + ctx->node_ref.tx_ack = NULL; + llcp_lr_check_done(conn, ctx); } @@ -426,19 +470,7 @@ static void lr_act_connect(struct ll_conn *conn) static void lr_act_disconnect(struct ll_conn *conn) { - struct proc_ctx *ctx; - - ctx = lr_dequeue(conn); - - /* - * we may have been disconnected in the - * middle of a control procedure, in - * which case we need to release context - */ - while (ctx != NULL) { - llcp_proc_ctx_release(ctx); - ctx = lr_dequeue(conn); - } + llcp_lr_flush_procedures(conn); } static void lr_st_disconnect(struct ll_conn *conn, uint8_t evt, void *param) @@ -582,17 +614,10 @@ void llcp_lr_disconnect(struct ll_conn *conn) lr_execute_fsm(conn, LR_EVT_DISCONNECT, NULL); } -void llcp_lr_abort(struct ll_conn *conn) +void llcp_lr_terminate(struct ll_conn *conn) { - struct proc_ctx *ctx; - - /* Flush all pending procedures */ - ctx = lr_dequeue(conn); - while (ctx) { - llcp_proc_ctx_release(ctx); - ctx = lr_dequeue(conn); - } + llcp_lr_flush_procedures(conn); llcp_lr_prt_stop(conn); llcp_rr_set_incompat(conn, 0U); lr_set_state(conn, LR_STATE_IDLE); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c index 402a2ed0cca..d91914ff392 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c @@ -4,18 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" #include "util/mem.h" #include "util/memq.h" +#include "util/mayfly.h" #include "util/dbuf.h" #include "pdu_df.h" @@ -171,12 +173,26 @@ void llcp_ntf_encode_feature_rsp(struct ll_conn *conn, struct pdu_data *pdu) sys_put_le64(conn->llcp.fex.features_peer, p->features); } +static uint64_t features_used(uint64_t featureset) +{ + uint64_t x; + + /* swap bits for role specific features */ + x = ((featureset >> BT_LE_FEAT_BIT_CIS_CENTRAL) ^ + (featureset >> BT_LE_FEAT_BIT_CIS_PERIPHERAL)) & 0x01; + x = (x << BT_LE_FEAT_BIT_CIS_CENTRAL) | + (x << BT_LE_FEAT_BIT_CIS_PERIPHERAL); + x ^= featureset; + + return ll_feat_get() & x; +} + void llcp_pdu_decode_feature_req(struct ll_conn *conn, struct pdu_data *pdu) { uint64_t featureset; feature_filter(pdu->llctrl.feature_req.features, &featureset); - conn->llcp.fex.features_used = ll_feat_get() & featureset; + conn->llcp.fex.features_used = features_used(featureset); featureset &= (FEAT_FILT_OCTET0 | conn->llcp.fex.features_used); conn->llcp.fex.features_peer = featureset; @@ -189,8 +205,7 @@ void llcp_pdu_decode_feature_rsp(struct ll_conn *conn, struct pdu_data *pdu) uint64_t featureset; feature_filter(pdu->llctrl.feature_rsp.features, &featureset); - conn->llcp.fex.features_used = ll_feat_get() & featureset; - + conn->llcp.fex.features_used = features_used(featureset); conn->llcp.fex.features_peer = featureset; conn->llcp.fex.valid = 1; } @@ -292,7 +307,7 @@ void llcp_pdu_decode_version_ind(struct ll_conn *conn, struct pdu_data *pdu) static int csrand_get(void *buf, size_t len) { - if (k_is_in_isr()) { + if (mayfly_is_running()) { return lll_csrand_isr_get(buf, len); } else { return lll_csrand_get(buf, len); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c index ddd42ed36de..31fc053f849 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" @@ -57,9 +58,9 @@ enum { LP_PU_STATE_WAIT_TX_PHY_UPDATE_IND, LP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND, LP_PU_STATE_WAIT_RX_PHY_UPDATE_IND, + LP_PU_STATE_WAIT_NTF_AVAIL, LP_PU_STATE_WAIT_INSTANT, LP_PU_STATE_WAIT_INSTANT_ON_AIR, - LP_PU_STATE_WAIT_NTF, }; /* LLCP Local Procedure PHY Update FSM events */ @@ -95,9 +96,9 @@ enum { RP_PU_STATE_WAIT_TX_PHY_UPDATE_IND, RP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND, RP_PU_STATE_WAIT_RX_PHY_UPDATE_IND, + RP_PU_STATE_WAIT_NTF_AVAIL, RP_PU_STATE_WAIT_INSTANT, RP_PU_STATE_WAIT_INSTANT_ON_AIR, - RP_PU_STATE_WAIT_NTF, }; /* LLCP Remote Procedure PHY Update FSM events */ @@ -372,38 +373,52 @@ static void pu_prepare_instant(struct ll_conn *conn, struct proc_ctx *ctx) * LLCP Local Procedure PHY Update FSM */ -static void lp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode) +static void lp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { struct node_tx *tx; struct pdu_data *pdu; - /* Allocate tx node */ - tx = llcp_tx_alloc(conn, ctx); - LL_ASSERT(tx); + LL_ASSERT(ctx->node_ref.tx); +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + if (!((ctx->tx_opcode == PDU_DATA_LLCTRL_TYPE_PHY_REQ) && + (conn->lll.role == BT_HCI_ROLE_CENTRAL))) { + if (!llcp_ntf_alloc_is_available()) { + /* No NTF nodes avail, so we need to hold off TX */ + ctx->state = LP_PU_STATE_WAIT_NTF_AVAIL; + return; + } + ctx->data.pu.ntf_dle_node = llcp_ntf_alloc(); + LL_ASSERT(ctx->data.pu.ntf_dle_node); + } +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + + tx = ctx->node_ref.tx; + ctx->node_ref.tx = NULL; + ctx->node_ref.tx_ack = tx; pdu = (struct pdu_data *)tx->pdu; /* Encode LL Control PDU */ - switch (opcode) { + switch (ctx->tx_opcode) { case PDU_DATA_LLCTRL_TYPE_PHY_REQ: pu_set_preferred_phys(conn, ctx); llcp_pdu_encode_phy_req(ctx, pdu); + llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE); + ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_REQ; break; #if defined(CONFIG_BT_CENTRAL) case PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND: pu_prep_update_ind(conn, ctx); pu_prepare_instant(conn, ctx); llcp_pdu_encode_phy_update_ind(ctx, pdu); + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; + ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND; break; #endif /* CONFIG_BT_CENTRAL */ default: LL_ASSERT(0); } - /* Always 'request' the ACK signal */ - ctx->tx_ack = tx; - ctx->tx_opcode = pdu->llctrl.opcode; - /* Enqueue LL Control PDU towards LLL */ llcp_tx_enqueue(conn, tx); @@ -416,21 +431,33 @@ static void pu_ntf(struct ll_conn *conn, struct proc_ctx *ctx) struct node_rx_pdu *ntf; struct node_rx_pu *pdu; - /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); + /* Piggy-back on stored RX node */ + ntf = ctx->node_ref.rx; LL_ASSERT(ntf); - ntf->hdr.type = NODE_RX_TYPE_PHY_UPDATE; - ntf->hdr.handle = conn->lll.handle; - pdu = (struct node_rx_pu *)ntf->pdu; - - pdu->status = ctx->data.pu.error; - pdu->rx = conn->lll.phy_rx; - pdu->tx = conn->lll.phy_tx; + if (ctx->data.pu.ntf_pu) { + LL_ASSERT(ntf->hdr.type == NODE_RX_TYPE_RETAIN); + ntf->hdr.type = NODE_RX_TYPE_PHY_UPDATE; + ntf->hdr.handle = conn->lll.handle; + pdu = (struct node_rx_pu *)ntf->pdu; + + pdu->status = ctx->data.pu.error; + pdu->rx = conn->lll.phy_rx; + pdu->tx = conn->lll.phy_tx; + } else { + ntf->hdr.type = NODE_RX_TYPE_RELEASE; + } /* Enqueue notification towards LL */ +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + /* only 'put' as the 'sched' is handled when handling DLE ntf */ + ll_rx_put(ntf->hdr.link, ntf); +#else ll_rx_put_sched(ntf->hdr.link, ntf); +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + ctx->data.pu.ntf_pu = 0; + ctx->node_ref.rx = NULL; } #if defined(CONFIG_BT_CTLR_DATA_LENGTH) @@ -439,82 +466,63 @@ static void pu_dle_ntf(struct ll_conn *conn, struct proc_ctx *ctx) struct node_rx_pdu *ntf; struct pdu_data *pdu; - /* Allocate ntf node */ - ntf = llcp_ntf_alloc(); - LL_ASSERT(ntf); + /* Retrieve DLE ntf node */ + ntf = ctx->data.pu.ntf_dle_node; + + if (!ctx->data.pu.ntf_dle) { + if (!ntf) { + /* If no DLE ntf was pre-allocated there is nothing more to do */ + /* This will happen in case of a completion on UNKNOWN_RSP to PHY_REQ + * in Central case. + */ + return; + } + /* Signal to release pre-allocated node in case there is no DLE ntf */ + ntf->hdr.type = NODE_RX_TYPE_RELEASE; + } else { + LL_ASSERT(ntf); - ntf->hdr.type = NODE_RX_TYPE_DC_PDU; - ntf->hdr.handle = conn->lll.handle; - pdu = (struct pdu_data *)ntf->pdu; + ntf->hdr.type = NODE_RX_TYPE_DC_PDU; + ntf->hdr.handle = conn->lll.handle; + pdu = (struct pdu_data *)ntf->pdu; - llcp_ntf_encode_length_change(conn, pdu); + llcp_ntf_encode_length_change(conn, pdu); + } /* Enqueue notification towards LL */ ll_rx_put_sched(ntf->hdr.link, ntf); + + ctx->data.pu.ntf_dle = 0; + ctx->data.pu.ntf_dle_node = NULL; } #endif -static void lp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt) +static void lp_pu_complete_finalize(struct ll_conn *conn, struct proc_ctx *ctx) { -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) -#define NTF_DLE (ctx->data.pu.ntf_dle) -#else -#define NTF_DLE 0 -#endif - uint8_t ntf_count = ctx->data.pu.ntf_pu + NTF_DLE; - - /* if we need to send both PHY and DLE notification, but we - * do not have 2 buffers available we serialize the sending - * of notifications - */ -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - if ((ntf_count > 1) && !llcp_ntf_alloc_num_available(ntf_count)) { - ntf_count = 1; - } -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ - if (ntf_count && !llcp_ntf_alloc_num_available(ntf_count)) { - ctx->state = LP_PU_STATE_WAIT_NTF; - } else { - if (ctx->data.pu.ntf_pu) { - pu_ntf(conn, ctx); -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - if (ntf_count == 1 && NTF_DLE == 1) { - ctx->state = LP_PU_STATE_WAIT_NTF; - return; - } -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ - } -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - if (ctx->data.pu.ntf_dle) { - pu_dle_ntf(conn, ctx); - } -#endif - llcp_lr_complete(conn); - ctx->state = LP_PU_STATE_IDLE; - llcp_rr_set_paused_cmd(conn, PROC_NONE); - } + llcp_lr_complete(conn); + llcp_rr_set_paused_cmd(conn, PROC_NONE); + ctx->state = LP_PU_STATE_IDLE; } -static void lp_pu_complete_after_inst_on_air(struct ll_conn *conn, struct proc_ctx *ctx, - uint8_t evt, void *param) +static void lp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - /* When complete reset timing restrictions - idempotent - * (so no problem if we need to wait for NTF buffer) - */ - pu_reset_timing_restrict(conn); - - /* Wait for instant on air to send notification */ - ctx->state = LP_PU_STATE_WAIT_INSTANT_ON_AIR; + pu_ntf(conn, ctx); +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + pu_dle_ntf(conn, ctx); +#endif + lp_pu_complete_finalize(conn, ctx); } static void lp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - /* when complete reset timing restrictions - idempotent - * (so no problem if we need to wait for NTF buffer) - */ pu_reset_timing_restrict(conn); - lp_pu_tx_ntf(conn, ctx, evt); + /* Postpone procedure completion (and possible NTF generation) to actual 'air instant' + * Since LLCP STM is driven from LLL prepare this actually happens BEFORE instant + * and thus NTFs are generated and propagated up prior to actual instant on air. + * Instead postpone completion/NTF to the beginning of RX handling + */ + ctx->state = LP_PU_STATE_WAIT_INSTANT_ON_AIR; } static void lp_pu_send_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) @@ -526,9 +534,11 @@ static void lp_pu_send_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8 } else { llcp_rr_set_incompat(conn, INCOMPAT_RESOLVABLE); llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); - lp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_REQ); - llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE); - ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_REQ; + ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_REQ; + + /* Allocate TX node */ + ctx->node_ref.tx = llcp_tx_alloc(conn, ctx); + lp_pu_tx(conn, ctx, evt, param); } } @@ -539,9 +549,11 @@ static void lp_pu_send_phy_update_ind(struct ll_conn *conn, struct proc_ctx *ctx if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_PU_STATE_WAIT_TX_PHY_UPDATE_IND; } else { - lp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND); - ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; - ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND; + ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND; + + /* Allocate TX node */ + ctx->node_ref.tx = llcp_tx_alloc(conn, ctx); + lp_pu_tx(conn, ctx, evt, param); } } #endif /* CONFIG_BT_CENTRAL */ @@ -587,6 +599,10 @@ static void lp_pu_st_wait_rx_phy_rsp(struct ll_conn *conn, struct proc_ctx *ctx, llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE); /* Combine with the 'Preferred' phys */ pu_combine_phys(conn, ctx, tx_pref, rx_pref); + + /* Mark RX node to NOT release */ + llcp_rx_node_retain(ctx); + lp_pu_send_phy_update_ind(conn, ctx, evt, param); break; case LP_PU_EVT_UNKNOWN: @@ -595,6 +611,10 @@ static void lp_pu_st_wait_rx_phy_rsp(struct ll_conn *conn, struct proc_ctx *ctx, * Peer does not accept PHY UPDATE, so disable non 1M phys on current connection */ feature_unmask_features(conn, LL_FEAT_BIT_PHY_2M | LL_FEAT_BIT_PHY_CODED); + + /* Mark RX node to NOT release */ + llcp_rx_node_retain(ctx); + ctx->data.pu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; ctx->data.pu.ntf_pu = 1; lp_pu_complete(conn, ctx, evt, param); @@ -699,6 +719,9 @@ static void lp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct llcp_pdu_decode_phy_update_ind(ctx, (struct pdu_data *)param); const uint8_t end_procedure = pu_check_update_ind(conn, ctx); + /* Mark RX node to NOT release */ + llcp_rx_node_retain(ctx); + if (!end_procedure) { if (ctx->data.pu.p_to_c_phy) { /* If periph to central phy changes apply tx timing restriction */ @@ -723,20 +746,18 @@ static void lp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE); break; case LP_PU_EVT_REJECT: - llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); - llcp_pdu_decode_reject_ext_ind(ctx, (struct pdu_data *) param); + llcp_pdu_decode_reject_ext_ind(ctx, (struct pdu_data *)param); ctx->data.pu.error = ctx->reject_ext_ind.error_code; - ctx->data.pu.ntf_pu = 1; - lp_pu_complete(conn, ctx, evt, param); - llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE); - break; + /* Fallthrough */ case LP_PU_EVT_UNKNOWN: llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); - /* Unsupported in peer, so disable locally for this connection - * Peer does not accept PHY UPDATE, so disable non 1M phys on current connection - */ - feature_unmask_features(conn, LL_FEAT_BIT_PHY_2M | LL_FEAT_BIT_PHY_CODED); - ctx->data.pu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; + if (evt == LP_PU_EVT_UNKNOWN) { + feature_unmask_features(conn, LL_FEAT_BIT_PHY_2M | LL_FEAT_BIT_PHY_CODED); + ctx->data.pu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; + } + /* Mark RX node to NOT release */ + llcp_rx_node_retain(ctx); + ctx->data.pu.ntf_pu = 1; lp_pu_complete(conn, ctx, evt, param); llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE); @@ -761,7 +782,7 @@ static void lp_pu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); ctx->data.pu.error = BT_HCI_ERR_SUCCESS; ctx->data.pu.ntf_pu = (phy_changed || ctx->data.pu.host_initiated); - lp_pu_complete_after_inst_on_air(conn, ctx, evt, param); + lp_pu_complete(conn, ctx, evt, param); } } @@ -778,11 +799,12 @@ static void lp_pu_st_wait_instant(struct ll_conn *conn, struct proc_ctx *ctx, ui } } -static void lp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt) +static void lp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) { switch (evt) { case LP_PU_EVT_NTF: - lp_pu_tx_ntf(conn, ctx, evt); + lp_pu_tx_ntf(conn, ctx, evt, param); break; default: /* Ignore other evts */ @@ -790,17 +812,20 @@ static void lp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx * } } -static void lp_pu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) +static void lp_pu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) { switch (evt) { case LP_PU_EVT_RUN: - lp_pu_tx_ntf(conn, ctx, evt); + lp_pu_tx(conn, ctx, evt, param); break; default: /* Ignore other evts */ break; } } +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ static void lp_pu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -834,11 +859,13 @@ static void lp_pu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ lp_pu_st_wait_instant(conn, ctx, evt, param); break; case LP_PU_STATE_WAIT_INSTANT_ON_AIR: - lp_pu_st_wait_instant_on_air(conn, ctx, evt); + lp_pu_st_wait_instant_on_air(conn, ctx, evt, param); break; - case LP_PU_STATE_WAIT_NTF: - lp_pu_st_wait_ntf(conn, ctx, evt, param); +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + case LP_PU_STATE_WAIT_NTF_AVAIL: + lp_pu_st_wait_ntf_avail(conn, ctx, evt, param); break; +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ default: /* Unknown state */ LL_ASSERT(0); @@ -904,22 +931,36 @@ bool llcp_lp_pu_awaiting_instant(struct proc_ctx *ctx) /* * LLCP Remote Procedure PHY Update FSM */ -static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode) +static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { struct node_tx *tx; struct pdu_data *pdu; - /* Allocate tx node */ - tx = llcp_tx_alloc(conn, ctx); - LL_ASSERT(tx); + LL_ASSERT(ctx->node_ref.tx); + +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + if (!llcp_ntf_alloc_is_available()) { + /* No NTF nodes avail, so we need to hold off TX */ + ctx->state = RP_PU_STATE_WAIT_NTF_AVAIL; + return; + } + + ctx->data.pu.ntf_dle_node = llcp_ntf_alloc(); + LL_ASSERT(ctx->data.pu.ntf_dle_node); +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + tx = ctx->node_ref.tx; + ctx->node_ref.tx = NULL; pdu = (struct pdu_data *)tx->pdu; + ctx->node_ref.tx_ack = tx; /* Encode LL Control PDU */ - switch (opcode) { + switch (ctx->tx_opcode) { #if defined(CONFIG_BT_PERIPHERAL) case PDU_DATA_LLCTRL_TYPE_PHY_RSP: llcp_pdu_encode_phy_rsp(conn, pdu); + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND; + ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_RSP; break; #endif /* CONFIG_BT_PERIPHERAL */ #if defined(CONFIG_BT_CENTRAL) @@ -927,15 +968,14 @@ static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode) pu_prep_update_ind(conn, ctx); pu_prepare_instant(conn, ctx); llcp_pdu_encode_phy_update_ind(ctx, pdu); + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; + ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND; break; #endif /* CONFIG_BT_CENTRAL */ default: LL_ASSERT(0); } - ctx->tx_ack = tx; - ctx->tx_opcode = pdu->llctrl.opcode; - /* Enqueue LL Control PDU towards LLL */ llcp_tx_enqueue(conn, tx); @@ -945,65 +985,29 @@ static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode) static void rp_pu_complete_finalize(struct ll_conn *conn, struct proc_ctx *ctx) { - llcp_rr_set_paused_cmd(conn, PROC_NONE); llcp_rr_complete(conn); + llcp_rr_set_paused_cmd(conn, PROC_NONE); ctx->state = RP_PU_STATE_IDLE; } static void rp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - /* when complete reset timing restrictions - idempotent - * (so no problem if we need to wait for NTF buffer) - */ pu_reset_timing_restrict(conn); - - /* For remote initiated PHY update Host is notified only if a PHY changes */ - if (ctx->data.pu.ntf_pu) { - /* Notification may be send after instant is on air */ - ctx->state = RP_PU_STATE_WAIT_INSTANT_ON_AIR; - } else { - rp_pu_complete_finalize(conn, ctx); - } + /* Postpone procedure completion (and possible NTF generation) to actual 'air instant' + * Since LLCP STM is driven from LLL prepare this actually happens BEFORE instant + * and thus NTFs are generated and propagated up prior to actual instant on air. + * Instead postpone completion/NTF to the beginning of RX handling + */ + ctx->state = RP_PU_STATE_WAIT_INSTANT_ON_AIR; } -void rp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) +static void rp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) -#define NTF_DLE (ctx->data.pu.ntf_dle) -#else -#define NTF_DLE 0 -#endif - uint8_t ntf_count = ctx->data.pu.ntf_pu + NTF_DLE; - - /* if we need to send both PHY and DLE notification, but we - * do not have 2 buffers available we serialize the sending - * of notifications - */ -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - if ((ntf_count > 1) && !llcp_ntf_alloc_num_available(ntf_count)) { - ntf_count = 1; - } -#endif /* CONFIG_BT_CTLR_DATA_LENGTH) */ - if ((ntf_count > 0) && !llcp_ntf_alloc_num_available(ntf_count)) { - ctx->state = RP_PU_STATE_WAIT_NTF; - } else { - if (ctx->data.pu.ntf_pu) { - pu_ntf(conn, ctx); -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - if (ntf_count == 1 && NTF_DLE == 1) { - ctx->state = RP_PU_STATE_WAIT_NTF; - return; - } -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ - } + pu_ntf(conn, ctx); #if defined(CONFIG_BT_CTLR_DATA_LENGTH) - if (ctx->data.pu.ntf_dle) { - pu_dle_ntf(conn, ctx); - } + pu_dle_ntf(conn, ctx); #endif - rp_pu_complete_finalize(conn, ctx); - } + rp_pu_complete_finalize(conn, ctx); } #if defined(CONFIG_BT_CENTRAL) @@ -1011,15 +1015,15 @@ static void rp_pu_send_phy_update_ind(struct ll_conn *conn, struct proc_ctx *ctx void *param) { if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx) || - (llcp_rr_get_paused_cmd(conn) == PROC_PHY_UPDATE) || + (llcp_rr_get_paused_cmd(conn) == PROC_PHY_UPDATE) || !ull_is_lll_tx_queue_empty(conn)) { ctx->state = RP_PU_STATE_WAIT_TX_PHY_UPDATE_IND; } else { llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); - rp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND); + ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND; + ctx->node_ref.tx = llcp_tx_alloc(conn, ctx); + rp_pu_tx(conn, ctx, evt, param); - ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; - ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND; } } #endif /* CONFIG_BT_CENTRAL */ @@ -1032,9 +1036,9 @@ static void rp_pu_send_phy_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8 ctx->state = RP_PU_STATE_WAIT_TX_PHY_RSP; } else { llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); - rp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_RSP); - ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND; - ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_RSP; + ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_RSP; + ctx->node_ref.tx = llcp_tx_alloc(conn, ctx); + rp_pu_tx(conn, ctx, evt, param); } } #endif /* CONFIG_BT_CENTRAL */ @@ -1064,6 +1068,8 @@ static void rp_pu_st_wait_rx_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, switch (conn->lll.role) { #if defined(CONFIG_BT_CENTRAL) case BT_HCI_ROLE_CENTRAL: + /* Mark RX node to NOT release */ + llcp_rx_node_retain(ctx); rp_pu_send_phy_update_ind(conn, ctx, evt, param); break; #endif /* CONFIG_BT_CENTRAL */ @@ -1165,12 +1171,14 @@ static void rp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct llcp_pdu_decode_phy_update_ind(ctx, (struct pdu_data *)param); const uint8_t end_procedure = pu_check_update_ind(conn, ctx); + /* Mark RX node to NOT release */ + llcp_rx_node_retain(ctx); + if (!end_procedure) { /* Since at least one phy will change, * stop the procedure response timeout */ llcp_rr_prt_stop(conn); - ctx->state = RP_PU_STATE_WAIT_INSTANT; } else { if (ctx->data.pu.error == BT_HCI_ERR_INSTANT_PASSED) { @@ -1230,17 +1238,20 @@ static void rp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx * } } -static void rp_pu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) +static void rp_pu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) { switch (evt) { case RP_PU_EVT_RUN: - rp_pu_tx_ntf(conn, ctx, evt, param); + rp_pu_tx(conn, ctx, evt, param); break; default: /* Ignore other evts */ break; } } +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ static void rp_pu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -1276,9 +1287,11 @@ static void rp_pu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ case RP_PU_STATE_WAIT_INSTANT_ON_AIR: rp_pu_st_wait_instant_on_air(conn, ctx, evt, param); break; - case RP_PU_STATE_WAIT_NTF: - rp_pu_st_wait_ntf(conn, ctx, evt, param); +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + case RP_PU_STATE_WAIT_NTF_AVAIL: + rp_pu_st_wait_ntf_avail(conn, ctx, evt, param); break; +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ default: /* Unknown state */ LL_ASSERT(0); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c index f778087ba5d..cb4f0995688 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" @@ -34,6 +35,7 @@ #include "ull_tx_queue.h" #include "isoal.h" +#include "ull_internal.h" #include "ull_iso_types.h" #include "ull_conn_iso_types.h" #include "ull_conn_iso_internal.h" @@ -48,7 +50,6 @@ #include "hal/debug.h" static struct proc_ctx *rr_dequeue(struct ll_conn *conn); -static void rr_abort(struct ll_conn *conn); /* LLCP Remote Request FSM State */ enum rr_state { @@ -190,7 +191,7 @@ struct proc_ctx *llcp_rr_peek(struct ll_conn *conn) bool llcp_rr_ispaused(struct ll_conn *conn) { - return conn->llcp.remote.pause == 1U; + return (conn->llcp.remote.pause == 1U); } void llcp_rr_pause(struct ll_conn *conn) @@ -213,8 +214,26 @@ void llcp_rr_prt_stop(struct ll_conn *conn) conn->llcp.remote.prt_expire = 0U; } -void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx) +void llcp_rr_flush_procedures(struct ll_conn *conn) { + struct proc_ctx *ctx; + + /* Flush all pending procedures */ + ctx = rr_dequeue(conn); + while (ctx) { + llcp_nodes_release(conn, ctx); + llcp_proc_ctx_release(ctx); + ctx = rr_dequeue(conn); + } +} + +void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, + struct node_rx_pdu *rx) +{ + /* Store RX node and link */ + ctx->node_ref.rx = rx; + ctx->node_ref.link = link; + switch (ctx->proc) { case PROC_UNKNOWN: /* Do nothing */ @@ -319,17 +338,15 @@ void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx * break; } + /* Clear TX node reference */ + ctx->node_ref.tx_ack = NULL; + llcp_rr_check_done(conn, ctx); } void llcp_rr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx) { switch (ctx->proc) { -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - case PROC_DATA_LENGTH_UPDATE: - /* llcp_rp_comm_tx_ntf(conn, ctx); */ - break; -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #ifdef CONFIG_BT_CTLR_PHY case PROC_PHY_UPDATE: llcp_rp_pu_tx_ntf(conn, ctx); @@ -523,19 +540,12 @@ static void rr_act_connect(struct ll_conn *conn) static void rr_act_disconnect(struct ll_conn *conn) { - struct proc_ctx *ctx; - - ctx = rr_dequeue(conn); - /* * we may have been disconnected in the * middle of a control procedure, in which * case we need to release all contexts */ - while (ctx != NULL) { - llcp_proc_ctx_release(ctx); - ctx = rr_dequeue(conn); - } + llcp_rr_flush_procedures(conn); } static void rr_st_disconnect(struct ll_conn *conn, uint8_t evt, void *param) @@ -867,7 +877,7 @@ static const struct proc_role new_proc_lut[] = { #endif /* CONFIG_BT_CTLR_SCA_UPDATE */ }; -void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu) +void llcp_rr_new(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx, bool valid_pdu) { struct proc_ctx *ctx; struct pdu_data *pdu; @@ -887,7 +897,8 @@ void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu) } if (proc == PROC_TERMINATE) { - rr_abort(conn); + llcp_rr_terminate(conn); + llcp_lr_terminate(conn); } ctx = llcp_create_remote_procedure(proc); @@ -906,21 +917,13 @@ void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu) /* Handle PDU */ ctx = llcp_rr_peek(conn); if (ctx) { - llcp_rr_rx(conn, ctx, rx); + llcp_rr_rx(conn, ctx, link, rx); } } -static void rr_abort(struct ll_conn *conn) +void llcp_rr_terminate(struct ll_conn *conn) { - struct proc_ctx *ctx; - - /* Flush all pending procedures */ - ctx = rr_dequeue(conn); - while (ctx) { - llcp_proc_ctx_release(ctx); - ctx = rr_dequeue(conn); - } - + llcp_rr_flush_procedures(conn); llcp_rr_prt_stop(conn); rr_set_collision(conn, 0U); rr_set_state(conn, RR_STATE_IDLE); diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c index a641a0add87..f1716c06573 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "util/util.h" @@ -441,8 +441,8 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, - TICKER_ID_ADV_STOP, NULL, NULL); + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, + TICKER_ID_ADV_STOP, NULL, NULL); } /* Start Peripheral */ @@ -523,7 +523,7 @@ void ull_periph_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, int ret; /* Handle any LL Control Procedures */ - ret = ull_conn_llcp(conn, ticks_at_expire, lazy); + ret = ull_conn_llcp(conn, ticks_at_expire, remainder, lazy); if (ret) { /* NOTE: Under BT_CTLR_LOW_LAT, ULL_LOW context is * disabled inside radio events, hence, abort any diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c index 756096cfccd..5bbac2528d0 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c @@ -5,9 +5,11 @@ */ #include -#include #include +#include +#include + #include "util/util.h" #include "util/memq.h" #include "util/mayfly.h" @@ -46,8 +48,6 @@ #include "ull_conn_iso_internal.h" #include "ull_llcp_internal.h" -#include - #include "hal/debug.h" #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL @@ -99,11 +99,21 @@ static struct ll_conn *ll_cis_get_acl_awaiting_reply(uint16_t handle, uint8_t *e uint8_t ll_cis_accept(uint16_t handle) { uint8_t status = BT_HCI_ERR_SUCCESS; - struct ll_conn *acl_conn = ll_cis_get_acl_awaiting_reply(handle, &status); + struct ll_conn *conn = ll_cis_get_acl_awaiting_reply(handle, &status); + + if (conn) { + uint32_t cis_offset_min; + + if (IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START)) { + /* Early start allows offset down to spec defined minimum */ + cis_offset_min = CIS_MIN_OFFSET_MIN; + } else { + cis_offset_min = HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) + + (EVENT_TICKER_RES_MARGIN_US << 1U); + } - if (acl_conn) { /* Accept request */ - ull_cp_cc_accept(acl_conn); + ull_cp_cc_accept(conn, cis_offset_min); } return status; @@ -250,12 +260,14 @@ uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl, cis->lll.rx.ft = req->c_ft; cis->lll.rx.max_pdu = sys_le16_to_cpu(req->c_max_pdu); cis->lll.rx.payload_count = 0; + cis->lll.rx.bn_curr = 1U; cis->lll.tx.phy = req->p_phy; cis->lll.tx.bn = req->p_bn; cis->lll.tx.ft = req->p_ft; cis->lll.tx.max_pdu = sys_le16_to_cpu(req->p_max_pdu); cis->lll.tx.payload_count = 0; + cis->lll.tx.bn_curr = 1U; if (!cis->lll.link_tx_free) { cis->lll.link_tx_free = &cis->lll.link_tx; @@ -296,7 +308,7 @@ uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind, cis_offset = sys_get_le24(ind->cis_offset); #if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START) - if (!cig->started) { + if (cig->state != CIG_STATE_ACTIVE) { /* This is the first CIS. Make sure we can make the anchorpoint, otherwise * we need to move up the instant up by one connection interval. */ @@ -310,16 +322,19 @@ uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind, cis->sync_delay = sys_get_le24(ind->cis_sync_delay); cis->offset = cis_offset; memcpy(cis->lll.access_addr, ind->aa, sizeof(ind->aa)); - cis->lll.event_count = -1; + cis->lll.event_count = LLL_CONN_ISO_EVENT_COUNT_MAX; cis->lll.next_subevent = 0U; cis->lll.sn = 0U; cis->lll.nesn = 0U; cis->lll.cie = 0U; - cis->lll.flushed = 0U; + cis->lll.npi = 0U; + cis->lll.flush = LLL_CIS_FLUSH_NONE; cis->lll.active = 0U; cis->lll.datapath_ready_rx = 0U; cis->lll.tx.payload_count = 0U; cis->lll.rx.payload_count = 0U; + cis->lll.rx.bn_curr = 1U; + cis->lll.tx.bn_curr = 1U; return 0; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan.c b/subsys/bluetooth/controller/ll_sw/ull_scan.c index 2643771756d..21d6cc9c401 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -500,6 +500,10 @@ uint8_t ull_scan_enable(struct ll_scan_set *scan) * enabled. */ } + +#if defined(CONFIG_BT_TICKER_EXT) + ll_scan_ticker_ext[handle].ticks_slot_window = 0U; +#endif /* CONFIG_BT_TICKER_EXT */ } /* 1M scan window starts without any offset */ @@ -559,6 +563,10 @@ uint8_t ull_scan_enable(struct ll_scan_set *scan) } else { ticks_offset = 0U; } + +#if defined(CONFIG_BT_TICKER_EXT) + ll_scan_ticker_ext[handle].ticks_slot_window = 0U; +#endif /* CONFIG_BT_TICKER_EXT */ } else { ticks_offset = 0U; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index eea0248dd44..eef4e3775f8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -40,7 +40,7 @@ #include "ull_sync_iso_internal.h" #include "ull_df_internal.h" -#include +#include #include #include "hal/debug.h" @@ -50,8 +50,10 @@ static inline struct ll_scan_aux_set *aux_acquire(void); static inline void aux_release(struct ll_scan_aux_set *aux); static inline uint8_t aux_handle_get(struct ll_scan_aux_set *aux); static inline struct ll_sync_set *sync_create_get(struct ll_scan_set *scan); +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) static inline struct ll_sync_iso_set * sync_iso_create_get(struct ll_sync_set *sync); +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ static void done_disabled_cb(void *param); static void flush_safe(void *param); static void flush(void *param); @@ -149,6 +151,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) ull_scan_handle_get(scan); break; +#if defined(CONFIG_BT_CTLR_PHY_CODED) case NODE_RX_TYPE_EXT_CODED_REPORT: lll_aux = NULL; aux = NULL; @@ -166,6 +169,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) ticker_yield_handle = TICKER_ID_SCAN_BASE + ull_scan_handle_get(scan); break; +#endif /* CONFIG_BT_CTLR_PHY_CODED */ case NODE_RX_TYPE_EXT_AUX_REPORT: sync_iso = NULL; @@ -246,9 +250,11 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) case PHY_2M: rx->type = NODE_RX_TYPE_EXT_2M_REPORT; break; +#if defined(CONFIG_BT_CTLR_PHY_CODED) case PHY_CODED: rx->type = NODE_RX_TYPE_EXT_CODED_REPORT; break; +#endif /* CONFIG_BT_CTLR_PHY_CODED */ default: LL_ASSERT(0); return; @@ -335,11 +341,11 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) } if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { - struct ll_sync_set *sync; + struct ll_sync_set *sync_set; - sync = HDR_LLL2ULL(sync_lll); - ftr->aux_data_len = sync->data_len + data_len; - sync->data_len = 0U; + sync_set = HDR_LLL2ULL(sync_lll); + ftr->aux_data_len = sync_set->data_len + data_len; + sync_set->data_len = 0U; } else if (aux) { aux->data_len += data_len; ftr->aux_data_len = aux->data_len; @@ -411,8 +417,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * Setup synchronization if address and SID match in the * Periodic Advertiser List or with the explicitly supplied. */ - if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync && adi && - ull_sync_setup_sid_match(scan, adi->sid)) { + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && aux && sync && adi && + ull_sync_setup_sid_match(scan, PDU_ADV_ADI_SID_GET(adi))) { ull_sync_setup(scan, aux, rx, si); } } @@ -456,16 +462,18 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) /* Do not ULL schedule auxiliary PDU reception if no aux pointer * or aux pointer is zero or scannable advertising has erroneous aux - * pointer being present or PHY in the aux pointer is invalid. + * pointer being present or PHY in the aux pointer is invalid or unsupported. */ if (!aux_ptr || !PDU_ADV_AUX_PTR_OFFSET_GET(aux_ptr) || is_scan_req || - (PDU_ADV_AUX_PTR_PHY_GET(aux_ptr) > EXT_ADV_AUX_PHY_LE_CODED)) { + (PDU_ADV_AUX_PTR_PHY_GET(aux_ptr) > EXT_ADV_AUX_PHY_LE_CODED) || + (!IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) && + PDU_ADV_AUX_PTR_PHY_GET(aux_ptr) == EXT_ADV_AUX_PHY_LE_CODED)) { if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { - struct ll_sync_set *sync; + struct ll_sync_set *sync_set; - sync = HDR_LLL2ULL(sync_lll); - ftr->aux_data_len = sync->data_len + data_len; - sync->data_len = 0U; + sync_set = HDR_LLL2ULL(sync_lll); + ftr->aux_data_len = sync_set->data_len + data_len; + sync_set->data_len = 0U; } else if (aux) { aux->data_len += data_len; ftr->aux_data_len = aux->data_len; @@ -501,11 +509,11 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { - struct ll_sync_set *sync; + struct ll_sync_set *sync_set; - sync = HDR_LLL2ULL(sync_lll); - ftr->aux_data_len = sync->data_len + data_len; - sync->data_len = 0U; + sync_set = HDR_LLL2ULL(sync_lll); + ftr->aux_data_len = sync_set->data_len + data_len; + sync_set->data_len = 0U; } @@ -529,17 +537,21 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) } else { aux->data_len += data_len; + + if (aux->data_len >= CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { + goto ull_scan_aux_rx_flush; + } } /* In sync context we can dispatch rx immediately, in scan context we * enqueue rx in aux context and will flush them after scan is complete. */ if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { - struct ll_sync_set *sync; + struct ll_sync_set *sync_set; - sync = HDR_LLL2ULL(sync_lll); - sync->data_len += data_len; - ftr->aux_data_len = sync->data_len; + sync_set = HDR_LLL2ULL(sync_lll); + sync_set->data_len += data_len; + ftr->aux_data_len = sync_set->data_len; } else { if (aux->rx_last) { aux->rx_last->rx_ftr.extra = rx; @@ -583,6 +595,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) /* Switching to ULL scheduling to receive auxiliary PDUs */ if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || lll) { + LL_ASSERT(scan); + /* Do not ULL schedule if scan disable requested */ if (unlikely(scan->is_stop)) { goto ull_scan_aux_rx_flush; @@ -593,14 +607,14 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) */ lll->lll_aux = NULL; } else { - struct ll_sync_set *sync; + struct ll_sync_set *sync_set; LL_ASSERT(sync_lll && (!sync_lll->lll_aux || sync_lll->lll_aux == lll_aux)); /* Do not ULL schedule if sync terminate requested */ - sync = HDR_LLL2ULL(sync_lll); - if (unlikely(sync->is_stop)) { + sync_set = HDR_LLL2ULL(sync_lll); + if (unlikely(sync_set->is_stop)) { goto ull_scan_aux_rx_flush; } @@ -670,6 +684,13 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) ticks_aux_offset = HAL_TICKER_US_TO_TICKS(aux_offset_us); +#if (CONFIG_BT_CTLR_ULL_HIGH_PRIO == CONFIG_BT_CTLR_ULL_LOW_PRIO) + /* disable ticker job, in order to chain yield and start to reduce + * CPU use by reducing successive calls to ticker_job(). + */ + mayfly_enable(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 0); +#endif + /* Yield the primary scan window or auxiliary or periodic sync event * in ticker. */ @@ -702,6 +723,13 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) ((ticker_status == TICKER_STATUS_FAILURE) && IS_ENABLED(CONFIG_BT_TICKER_LOW_LAT))); +#if (CONFIG_BT_CTLR_ULL_HIGH_PRIO == CONFIG_BT_CTLR_ULL_LOW_PRIO) + /* enable ticker job, queued ticker operation will be handled + * thereafter. + */ + mayfly_enable(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1); +#endif + return; ull_scan_aux_rx_flush: @@ -716,6 +744,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * immediately since we are in sync context. */ if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || aux->rx_last) { + LL_ASSERT(scan); + /* If scan is being disabled, rx could already be * enqueued before coming here to ull_scan_aux_rx_flush. * Check if rx not the last in the list of received PDUs @@ -742,14 +772,14 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) aux->rx_last->rx_ftr.extra = rx; aux->rx_last = rx; } else { - const struct ll_sync_set *sync; + const struct ll_sync_set *sync_set; LL_ASSERT(sync_lll); ll_rx_put_sched(link, rx); - sync = HDR_LLL2ULL(sync_lll); - if (unlikely(sync->is_stop && sync_lll->lll_aux)) { + sync_set = HDR_LLL2ULL(sync_lll); + if (unlikely(sync_set->is_stop && sync_lll->lll_aux)) { return; } } @@ -837,12 +867,12 @@ void *ull_scan_aux_lll_parent_get(struct lll_scan_aux *lll, if (is_lll_scan) { struct ll_scan_set *scan; - struct lll_scan *lll; + struct lll_scan *lllscan; - lll = aux->parent; - LL_ASSERT(lll); + lllscan = aux->parent; + LL_ASSERT(lllscan); - scan = HDR_LLL2ULL(lll); + scan = HDR_LLL2ULL(lllscan); *is_lll_scan = !!ull_scan_is_valid_get(scan); } @@ -1076,6 +1106,7 @@ static inline struct ll_sync_set *sync_create_get(struct ll_scan_set *scan) #endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC */ } +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) static inline struct ll_sync_iso_set * sync_iso_create_get(struct ll_sync_set *sync) { @@ -1085,6 +1116,7 @@ static inline struct ll_sync_iso_set * return NULL; #endif /* !CONFIG_BT_CTLR_SYNC_ISO */ } +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ static void done_disabled_cb(void *param) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index b1c1d77953f..a445d986248 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -5,7 +5,9 @@ */ #include -#include +#include + +#include #include "hal/ccm.h" #include "hal/radio.h" @@ -32,6 +34,7 @@ #include "lll_scan.h" #include "lll/lll_df_types.h" #include "lll_conn.h" +#include "lll_conn_iso.h" #include "ll_sw/ull_tx_queue.h" @@ -39,9 +42,14 @@ #include "ull_scan_types.h" #include "ull_conn_types.h" +#include "isoal.h" +#include "ull_iso_types.h" +#include "ull_conn_iso_types.h" + #include "ull_internal.h" #include "ull_adv_internal.h" #include "ull_conn_internal.h" +#include "ull_conn_iso_internal.h" #include "ll_feat.h" @@ -60,7 +68,7 @@ typedef struct ull_hdr *(*ull_hdr_get_func)(uint8_t ticker_id, uint32_t *ticks_slot); static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, ticker_op_match_func ticker_match_op_cb, - ull_hdr_get_func ull_hdr_get_cb, + ull_hdr_get_func ull_hdr_get_cb_fn, uint32_t *ticks_anchor, uint32_t *ticks_to_expire_match, uint32_t *remainder_match, @@ -68,111 +76,49 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, static void ticker_op_cb(uint32_t status, void *param); static struct ull_hdr *ull_hdr_get_cb(uint8_t ticker_id, uint32_t *ticks_slot); -#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER) +#if (defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)) || \ + defined(CONFIG_BT_CTLR_CENTRAL_ISO) +static int group_free_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, + uint32_t *ticks_to_expire_prev, + uint32_t *ticks_slot_prev, + uint32_t *ticks_anchor); static bool ticker_match_any_op_cb(uint8_t ticker_id, uint32_t ticks_slot, uint32_t ticks_to_expire, void *op_context); +#endif /* (CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER) || + * CONFIG_BT_CTLR_CENTRAL_ISO + */ -int ull_sched_adv_aux_sync_free_slot_get(uint8_t user_id, - uint32_t ticks_slot_abs, - uint32_t *ticks_anchor) +#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER) +int ull_sched_adv_aux_sync_free_anchor_get(uint32_t ticks_slot_abs, + uint32_t *ticks_anchor) { uint32_t ticks_to_expire; uint32_t ticks_slot; - uint32_t remainder; - uint8_t ticker_id; - - ticker_id = after_match_slot_get(user_id, ticks_slot_abs, - ticker_match_any_op_cb, ull_hdr_get_cb, - ticks_anchor, &ticks_to_expire, - &remainder, &ticks_slot); - if (ticker_id != TICKER_NULL) { - if (false) { - - } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE, - TICKER_ID_ADV_AUX_LAST)) { - const struct ll_adv_aux_set *aux; - - *ticks_anchor += ticks_to_expire; - *ticks_anchor += ticks_slot; - - aux = ull_adv_aux_get(ticker_id - - TICKER_ID_ADV_AUX_BASE); - -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) - if (aux->lll.adv->sync) { - const struct ll_adv_sync_set *sync; - - sync = HDR_LLL2ULL(aux->lll.adv->sync); - if (sync->is_started) { - *ticks_anchor += sync->ull.ticks_slot; - *ticks_anchor += HAL_TICKER_US_TO_TICKS( - EVENT_TICKER_RES_MARGIN_US << 1); - } - } -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ - - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - *ticks_anchor += - MAX(aux->ull.ticks_active_to_start, - aux->ull.ticks_prepare_to_start); - } - - return 0; - -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) - } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE, - TICKER_ID_ADV_SYNC_LAST)) { - *ticks_anchor += ticks_to_expire; - *ticks_anchor += ticks_slot; - - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - const struct ll_adv_sync_set *sync; - - sync = ull_adv_sync_get(ticker_id - - TICKER_ID_ADV_SYNC_BASE); - *ticks_anchor += - MAX(sync->ull.ticks_active_to_start, - sync->ull.ticks_prepare_to_start); - } - - return 0; - -#if defined(CONFIG_BT_CTLR_ADV_ISO) - } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_ISO_BASE, - TICKER_ID_ADV_ISO_LAST)) { - *ticks_anchor += ticks_to_expire; - *ticks_anchor += ticks_slot; - - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - const struct ll_adv_iso_set *iso; - - iso = ull_adv_iso_get(ticker_id - - TICKER_ID_ADV_ISO_BASE); - *ticks_anchor += - MAX(iso->ull.ticks_active_to_start, - iso->ull.ticks_prepare_to_start); - } - return 0; - -#endif /* CONFIG_BT_CTLR_ADV_ISO */ -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ - -#if defined(CONFIG_BT_CONN) - } else if (IN_RANGE(ticker_id, TICKER_ID_CONN_BASE, - TICKER_ID_CONN_LAST)) { - *ticks_anchor += ticks_to_expire; - *ticks_anchor += ticks_slot; + return group_free_slot_get(TICKER_USER_ID_THREAD, ticks_slot_abs, + &ticks_to_expire, &ticks_slot, ticks_anchor); +} +#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */ - return 0; -#endif /* CONFIG_BT_CONN */ +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) +int ull_sched_conn_iso_free_offset_get(uint32_t ticks_slot_abs, + uint32_t *ticks_to_expire) +{ + uint32_t ticks_anchor; + uint32_t ticks_slot; + int err; - } + err = group_free_slot_get(TICKER_USER_ID_ULL_LOW, ticks_slot_abs, + ticks_to_expire, &ticks_slot, &ticks_anchor); + if (err) { + return err; } - return -ECHILD; + *ticks_to_expire += ticks_slot; + + return err; } -#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */ +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) @@ -352,9 +298,122 @@ static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot, #endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CONN */ +#if (defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)) || \ + defined(CONFIG_BT_CTLR_CENTRAL_ISO) +static int group_free_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, + uint32_t *ticks_to_expire_prev, + uint32_t *ticks_slot_prev, + uint32_t *ticks_anchor) +{ + uint32_t remainder_prev; + uint8_t ticker_id; + + ticker_id = after_match_slot_get(user_id, ticks_slot_abs, + ticker_match_any_op_cb, ull_hdr_get_cb, + ticks_anchor, ticks_to_expire_prev, + &remainder_prev, ticks_slot_prev); + if (ticker_id != TICKER_NULL) { + uint32_t ticks_to_expire; + uint32_t ticks_slot; + + ticks_to_expire = *ticks_to_expire_prev; + ticks_slot = *ticks_slot_prev; + + if (false) { + +#if defined(CONFIG_BT_BROADCASTER) + } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE, + TICKER_ID_ADV_AUX_LAST)) { + const struct ll_adv_aux_set *aux; + + *ticks_anchor += ticks_to_expire; + *ticks_anchor += ticks_slot; + + aux = ull_adv_aux_get(ticker_id - + TICKER_ID_ADV_AUX_BASE); + +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + if (aux->lll.adv->sync) { + const struct ll_adv_sync_set *sync; + + sync = HDR_LLL2ULL(aux->lll.adv->sync); + if (sync->is_started) { + *ticks_anchor += sync->ull.ticks_slot; + *ticks_anchor += HAL_TICKER_US_TO_TICKS( + EVENT_TICKER_RES_MARGIN_US << 1); + } + } +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ + + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + *ticks_anchor += + MAX(aux->ull.ticks_active_to_start, + aux->ull.ticks_prepare_to_start); + } + + return 0; + +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE, + TICKER_ID_ADV_SYNC_LAST)) { + *ticks_anchor += ticks_to_expire; + *ticks_anchor += ticks_slot; + + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + const struct ll_adv_sync_set *sync; + + sync = ull_adv_sync_get(ticker_id - + TICKER_ID_ADV_SYNC_BASE); + *ticks_anchor += + MAX(sync->ull.ticks_active_to_start, + sync->ull.ticks_prepare_to_start); + } + + return 0; + +#if defined(CONFIG_BT_CTLR_ADV_ISO) + } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_ISO_BASE, + TICKER_ID_ADV_ISO_LAST)) { + *ticks_anchor += ticks_to_expire; + *ticks_anchor += ticks_slot; + + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + const struct ll_adv_iso_set *iso; + + iso = ull_adv_iso_get(ticker_id - + TICKER_ID_ADV_ISO_BASE); + *ticks_anchor += + MAX(iso->ull.ticks_active_to_start, + iso->ull.ticks_prepare_to_start); + } + + return 0; + +#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ +#endif /* CONFIG_BT_BROADCASTER */ + +#if defined(CONFIG_BT_CONN) + } else if (IN_RANGE(ticker_id, TICKER_ID_CONN_BASE, + TICKER_ID_CONN_LAST)) { + *ticks_anchor += ticks_to_expire; + *ticks_anchor += ticks_slot; + + return 0; +#endif /* CONFIG_BT_CONN */ + + } + } + + return -ECHILD; +} +#endif /* (CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER) || + * CONFIG_BT_CTLR_CENTRAL_ISO + */ + static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, ticker_op_match_func ticker_match_op_cb, - ull_hdr_get_func ull_hdr_get_cb, + ull_hdr_get_func ull_hdr_get_cb_fn, uint32_t *ticks_anchor, uint32_t *ticks_to_expire_match, uint32_t *remainder_match, @@ -459,7 +518,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, } #endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ - hdr = ull_hdr_get_cb(ticker_id, &ticks_slot); + hdr = ull_hdr_get_cb_fn(ticker_id, &ticks_slot); if (!hdr) { continue; } @@ -518,7 +577,8 @@ static void ticker_op_cb(uint32_t status, void *param) *((uint32_t volatile *)param) = status; } -#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER) +#if (defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)) || \ + defined(CONFIG_BT_CTLR_CENTRAL_ISO) static bool ticker_match_any_op_cb(uint8_t ticker_id, uint32_t ticks_slot, uint32_t ticks_to_expire, void *op_context) { @@ -546,11 +606,18 @@ static bool ticker_match_any_op_cb(uint8_t ticker_id, uint32_t ticks_slot, #if defined(CONFIG_BT_CONN) IN_RANGE(ticker_id, TICKER_ID_CONN_BASE, TICKER_ID_CONN_LAST) || + +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) + IN_RANGE(ticker_id, TICKER_ID_CONN_ISO_BASE, + TICKER_ID_CONN_ISO_LAST) || +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ #endif /* CONFIG_BT_CONN */ false; } -#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */ +#endif /* (CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER) || + * CONFIG_BT_CTLR_CENTRAL_ISO + */ #if defined(CONFIG_BT_CENTRAL) static bool ticker_match_cen_op_cb(uint8_t ticker_id, uint32_t ticks_slot, @@ -561,7 +628,15 @@ static bool ticker_match_cen_op_cb(uint8_t ticker_id, uint32_t ticks_slot, ARG_UNUSED(op_context); return IN_RANGE(ticker_id, TICKER_ID_CONN_BASE, - TICKER_ID_CONN_LAST); + TICKER_ID_CONN_LAST) || +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) && \ + (CONFIG_BT_CTLR_CENTRAL_SPACING == 0) + IN_RANGE(ticker_id, TICKER_ID_CONN_ISO_BASE, + TICKER_ID_CONN_ISO_LAST) || +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO && + * (CONFIG_BT_CTLR_CENTRAL_SPACING == 0) + */ + false; } #endif /* CONFIG_BT_CENTRAL */ @@ -677,13 +752,27 @@ static struct ull_hdr *ull_hdr_get_cb(uint8_t ticker_id, uint32_t *ticks_slot) *ticks_slot = conn->ull.ticks_slot; } - if (*ticks_slot < CONFIG_BT_CTLR_CENTRAL_SPACING) { + if (*ticks_slot < HAL_TICKER_US_TO_TICKS(CONFIG_BT_CTLR_CENTRAL_SPACING)) { *ticks_slot = HAL_TICKER_US_TO_TICKS(CONFIG_BT_CTLR_CENTRAL_SPACING); } return &conn->ull; } + +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) + } else if (IN_RANGE(ticker_id, TICKER_ID_CONN_ISO_BASE, + TICKER_ID_CONN_ISO_LAST)) { + struct ll_conn_iso_group *cig; + + cig = ll_conn_iso_group_get(ticker_id - TICKER_ID_CONN_ISO_BASE); + if (cig) { + *ticks_slot = cig->ull.ticks_slot; + + return &cig->ull; + } + +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ #endif /* CONFIG_BT_CONN */ } diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h b/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h index e40ece6670f..481f38dbae3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h @@ -4,9 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -int ull_sched_adv_aux_sync_free_slot_get(uint8_t user_id, - uint32_t ticks_slot_abs, - uint32_t *ticks_anchor); +int ull_sched_adv_aux_sync_free_anchor_get(uint32_t ticks_slot_abs, + uint32_t *ticks_anchor); +int ull_sched_conn_iso_free_offset_get(uint32_t ticks_slot_abs, + uint32_t *ticks_to_expire); int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, uint32_t *ticks_anchor, uint32_t *us_offset); void ull_sched_mfy_win_offset_use(void *param); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index d2ef126d408..6c674885810 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "util/util.h" #include "util/mem.h" @@ -1149,7 +1149,7 @@ void ull_sync_chm_update(uint8_t sync_handle, uint8_t *acad, uint8_t acad_len) ad_len = acad[PDU_ADV_DATA_HEADER_LEN_OFFSET]; if (ad_len && (acad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] == - BT_DATA_CHANNEL_MAP_UPDATE_IND)) { + PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND)) { break; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 3715cd3523e..fbacb56f8b4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -6,8 +6,7 @@ #include #include -#include -#include +#include #include "util/util.h" #include "util/mem.h" @@ -422,11 +421,12 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, lll->irc = bi->irc; lll->sdu_interval = sys_le24_to_cpu(bi->sdu_interval); + /* Pick the 39-bit payload count, 1 MSb is framing bit */ lll->payload_count = (uint64_t)bi->payload_count_framing[0]; lll->payload_count |= (uint64_t)bi->payload_count_framing[1] << 8; lll->payload_count |= (uint64_t)bi->payload_count_framing[2] << 16; lll->payload_count |= (uint64_t)bi->payload_count_framing[3] << 24; - lll->payload_count |= (uint64_t)bi->payload_count_framing[4] << 32; + lll->payload_count |= (uint64_t)(bi->payload_count_framing[4] & 0x7f) << 32; if (lll->enc && (bi_size == PDU_BIG_INFO_ENCRYPTED_SIZE)) { const uint8_t BIG3[4] = {0x33, 0x47, 0x49, 0x42}; diff --git a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c index f253460c110..6d188b8d520 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c +++ b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include "ull_tx_queue.h" void ull_tx_q_init(struct ull_tx_q *queue) diff --git a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h index 33ae8783cd9..bdeac3202b3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h +++ b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - struct ull_tx_q { uint8_t pause_data; /* Data pause state of the tx queue */ diff --git a/subsys/bluetooth/controller/ticker/ticker.c b/subsys/bluetooth/controller/ticker/ticker.c index b7e5a9b076d..ead148e85ba 100644 --- a/subsys/bluetooth/controller/ticker/ticker.c +++ b/subsys/bluetooth/controller/ticker/ticker.c @@ -11,6 +11,7 @@ #include "hal/cntr.h" #include "hal/ticker.h" +#include "hal/cpu.h" #include "ticker.h" @@ -21,7 +22,7 @@ ****************************************************************************/ #define DOUBLE_BUFFER_SIZE 2 -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) #if !defined(CONFIG_BT_CTLR_ADV_AUX_SET) #define BT_CTLR_ADV_AUX_SET 0 #else @@ -37,7 +38,7 @@ #else #define TICKER_EXPIRE_INFO_MAX (BT_CTLR_ADV_AUX_SET + BT_CTLR_ADV_SYNC_SET) #endif /* !CONFIG_BT_CTLR_ADV_ISO */ -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /***************************************************************************** * Types @@ -51,9 +52,12 @@ struct ticker_node { * between req and ack indicates * ongoing operation */ - uint8_t force; /* If non-zero, node timeout should + uint8_t force:1; /* If non-zero, node timeout should * be forced at next expiration */ + uint8_t start_pending:1; /* If non-zero, start is pending for + * bottom half of ticker_job. + */ uint32_t ticks_periodic; /* If non-zero, interval * between expirations */ @@ -157,11 +161,17 @@ struct ticker_user_op_start { uint16_t lazy; /* Periodic latency in number of * periods */ +#if defined(CONFIG_BT_TICKER_REMAINDER) + uint32_t remainder_first; /* Sub-microsecond tick remainder */ +#endif /* CONFIG_BT_TICKER_REMAINDER */ + #if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) uint32_t ticks_slot; /* Air-time reservation ticks */ #endif /* CONFIG_BT_TICKER_SLOT_AGNOSTIC */ + ticker_timeout_func fp_timeout_func; /* Timeout callback function */ void *context; /* Context passed in timeout callback */ + #if defined(CONFIG_BT_TICKER_EXT) struct ticker_ext *ext_data; /* Ticker extension data instance */ #endif /* CONFIG_BT_TICKER_EXT */ @@ -196,9 +206,9 @@ struct ticker_user_op_update { * 0x02: Enable must_expire */ #endif -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) uint8_t expire_info_id; -#endif +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ }; /* User operation data structure for yield/stop opcode. Used for passing yield/ @@ -306,10 +316,10 @@ struct ticker_instance { */ #endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) struct ticker_expire_info_internal expire_infos[TICKER_EXPIRE_INFO_MAX]; bool expire_infos_outdated; -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ ticker_caller_id_get_cb_t caller_id_get_cb; /* Function for retrieving * the caller id from user @@ -977,7 +987,7 @@ static uint8_t ticker_resolve_collision(struct ticker_node *nodes, * !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) /** * @brief Get expiration delta from one ticker id to another ticker id * @@ -1150,7 +1160,40 @@ static void ticker_mark_expire_info_outdated(struct ticker_instance *instance, u } } } -#endif /* CONFIG_BT_TICKER_EXT */ + +/** + * @brief Run through all expire infos and update them if needed + * + * @details Runs through all expire_infos and runs ticker_get_expire_info() + * for any that are marked as outdated. Clears the expire_infos_outdated + * flag when done + * + * @param param Pointer to ticker instance + * + * @internal + */ +static void ticker_job_update_expire_infos(struct ticker_instance *instance) +{ + for (int i = 0; i < TICKER_EXPIRE_INFO_MAX; i++) { + struct ticker_expire_info_internal *info = &instance->expire_infos[i]; + + if (info->ticker_id != TICKER_NULL && info->outdated) { + struct ticker_node *ticker = &instance->nodes[info->ticker_id]; + + ticker_get_expire_info(instance, ticker->ext_data->expire_info_id, + info->ticker_id, info); + info->outdated = false; + } + + if (info->last) { + break; + } + } + + instance->expire_infos_outdated = false; +} + +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /** * @brief Ticker worker @@ -1314,11 +1357,7 @@ void ticker_worker(void *param) /* Scheduled timeout is acknowledged to be complete */ ticker->ack--; - if (ticker->timeout_func -#if defined(CONFIG_BT_TICKER_EXT) - || (ticker->ext_data && ticker->ext_data->ext_timeout_func) -#endif /* CONFIG_BT_TICKER_EXT */ - ) { + if (ticker->timeout_func) { uint32_t ticks_at_expire; ticks_at_expire = (instance->ticks_current + @@ -1326,20 +1365,15 @@ void ticker_worker(void *param) ticker->ticks_to_expire_minus) & HAL_TICKER_CNTR_MASK; -#if defined(CONFIG_BT_TICKER_EXT) -#endif /* CONFIG_BT_TICKER_EXT */ - DEBUG_TICKER_TASK(1); - /* Invoke the timeout callback */ - -#if defined(CONFIG_BT_TICKER_EXT) - if (ticker->ext_data && ticker->ext_data->ext_timeout_func) { +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + if (ticker->ext_data && + ticker->ext_data->ext_timeout_func) { struct ticker_expire_info_internal *expire_info; struct ticker_ext_context ext_context; ticker_timeout_func timeout_func; timeout_func = ticker->ext_data->ext_timeout_func; expire_info = ticker->ext_data->other_expire_info; - if (ticker->ext_data->expire_info_id != TICKER_NULL) { LL_ASSERT(expire_info && !expire_info->outdated); } @@ -1351,6 +1385,9 @@ void ticker_worker(void *param) ext_context.other_expire_info = NULL; } + DEBUG_TICKER_TASK(1); + + /* Invoke the timeout callback */ timeout_func(ticks_at_expire, ticks_drift, ticker->remainder_current, @@ -1360,8 +1397,11 @@ void ticker_worker(void *param) ticker->force, &ext_context); } else -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ { + DEBUG_TICKER_TASK(1); + + /* Invoke the timeout callback */ ticker->timeout_func(ticks_at_expire, ticks_drift, ticker->remainder_current, @@ -1370,8 +1410,8 @@ void ticker_worker(void *param) ticker->lazy_current, ticker->force, ticker->context); + DEBUG_TICKER_TASK(0); } - DEBUG_TICKER_TASK(0); if (!IS_ENABLED(CONFIG_BT_TICKER_LOW_LAT) && (must_expire_skip == 0U)) { @@ -1664,7 +1704,7 @@ static inline uint32_t ticker_job_node_update(struct ticker_instance *instance, } #endif /* CONFIG_BT_TICKER_EXT */ -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (ticker->ext_data && user_op->params.update.expire_info_id != user_op->id) { if (user_op->params.update.expire_info_id != TICKER_NULL && !ticker->ext_data->other_expire_info) { @@ -1685,7 +1725,7 @@ static inline uint32_t ticker_job_node_update(struct ticker_instance *instance, ticker_mark_expire_info_outdated(instance, user_op->id); } } -#endif +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ ticker->next = *insert_head; *insert_head = user_op->id; @@ -1726,9 +1766,9 @@ static inline void ticker_job_node_manage(struct ticker_instance *instance, instance->ticks_current, ticks_elapsed, insert_head); -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) ticker_mark_expire_info_outdated(instance, user_op->id); -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /* Set schedule status of node * as updating. @@ -1741,14 +1781,14 @@ static inline void ticker_job_node_manage(struct ticker_instance *instance, ticker->ticks_to_expire = ticker_dequeue(instance, user_op->id); -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (ticker->ext_data && ticker->ext_data->expire_info_id != TICKER_NULL) { ticker_free_expire_info(instance, user_op->id); ticker->ext_data->other_expire_info = NULL; } ticker_mark_expire_info_outdated(instance, user_op->id); -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /* Reset schedule status of node */ ticker->req = ticker->ack; @@ -1867,6 +1907,12 @@ static inline uint8_t ticker_job_list_manage(struct ticker_instance *instance, /* if op is start, then skip update and stop ops */ if (user_op->op < TICKER_USER_OP_TYPE_UPDATE) { + if (user_op->op == TICKER_USER_OP_TYPE_START) { + /* Set start pending to validate a + * successive, inline stop operation. + */ + ticker->start_pending = 1U; + } continue; } @@ -1877,7 +1923,7 @@ static inline uint8_t ticker_job_list_manage(struct ticker_instance *instance, * set status and continue. */ if ((user_op->op > TICKER_USER_OP_TYPE_STOP_ABS) || - ((state == 0U) && + (((state == 0U) && !ticker->start_pending) && (user_op->op != TICKER_USER_OP_TYPE_YIELD_ABS)) || ((user_op->op == TICKER_USER_OP_TYPE_UPDATE) && (user_op->params.update.ticks_drift_plus == 0U) && @@ -1886,10 +1932,10 @@ static inline uint8_t ticker_job_list_manage(struct ticker_instance *instance, (user_op->params.update.ticks_slot_plus == 0U) && (user_op->params.update.ticks_slot_minus == 0U) && #endif /* CONFIG_BT_TICKER_SLOT_AGNOSTIC */ -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) (!ticker->ext_data || user_op->params.update.expire_info_id == user_op->id) && -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ (user_op->params.update.lazy == 0U) && (user_op->params.update.force == 0U))) { ticker_job_op_cb(user_op, @@ -2014,9 +2060,9 @@ static inline void ticker_job_worker_bh(struct ticker_instance *instance, /* ticker expired, set ticks_to_expire zero */ ticker->ticks_to_expire = 0U; -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) ticker_mark_expire_info_outdated(instance, instance->ticker_id_head); -#endif +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /* remove the expired ticker from head */ instance->ticker_id_head = ticker->next; @@ -2171,12 +2217,14 @@ static inline uint32_t ticker_job_op_start(struct ticker_instance *instance, } #endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ #endif /* CONFIG_BT_TICKER_LOW_LAT */ + #if defined(CONFIG_BT_TICKER_EXT) ticker->ext_data = start->ext_data; + +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (ticker->ext_data) { ticker->ext_data->other_expire_info = NULL; - if (ticker->ext_data->ext_timeout_func && - ticker->ext_data->expire_info_id != TICKER_NULL) { + if (ticker->ext_data->expire_info_id != TICKER_NULL) { uint32_t status; status = ticker_alloc_expire_info(instance, user_op->id); @@ -2187,6 +2235,7 @@ static inline uint32_t ticker_job_op_start(struct ticker_instance *instance, } ticker_mark_expire_info_outdated(instance, user_op->id); +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ #endif /* CONFIG_BT_TICKER_EXT */ ticker->ticks_periodic = start->ticks_periodic; @@ -2202,7 +2251,11 @@ static inline uint32_t ticker_job_op_start(struct ticker_instance *instance, ticker->ticks_to_expire = start->ticks_first; ticker->ticks_to_expire_minus = 0U; ticks_to_expire_prep(ticker, ticks_current, start->ticks_at_start); +#if defined(CONFIG_BT_TICKER_REMAINDER) + ticker->remainder_current = start->remainder_first; +#else /* !CONFIG_BT_TICKER_REMAINDER */ ticker->remainder_current = 0U; +#endif /* !CONFIG_BT_TICKER_REMAINDER */ ticker->lazy_current = 0U; ticker->force = 1U; @@ -2480,7 +2533,9 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, ext_data->reschedule_state = TICKER_RESCHEDULE_STATE_DONE; +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) ticker_mark_expire_info_outdated(instance, ticker_id_head); +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /* Check for other pending re-schedules and set exit flag */ rescheduling = 1U; @@ -2676,6 +2731,8 @@ static inline void ticker_job_list_insert(struct ticker_instance *instance, continue; } + ticker->start_pending = 0U; + if (((ticker->req - ticker->ack) & 0xff) != 0U) { ticker_job_op_cb(user_op, @@ -2947,40 +3004,6 @@ ticker_job_compare_update(struct ticker_instance *instance, return 0U; } -#if defined(CONFIG_BT_TICKER_EXT) -/** - * @brief Run through all expire infos and update them if needed - * - * @details Runs through all expire_infos and runs ticker_get_expire_info() - * for any that are marked as outdated. Clears the expire_infos_outdated - * flag when done - * - * @param param Pointer to ticker instance - * - * @internal - */ -static void ticker_job_update_expire_infos(struct ticker_instance *instance) -{ - for (int i = 0; i < TICKER_EXPIRE_INFO_MAX; i++) { - struct ticker_expire_info_internal *info = &instance->expire_infos[i]; - - if (info->ticker_id != TICKER_NULL && info->outdated) { - struct ticker_node *ticker = &instance->nodes[info->ticker_id]; - - ticker_get_expire_info(instance, ticker->ext_data->expire_info_id, - info->ticker_id, info); - info->outdated = false; - } - - if (info->last) { - break; - } - } - - instance->expire_infos_outdated = false; -} -#endif /* CONFIG_BT_TICKER_EXT */ - /** * @brief Ticker job * @@ -3108,11 +3131,11 @@ void ticker_job(void *param) * CONFIG_BT_TICKER_PRIORITY_SET */ -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (instance->expire_infos_outdated) { ticker_job_update_expire_infos(instance); } -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ /* update compare if head changed */ if (flag_compare_update) { @@ -3126,6 +3149,7 @@ void ticker_job(void *param) instance->job_guard = 0U; /* trigger worker if deferred */ + cpu_dmb(); if (instance->worker_trigger || compare_trigger) { instance->sched_cb(TICKER_CALL_ID_JOB, TICKER_CALL_ID_WORKER, 1, instance); @@ -3218,12 +3242,12 @@ uint8_t ticker_init(uint8_t instance_index, uint8_t count_node, void *node, instance->ticks_slot_previous = 0U; #endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ -#if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) for (int i = 0; i < TICKER_EXPIRE_INFO_MAX; i++) { instance->expire_infos[i].ticker_id = TICKER_NULL; instance->expire_infos[i].last = 1; } -#endif +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ return TICKER_STATUS_SUCCESS; } @@ -3311,6 +3335,32 @@ uint8_t ticker_start(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, NULL); } +static uint8_t start_us(uint8_t instance_index, uint8_t user_id, + uint8_t ticker_id, uint32_t ticks_anchor, + uint32_t ticks_first, uint32_t remainder_first, + uint32_t ticks_periodic, uint32_t remainder_periodic, + uint16_t lazy, uint32_t ticks_slot, + ticker_timeout_func fp_timeout_func, void *context, + ticker_op_func fp_op_func, void *op_context, + struct ticker_ext *ext_data); + +uint8_t ticker_start_us(uint8_t instance_index, uint8_t user_id, + uint8_t ticker_id, uint32_t ticks_anchor, + uint32_t ticks_first, uint32_t remainder_first, + uint32_t ticks_periodic, uint32_t remainder_periodic, + uint16_t lazy, uint32_t ticks_slot, + ticker_timeout_func fp_timeout_func, void *context, + ticker_op_func fp_op_func, void *op_context) +{ + return start_us(instance_index, user_id, ticker_id, ticks_anchor, + ticks_first, remainder_first, + ticks_periodic, remainder_periodic, + lazy, ticks_slot, + fp_timeout_func, context, + fp_op_func, op_context, + NULL); +} + uint8_t ticker_start_ext(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, uint32_t ticks_anchor, uint32_t ticks_first, uint32_t ticks_periodic, uint32_t remainder_periodic, @@ -3318,13 +3368,49 @@ uint8_t ticker_start_ext(uint8_t instance_index, uint8_t user_id, uint8_t ticker ticker_timeout_func fp_timeout_func, void *context, ticker_op_func fp_op_func, void *op_context, struct ticker_ext *ext_data) -#else +{ + return start_us(instance_index, user_id, ticker_id, ticks_anchor, + ticks_first, 0U, ticks_periodic, remainder_periodic, + lazy, ticks_slot, + fp_timeout_func, context, + fp_op_func, op_context, + ext_data); +} + +static uint8_t start_us(uint8_t instance_index, uint8_t user_id, + uint8_t ticker_id, uint32_t ticks_anchor, + uint32_t ticks_first, uint32_t remainder_first, + uint32_t ticks_periodic, uint32_t remainder_periodic, + uint16_t lazy, uint32_t ticks_slot, + ticker_timeout_func fp_timeout_func, void *context, + ticker_op_func fp_op_func, void *op_context, + struct ticker_ext *ext_data) + +#else /* !CONFIG_BT_TICKER_EXT */ uint8_t ticker_start(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, uint32_t ticks_anchor, uint32_t ticks_first, uint32_t ticks_periodic, uint32_t remainder_periodic, uint16_t lazy, uint32_t ticks_slot, ticker_timeout_func fp_timeout_func, void *context, ticker_op_func fp_op_func, void *op_context) -#endif +{ + return ticker_start_us(instance_index, user_id, + ticker_id, ticks_anchor, + ticks_first, 0U, + ticks_periodic, remainder_periodic, + lazy, ticks_slot, + fp_timeout_func, context, + fp_op_func, op_context); +} + +uint8_t ticker_start_us(uint8_t instance_index, uint8_t user_id, + uint8_t ticker_id, uint32_t ticks_anchor, + uint32_t ticks_first, uint32_t remainder_first, + uint32_t ticks_periodic, uint32_t remainder_periodic, + uint16_t lazy, uint32_t ticks_slot, + ticker_timeout_func fp_timeout_func, void *context, + ticker_op_func fp_op_func, void *op_context) +#endif /* !CONFIG_BT_TICKER_EXT */ + { struct ticker_instance *instance = &_instance[instance_index]; struct ticker_user_op *user_op; @@ -3347,6 +3433,9 @@ uint8_t ticker_start(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, user_op->id = ticker_id; user_op->params.start.ticks_at_start = ticks_anchor; user_op->params.start.ticks_first = ticks_first; +#if defined(CONFIG_BT_TICKER_REMAINDER) + user_op->params.start.remainder_first = remainder_first; +#endif /* !CONFIG_BT_TICKER_REMAINDER */ user_op->params.start.ticks_periodic = ticks_periodic; user_op->params.start.remainder_periodic = remainder_periodic; #if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) @@ -3362,6 +3451,8 @@ uint8_t ticker_start(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), @@ -3410,11 +3501,12 @@ uint8_t ticker_update(uint8_t instance_index, uint8_t user_id, uint32_t ticks_slot_minus, uint16_t lazy, uint8_t force, ticker_op_func fp_op_func, void *op_context) #if defined(CONFIG_BT_TICKER_EXT) +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) { return ticker_update_ext(instance_index, user_id, ticker_id, ticks_drift_plus, ticks_drift_minus, ticks_slot_plus, ticks_slot_minus, lazy, - force, fp_op_func, op_context, 0, ticker_id); + force, fp_op_func, op_context, 0U, ticker_id); } uint8_t ticker_update_ext(uint8_t instance_index, uint8_t user_id, @@ -3424,6 +3516,22 @@ uint8_t ticker_update_ext(uint8_t instance_index, uint8_t user_id, uint16_t lazy, uint8_t force, ticker_op_func fp_op_func, void *op_context, uint8_t must_expire, uint8_t expire_info_id) +#else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +{ + return ticker_update_ext(instance_index, user_id, ticker_id, + ticks_drift_plus, ticks_drift_minus, + ticks_slot_plus, ticks_slot_minus, lazy, + force, fp_op_func, op_context, 0U); +} + +uint8_t ticker_update_ext(uint8_t instance_index, uint8_t user_id, + uint8_t ticker_id, uint32_t ticks_drift_plus, + uint32_t ticks_drift_minus, + uint32_t ticks_slot_plus, uint32_t ticks_slot_minus, + uint16_t lazy, uint8_t force, + ticker_op_func fp_op_func, void *op_context, + uint8_t must_expire) +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ #endif /* CONFIG_BT_TICKER_EXT */ { struct ticker_instance *instance = &_instance[instance_index]; @@ -3457,12 +3565,16 @@ uint8_t ticker_update_ext(uint8_t instance_index, uint8_t user_id, #if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) && !defined(CONFIG_BT_TICKER_LOW_LAT) user_op->params.update.must_expire = must_expire; #endif /* CONFIG_BT_TICKER_EXT && !CONFIG_BT_TICKER_SLOT_AGNOSTIC && !CONFIG_BT_TICKER_LOW_LAT */ +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) user_op->params.update.expire_info_id = expire_info_id; +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ #endif /* CONFIG_BT_TICKER_EXT */ user_op->status = TICKER_STATUS_BUSY; user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), @@ -3519,6 +3631,8 @@ uint8_t ticker_yield_abs(uint8_t instance_index, uint8_t user_id, user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), @@ -3571,6 +3685,8 @@ uint8_t ticker_stop(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), @@ -3626,6 +3742,8 @@ uint8_t ticker_stop_abs(uint8_t instance_index, uint8_t user_id, user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), @@ -3720,6 +3838,8 @@ uint8_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id, user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), @@ -3774,6 +3894,8 @@ uint8_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id, user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), @@ -3835,6 +3957,8 @@ uint8_t ticker_priority_set(uint8_t instance_index, uint8_t user_id, uint8_t tic user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; + /* Make sure transaction is completed before committing */ + cpu_dmb(); user->last = last; instance->sched_cb(instance->caller_id_get_cb(user_id), diff --git a/subsys/bluetooth/controller/ticker/ticker.h b/subsys/bluetooth/controller/ticker/ticker.h index 0b0d0bf88c3..aa19ecbff8f 100644 --- a/subsys/bluetooth/controller/ticker/ticker.h +++ b/subsys/bluetooth/controller/ticker/ticker.h @@ -64,16 +64,24 @@ #if defined(CONFIG_BT_TICKER_EXT) #if defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) #define TICKER_USER_OP_T_SIZE 44 -#else +#else /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ +#if defined(CONFIG_BT_TICKER_REMAINDER) +#define TICKER_USER_OP_T_SIZE 52 +#else /* !CONFIG_BT_TICKER_REMAINDER */ #define TICKER_USER_OP_T_SIZE 48 -#endif /* CONFIG_BT_TICKER_SLOT_AGNOSTIC */ -#else +#endif /* !CONFIG_BT_TICKER_REMAINDER */ +#endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ +#else /* !CONFIG_BT_TICKER_EXT */ #if defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) #define TICKER_USER_OP_T_SIZE 40 -#else +#else /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ +#if defined(CONFIG_BT_TICKER_REMAINDER) +#define TICKER_USER_OP_T_SIZE 48 +#else /* !CONFIG_BT_TICKER_REMAINDER */ #define TICKER_USER_OP_T_SIZE 44 -#endif /* CONFIG_BT_TICKER_SLOT_AGNOSTIC */ -#endif /* CONFIG_BT_TICKER_EXT */ +#endif /* !CONFIG_BT_TICKER_REMAINDER */ +#endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ +#endif /* !CONFIG_BT_TICKER_EXT */ #define TICKER_CALL_ID_NONE 0 #define TICKER_CALL_ID_ISR 1 @@ -158,6 +166,13 @@ uint8_t ticker_start(uint8_t instance_index, uint8_t user_id, uint32_t ticks_slot, ticker_timeout_func fp_timeout_func, void *context, ticker_op_func fp_op_func, void *op_context); +uint8_t ticker_start_us(uint8_t instance_index, uint8_t user_id, + uint8_t ticker_id, uint32_t ticks_anchor, + uint32_t ticks_first, uint32_t remainder_first, + uint32_t ticks_periodic, uint32_t remainder_periodic, + uint16_t lazy, uint32_t ticks_slot, + ticker_timeout_func fp_timeout_func, void *context, + ticker_op_func fp_op_func, void *op_context); uint8_t ticker_update(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, uint32_t ticks_drift_plus, uint32_t ticks_drift_minus, uint32_t ticks_slot_plus, @@ -197,8 +212,6 @@ uint8_t ticker_priority_set(uint8_t instance_index, uint8_t user_id, #if defined(CONFIG_BT_TICKER_EXT) struct ticker_ext { - ticker_timeout_func ext_timeout_func; - #if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) uint32_t ticks_slot_window;/* Window in which the slot * reservation may be re-scheduled @@ -210,12 +223,16 @@ struct ticker_ext { * TICKER_RESCHEDULE_STATE_XXX */ #endif /* CONFIG_BT_TICKER_SLOT_AGNOSTIC */ + +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) uint8_t expire_info_id; /* Other ticker ID for which * the ext_timeout_func should include expire * info for * Set to TICKER_NULL if not used */ + ticker_timeout_func ext_timeout_func; void *other_expire_info; +#endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ }; uint8_t ticker_start_ext(uint8_t instance_index, uint8_t user_id, @@ -226,6 +243,8 @@ uint8_t ticker_start_ext(uint8_t instance_index, uint8_t user_id, ticker_timeout_func fp_timeout_func, void *context, ticker_op_func fp_op_func, void *op_context, struct ticker_ext *ext_data); + +#if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) uint8_t ticker_update_ext(uint8_t instance_index, uint8_t user_id, uint8_t ticker_id, uint32_t ticks_drift_plus, uint32_t ticks_drift_minus, @@ -233,4 +252,14 @@ uint8_t ticker_update_ext(uint8_t instance_index, uint8_t user_id, uint16_t lazy, uint8_t force, ticker_op_func fp_op_func, void *op_context, uint8_t must_expire, uint8_t expire_info_id); +#else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +uint8_t ticker_update_ext(uint8_t instance_index, uint8_t user_id, + uint8_t ticker_id, uint32_t ticks_drift_plus, + uint32_t ticks_drift_minus, + uint32_t ticks_slot_plus, uint32_t ticks_slot_minus, + uint16_t lazy, uint8_t force, + ticker_op_func fp_op_func, void *op_context, + uint8_t must_expire); +#endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ + #endif /* CONFIG_BT_TICKER_EXT */ diff --git a/subsys/bluetooth/controller/util/mayfly.c b/subsys/bluetooth/controller/util/mayfly.c index e8de3acfd80..b55340ca055 100644 --- a/subsys/bluetooth/controller/util/mayfly.c +++ b/subsys/bluetooth/controller/util/mayfly.c @@ -8,6 +8,9 @@ #include #include #include + +#include "hal/cpu.h" + #include "memq.h" #include "mayfly.h" @@ -154,10 +157,12 @@ static void dequeue(uint8_t callee_id, uint8_t caller_id, memq_link_t *link, m->_link = link; /* reset mayfly state to idle */ + cpu_dmb(); ack = m->_ack; m->_ack = req; /* re-insert, if re-pended by interrupt */ + cpu_dmb(); if (((m->_req - ack) & 0x03) == 1U) { #if defined(MAYFLY_UT) printk("%s: RACE\n", __func__); diff --git a/subsys/bluetooth/controller/util/mem.c b/subsys/bluetooth/controller/util/mem.c index 760db75df99..1bd67ee7eb1 100644 --- a/subsys/bluetooth/controller/util/mem.c +++ b/subsys/bluetooth/controller/util/mem.c @@ -97,12 +97,12 @@ uint16_t mem_free_count_get(void *mem_head) return free_count; } -void *mem_get(void *mem_pool, uint16_t mem_size, uint16_t index) +void *mem_get(const void *mem_pool, uint16_t mem_size, uint16_t index) { return ((void *)((uint8_t *)mem_pool + (mem_size * index))); } -uint16_t mem_index_get(void *mem, void *mem_pool, uint16_t mem_size) +uint16_t mem_index_get(const void *mem, const void *mem_pool, uint16_t mem_size) { return ((uint8_t *)mem - (uint8_t *)mem_pool) / mem_size; } diff --git a/subsys/bluetooth/controller/util/mem.h b/subsys/bluetooth/controller/util/mem.h index a2b8f88001e..8a8bdb3a62d 100644 --- a/subsys/bluetooth/controller/util/mem.h +++ b/subsys/bluetooth/controller/util/mem.h @@ -58,8 +58,8 @@ void *mem_acquire(void **mem_head); void mem_release(void *mem, void **mem_head); uint16_t mem_free_count_get(void *mem_head); -void *mem_get(void *mem_pool, uint16_t mem_size, uint16_t index); -uint16_t mem_index_get(void *mem, void *mem_pool, uint16_t mem_size); +void *mem_get(const void *mem_pool, uint16_t mem_size, uint16_t index); +uint16_t mem_index_get(const void *mem, const void *mem_pool, uint16_t mem_size); void mem_rcopy(uint8_t *dst, uint8_t const *src, uint16_t len); uint8_t mem_nz(uint8_t *src, uint16_t len);