diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 3feeb22c7..c1d0b3e80 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -186,6 +186,8 @@ struct hci_conn_update; #define BLE_GAP_EVENT_MONITOR_ADV_REPORT 52 #define BLE_GAP_EVENT_CACHE_ASSOC 53 +#define BLE_GAP_EVENT_FRAME_SPACE_UPDATE 54 +#define BLE_GAP_EVENT_UTP_RECEIVE 55 /* DTM events */ #define BLE_GAP_DTM_TX_START_EVT 0 @@ -2038,6 +2040,54 @@ struct ble_gap_event { } monitor_adv_report; #endif + +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) + /* + * Represents a change in the Inter-Frame Space (IFS). + */ + struct { + /* The status of the frame space update attempt (0 on success). */ + int status; + + /* The handle of the connection where the update occurred. */ + uint16_t conn_handle; + + /* + * Indicates whether the local Host initiated the update. + * 0: Controller initiated + * 1: Local Host initiated + */ + uint8_t initiator; + + /* The new frame space value in microseconds. */ + uint16_t frame_space; + + /* Bitmask indicating the PHYs to which the frame space applies. */ + uint8_t phys; + + /* Bitmask indicating the spacing types. */ + uint16_t spacing_types; + } frame_space_update; +#endif + +#if MYNEWT_VAL(BLE_UTP_OTA) + /* + * Represents a received Unified Test Protocol (UTP) packet. + */ + struct { + /* The connection handle associated with the packet. + * Note: Currently set to BLE_HS_CONN_HANDLE_NONE as the + * controller event does not provide a handle. + */ + uint16_t conn_handle; + + /* The length of the UTP data payload. */ + uint8_t len; + + /* Pointer to the UTP data payload. */ + const uint8_t *data; + } utp_receive; +#endif }; }; @@ -4175,6 +4225,24 @@ int ble_gap_read_local_irk(uint8_t * out_irk); int ble_gap_set_host_feat(uint8_t bit_num,uint8_t bit_val); #endif +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) +/* * Request a Frame Space Update. + * phys: Bitmask of PHYs (0=1M, 1=2M, 2=Coded) + * spacing_types: Bitmask of spacing types to update + */ +int ble_gap_frame_space_update(uint16_t conn_handle, + uint16_t frame_space_min, + uint16_t frame_space_max, + uint8_t phys, + uint16_t spacing_types); +#endif + +#if MYNEWT_VAL(BLE_UTP_OTA) +int ble_gap_enable_utp_ota_mode(uint8_t enable); + +int ble_gap_utp_send(uint8_t len, const uint8_t *data); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 9b572b6e8..e07e29556 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -2501,6 +2501,59 @@ ble_gap_rx_rd_monitor_adv_report(const struct ble_hci_ev_le_subev_monitor_adv_re } #endif +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) +void +ble_gap_rx_frame_space_update_complete(const struct ble_hci_ev_le_subev_frame_space_update_complete *ev) +{ +#if NIMBLE_BLE_CONNECT + struct ble_gap_event event; + uint16_t conn_handle; + + conn_handle = le16toh(ev->conn_handle); + + memset(&event, 0, sizeof(event)); + event.type = BLE_GAP_EVENT_FRAME_SPACE_UPDATE; + + event.frame_space_update.status = ev->status; + event.frame_space_update.conn_handle = conn_handle; + event.frame_space_update.initiator = ev->initiator; + event.frame_space_update.frame_space = le16toh(ev->frame_space); + event.frame_space_update.phys = ev->phys; + event.frame_space_update.spacing_types = le16toh(ev->spacing_types); + + ble_gap_event_listener_call(&event); + ble_gap_call_conn_event_cb(&event, conn_handle); +#endif +} +#endif + +#if MYNEWT_VAL(BLE_UTP_OTA) +void +ble_gap_rx_utp_receive(const struct ble_hci_ev_le_subev_utp_receive *ev, uint8_t len) +{ + struct ble_gap_event event; + const uint8_t *data_ptr; + + if (len < sizeof(*ev)) { + return; + } + + if (len < (sizeof(*ev) + ev->len)) { + return; + } + + data_ptr = (const uint8_t *)ev + sizeof(*ev); + + memset(&event, 0, sizeof(event)); + event.type = BLE_GAP_EVENT_UTP_RECEIVE; + event.utp_receive.conn_handle = BLE_HS_CONN_HANDLE_NONE; + event.utp_receive.len = ev->len; + event.utp_receive.data = data_ptr; + + ble_gap_event_listener_call(&event); +} +#endif + void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc) { @@ -10954,3 +11007,92 @@ bool ble_gap_rpa_resolve(uint8_t *rpa, uint8_t *ida, uint8_t *addr_type) return false; /* No match */ } + +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) +int +ble_gap_frame_space_update(uint16_t conn_handle, + uint16_t frame_space_min, + uint16_t frame_space_max, + uint8_t phys, + uint16_t spacing_types) +{ +#if NIMBLE_BLE_CONNECT + struct ble_hci_le_frame_space_update_cp cmd; + struct ble_hs_conn *conn; + + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + ble_hs_unlock(); + + if (conn == NULL) { + return BLE_HS_ENOTCONN; + } + + if (frame_space_min > 10000 || frame_space_max > 10000) { + return BLE_HS_EINVAL; + } + + if (frame_space_min > frame_space_max) { + return BLE_HS_EINVAL; + } + + if ((phys & ~0x07) || (phys == 0)) { + return BLE_HS_EINVAL; + } + + if ((spacing_types & ~0x1F) || (spacing_types == 0)) { + return BLE_HS_EINVAL; + } + + cmd.conn_handle = htole16(conn_handle); + cmd.frame_space_min = htole16(frame_space_min); + cmd.frame_space_max = htole16(frame_space_max); + cmd.phys = phys; + cmd.spacing_types = htole16(spacing_types); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_FRAME_SPACE_UPDATE), &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} +#endif + +#if MYNEWT_VAL(BLE_UTP_OTA) +int +ble_gap_enable_utp_ota_mode(uint8_t enable) +{ + struct ble_hci_le_enable_utp_ota_mode_cp cmd; + + if (enable > 1) { + return BLE_HS_EINVAL; + } + + cmd.enable = enable; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ENABLE_UTP_OTA_MODE), &cmd, sizeof(cmd), NULL, 0); +} + +int +ble_gap_utp_send(uint8_t len, const uint8_t *data) +{ + uint8_t buf[sizeof(struct ble_hci_le_utp_send_cp) + 254]; + struct ble_hci_le_utp_send_cp *cmd = (void *)buf; + + if (len == 0 || len > 254) { + return BLE_HS_EINVAL; + } + + cmd->len = len; + + if (data == NULL) + { + return BLE_HS_EINVAL; + } + memcpy(buf + sizeof(*cmd), data, len); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_UTP_SEND), cmd, sizeof(*cmd) + len, NULL, 0); +} +#endif \ No newline at end of file diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index 2d471ec20..bf5bef24a 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -208,6 +208,14 @@ void ble_gap_rx_rd_all_remote_feat(const struct ble_hci_ev_le_subev_rd_all_rem_f void ble_gap_rx_rd_monitor_adv_report(const struct ble_hci_ev_le_subev_monitor_adv_report *ev); #endif +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) +void ble_gap_rx_frame_space_update_complete(const struct ble_hci_ev_le_subev_frame_space_update_complete *ev); +#endif + +#if MYNEWT_VAL(BLE_UTP_OTA) +void ble_gap_rx_utp_receive(const struct ble_hci_ev_le_subev_utp_receive *ev, uint8_t len); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index 333c3f720..3cd94cb6b 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -215,6 +215,12 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_cis_estab_v2; #if NIMBLE_BLE_CONNECT static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_rd_all_rem_feat; #endif +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_frame_space_update; +#endif +#if MYNEWT_VAL(BLE_UTP_OTA) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_utp_receive; +#endif #if MYNEWT_VAL(BLE_MONITOR_ADV) static ble_hs_hci_evt_le_fn ble_hci_ev_le_subev_monitor_adv_report; #endif @@ -364,6 +370,12 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { #if MYNEWT_VAL(BLE_MONITOR_ADV) [BLE_HCI_LE_SUBEV_MONITOR_ADV_REPORT] = ble_hci_ev_le_subev_monitor_adv_report, #endif +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) + [BLE_HCI_LE_SUBEV_FRAME_SPACE_UPDATE_COMPLETE] = ble_hs_hci_evt_le_frame_space_update, +#endif +#if MYNEWT_VAL(BLE_UTP_OTA) + [BLE_HCI_LE_SUBEV_UTP_RECEIVE] = ble_hs_hci_evt_le_utp_receive, +#endif }; @@ -1858,6 +1870,39 @@ ble_hs_hci_evt_le_rd_all_rem_feat(uint8_t subevent, const void *data, #endif +#if MYNEWT_VAL(BLE_FRAME_SPACE_UPDATE) +static int +ble_hs_hci_evt_le_frame_space_update(uint8_t subevent, const void *data, unsigned int len) +{ + /* FSU is strictly a connection-oriented feature. + * If connections are disabled, ignore the event or return error. + */ +#if NIMBLE_BLE_CONNECT + if (len != sizeof(struct ble_hci_ev_le_subev_frame_space_update_complete)) { + return BLE_HS_EBADDATA; + } + ble_gap_rx_frame_space_update_complete(data); + return 0; +#else + return BLE_HS_ENOTSUP; +#endif +} +#endif + +#if MYNEWT_VAL(BLE_UTP_OTA) +static int +ble_hs_hci_evt_le_utp_receive(uint8_t subevent, const void *data, unsigned int len) +{ + const struct ble_hci_ev_le_subev_utp_receive *ev = data; + + if (len < sizeof(*ev) || len != (sizeof(*ev) + ev->len)) { + return BLE_HS_EBADDATA; + } + ble_gap_rx_utp_receive(data, (uint8_t)len); + return 0; +} +#endif + #if MYNEWT_VAL(BLE_MONITOR_ADV) static int ble_hci_ev_le_subev_monitor_adv_report(uint8_t subevent, const void *data, diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 56d86479e..8dec5526d 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -1583,6 +1583,25 @@ struct ble_hci_le_enable_monitor_adv_cp { uint8_t enable; } __attribute__((packed)); +#define BLE_HCI_OCF_LE_FRAME_SPACE_UPDATE (0x009D) +struct ble_hci_le_frame_space_update_cp { + uint16_t conn_handle; + uint16_t frame_space_min; + uint16_t frame_space_max; + uint8_t phys; + uint16_t spacing_types; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_ENABLE_UTP_OTA_MODE (0x009F) +struct ble_hci_le_enable_utp_ota_mode_cp { + uint8_t enable; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_UTP_SEND (0x00A0) +struct ble_hci_le_utp_send_cp { + uint8_t len; +} __attribute__((packed)); + /* --- Vendor specific commands (OGF 0x003F) */ /* Read Random Static Address */ #define BLE_HCI_OCF_VS_RD_STATIC_ADDR (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0001)) @@ -2608,6 +2627,23 @@ struct ble_hci_ev_le_subev_monitor_adv_report { uint8_t condition; } __attribute__((packed)); +#define BLE_HCI_LE_SUBEV_FRAME_SPACE_UPDATE_COMPLETE (0x35) +struct ble_hci_ev_le_subev_frame_space_update_complete { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t initiator; + uint16_t frame_space; + uint8_t phys; + uint16_t spacing_types; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_UTP_RECEIVE (0x36) +struct ble_hci_ev_le_subev_utp_receive { + uint8_t subev_code; + uint8_t len; +} __attribute__((packed)); + #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) // LE vendor hci event #define BLE_HCI_LE_SUBEV_DISCARD_REPORT_EVT 0XF0