diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index f9b516eef..ade813fcd 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -135,7 +135,9 @@ struct hci_conn_update; #define BLE_GAP_EVENT_PERIODIC_SYNC_LOST 22 #define BLE_GAP_EVENT_SCAN_REQ_RCVD 23 #define BLE_GAP_EVENT_PERIODIC_TRANSFER 24 -#define BLE_GAP_EVENT_SUBRATE_CHANGE 25 +#define BLE_GAP_EVENT_PATHLOSS_THRESHOLD 25 +#define BLE_GAP_EVENT_TRANSMIT_POWER 26 +#define BLE_GAP_EVENT_SUBRATE_CHANGE 27 /*** Reason codes for the subscribe GAP event. */ @@ -974,8 +976,57 @@ struct ble_gap_event { uint8_t adv_clk_accuracy; } periodic_transfer; #endif + +#if MYNEWT_VAL(BLE_POWER_CONTROL) + /** + * Represents a change in either local transmit power or remote transmit + * power. Valid for the following event types: + * o BLE_GAP_EVENT_PATHLOSS_THRESHOLD + */ + + struct { + /** Connection handle */ + uint16_t conn_handle; + + /** Current Path Loss */ + uint8_t current_path_loss; + + /** Entered Zone */ + uint8_t zone_entered; + } pathloss_threshold; + + /** + * Represents crossing of path loss threshold set via LE Set Path Loss + * Reporting Parameter command. Valid for the following event types: + * o BLE_GAP_EVENT_TRANSMIT_POWER + */ + + struct { + /** BLE_ERR_SUCCESS on success or error code on failure */ + uint8_t status; + + /** Connection Handle */ + uint16_t conn_handle; + + /** Reason indicating why event was sent */ + uint8_t reason; + + /** Advertising PHY */ + uint8_t phy; + + /** Transmit power Level */ + uint8_t transmit_power_level; + + /** Transmit Power Level Flag */ + uint8_t transmit_power_level_flag; + + /** Delta indicating change in transmit Power Level */ + uint8_t delta; + } transmit_power; +#endif + #if MYNEWT_VAL(BLE_CONN_SUBRATING) - /** + /** * Represents a subrate change event that indicates connection subrate update procedure * has completed and some parameters have changed Valid for * the following event types: @@ -2180,7 +2231,6 @@ ble_gap_subrate_req(uint16_t conn_handle, uint16_t subrate_min, uint16_t subrate uint16_t max_latency, uint16_t cont_num, uint16_t supervision_timeout); #endif - /** * Event listener structure * @@ -2220,6 +2270,79 @@ int ble_gap_event_listener_register(struct ble_gap_event_listener *listener, */ int ble_gap_event_listener_unregister(struct ble_gap_event_listener *listener); +/** + * Enable Set Path Loss Reporting. + * + * @param conn_handle Connection handle + * @params enable 1: Enable + * 0: Disable + * + * @return 0 on success; nonzero on failure. + */ + +int ble_gap_set_path_loss_reporting_enable(uint16_t conn_handle, uint8_t enable); + +/** + * Enable Reporting of Transmit Power + * + * @param conn_handle Connection handle + * @params local_enable 1: Enable local transmit power reports + * 0: Disable local transmit power reports + * + * @params remote_enable 1: Enable remote transmit power reports + * 0: Disable remote transmit power reports + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_set_transmit_power_reporting_enable(uint16_t conn_handle, + uint8_t local_enable, + uint8_t remote_enable); + +/** + * LE Enhanced Read Transmit Power Level + * + * @param conn_handle Connection handle + * @params phy Advertising Phy + * + * @params status 0 on success; nonzero on failure. + * @params conn_handle Connection handle + * @params phy Advertising Phy + * + * @params curr_tx_power_level Current trasnmit Power Level + * + * @params mx_tx_power_level Maximum transmit power level + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_enh_read_transmit_power_level(uint16_t conn_handle, uint8_t phy, uint8_t *out_status, uint8_t *out_phy , + uint8_t *out_curr_tx_power_level, uint8_t *out_max_tx_power_level); + +/** + * Read Remote Transmit Power Level + * + * @param conn_handle Connection handle + * @params phy Advertising Phy + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_read_remote_transmit_power_level(uint16_t conn_handle, uint8_t phy); + +/** + * Set Path Loss Reproting Param + * + * @param conn_handle Connection handle + * @params high_threshold High Threshold value for path loss + * @params high_hysteresis Hysteresis value for high threshold + * @params low_threshold Low Threshold value for path loss + * @params low_hysteresis Hysteresis value for low threshold + * @params min_time_spent Minimum time controller observes the path loss + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_set_path_loss_reporting_param(uint16_t conn_handle, uint8_t high_threshold, + uint8_t high_hysteresis, uint8_t low_threshold, + uint8_t low_hysteresis, uint16_t min_time_spent); + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index f8f940bf5..45a5f6be1 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -1771,6 +1771,42 @@ ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_ } #endif +#if MYNEWT_VAL(BLE_POWER_CONTROL) +void +ble_gap_rx_le_pathloss_threshold(const struct ble_hci_ev_le_subev_path_loss_threshold *ev) +{ + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + + event.type = BLE_GAP_EVENT_PATHLOSS_THRESHOLD; + event.pathloss_threshold.conn_handle = le16toh(ev->conn_handle); + event.pathloss_threshold.current_path_loss = ev->current_path_loss; + event.pathloss_threshold.zone_entered = ev->zone_entered; + + ble_gap_event_listener_call(&event); +} + +void +ble_gap_rx_transmit_power_report(const struct ble_hci_ev_le_subev_transmit_power_report *ev) +{ + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + + event.type = BLE_GAP_EVENT_TRANSMIT_POWER; + event.transmit_power.status = ev->status; + event.transmit_power.conn_handle = le16toh(ev->conn_handle); + event.transmit_power.reason = ev->reason; + event.transmit_power.phy = ev->phy; + event.transmit_power.transmit_power_level = ev->transmit_power_level; + event.transmit_power.transmit_power_level_flag = ev->transmit_power_level_flag; + event.transmit_power.delta = ev->delta; + + ble_gap_event_listener_call(&event); +} +#endif + #if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) static int periodic_adv_transfer_disable(uint16_t conn_handle) @@ -6619,3 +6655,122 @@ ble_gap_deinit(void) { ble_npl_mutex_deinit(&preempt_done_mutex); } + +int +ble_gap_enh_read_transmit_power_level(uint16_t conn_handle, uint8_t phy, uint8_t *out_status, uint8_t *out_phy , + uint8_t *out_curr_tx_power_level, uint8_t *out_max_tx_power_level) + +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_enh_read_transmit_power_level_cp cmd; + struct ble_hci_le_enh_read_transmit_power_level_rp rsp; + uint16_t opcode; + int rc; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ENH_READ_TRANSMIT_POWER_LEVEL); + + cmd.conn_handle = htole16(conn_handle); + cmd.phy = phy; + + rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), &rsp, sizeof(rsp)); + + if (rc!=0) { + return rc; + } + + *out_status = rsp.status; + *out_phy = rsp.phy; + *out_curr_tx_power_level = rsp.curr_tx_power_level; + *out_max_tx_power_level = rsp.max_tx_power_level; + + return 0; +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_read_remote_transmit_power_level(uint16_t conn_handle, + uint8_t phy) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_read_remote_transmit_power_level_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL); + + cmd.conn_handle = htole16(conn_handle); + cmd.phy = phy; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_set_path_loss_reporting_param(uint16_t conn_handle, + uint8_t high_threshold, + uint8_t high_hysteresis, + uint8_t low_threshold, + uint8_t low_hysteresis, + uint16_t min_time_spent) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_set_path_loss_report_param_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_PARAM); + + cmd.conn_handle = htole16(conn_handle); + cmd.high_threshold = high_threshold; + cmd.high_hysteresis = high_hysteresis; + cmd.low_threshold = low_threshold; + cmd.low_hysteresis = low_hysteresis; + cmd.min_time_spent = min_time_spent; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_set_path_loss_reporting_enable(uint16_t conn_handle, + uint8_t enable) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_set_path_loss_report_enable_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_ENABLE); + + cmd.conn_handle = htole16(conn_handle); + cmd.enable = enable; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_set_transmit_power_reporting_enable(uint16_t conn_handle, + uint8_t local_enable, + uint8_t remote_enable) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_set_transmit_power_report_enable_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_TRANS_PWR_REPORT_ENABLE); + + cmd.conn_handle = htole16(conn_handle); + cmd.local_enable = local_enable; + cmd.remote_enable = remote_enable; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index db3b63647..ef2adbb2d 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -95,6 +95,10 @@ void ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem #if MYNEWT_VAL(BLE_CONN_SUBRATING) void ble_gap_rx_subrate_change(const struct ble_hci_ev_le_subev_subrate_change *ev); #endif +#if MYNEWT_VAL(BLE_POWER_CONTROL) +void ble_gap_rx_transmit_power_report(const struct ble_hci_ev_le_subev_transmit_power_report *ev); +void ble_gap_rx_le_pathloss_threshold(const struct ble_hci_ev_le_subev_path_loss_threshold *ev); +#endif struct ble_gap_conn_complete { diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index c7da77ab3..719a58e5f 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -79,13 +79,16 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_rpt; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_lost; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_scan_req_rcvd; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_transfer; +#if MYNEWT_VAL(BLE_POWER_CONTROL) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_pathloss_threshold; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_transmit_power_report; +#endif #if MYNEWT_VAL(BLE_CONN_SUBRATING) static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_subrate_change; #endif /* Statistics */ -struct host_hci_stats -{ +struct host_hci_stats { uint32_t events_rxd; uint32_t good_acks_rxd; uint32_t bad_acks_rxd; @@ -138,6 +141,10 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { [BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED] = ble_hs_hci_evt_le_adv_set_terminated, [BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD] = ble_hs_hci_evt_le_scan_req_rcvd, [BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER] = ble_hs_hci_evt_le_periodic_adv_sync_transfer, +#if MYNEWT_VAL(BLE_POWER_CONTROL) + [BLE_HCI_LE_SUBEV_PATH_LOSS_THRESHOLD] = ble_hs_hci_evt_le_pathloss_threshold, + [BLE_HCI_LE_SUBEV_TRANSMIT_POWER_REPORT] = ble_hs_hci_evt_le_transmit_power_report, +#endif #if MYNEWT_VAL(BLE_CONN_SUBRATING) [BLE_HCI_LE_SUBEV_SUBRATE_CHANGE] = ble_hs_hci_evt_le_subrate_change, #endif @@ -755,6 +762,36 @@ ble_hs_hci_evt_le_periodic_adv_sync_lost(uint8_t subevent, const void *data, return 0; } +#if MYNEWT_VAL(BLE_POWER_CONTROL) +static int +ble_hs_hci_evt_le_pathloss_threshold(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_path_loss_threshold *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_gap_rx_le_pathloss_threshold(ev); + return 0; +} + +static int +ble_hs_hci_evt_le_transmit_power_report(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_transmit_power_report *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_gap_rx_transmit_power_report(ev); + return 0; +} +#endif + static int ble_hs_hci_evt_le_periodic_adv_sync_transfer(uint8_t subevent, const void *data, unsigned int len) diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c index a66e43369..fa8b7f44a 100644 --- a/nimble/host/src/ble_hs_startup.c +++ b/nimble/host/src/ble_hs_startup.c @@ -245,6 +245,16 @@ ble_hs_startup_le_set_evmask_tx(void) * 0x0000000400000000 LE Subrate change event */ mask |= 0x0000000400000000; +#endif + +#if MYNEWT_VAL(BLE_POWER_CONTROL) + if (version >= BLE_HCI_VER_BCS_5_2) { + /** + * Enable the following LE events: + * 0x0000000080000000 LE Path Loss Threshold event + * 0x0000000100000000 LE Transmit Power Reporting event + */ + mask |= 0x0000000180000000; } #endif diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 1c26681ce..f50b32551 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -1061,7 +1061,49 @@ struct ble_hci_le_set_host_feat_cp { uint8_t val; } __attribute__((packed)); -#define BLE_HCI_OCF_LE_SET_DEFAULT_SUBRATE (0x007D) +#define BLE_HCI_OCF_LE_ENH_READ_TRANSMIT_POWER_LEVEL (0x0076) +struct ble_hci_le_enh_read_transmit_power_level_cp { + uint16_t conn_handle; + uint8_t phy; +} __attribute__((packed)); +struct ble_hci_le_enh_read_transmit_power_level_rp { + uint8_t status; + uint16_t conn_handle; + uint8_t phy; + uint8_t curr_tx_power_level; + uint8_t max_tx_power_level; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL (0x0077) +struct ble_hci_le_read_remote_transmit_power_level_cp { + uint16_t conn_handle; + uint8_t phy; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_PARAM (0x0078) +struct ble_hci_le_set_path_loss_report_param_cp { + uint16_t conn_handle; + uint8_t high_threshold; + uint8_t high_hysteresis; + uint8_t low_threshold; + uint8_t low_hysteresis; + uint16_t min_time_spent; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_ENABLE (0x0079) +struct ble_hci_le_set_path_loss_report_enable_cp { + uint16_t conn_handle; + uint8_t enable; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_TRANS_PWR_REPORT_ENABLE (0x007A) +struct ble_hci_le_set_transmit_power_report_enable_cp { + uint16_t conn_handle; + uint8_t local_enable; + uint8_t remote_enable; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_DEFAULT_SUBRATE (0x007D) struct ble_hci_le_set_default_subrate_cp { uint16_t subrate_min; uint16_t subrate_max; @@ -1070,7 +1112,7 @@ struct ble_hci_le_set_default_subrate_cp { uint16_t supervision_tmo; } __attribute__((packed)); -#define BLE_HCI_OCF_LE_SUBRATE_REQ (0x007E) +#define BLE_HCI_OCF_LE_SUBRATE_REQ (0x007E) struct ble_hci_le_subrate_req_cp { uint16_t conn_handle; uint16_t subrate_min; @@ -1791,6 +1833,26 @@ struct ble_hci_ev_le_subev_peer_sca_complete { uint8_t sca; } __attribute__((packed)); +#define BLE_HCI_LE_SUBEV_PATH_LOSS_THRESHOLD (0x20) +struct ble_hci_ev_le_subev_path_loss_threshold { + uint8_t subev_code; + uint16_t conn_handle; + uint8_t current_path_loss; + uint8_t zone_entered; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_TRANSMIT_POWER_REPORT (0x21) +struct ble_hci_ev_le_subev_transmit_power_report { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t reason; + uint8_t phy; + uint8_t transmit_power_level; + uint8_t transmit_power_level_flag; + uint8_t delta; +} __attribute__((packed)); + #define BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT (0x22) struct ble_hci_ev_le_subev_biginfo_adv_report { uint8_t subev_code; @@ -1809,7 +1871,7 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { uint8_t encryption; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_SUBRATE_CHANGE (0x23) +#define BLE_HCI_LE_SUBEV_SUBRATE_CHANGE (0x23) struct ble_hci_ev_le_subev_subrate_change { uint8_t subev_code; uint8_t status; @@ -1820,7 +1882,6 @@ struct ble_hci_ev_le_subev_subrate_change { uint16_t supervision_tmo; } __attribute__((packed)); - /* Data buffer overflow event */ #define BLE_HCI_EVENT_ACL_BUF_OVERFLOW (0x01)