diff --git a/ble/gap_le.h b/ble/gap_le.h index 7e7b45a70..d16a211f3 100644 --- a/ble/gap_le.h +++ b/ble/gap_le.h @@ -82,6 +82,18 @@ gap_random_address_type_t gap_random_address_get_mode(void); int gap_update_connection_parameters(hci_con_handle_t con_handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout); +/** + * @brief Request an update of the connection parameter for a given LE connection + * @param handle + * @param conn_interval_min (unit: 1.25ms) + * @param conn_interval_max (unit: 1.25ms) + * @param conn_latency + * @param supervision_timeout (unit: 10ms) + * @returns 0 if ok + */ +int gap_request_connection_parameter_update(hci_con_handle_t con_handle, uint16_t conn_interval_min, + uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout); + /** * @brief Set Advertisement Data * @param advertising_data_length diff --git a/src/hci.c b/src/hci.c index 3913b55ad..c7cf90f92 100644 --- a/src/hci.c +++ b/src/hci.c @@ -3091,6 +3091,28 @@ int gap_update_connection_parameters(hci_con_handle_t con_handle, uint16_t conn_ return 0; } +/** + * @brief Request an update of the connection parameter for a given LE connection + * @param handle + * @param conn_interval_min (unit: 1.25ms) + * @param conn_interval_max (unit: 1.25ms) + * @param conn_latency + * @param supervision_timeout (unit: 10ms) + * @returns 0 if ok + */ +int gap_request_connection_parameter_update(hci_con_handle_t con_handle, uint16_t conn_interval_min, + uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout){ + hci_connection_t * connection = hci_connection_for_handle(con_handle); + if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + connection->le_conn_interval_min = conn_interval_min; + connection->le_conn_interval_max = conn_interval_max; + connection->le_conn_latency = conn_latency; + connection->le_supervision_timeout = supervision_timeout; + connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_SEND_REQUEST; + hci_run(); + return 0; +} + /** * @brief Set Advertisement Data * @param advertising_data_length diff --git a/src/hci.h b/src/hci.h index 0158ff70a..52a14a67b 100644 --- a/src/hci.h +++ b/src/hci.h @@ -242,6 +242,7 @@ extern "C" { typedef enum { CON_PARAMETER_UPDATE_NONE, + CON_PARAMETER_UPDATE_SEND_REQUEST, CON_PARAMETER_UPDATE_SEND_RESPONSE, CON_PARAMETER_UPDATE_CHANGE_HCI_CON_PARAMETERS, CON_PARAMETER_UPDATE_DENY diff --git a/src/l2cap.c b/src/l2cap.c index 1bedef9e4..73539a849 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -705,24 +705,24 @@ void l2cap_run(void){ hci_connections_get_iterator(&it); while(linked_list_iterator_has_next(&it)){ hci_connection_t * connection = (hci_connection_t *) linked_list_iterator_next(&it); - int result; - + if (!hci_can_send_acl_packet_now(connection->con_handle)) continue; switch (connection->le_con_parameter_update_state){ + case CON_PARAMETER_UPDATE_SEND_REQUEST: + connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE; + l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_REQUEST, connection->le_con_param_update_identifier, + connection->le_conn_interval_min, connection->le_conn_interval_max, connection->le_conn_latency, connection->le_supervision_timeout); + break; case CON_PARAMETER_UPDATE_SEND_RESPONSE: - result = 0; + connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_CHANGE_HCI_CON_PARAMETERS; + l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 0); break; case CON_PARAMETER_UPDATE_DENY: - result = 1; + connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE; + l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 1); break; default: - result = -1; break; } - if (result < 0) continue; - if (!hci_can_send_acl_packet_now(connection->con_handle)) break; - - connection->le_con_parameter_update_state = (result == 0) ? CON_PARAMETER_UPDATE_CHANGE_HCI_CON_PARAMETERS : CON_PARAMETER_UPDATE_NONE; - l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, result); } #endif @@ -1584,16 +1584,7 @@ void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint1 // Request LE connection parameter update int l2cap_le_request_connection_parameter_update(uint16_t handle, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier){ - if (!hci_can_send_acl_packet_now(handle)){ - log_info("l2cap_send_signaling_packet, cannot send"); - return BTSTACK_ACL_BUFFERS_FULL; - } - // log_info("l2cap_send_signaling_packet type %u", cmd); - hci_reserve_packet_buffer(); - uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); - // TODO: find better way to get signaling identifier - uint16_t len = l2cap_le_create_connection_parameter_update_request(acl_buffer, handle, 1, interval_min, interval_max, slave_latency, timeout_multiplier); - return hci_send_acl_packet_buffer(len); + return gap_request_connection_parameter_update(handle, interval_min, interval_max, slave_latency, timeout_multiplier); } #endif diff --git a/src/l2cap_signaling.c b/src/l2cap_signaling.c index 3d3a796d6..85301f59c 100644 --- a/src/l2cap_signaling.c +++ b/src/l2cap_signaling.c @@ -149,39 +149,7 @@ uint16_t l2cap_create_signaling_classic(uint8_t * acl_buffer, hci_con_handle_t h } #ifdef HAVE_BLE - uint16_t l2cap_create_signaling_le(uint8_t * acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){ return l2cap_create_signaling_internal(acl_buffer, handle, 5, cmd, identifier, argptr); } - -uint16_t l2cap_le_create_connection_parameter_update_request(uint8_t * acl_buffer, uint16_t handle, uint8_t identifier, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier){ - - int pb = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02; - - // 0 - Connection handle : PB=pb : BC=00 - bt_store_16(acl_buffer, 0, handle | (pb << 12) | (0 << 14)); - // 6 - L2CAP LE Signaling channel = 5 - bt_store_16(acl_buffer, 6, 5); - // 8 - Code - acl_buffer[8] = CONNECTION_PARAMETER_UPDATE_REQUEST; - // 9 - id - acl_buffer[9] = identifier; - uint16_t pos = 12; - bt_store_16(acl_buffer, pos, interval_min); - pos += 2; - bt_store_16(acl_buffer, pos, interval_max); - pos += 2; - bt_store_16(acl_buffer, pos, slave_latency); - pos += 2; - bt_store_16(acl_buffer, pos, timeout_multiplier); - pos += 2; - // 2 - ACL length - bt_store_16(acl_buffer, 2, pos - 4); - // 4 - L2CAP packet length - bt_store_16(acl_buffer, 4, pos - 6 - 2); - // 10 - L2CAP signaling parameter length - bt_store_16(acl_buffer, 10, pos - 12); - return pos; -} - #endif diff --git a/src/l2cap_signaling.h b/src/l2cap_signaling.h index 8fe9ccfbb..9106fb084 100644 --- a/src/l2cap_signaling.h +++ b/src/l2cap_signaling.h @@ -76,7 +76,6 @@ typedef enum { uint16_t l2cap_create_signaling_classic(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr); uint16_t l2cap_create_signaling_le(uint8_t * acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr); -uint16_t l2cap_le_create_connection_parameter_update_request(uint8_t * acl_buffer, uint16_t handle, uint8_t identifier, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier); uint8_t l2cap_next_sig_id(void); uint16_t l2cap_next_local_cid(void);