diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h new file mode 100644 index 000000000..7b5381941 --- /dev/null +++ b/include/btstack/hci_cmds.h @@ -0,0 +1,1214 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/* + * hci_cmds.h + * + * Created by Matthias Ringwald on 7/23/09. + */ + +#ifndef __HCI_CMDS_H +#define __HCI_CMDS_H + +#include + +#if defined __cplusplus +extern "C" { +#endif + +/** + * packet types - used in BTstack and over the H4 UART interface + */ +#define HCI_COMMAND_DATA_PACKET 0x01 +#define HCI_ACL_DATA_PACKET 0x02 +#define HCI_SCO_DATA_PACKET 0x03 +#define HCI_EVENT_PACKET 0x04 + +// extension for client/server communication +#define DAEMON_EVENT_PACKET 0x05 + +// L2CAP data +#define L2CAP_DATA_PACKET 0x06 + +// RFCOMM data +#define RFCOMM_DATA_PACKET 0x07 + +// Attribute protocol data +#define ATT_DATA_PACKET 0x08 + +// Security Manager protocol data +#define SM_DATA_PACKET 0x09 + +// SDP query result +// format: type (8), record_id (16), attribute_id (16), attribute_length (16), attribute_value (max 1k) +#define SDP_CLIENT_PACKET 0x0a + +// BNEP data +#define BNEP_DATA_PACKET 0x0b + +// Unicast Connectionless Data +#define UCD_DATA_PACKET 0x0c + +// debug log messages +#define LOG_MESSAGE_PACKET 0xfc + + +// Fixed PSM numbers +#define PSM_SDP 0x01 +#define PSM_RFCOMM 0x03 +#define PSM_HID_CONTROL 0x11 +#define PSM_HID_INTERRUPT 0x13 +#define PSM_BNEP 0x0F + +// Events from host controller to host + +/** + * @format 1 + * @param status + */ +#define HCI_EVENT_INQUIRY_COMPLETE 0x01 +// no format yet, can contain multiple results + +/** + * @format 1B11132 + * @param num_responses + * @param bd_addr + * @param page_scan_repetition_mode + * @param reserved1 + * @param reserved2 + * @param class_of_device + * @param clock_offset + */ +#define HCI_EVENT_INQUIRY_RESULT 0x02 + +/** + * @format 12B11 + * @param status + * @param connection_handle + * @param bd_addr + * @param link_type + * @param encryption_enabled + */ +#define HCI_EVENT_CONNECTION_COMPLETE 0x03 +/** + * @format B31 + * @param bd_addr + * @param class_of_device + * @param link_type + */ +#define HCI_EVENT_CONNECTION_REQUEST 0x04 +/** + * @format 121 + * @param status + * @param connection_handle + * @param reason + */ +#define HCI_EVENT_DISCONNECTION_COMPLETE 0x05 +/** + * @format 12 + * @param status + * @param connection_handle + */ +#define HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT 0x06 +/** + * @format 1BN + * @param status + * @param bd_addr + * @param remote_name + */ +#define HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE 0x07 +/** + * @format 121 + * @param status + * @param connection_handle + * @param encryption_enabled + */ +#define HCI_EVENT_ENCRYPTION_CHANGE 0x08 +/** + * @format 12 + * @param status + * @param connection_handle + */ +#define HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE 0x09 +/** + * @format 121 + * @param status + * @param connection_handle + * @param key_flag + */ +#define HCI_EVENT_MASTER_LINK_KEY_COMPLETE 0x0A +#define HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE 0x0B +#define HCI_EVENT_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C +#define HCI_EVENT_QOS_SETUP_COMPLETE 0x0D + +/** + * @format 12R + * @param num_hci_command_packets + * @param command_opcode + * @param return_parameters + */ +#define HCI_EVENT_COMMAND_COMPLETE 0x0E +/** + * @format 112 + * @param status + * @param num_hci_command_packets + * @param command_opcode + */ +#define HCI_EVENT_COMMAND_STATUS 0x0F + +/** + * @format 121 + * @param hardware_code + */ +#define HCI_EVENT_HARDWARE_ERROR 0x10 + +#define HCI_EVENT_FLUSH_OCCURED 0x11 + +/** + * @format 1B1 + * @param status + * @param bd_addr + * @param role + */ +#define HCI_EVENT_ROLE_CHANGE 0x12 + +#define HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS 0x13 +#define HCI_EVENT_MODE_CHANGE_EVENT 0x14 +#define HCI_EVENT_RETURN_LINK_KEYS 0x15 +#define HCI_EVENT_PIN_CODE_REQUEST 0x16 +#define HCI_EVENT_LINK_KEY_REQUEST 0x17 +#define HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 +#define HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1A +#define HCI_EVENT_MAX_SLOTS_CHANGED 0x1B +#define HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE 0x1C +#define HCI_EVENT_PACKET_TYPE_CHANGED 0x1D + +/** + * @format 1B11321 + * @param num_responses + * @param bd_addr + * @param page_scan_repetition_mode + * @param reserved + * @param class_of_device + * @param clock_offset + * @param rssi + */ +#define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI 0x22 + +/** + * @format 1HB111221 + * @param status + * @param handle + * @param bd_addr + * @param link_type + * @param transmission_interval + * @param retransmission_interval + * @param rx_packet_length + * @param tx_packet_length + * @param air_mode + */ +#define HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE 0x2C + +// TODO: serialize extended_inquiry_response and provide parser +/** + * @format 1B11321 + * @param num_responses + * @param bd_addr + * @param page_scan_repetition_mode + * @param reserved + * @param class_of_device + * @param clock_offset + * @param rssi + */ +#define HCI_EVENT_EXTENDED_INQUIRY_RESPONSE 0x2F + + /** + * @format 1H + * @param status + * @param handle + */ +#define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30 + +#define HCI_EVENT_IO_CAPABILITY_REQUEST 0x31 +#define HCI_EVENT_IO_CAPABILITY_RESPONSE 0x32 +#define HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33 +#define HCI_EVENT_USER_PASSKEY_REQUEST 0x34 +#define HCI_EVENT_REMOTE_OOB_DATA_REQUEST 0x35 +#define HCI_EVENT_SIMPLE_PAIRING_COMPLETE 0x36 + +#define HCI_EVENT_LE_META 0x3E + +/** + * @format 11211B2221 + * @param subevent_code + * @param status + * @param connection_handle + * @param role + * @param peer_address_type + * @param peer_address + * @param conn_interval + * @param conn_latency + * @param supervision_timeout + * @param master_clock_accuracy + */ +#define HCI_SUBEVENT_LE_CONNECTION_COMPLETE 0x01 +#define HCI_SUBEVENT_LE_ADVERTISING_REPORT 0x02 +#define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE 0x03 +#define HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04 +#define HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST 0x05 + +// last used HCI_EVENT in 2.1 is 0x3d +// last used HCI_EVENT in 4.1 is 0x57 + +/** + * @format 1 + * @param state + */ +#define BTSTACK_EVENT_STATE 0x60 + +// data: event(8), len(8), nr hci connections +#define BTSTACK_EVENT_NR_CONNECTIONS_CHANGED 0x61 + +/** + * @format + */ +#define BTSTACK_EVENT_POWERON_FAILED 0x62 + +/** + * @format 112 + * @param major + * @param minor + @ @param revision + */ +#define BTSTACK_EVENT_VERSION 0x63 + +// data: system bluetooth on/off (bool) +#define BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED 0x64 + +// data: event (8), len(8), status (8) == 0, address (48), name (1984 bits = 248 bytes) +#define BTSTACK_EVENT_REMOTE_NAME_CACHED 0x65 + +// data: discoverable enabled (bool) +#define BTSTACK_EVENT_DISCOVERABLE_ENABLED 0x66 + +// Daemon Events used internally + +// data: event(8) +#define DAEMON_EVENT_CONNECTION_OPENED 0x68 + +// data: event(8) +#define DAEMON_EVENT_CONNECTION_CLOSED 0x69 + +// data: event(8), nr_connections(8) +#define DAEMON_NR_CONNECTIONS_CHANGED 0x6A + +// data: event(8) +#define DAEMON_EVENT_NEW_RFCOMM_CREDITS 0x6B + +// data: event(8) +#define DAEMON_EVENT_HCI_PACKET_SENT 0x6C + +// L2CAP EVENTS + +// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16), flush_timeout(16) +#define L2CAP_EVENT_CHANNEL_OPENED 0x70 + +// data: event (8), len(8), channel (16) +#define L2CAP_EVENT_CHANNEL_CLOSED 0x71 + +// data: event (8), len(8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16) +#define L2CAP_EVENT_INCOMING_CONNECTION 0x72 + +// data: event(8), len(8), handle(16) +#define L2CAP_EVENT_TIMEOUT_CHECK 0x73 + +// data: event(8), len(8), local_cid(16), credits(8) +#define L2CAP_EVENT_CREDITS 0x74 + +// data: event(8), len(8), status (8), psm (16) +#define L2CAP_EVENT_SERVICE_REGISTERED 0x75 + +// data: event(8), len(8), handle(16), interval min(16), interval max(16), latency(16), timeout multiplier(16) +#define L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST 0x76 + +// data: event(8), len(8), handle(16), result (16) (0 == ok, 1 == fail) +#define L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE 0x77 + +// RFCOMM EVENTS +/** + * @format 1B2122 + * @param status + * @param bd_addr + * @param con_handle + * @param server_channel + * @param rfcomm_cid + * @param max_frame_size + */ +#define RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE 0x80 + +/** + * @format 2 + * @param rfcomm_cid + */ +#define RFCOMM_EVENT_CHANNEL_CLOSED 0x81 + +/** + * @format B12 + * @param bd_addr + * @param server_channel + * @param rfcomm_cid + */ +#define RFCOMM_EVENT_INCOMING_CONNECTION 0x82 + +/** + * @format 21 + * @param rfcomm_cid + * @param line_status + */ +#define RFCOMM_EVENT_REMOTE_LINE_STATUS 0x83 + +/** + * @format 21 + * @param rfcomm_cid + * @param credits + */ +#define RFCOMM_EVENT_CREDITS 0x84 + +/** + * @format 11 + * @param status + * @param channel_id + */ +#define RFCOMM_EVENT_SERVICE_REGISTERED 0x85 + +/** + * @format 11 + * @param status + * @param server_channel_id + */ +#define RFCOMM_EVENT_PERSISTENT_CHANNEL 0x86 + +// data: event (8), len(8), rfcomm_cid (16), modem status (8) + +/** + * @format 21 + * @param rfcomm_cid + * @param modem_status + */ +#define RFCOMM_EVENT_REMOTE_MODEM_STATUS 0x87 + +// data: event (8), len(8), rfcomm_cid (16), rpn_data_t (67) + /** + * TODO: format for variable data + * @param rfcomm_cid + * @param rpn_data + */ +#define RFCOMM_EVENT_PORT_CONFIGURATION 0x88 + + +// data: event(8), len(8), status(8), service_record_handle(32) + /** + * @format 14 + * @param status + * @param service_record_handle + */ +#define SDP_SERVICE_REGISTERED 0x90 + +// data: event(8), len(8), status(8) +/** + * @format 1 + * @param status + */ +#define SDP_QUERY_COMPLETE 0x91 + +// data: event(8), len(8), rfcomm channel(8), name(var) +/** + * @format 1T + * @param rfcomm_channel + * @param name + * @brief SDP_QUERY_RFCOMM_SERVICE 0x92 + */ +#define SDP_QUERY_RFCOMM_SERVICE 0x92 + +// data: event(8), len(8), record nr(16), attribute id(16), attribute value(var) +/** + * TODO: format for variable data + * @param record_nr + * @param attribute_id + * @param attribute_value + */ +#define SDP_QUERY_ATTRIBUTE_VALUE 0x93 + +// not provided by daemon, only used for internal testing +#define SDP_QUERY_SERVICE_RECORD_HANDLE 0x94 + +/** + * @format H1 + * @param handle + * @param status + */ +#define GATT_QUERY_COMPLETE 0xA0 + +/** + * @format HX + * @param handle + * @param service + */ +#define GATT_SERVICE_QUERY_RESULT 0xA1 + +/** + * @format HY + * @param handle + * @param characteristic + */ +#define GATT_CHARACTERISTIC_QUERY_RESULT 0xA2 + +/** + * @format HX + * @param handle + * @param service + */ +#define GATT_INCLUDED_SERVICE_QUERY_RESULT 0xA3 + +/** + * @format HZ + * @param handle + * @param characteristic_descriptor + */ +#define GATT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT 0xA4 + +/** + * @format H2LV + * @param handle + * @param value_handle + * @param value_length + * @param value + */ +#define GATT_CHARACTERISTIC_VALUE_QUERY_RESULT 0xA5 + +/** + * @format H2LV + * @param handle + * @param value_handle + * @param value_length + * @param value + */ +#define GATT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT 0xA6 + +/** + * @format H2LV + * @param handle + * @param value_handle + * @param value_length + * @param value + */ +#define GATT_NOTIFICATION 0xA7 + +/** + * @format H2LV + * @param handle + * @param value_handle + * @param value_length + * @param value + */ +#define GATT_INDICATION 0xA8 + +#define GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT 0xA9 +#define GATT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT 0xAA + +/** + * @format H2 + * @param handle + * @param MTU + */ +#define GATT_MTU 0xAB + +/** + * @format H2 + * @param handle + * @param MTU + */ +#define ATT_MTU_EXCHANGE_COMPLETE 0xB5 + +// data: event(8), len(8), status (8), hci_handle (16), attribute_handle (16) +#define ATT_HANDLE_VALUE_INDICATION_COMPLETE 0xB6 + + +// data: event(8), len(8), status (8), bnep service uuid (16) +#define BNEP_EVENT_SERVICE_REGISTERED 0xC0 + +// data: event(8), len(8), status (8), bnep source uuid (16), bnep destination uuid (16), mtu (16), remote_address (48) +#define BNEP_EVENT_OPEN_CHANNEL_COMPLETE 0xC1 + +// data: event(8), len(8), bnep source uuid (16), bnep destination uuid (16), remote_address (48) +#define BNEP_EVENT_CHANNEL_CLOSED 0xC2 + +// data: event(8), len(8), bnep source uuid (16), bnep destination uuid (16), remote_address (48), channel state (8) +#define BNEP_EVENT_CHANNEL_TIMEOUT 0xC3 + +// data: event(8), len(8) +#define BNEP_EVENT_READY_TO_SEND 0xC4 + +// data: event(8), address_type(8), address (48), [number(32)] +#define SM_JUST_WORKS_REQUEST 0xD0 +#define SM_JUST_WORKS_CANCEL 0xD1 +#define SM_PASSKEY_DISPLAY_NUMBER 0xD2 +#define SM_PASSKEY_DISPLAY_CANCEL 0xD3 +#define SM_PASSKEY_INPUT_NUMBER 0xD4 +#define SM_PASSKEY_INPUT_CANCEL 0xD5 +#define SM_IDENTITY_RESOLVING_STARTED 0xD6 +#define SM_IDENTITY_RESOLVING_FAILED 0xD7 +#define SM_IDENTITY_RESOLVING_SUCCEEDED 0xD8 +#define SM_AUTHORIZATION_REQUEST 0xD9 +#define SM_AUTHORIZATION_RESULT 0xDA + +// GAP + +// data: event(8), len(8), hci_handle (16), security_level (8) +#define GAP_SECURITY_LEVEL 0xE0 + +// data: event(8), len(8), status (8), bd_addr(48) +#define GAP_DEDICATED_BONDING_COMPLETED 0xE1 + +/** + * @format 11B1JV + * @param advertising_event_type + * @param address_type + * @param address + * @param rssi + * @param data_length + * @param data + */ +#define GAP_LE_ADVERTISING_REPORT 0xE2 + +#define HCI_EVENT_HSP_META 0xE8 + +// data: event(8), len(8), subevent(8), status(8) +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE 0x01 + +// data: event(8), len(8), subevent(8), status(8) +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE 0x02 + + +// data: event(8), len(8), subevent(8), status(8) +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x03 + +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE 0x04 + +/** + * @format 1 + * @param subevent_code + */ +#define HSP_SUBEVENT_RING 0x05 + +/** + * @format 11 + * @param subevent_code + * @param gain Valid range: [0,15] + */ +#define HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED 0x06 + +/** + * @format 11 + * @param subevent_code + * @param gain Valid range: [0,15] + */ +#define HSP_SUBEVENT_SPEAKER_GAIN_CHANGED 0x07 + +/** + * @format 1JV + * @param subevent_code + * @param value_length + * @param value + */ +#define HSP_SUBEVENT_HS_COMMAND 0x08 + +/** + * @format 1JV + * @param subevent_code + * @param value_length + * @param value + */ +#define HSP_SUBEVENT_AG_INDICATION 0x09 + + +#define HCI_EVENT_HFP_META 0xE9 + +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED 0x01 + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02 + +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED 0x03 + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED 0x04 + +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HFP_SUBEVENT_COMPLETE 0x05 + +/** + * @format 111T + * @param subevent_code + * @param indicator_index + * @param indicator_status + * @param indicator_name + */ +#define HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED 0x06 + +/** + * @format 1111T + * @param subevent_code + * @param network_operator_mode + * @param network_operator_format + * @param network_operator_name + */ +#define HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED 0x07 + +/** + * @format 11 + * @param subevent_code + * @param error + */ +#define HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR 0x08 + +/** + * @format 11 + * @param subevent_code + * @param status + */ +#define HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE 0x09 + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_START_RINGINIG 0x0A + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_STOP_RINGINIG 0x0B + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_CALL_TERMINATED 0x0C + +/** + * @format 1T + * @param subevent_code + * @param number + */ +#define HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER 0x0D + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG 0x0E + +/** + * @format 1T + * @param subevent_code + * @param number + */ +#define HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG 0x0F + +/** + * @format 1T + * @param subevent_code + * @param dtmf code + */ +#define HFP_SUBEVENT_TRANSMIT_DTMF_CODES 0x10 + +/** + * @format 1 + * @param subevent_code + */ + #define HFP_SUBEVENT_CALL_ANSWERED 0x11 + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_CONFERENCE_CALL 0x12 + +/** + * @format 1 + * @param subevent_code + */ +#define HFP_SUBEVENT_RING 0x13 + +/** + * @format 111 + * @param subevent_code + * @param status + * @param gain + */ + #define HFP_SUBEVENT_SPEAKER_VOLUME 0x14 + +/** + * @format 111 + * @param subevent_code + * @param status + * @param gain + */ +#define HFP_SUBEVENT_MICROPHONE_VOLUME 0x15 + +/** + * @format 11T + * @param subevent_code + * @param type + * @param number + */ +#define HFP_SUBEVENT_CALL_WAITING_NOTIFICATION 0x16 + +/** + * @format 11T + * @param subevent_code + * @param type + * @param number + */ +#define HFP_SUBEVENT_CALLING_LINE_INDETIFICATION_NOTIFICATION 0x17 + +/** + * @format 111111T + * @param subevent_code + * @param clcc_idx + * @param clcc_dir + * @param clcc_status + * @param clcc_mpty + * @param bnip_type + * @param bnip_number + */ +#define HFP_SUBEVENT_ENHANCED_CALL_STATUS 0x18 + +/** + * @format 111T + * @param subevent_code + * @param status + * @param bnip_type + * @param bnip_number + */ + #define HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION 0x19 + +/** + * @format 1T + * @param subevent_code + * @param value + */ +#define HFP_SUBEVENT_RESPONSE_AND_HOLD_STATUS 0x1A + +// ANCS Client +#define ANCS_CLIENT_CONNECTED 0xF0 +#define ANCS_CLIENT_NOTIFICATION 0xF1 +#define ANCS_CLIENT_DISCONNECTED 0xF2 + + + +// #define HCI_EVENT_HFP_META 0xxx +// #define HCI_EVENT_GATT_META 0xxx +// #define HCI_EVENT_SDP_META 0xxx +// #define HCI_EVENT_ANCS_META 0xxx +// #define HCI_EVENT_SM_META 0xxx +// #define HCI_EVENT_GAP_META 0xxx +// #define HCI_EVENT_BNEP_META 0xxx +// #define HCI_EVENT_PAN_META 0xxx + + +#define HCI_EVENT_VENDOR_SPECIFIC 0xFF + +// +// Error Codes +// + +// from Bluetooth Core Specification +#define ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 +#define ERROR_CODE_AUTHENTICATION_FAILURE 0x05 +#define ERROR_CODE_MEMORY_CAPACITY_EXCEEDED 0x07 +#define ERROR_CODE_COMMAND_DISALLOWED 0x0C +#define ERROR_CODE_PAIRING_NOT_ALLOWED 0x18 +#define ERROR_CODE_INSUFFICIENT_SECURITY 0x2F + +// last error code in 2.1 is 0x38 - we start with 0x50 for BTstack errors +#define BTSTACK_CONNECTION_TO_BTDAEMON_FAILED 0x50 +#define BTSTACK_ACTIVATION_FAILED_SYSTEM_BLUETOOTH 0x51 +#define BTSTACK_ACTIVATION_POWERON_FAILED 0x52 +#define BTSTACK_ACTIVATION_FAILED_UNKNOWN 0x53 +#define BTSTACK_NOT_ACTIVATED 0x54 +#define BTSTACK_BUSY 0x55 +#define BTSTACK_MEMORY_ALLOC_FAILED 0x56 +#define BTSTACK_ACL_BUFFERS_FULL 0x57 + +// l2cap errors - enumeration by the command that created them +#define L2CAP_COMMAND_REJECT_REASON_COMMAND_NOT_UNDERSTOOD 0x60 +#define L2CAP_COMMAND_REJECT_REASON_SIGNALING_MTU_EXCEEDED 0x61 +#define L2CAP_COMMAND_REJECT_REASON_INVALID_CID_IN_REQUEST 0x62 + +#define L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL 0x63 +#define L2CAP_CONNECTION_RESPONSE_RESULT_PENDING 0x64 +#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_PSM 0x65 +#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY 0x66 +#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES 0x67 +#define L2CAP_CONNECTION_RESPONSE_RESULT_RTX_TIMEOUT 0x68 + +#define L2CAP_SERVICE_ALREADY_REGISTERED 0x69 +#define L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU 0x6A + +#define RFCOMM_MULTIPLEXER_STOPPED 0x70 +#define RFCOMM_CHANNEL_ALREADY_REGISTERED 0x71 +#define RFCOMM_NO_OUTGOING_CREDITS 0x72 +#define RFCOMM_AGGREGATE_FLOW_OFF 0x73 +#define RFCOMM_DATA_LEN_EXCEEDS_MTU 0x74 + +#define SDP_HANDLE_ALREADY_REGISTERED 0x80 +#define SDP_QUERY_INCOMPLETE 0x81 +#define SDP_SERVICE_NOT_FOUND 0x82 + +#define ATT_HANDLE_VALUE_INDICATION_IN_PORGRESS 0x90 +#define ATT_HANDLE_VALUE_INDICATION_TIMEOUT 0x91 + +#define GATT_CLIENT_NOT_CONNECTED 0x93 +#define GATT_CLIENT_BUSY 0x94 + +#define BNEP_SERVICE_ALREADY_REGISTERED 0xA0 +#define BNEP_CHANNEL_NOT_CONNECTED 0xA1 +#define BNEP_DATA_LEN_EXCEEDS_MTU 0xA2 + +typedef enum { + BLE_PERIPHERAL_OK = 0xA0, + BLE_PERIPHERAL_IN_WRONG_STATE, + BLE_PERIPHERAL_DIFFERENT_CONTEXT_FOR_ADDRESS_ALREADY_EXISTS, + BLE_PERIPHERAL_NOT_CONNECTED, + BLE_VALUE_TOO_LONG, + BLE_PERIPHERAL_BUSY, + BLE_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED, + BLE_CHARACTERISTIC_INDICATION_NOT_SUPPORTED +} le_command_status_t; + +/** + * Default INQ Mode + */ +#define HCI_INQUIRY_LAP 0x9E8B33L // 0x9E8B33: General/Unlimited Inquiry Access Code (GIAC) + +/** + * SSP IO Capabilities - if capability is set, BTstack answers IO Capability Requests + */ +#define SSP_IO_CAPABILITY_DISPLAY_ONLY 0 +#define SSP_IO_CAPABILITY_DISPLAY_YES_NO 1 +#define SSP_IO_CAPABILITY_KEYBOARD_ONLY 2 +#define SSP_IO_CAPABILITY_NO_INPUT_NO_OUTPUT 3 +#define SSP_IO_CAPABILITY_UNKNOWN 0xff + +/** + * SSP Authentication Requirements, see IO Capability Request Reply Commmand + */ + +// Numeric comparison with automatic accept allowed. +#define SSP_IO_AUTHREQ_MITM_PROTECTION_NOT_REQUIRED_NO_BONDING 0x00 + +// Use IO Capabilities to deter- mine authentication procedure +#define SSP_IO_AUTHREQ_MITM_PROTECTION_REQUIRED_NO_BONDING 0x01 + +// Numeric compar- ison with automatic accept allowed. +#define SSP_IO_AUTHREQ_MITM_PROTECTION_NOT_REQUIRED_DEDICATED_BONDING 0x02 + +// Use IO Capabilities to determine authentication procedure +#define SSP_IO_AUTHREQ_MITM_PROTECTION_REQUIRED_DEDICATED_BONDING 0x03 + +// Numeric Compari- son with automatic accept allowed. +#define SSP_IO_AUTHREQ_MITM_PROTECTION_NOT_REQUIRED_GENERAL_BONDING 0x04 + +// . Use IO capabilities to determine authentication procedure. +#define SSP_IO_AUTHREQ_MITM_PROTECTION_REQUIRED_GENERAL_BONDING 0x05 + +/** + * Address types + * @note: BTstack uses a custom addr type to refer to classic ACL and SCO devices + */ + typedef enum { + BD_ADDR_TYPE_LE_PUBLIC = 0, + BD_ADDR_TYPE_LE_RANDOM = 1, + BD_ADDR_TYPE_SCO = 0xfe, + BD_ADDR_TYPE_CLASSIC = 0xff, + BD_ADDR_TYPE_UNKNOWN = 0xfe + } bd_addr_type_t; + +/** + * Hardware state of Bluetooth controller + */ +typedef enum { + HCI_POWER_OFF = 0, + HCI_POWER_ON, + HCI_POWER_SLEEP +} HCI_POWER_MODE; + +/** + * State of BTstack + */ +typedef enum { + HCI_STATE_OFF = 0, + HCI_STATE_INITIALIZING, + HCI_STATE_WORKING, + HCI_STATE_HALTING, + HCI_STATE_SLEEPING, + HCI_STATE_FALLING_ASLEEP +} HCI_STATE; + +/** + * compact HCI Command packet description + */ + typedef struct { + uint16_t opcode; + const char *format; +} hci_cmd_t; + + +// HCI Commands - see hci_cmds.c for info on parameters +extern const hci_cmd_t btstack_get_state; +extern const hci_cmd_t btstack_set_power_mode; +extern const hci_cmd_t btstack_set_acl_capture_mode; +extern const hci_cmd_t btstack_get_version; +extern const hci_cmd_t btstack_get_system_bluetooth_enabled; +extern const hci_cmd_t btstack_set_system_bluetooth_enabled; +extern const hci_cmd_t btstack_set_discoverable; +extern const hci_cmd_t btstack_set_bluetooth_enabled; // only used by btstack config + +extern const hci_cmd_t hci_accept_connection_request; +extern const hci_cmd_t hci_accept_synchronous_connection; +extern const hci_cmd_t hci_authentication_requested; +extern const hci_cmd_t hci_change_connection_link_key; +extern const hci_cmd_t hci_change_connection_packet_type; +extern const hci_cmd_t hci_create_connection; +extern const hci_cmd_t hci_create_connection_cancel; +extern const hci_cmd_t hci_delete_stored_link_key; +extern const hci_cmd_t hci_enhanced_setup_synchronous_connection; +extern const hci_cmd_t hci_enhanced_accept_synchronous_connection; +extern const hci_cmd_t hci_disconnect; +extern const hci_cmd_t hci_host_buffer_size; +extern const hci_cmd_t hci_inquiry; +extern const hci_cmd_t hci_io_capability_request_reply; +extern const hci_cmd_t hci_io_capability_request_negative_reply; +extern const hci_cmd_t hci_inquiry_cancel; +extern const hci_cmd_t hci_link_key_request_negative_reply; +extern const hci_cmd_t hci_link_key_request_reply; +extern const hci_cmd_t hci_pin_code_request_reply; +extern const hci_cmd_t hci_pin_code_request_negative_reply; +extern const hci_cmd_t hci_qos_setup; +extern const hci_cmd_t hci_read_bd_addr; +extern const hci_cmd_t hci_read_buffer_size; +extern const hci_cmd_t hci_read_le_host_supported; +extern const hci_cmd_t hci_read_link_policy_settings; +extern const hci_cmd_t hci_read_link_supervision_timeout; +extern const hci_cmd_t hci_read_local_version_information; +extern const hci_cmd_t hci_read_local_supported_commands; +extern const hci_cmd_t hci_read_local_supported_features; +extern const hci_cmd_t hci_read_num_broadcast_retransmissions; +extern const hci_cmd_t hci_read_remote_supported_features_command; +extern const hci_cmd_t hci_read_rssi; +extern const hci_cmd_t hci_reject_connection_request; +extern const hci_cmd_t hci_remote_name_request; +extern const hci_cmd_t hci_remote_name_request_cancel; +extern const hci_cmd_t hci_remote_oob_data_request_negative_reply; +extern const hci_cmd_t hci_reset; +extern const hci_cmd_t hci_role_discovery; +extern const hci_cmd_t hci_set_event_mask; +extern const hci_cmd_t hci_set_connection_encryption; +extern const hci_cmd_t hci_setup_synchronous_connection; +extern const hci_cmd_t hci_sniff_mode; +extern const hci_cmd_t hci_switch_role_command; +extern const hci_cmd_t hci_user_confirmation_request_negative_reply; +extern const hci_cmd_t hci_user_confirmation_request_reply; +extern const hci_cmd_t hci_user_passkey_request_negative_reply; +extern const hci_cmd_t hci_user_passkey_request_reply; +extern const hci_cmd_t hci_write_authentication_enable; +extern const hci_cmd_t hci_write_class_of_device; +extern const hci_cmd_t hci_write_extended_inquiry_response; +extern const hci_cmd_t hci_write_inquiry_mode; +extern const hci_cmd_t hci_write_le_host_supported; +extern const hci_cmd_t hci_write_link_policy_settings; +extern const hci_cmd_t hci_write_link_supervision_timeout; +extern const hci_cmd_t hci_write_local_name; +extern const hci_cmd_t hci_write_num_broadcast_retransmissions; +extern const hci_cmd_t hci_write_page_timeout; +extern const hci_cmd_t hci_write_scan_enable; +extern const hci_cmd_t hci_write_simple_pairing_mode; +extern const hci_cmd_t hci_write_synchronous_flow_control_enable; +extern const hci_cmd_t hci_read_loopback_mode; +extern const hci_cmd_t hci_write_loopback_mode; + +extern const hci_cmd_t hci_le_add_device_to_white_list; +extern const hci_cmd_t hci_le_clear_white_list; +extern const hci_cmd_t hci_le_connection_update; +extern const hci_cmd_t hci_le_create_connection; +extern const hci_cmd_t hci_le_create_connection_cancel; +extern const hci_cmd_t hci_le_encrypt; +extern const hci_cmd_t hci_le_long_term_key_negative_reply; +extern const hci_cmd_t hci_le_long_term_key_request_reply; +extern const hci_cmd_t hci_le_rand; +extern const hci_cmd_t hci_le_read_advertising_channel_tx_power; +extern const hci_cmd_t hci_le_read_buffer_size ; +extern const hci_cmd_t hci_le_read_channel_map; +extern const hci_cmd_t hci_le_read_remote_used_features; +extern const hci_cmd_t hci_le_read_supported_features; +extern const hci_cmd_t hci_le_read_supported_states; +extern const hci_cmd_t hci_le_read_white_list_size; +extern const hci_cmd_t hci_le_receiver_test; +extern const hci_cmd_t hci_le_remove_device_from_white_list; +extern const hci_cmd_t hci_le_set_advertise_enable; +extern const hci_cmd_t hci_le_set_advertising_data; +extern const hci_cmd_t hci_le_set_advertising_parameters; +extern const hci_cmd_t hci_le_set_event_mask; +extern const hci_cmd_t hci_le_set_host_channel_classification; +extern const hci_cmd_t hci_le_set_random_address; +extern const hci_cmd_t hci_le_set_scan_enable; +extern const hci_cmd_t hci_le_set_scan_parameters; +extern const hci_cmd_t hci_le_set_scan_response_data; +extern const hci_cmd_t hci_le_start_encryption; +extern const hci_cmd_t hci_le_test_end; +extern const hci_cmd_t hci_le_transmitter_test; + +extern const hci_cmd_t l2cap_accept_connection; +extern const hci_cmd_t l2cap_create_channel; +extern const hci_cmd_t l2cap_create_channel_mtu; +extern const hci_cmd_t l2cap_decline_connection; +extern const hci_cmd_t l2cap_disconnect; +extern const hci_cmd_t l2cap_register_service; +extern const hci_cmd_t l2cap_unregister_service; + +extern const hci_cmd_t sdp_register_service_record; +extern const hci_cmd_t sdp_unregister_service_record; +extern const hci_cmd_t sdp_client_query_rfcomm_services; +extern const hci_cmd_t sdp_client_query_services; + + +// accept connection @param bd_addr(48), rfcomm_cid (16) +extern const hci_cmd_t rfcomm_accept_connection; +// create rfcomm channel: @param bd_addr(48), channel (8) +extern const hci_cmd_t rfcomm_create_channel; +// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8) +extern const hci_cmd_t rfcomm_create_channel_with_initial_credits; +// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8) +extern const hci_cmd_t rfcomm_decline_connection; +// disconnect rfcomm disconnect, @param rfcomm_cid(8), reason(8) +extern const hci_cmd_t rfcomm_disconnect; +// register rfcomm service: @param channel(8), mtu (16) +extern const hci_cmd_t rfcomm_register_service; +// register rfcomm service: @param channel(8), mtu (16), initial credits (8) +extern const hci_cmd_t rfcomm_register_service_with_initial_credits; +// unregister rfcomm service, @param service_channel(16) +extern const hci_cmd_t rfcomm_unregister_service; +// request persisten rfcomm channel for service name: serive name (char*) +extern const hci_cmd_t rfcomm_persistent_channel_for_service; +extern const hci_cmd_t rfcomm_grants_credits; + +extern const hci_cmd_t gap_disconnect_cmd; +extern const hci_cmd_t gap_le_scan_start; +extern const hci_cmd_t gap_le_scan_stop; +extern const hci_cmd_t gap_le_set_scan_parameters; +extern const hci_cmd_t gap_le_connect_cmd; +extern const hci_cmd_t gap_le_connect_cancel_cmd; +extern const hci_cmd_t gatt_discover_primary_services_cmd; + +extern const hci_cmd_t gatt_discover_primary_services_by_uuid16_cmd; +extern const hci_cmd_t gatt_discover_primary_services_by_uuid128_cmd; +extern const hci_cmd_t gatt_find_included_services_for_service_cmd; +extern const hci_cmd_t gatt_discover_characteristics_for_service_cmd; +extern const hci_cmd_t gatt_discover_characteristics_for_service_by_uuid128_cmd; +extern const hci_cmd_t gatt_discover_characteristic_descriptors_cmd; +extern const hci_cmd_t gatt_read_value_of_characteristic_cmd; +extern const hci_cmd_t gatt_read_long_value_of_characteristic_cmd; +extern const hci_cmd_t gatt_write_value_of_characteristic_without_response_cmd; +extern const hci_cmd_t gatt_write_value_of_characteristic_cmd; +extern const hci_cmd_t gatt_write_long_value_of_characteristic_cmd; +extern const hci_cmd_t gatt_reliable_write_long_value_of_characteristic_cmd; +extern const hci_cmd_t gatt_read_characteristic_descriptor_cmd; +extern const hci_cmd_t gatt_read_long_characteristic_descriptor_cmd; +extern const hci_cmd_t gatt_write_characteristic_descriptor_cmd; +extern const hci_cmd_t gatt_write_long_characteristic_descriptor_cmd; +extern const hci_cmd_t gatt_write_client_characteristic_configuration_cmd; +extern const hci_cmd_t gatt_get_mtu; + + +#if defined __cplusplus +} +#endif + +#endif // __HCI_CMDS_H diff --git a/src/btstack_defines.h b/src/btstack_defines.h index 8bbc60a33..9444c2001 100644 --- a/src/btstack_defines.h +++ b/src/btstack_defines.h @@ -769,40 +769,57 @@ typedef uint8_t sm_key_t[16]; /** HSP Subevent */ +// data: event(8), len(8), subevent(8), status(8) /** - * @format 112 + * @format 11 * @param subevent_code * @param status 0 == OK - * @param handle */ -#define HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x01 +#define HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE 0x01 + +// data: event(8), len(8), subevent(8), status(8) +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE 0x02 + + +// data: event(8), len(8), subevent(8), status(8) +/** + * @format 11 + * @param subevent_code + * @param status 0 == OK + */ +#define HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x03 /** * @format 11 * @param subevent_code * @param status 0 == OK */ -#define HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE 0x02 +#define HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE 0x04 /** * @format 1 * @param subevent_code */ -#define HSP_SUBEVENT_RING 0x03 +#define HSP_SUBEVENT_RING 0x05 /** * @format 11 * @param subevent_code * @param gain Valid range: [0,15] */ -#define HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED 0x04 +#define HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED 0x06 /** * @format 11 * @param subevent_code * @param gain Valid range: [0,15] */ -#define HSP_SUBEVENT_SPEAKER_GAIN_CHANGED 0x05 +#define HSP_SUBEVENT_SPEAKER_GAIN_CHANGED 0x07 /** * @format 1JV @@ -810,7 +827,7 @@ typedef uint8_t sm_key_t[16]; * @param value_length * @param value */ -#define HSP_SUBEVENT_HS_COMMAND 0x06 +#define HSP_SUBEVENT_HS_COMMAND 0x08 /** * @format 1JV @@ -818,7 +835,7 @@ typedef uint8_t sm_key_t[16]; * @param value_length * @param value */ -#define HSP_SUBEVENT_AG_INDICATION 0x07 +#define HSP_SUBEVENT_AG_INDICATION 0x09 /** HFP Subevent */ diff --git a/src/classic/hfp_ag.c b/src/classic/hfp_ag.c index ac010066b..cce12a770 100644 --- a/src/classic/hfp_ag.c +++ b/src/classic/hfp_ag.c @@ -103,6 +103,10 @@ static hfp_phone_number_t * subscriber_numbers = NULL; static int subscriber_numbers_count = 0; static btstack_packet_callback_registration_t hci_event_callback_registration; +static void hfp_run_for_context(hfp_connection_t *hfp_connection); +static void hfp_ag_setup_audio_connection(hfp_connection_t * hfp_connection); +static void hfp_ag_hf_start_ringing(hfp_connection_t * hfp_connection); +hfp_ag_indicator_t * hfp_ag_get_ag_indicators(hfp_connection_t * hfp_connection); static int hfp_ag_get_ag_indicators_nr(hfp_connection_t * hfp_connection){ diff --git a/src/classic/hsp_hs.c b/src/classic/hsp_hs.c index 4693e9560..c75972dd8 100644 --- a/src/classic/hsp_hs.c +++ b/src/classic/hsp_hs.c @@ -87,24 +87,33 @@ static int hs_microphone_gain = -1; static int hs_speaker_gain = -1; static uint8_t hs_send_button_press = 0; -static uint8_t hs_support_custom_indications = 0; -static uint8_t hs_outgoing_connection = 0; +static uint8_t wait_ok = 0; +static uint8_t hs_support_custom_indications = 0; static btstack_packet_callback_registration_t hci_event_callback_registration; +static uint8_t hsp_disconnect_rfcomm = 0; +static uint8_t hsp_establish_audio_connection = 0; +static uint8_t hsp_release_audio_connection = 0; typedef enum { HSP_IDLE, HSP_SDP_QUERY_RFCOMM_CHANNEL, - HSP_W4_SDP_EVENT_QUERY_COMPLETE, + HSP_W4_SDP_QUERY_COMPLETE, HSP_W4_RFCOMM_CONNECTED, - HSP_W4_USER_ACTION, + + HSP_RFCOMM_CONNECTION_ESTABLISHED, + HSP_W2_CONNECT_SCO, HSP_W4_SCO_CONNECTED, - HSP_ACTIVE, + + HSP_AUDIO_CONNECTION_ESTABLISHED, + HSP_W2_DISCONNECT_SCO, - HSP_W4_SCO_DISCONNECTED, + HSP_W4_SCO_DISCONNECTED, + HSP_W2_DISCONNECT_RFCOMM, HSP_W4_RFCOMM_DISCONNECTED, + HSP_W4_RFCOMM_DISCONNECTED_AND_RESTART, HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN } hsp_state_t; @@ -250,15 +259,11 @@ void hsp_hs_create_sdp_record(uint8_t * service, uint32_t service_record_handle static void hsp_hs_reset_state(void){ hsp_state = HSP_IDLE; - - rfcomm_cid = 0; - rfcomm_handle = 0; - sco_handle = 0; - hs_microphone_gain = -1; hs_speaker_gain = -1; hs_send_button_press = 0; + wait_ok = 0; hs_support_custom_indications = 0; } @@ -279,27 +284,59 @@ void hsp_hs_init(uint8_t rfcomm_channel_nr){ void hsp_hs_connect(bd_addr_t bd_addr){ if (hsp_state != HSP_IDLE) return; - hs_outgoing_connection = 1; hsp_state = HSP_SDP_QUERY_RFCOMM_CHANNEL; memcpy(remote, bd_addr, 6); hsp_run(); } -void hsp_hs_disconnect(bd_addr_t bd_addr){ +void hsp_hs_disconnect(void){ + hsp_hs_release_audio_connection(); + + if (hsp_state < HSP_W4_RFCOMM_CONNECTED){ + hsp_state = HSP_IDLE; + return; + } + + if (hsp_state == HSP_W4_RFCOMM_CONNECTED){ + hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN; + return; + } + + if (hsp_state < HSP_W4_SCO_CONNECTED){ + hsp_state = HSP_W2_DISCONNECT_RFCOMM; + return; + } + + if (hsp_state < HSP_W4_SCO_DISCONNECTED){ + hsp_state = HSP_W2_DISCONNECT_SCO; + return; + } + hsp_disconnect_rfcomm = 1; + hsp_run(); +} + + +void hsp_hs_establish_audio_connection(void){ switch (hsp_state){ - case HSP_ACTIVE: - hsp_state = HSP_W4_USER_ACTION; - hs_send_button_press = 1; + case HSP_RFCOMM_CONNECTION_ESTABLISHED: + hsp_establish_audio_connection = 1; + hsp_state = HSP_W4_SCO_CONNECTED; break; case HSP_W4_RFCOMM_CONNECTED: hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN; break; default: - return; + break; } hsp_run(); } +void hsp_hs_release_audio_connection(void){ + if (hsp_state >= HSP_W2_DISCONNECT_SCO) return; + if (hsp_state < HSP_AUDIO_CONNECTION_ESTABLISHED) return; + hsp_release_audio_connection = 1; + hsp_run(); +} void hsp_hs_set_microphone_gain(uint8_t gain){ if (gain < 0 || gain >15) { @@ -322,57 +359,64 @@ void hsp_hs_set_speaker_gain(uint8_t gain){ static void hsp_run(void){ - int err; + if (!rfcomm_can_send_packet_now(rfcomm_cid)) return; + if (wait_ok) return; + if (hsp_release_audio_connection){ + hsp_release_audio_connection = 0; + wait_ok = 1; + hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD); + return; + } + + if (hsp_disconnect_rfcomm){ + hsp_disconnect_rfcomm = 0; + hsp_establish_audio_connection = 0; + rfcomm_disconnect(rfcomm_cid); + return; + } + + if (hsp_establish_audio_connection){ + hsp_establish_audio_connection = 0; + wait_ok = 1; + hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD); + return; + } + if (hs_send_button_press){ hs_send_button_press = 0; - err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD); - if (err) { - hs_send_button_press = 1; - } + wait_ok = 1; + hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD); return; } switch (hsp_state){ case HSP_SDP_QUERY_RFCOMM_CHANNEL: - hsp_state = HSP_W4_SDP_EVENT_QUERY_COMPLETE; + hsp_state = HSP_W4_SDP_QUERY_COMPLETE; sdp_client_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, SDP_Headset_AG); break; - case HSP_W2_CONNECT_SCO: - hsp_state = HSP_W4_SCO_CONNECTED; - break; - - case HSP_W2_DISCONNECT_SCO: - hsp_state = HSP_W4_SCO_DISCONNECTED; - break; + case HSP_AUDIO_CONNECTION_ESTABLISHED: + case HSP_RFCOMM_CONNECTION_ESTABLISHED : - case HSP_ACTIVE: - - if (hs_microphone_gain >= 0){ - int gain = hs_microphone_gain; - hs_microphone_gain = -1; + if (hs_microphone_gain >= 0){ char buffer[20]; - sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, gain); - err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer); - if (err) { - hs_microphone_gain = gain; - } + sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain); + hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer); + hs_microphone_gain = -1; break; } if (hs_speaker_gain >= 0){ - int gain = hs_speaker_gain; - hs_speaker_gain = -1; char buffer[20]; - sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, gain); - err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer); - if (err) { - hs_speaker_gain = gain; - } + sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, hs_speaker_gain); + hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer); + hs_speaker_gain = -1; break; } - + break; + case HSP_W4_RFCOMM_DISCONNECTED: + rfcomm_disconnect(rfcomm_cid); break; default: break; @@ -391,16 +435,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){ emit_ring_event(); } else if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){ - switch (hsp_state){ - case HSP_W4_RFCOMM_CONNECTED: - hsp_state = HSP_W2_CONNECT_SCO; - break; - case HSP_W4_USER_ACTION: - hsp_state = HSP_W2_DISCONNECT_SCO; - break; - default: - break; - } + wait_ok = 0; } else if (strncmp((char *)packet, HSP_MICROPHONE_GAIN, strlen(HSP_MICROPHONE_GAIN)) == 0){ uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_MICROPHONE_GAIN)]); emit_event(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain); @@ -435,6 +470,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack switch (event) { case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{ + if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED) return; int index = 2; uint8_t status = packet[index++]; sco_handle = little_endian_read_16(packet, index); @@ -454,8 +490,10 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack if (status != 0){ log_error("(e)SCO Connection failed, status %u", status); emit_event_audio_connected(status, sco_handle); + hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED ; break; } + switch (link_type){ case 0x00: log_info("SCO Connection established."); @@ -475,16 +513,11 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle, bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode); - if (hsp_state == HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){ - hsp_state = HSP_W2_DISCONNECT_SCO; - break; - } - // forward event to app hsp_hs_callback(packet, size); - hsp_state = HSP_ACTIVE; - emit_event_audio_connected(0, sco_handle); + hsp_state = HSP_AUDIO_CONNECTION_ESTABLISHED; + emit_event_audio_connected(status, sco_handle); break; } @@ -495,42 +528,27 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack reverse_bd_addr(&packet[2], event_addr); rfcomm_cid = little_endian_read_16(packet, 9); log_info("RFCOMM channel %u requested for %s", packet[8], bd_addr_to_str(event_addr)); - rfcomm_accept_connection(rfcomm_cid); - hsp_state = HSP_W4_RFCOMM_CONNECTED; + rfcomm_accept_connection(rfcomm_cid); break; case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE: // printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16) + if (hsp_state != HSP_W4_RFCOMM_CONNECTED) return; if (packet[2]) { log_info("RFCOMM channel open failed, status %u", packet[2]); + hsp_state = HSP_IDLE; hsp_hs_reset_state(); - emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]); - hs_outgoing_connection = 0; } else { // data: event(8) , len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16) rfcomm_handle = little_endian_read_16(packet, 9); rfcomm_cid = little_endian_read_16(packet, 12); mtu = little_endian_read_16(packet, 14); - log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u", rfcomm_cid, mtu); - - if (hs_outgoing_connection){ - hs_outgoing_connection = 0; - hs_send_button_press = 1; - } - - switch (hsp_state){ - case HSP_W4_RFCOMM_CONNECTED: - hsp_state = HSP_W2_CONNECT_SCO; - break; - case HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN: - hsp_state = HSP_W2_DISCONNECT_RFCOMM; - break; - default: - break; - } + log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, handle %02x", rfcomm_cid, mtu, rfcomm_handle); + hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED; } + emit_event(HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE, packet[2]); break; case RFCOMM_EVENT_CAN_SEND_NOW: @@ -541,13 +559,21 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack handle = little_endian_read_16(packet,3); if (handle == sco_handle){ sco_handle = 0; - hsp_state = HSP_W2_DISCONNECT_RFCOMM; + hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED ; + hsp_hs_reset_state(); + emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0); break; + } + if (handle == rfcomm_handle) { + rfcomm_handle = 0; + hsp_state = HSP_IDLE; + hsp_hs_callback(packet, size); + hsp_hs_reset_state(); } break; case RFCOMM_EVENT_CHANNEL_CLOSED: hsp_hs_reset_state(); - emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0); + hsp_hs_callback(packet, size); break; default: break; @@ -564,7 +590,7 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uin case SDP_EVENT_QUERY_COMPLETE: if (channel_nr > 0){ hsp_state = HSP_W4_RFCOMM_CONNECTED; - log_info("RFCOMM create channel"); + log_info("HSP: SDP_QUERY_COMPLETE. RFCOMM create channel, addr %s, rfcomm channel nr %d", bd_addr_to_str(remote), channel_nr); rfcomm_create_channel(packet_handler, remote, channel_nr, NULL); break; } @@ -575,6 +601,7 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uin } void hsp_hs_send_button_press(void){ + if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED || hsp_state >= HSP_W4_RFCOMM_DISCONNECTED) return; hs_send_button_press = 1; hsp_run(); } diff --git a/src/classic/hsp_hs.h b/src/classic/hsp_hs.h index e0c2e949e..e54d2c064 100644 --- a/src/classic/hsp_hs.h +++ b/src/classic/hsp_hs.h @@ -110,7 +110,27 @@ void hsp_hs_connect(bd_addr_t bd_addr); * Releases the RFCOMM channel. * @param bd_addr */ -void hsp_hs_disconnect(bd_addr_t bd_addr); +void hsp_hs_disconnect(void); + + +/** + * @brief Send button press action. Toggle establish/release of audio connection. + */ +void hsp_hs_send_button_press(void); + +/** + * @brief Triger establishing audio connection. + * + * @param bd_addr + */ +void hsp_hs_establish_audio_connection(void); + +/** + * @brief Trigger releasing audio connection. + * + * @param bd_addr + */ +void hsp_hs_release_audio_connection(void); /** * @brief Set microphone gain. @@ -130,11 +150,7 @@ void hsp_hs_set_microphone_gain(uint8_t gain); */ void hsp_hs_set_speaker_gain(uint8_t gain); -/** - * @brief Send button press action. - * @param gain Valid range: [0,15] - */ -void hsp_hs_send_button_press(void); + /** * @brief Enable custom indications. diff --git a/test/pts/classic_test.c b/test/pts/classic_test.c index 2f25138bd..0ae107ba6 100644 --- a/test/pts/classic_test.c +++ b/test/pts/classic_test.c @@ -49,19 +49,20 @@ #include #include -#include "hci_cmd.h" -#include "btstack_run_loop.h" - -#include "hci.h" -#include "gap.h" -#include "btstack_memory.h" +#include "ble/sm.h" #include "btstack_event.h" +#include "btstack_memory.h" +#include "btstack_run_loop.h" +#include "classic/rfcomm.h" +#include "classic/sdp_client_rfcomm.h" +#include "classic/sdp_server.h" +#include "classic/sdp_util.h" +#include "classic/spp_server.h" +#include "gap.h" +#include "hci.h" +#include "hci_cmd.h" #include "hci_dump.h" #include "l2cap.h" -#include "classic/rfcomm.h" -#include "classic/sdp_server.h" -#include "classic/sdp_client_rfcomm.h" -#include "ble/sm.h" #include "stdin_support.h" static void show_usage(); diff --git a/test/pts/hsp_hs_test.c b/test/pts/hsp_hs_test.c index a04218c59..d28e2f047 100644 --- a/test/pts/hsp_hs_test.c +++ b/test/pts/hsp_hs_test.c @@ -86,90 +86,6 @@ static char hs_cmd_buffer[100]; // prototypes static void show_usage(); -#define TABLE_SIZE (50) -static uint8_t sine[TABLE_SIZE]; -static void setup_sine(void){ - // create sine wave table - int i; - for( i=0; i - -// portaudio config -#define NUM_CHANNELS 1 -#define SAMPLE_RATE 8000 -#define FRAMES_PER_BUFFER 1000 -#define PA_SAMPLE_TYPE paInt8 - -// portaudio globals -int phase = 0; -static PaStream * stream; - -static void try_send_sco(void){ - printf("try send handle %x\n", sco_handle); - if (!sco_handle) return; - if (!hci_can_send_sco_packet_now()) { - printf("try_send_sco, cannot send now\n"); - return; - } - const int frames_per_packet = 9; - hci_reserve_packet_buffer(); - uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); - // set handle + flags - little_endian_store_16(sco_packet, 0, sco_handle); - // set len - sco_packet[2] = frames_per_packet; - int i; - for (i=0;i= TABLE_SIZE) phase = 0; - } - hci_send_sco_packet_buffer(3 + frames_per_packet); -} - - -static void setup_audio(void){ - - int err; - PaStreamParameters outputParameters; - - /* -- initialize PortAudio -- */ - err = Pa_Initialize(); - if( err != paNoError ) return; - /* -- setup input and output -- */ - outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ - outputParameters.channelCount = NUM_CHANNELS; - outputParameters.sampleFormat = PA_SAMPLE_TYPE; - outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - /* -- setup stream -- */ - err = Pa_OpenStream( - &stream, - NULL, // &inputParameters, - &outputParameters, - SAMPLE_RATE, - FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - NULL, /* no callback, use blocking API */ - NULL ); /* no callback, so no callback userData */ - if( err != paNoError ) return; - /* -- start stream -- */ - err = Pa_StartStream( stream ); - if( err != paNoError ) return; - printf("Portaudio setup\n"); -} -static void sco_packet_handler(uint8_t packet_type, uint8_t * packet, uint16_t size){ - Pa_WriteStream( stream, &packet[3], size -3); -} - -#endif - // Testig User Interface static void show_usage(void){ uint8_t iut_address_type; @@ -210,7 +126,7 @@ static int stdin_process(struct btstack_data_source *ds){ break; case 'd': printf("Releasing audio connection.\n"); - hsp_hs_disconnect(current_addr); + hsp_hs_disconnect(); break; case 'z': printf("Setting microphone gain 0\n"); @@ -250,33 +166,26 @@ static int stdin_process(struct btstack_data_source *ds){ static void packet_handler(uint8_t * event, uint16_t event_size){ // printf("Packet handler event 0x%02x\n", event[0]); - // try_send_sco(); switch (event[0]) { case BTSTACK_EVENT_STATE: if (event[2] != HCI_STATE_WORKING) break; show_usage(); - // request loopback mode - hci_send_cmd(&hci_write_synchronous_flow_control_enable, 1); break; - case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE: - // printf("HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE status %u, %x\n", event[2], little_endian_read_16(event, 3)); - if (event[2]) break; - sco_handle = little_endian_read_16(event, 3); - break; case HCI_EVENT_HSP_META: switch (event[2]) { case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: if (event[3] == 0){ + sco_handle = little_endian_read_16(event, 4); printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle); - // try_send_sco(); } else { printf("Audio connection establishment failed with status %u\n", event[3]); + sco_handle = 0; } break; case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE: if (event[3] == 0){ printf("Audio connection released.\n\n"); - sco_handle = 0; + sco_handle = 0; } else { printf("Audio connection releasing failed with status %u\n", event[3]); } @@ -309,13 +218,6 @@ static void packet_handler(uint8_t * event, uint16_t event_size){ int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]){ - setup_sine(); - -#ifdef HAVE_PORTAUDIO - setup_audio(); - hci_register_sco_packet_handler(&sco_packet_handler); -#endif - hsp_hs_init(rfcomm_channel_nr); hsp_hs_register_packet_handler(packet_handler);