mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-21 04:21:03 +00:00
merge from master
This commit is contained in:
commit
aa4dd81512
@ -61,7 +61,6 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "btstack_memory.h"
|
||||
#include "ble/gap.h"
|
||||
#include "hci.h"
|
||||
#include "hci_dump.h"
|
||||
#include "l2cap.h"
|
||||
|
@ -59,7 +59,6 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "btstack_memory.h"
|
||||
#include "gap_le.h"
|
||||
#include "hci.h"
|
||||
#include "hci_dump.h"
|
||||
|
||||
|
@ -112,9 +112,10 @@ static int get_link_key(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t
|
||||
int scan_result = sscan_link_key(link_key_str, link_key);
|
||||
if (scan_result == 0 ) return 0;
|
||||
|
||||
scan_result = sscanf( (char *) link_key_type_str, "%d", link_key_type);
|
||||
int link_key_type_buffer;
|
||||
scan_result = sscanf( (char *) link_key_type_str, "%d", &link_key_type_buffer);
|
||||
if (scan_result == 0 ) return 0;
|
||||
|
||||
*link_key_type = (link_key_type_t) link_key_type_buffer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
27
platforms/posix-h4/.gitignore
vendored
Normal file
27
platforms/posix-h4/.gitignore
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
ancs_client
|
||||
ancs_client.h
|
||||
ble_central_test
|
||||
ble_peripheral
|
||||
ble_peripheral_sm_minimal
|
||||
bnep_test
|
||||
classic_test
|
||||
gap_dedicated_bonding
|
||||
gap_inquiry
|
||||
gap_inquiry_and_bond
|
||||
gatt_battery_query
|
||||
gatt_browser
|
||||
hsp_ag_test
|
||||
hsp_hs_test
|
||||
l2cap_test
|
||||
profile.h
|
||||
sdp_bnep_query
|
||||
sdp_general_query
|
||||
sdp_rfcomm_query
|
||||
spp_and_le_counter
|
||||
spp_and_le_counter.h
|
||||
spp_counter
|
||||
spp_streamer
|
||||
led_counter
|
||||
le_counter.h
|
||||
ble_peripheral_test
|
||||
le_counter
|
27
platforms/posix-h4/Makefile
Normal file
27
platforms/posix-h4/Makefile
Normal file
@ -0,0 +1,27 @@
|
||||
# Makefile for libusb based examples
|
||||
BTSTACK_ROOT = ../..
|
||||
POSIX_ROOT= ${BTSTACK_ROOT}/platforms/posix
|
||||
|
||||
CORE += main.c stdin_support.c
|
||||
|
||||
COMMON += hci_transport_h4.c run_loop_posix.c remote_device_db_fs.c
|
||||
|
||||
include ${BTSTACK_ROOT}/example/embedded/Makefile.inc
|
||||
|
||||
# CC = gcc-fsf-4.9
|
||||
CFLAGS += -g -Wall
|
||||
# CFLAGS += -Werror
|
||||
|
||||
VPATH += ${BTSTACK_ROOT}/platforms/posix/src
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
LDFLAGS += -lws2_32
|
||||
endif
|
||||
|
||||
# Command Line examples require porting to win32, so only build on other unix-ish hosts
|
||||
ifneq ($(OS),Windows_NT)
|
||||
EXAMPLES += ${EXAMPLES_CLI}
|
||||
CFLAGS += -I${POSIX_ROOT}/src
|
||||
endif
|
||||
|
||||
all: ${BTSTACK_ROOT}/include/btstack/version.h ${EXAMPLES}
|
24
platforms/posix-h4/btstack-config.h
Normal file
24
platforms/posix-h4/btstack-config.h
Normal file
@ -0,0 +1,24 @@
|
||||
// config.h created by configure for BTstack Tue Jun 4 23:10:20 CEST 2013
|
||||
|
||||
#ifndef __BTSTACK_CONFIG
|
||||
#define __BTSTACK_CONFIG
|
||||
|
||||
#define HAVE_TRANSPORT_USB
|
||||
#define HAVE_BLE
|
||||
#define USE_POSIX_RUN_LOOP
|
||||
#define HAVE_SDP
|
||||
#define HAVE_RFCOMM
|
||||
#define REMOTE_DEVICE_DB remote_device_db_iphone
|
||||
#define HAVE_SO_NOSIGPIPE
|
||||
#define HAVE_TIME
|
||||
#define HAVE_MALLOC
|
||||
#define HAVE_BZERO
|
||||
#define SDP_DES_DUMP
|
||||
#define ENABLE_LOG_INFO
|
||||
#define ENABLE_LOG_ERROR
|
||||
#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof benep heade, avoid memcpy
|
||||
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
|
||||
#define HAVE_HCI_DUMP
|
||||
#define SDP_DES_DUMP
|
||||
|
||||
#endif
|
115
platforms/posix-h4/main.c
Normal file
115
platforms/posix-h4/main.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// minimal setup for HCI code
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "btstack-config.h"
|
||||
|
||||
#include <btstack/run_loop.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "btstack_memory.h"
|
||||
#include "hci.h"
|
||||
#include "hci_dump.h"
|
||||
#include "stdin_support.h"
|
||||
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
|
||||
static hci_uart_config_t hci_uart_config_generic = {
|
||||
NULL,
|
||||
115200,
|
||||
};
|
||||
|
||||
static void sigint_handler(int param){
|
||||
|
||||
#ifndef _WIN32
|
||||
// reset anyway
|
||||
btstack_stdin_reset();
|
||||
#endif
|
||||
|
||||
log_info(" <= SIGINT received, shutting down..\n");
|
||||
hci_power_control(HCI_POWER_OFF);
|
||||
hci_close();
|
||||
log_info("Good bye, see you.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int led_state = 0;
|
||||
void hal_led_toggle(void){
|
||||
led_state = 1 - led_state;
|
||||
printf("LED State %u\n", led_state);
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]){
|
||||
|
||||
/// GET STARTED with BTstack ///
|
||||
btstack_memory_init();
|
||||
run_loop_init(RUN_LOOP_POSIX);
|
||||
|
||||
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
|
||||
hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
|
||||
|
||||
// pick serial port
|
||||
hci_uart_config_generic.device_name = "/dev/tty.usbmodem1413";
|
||||
|
||||
// init HCI
|
||||
hci_transport_t * transport = hci_transport_h4_instance();
|
||||
remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_fs;
|
||||
|
||||
hci_init(transport, (void*) &hci_uart_config_generic, NULL, remote_db);
|
||||
|
||||
// handle CTRL-c
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
// setup app
|
||||
btstack_main(argc, argv);
|
||||
|
||||
// go
|
||||
run_loop_execute();
|
||||
|
||||
return 0;
|
||||
}
|
@ -21,4 +21,6 @@
|
||||
#define HAVE_HCI_DUMP
|
||||
#define SDP_DES_DUMP
|
||||
|
||||
// #define HAVE_SCO
|
||||
|
||||
#endif
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "hci.h"
|
||||
#include "hci_dump.h"
|
||||
#include "stdin_support.h"
|
||||
#include "hal_led.h"
|
||||
#include "bt_control_cc256x.h"
|
||||
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "ble/att.h"
|
||||
#include "utils.h"
|
||||
#include "debug.h"
|
||||
#include "bluetooth.h"
|
||||
|
||||
// ATT DB Storage
|
||||
#ifndef HAVE_MALLOC
|
||||
|
@ -683,7 +683,12 @@
|
||||
#define HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED 0x07
|
||||
#define HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR 0x08
|
||||
#define HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE 0x09
|
||||
#define HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x0A
|
||||
#define HFP_SUBEVENT_START_RINGINIG 0x0A
|
||||
#define HFP_SUBEVENT_STOP_RINGINIG 0x0B
|
||||
#define HFP_SUBEVENT_CALL_TERMINATED 0x0C
|
||||
#define HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER 0x0D
|
||||
#define HFP_SUBEVENT_REDIAL_LAST_NUMBER 0x0E
|
||||
#define HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG 0x0F
|
||||
|
||||
// ANCS Client
|
||||
#define ANCS_CLIENT_CONNECTED 0xF0
|
||||
|
@ -204,6 +204,28 @@ void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t valu
|
||||
(*callback)(event, sizeof(event));
|
||||
}
|
||||
|
||||
void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const char * value){
|
||||
if (!callback) return;
|
||||
uint8_t event[24];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = event_subtype;
|
||||
int size = (strlen(value) < sizeof(event) - 4) ? strlen(value) : sizeof(event) - 4;
|
||||
strncpy((char*)&event[3], value, size);
|
||||
event[3 + size] = 0;
|
||||
(*callback)(event, sizeof(event));
|
||||
}
|
||||
|
||||
static void hfp_emit_audio_connection_established_event(hfp_callback_t callback, uint8_t value, uint16_t sco_handle){
|
||||
if (!callback) return;
|
||||
uint8_t event[6];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED;
|
||||
event[3] = value; // status 0 == OK
|
||||
bt_store_16(event, 4, sco_handle);
|
||||
(*callback)(event, sizeof(event));
|
||||
}
|
||||
|
||||
linked_list_t * hfp_get_connections(){
|
||||
return (linked_list_t *) &hfp_connections;
|
||||
@ -233,12 +255,12 @@ hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
|
||||
hfp_connection_t * get_hfp_connection_context_for_sco_handle(uint16_t handle){
|
||||
linked_list_iterator_t it;
|
||||
linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (linked_list_iterator_has_next(&it)){
|
||||
hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
|
||||
if (connection->con_handle == handle){
|
||||
if (connection->sco_handle == handle){
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@ -247,35 +269,18 @@ static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle)
|
||||
|
||||
void hfp_reset_context_flags(hfp_connection_t * context){
|
||||
if (!context) return;
|
||||
context->wait_ok = 0;
|
||||
context->send_ok = 0;
|
||||
context->ok_pending = 0;
|
||||
context->send_error = 0;
|
||||
|
||||
context->keep_separator = 0;
|
||||
|
||||
context->retrieve_ag_indicators = 0; // HFP_CMD_INDICATOR, check if needed
|
||||
context->retrieve_ag_indicators_status = 0;
|
||||
|
||||
context->list_generic_status_indicators = 0; // HFP_CMD_LIST_GENERIC_STATUS_INDICATOR
|
||||
context->retrieve_generic_status_indicators = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR
|
||||
context->retrieve_generic_status_indicators_state = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR_STATE
|
||||
|
||||
context->change_status_update_for_individual_ag_indicators = 0;
|
||||
|
||||
context->operator_name_format = 0;
|
||||
context->operator_name = 0;
|
||||
context->operator_name_changed = 0;
|
||||
|
||||
context->enable_extended_audio_gateway_error_report = 0;
|
||||
context->extended_audio_gateway_error = 0;
|
||||
|
||||
// can come any time (here taken into account only after SLE),
|
||||
// if codec negotiation feature is set
|
||||
context->notify_ag_on_new_codecs = 0;
|
||||
|
||||
// establish codecs connection
|
||||
context->ag_trigger_codec_connection_setup = 0;
|
||||
context->hf_trigger_codec_connection_setup = 0;
|
||||
context->suggested_codec = 0;
|
||||
context->negotiated_codec = 0;
|
||||
context->codec_confirmed = 0;
|
||||
@ -290,6 +295,9 @@ static hfp_connection_t * create_hfp_connection_context(){
|
||||
memset(context,0, sizeof(hfp_connection_t));
|
||||
|
||||
context->state = HFP_IDLE;
|
||||
context->call_state = HFP_CALL_IDLE;
|
||||
context->codecs_state = HFP_CODECS_IDLE;
|
||||
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->negotiated_codec = 0;
|
||||
@ -311,10 +319,15 @@ static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t b
|
||||
hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (context) return context;
|
||||
context = create_hfp_connection_context();
|
||||
printf("created context for address %s\n", bd_addr_to_str(bd_addr));
|
||||
memcpy(context->remote_addr, bd_addr, 6);
|
||||
return context;
|
||||
}
|
||||
|
||||
/* @param network.
|
||||
* 0 == no ability to reject a call.
|
||||
* 1 == ability to reject a call.
|
||||
*/
|
||||
|
||||
/* @param suported_features
|
||||
* HF bit 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
|
||||
@ -333,8 +346,7 @@ static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t b
|
||||
* AG bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
|
||||
*/
|
||||
|
||||
|
||||
void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features){
|
||||
void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name){
|
||||
uint8_t* attribute;
|
||||
de_create_sequence(service);
|
||||
|
||||
@ -396,8 +408,6 @@ void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_
|
||||
// 0x0100 "Service Name"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
|
||||
de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name);
|
||||
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
|
||||
}
|
||||
|
||||
static hfp_connection_t * connection_doing_sdp_query = NULL;
|
||||
@ -439,6 +449,8 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
uint16_t rfcomm_cid, handle;
|
||||
hfp_connection_t * context = NULL;
|
||||
|
||||
// printf("AG packet_handler type %u, packet[0] %x, size %u\n", packet_type, packet[0], size);
|
||||
|
||||
switch (packet[0]) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
// bt stack activated, get started
|
||||
@ -457,7 +469,7 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
case RFCOMM_EVENT_INCOMING_CONNECTION:
|
||||
// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
|
||||
bt_flip_addr(event_addr, &packet[2]);
|
||||
context = get_hfp_connection_context_for_bd_addr(event_addr);
|
||||
context = provide_hfp_connection_context_for_bd_addr(event_addr);
|
||||
|
||||
if (!context || context->state != HFP_IDLE) return;
|
||||
|
||||
@ -469,7 +481,8 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
|
||||
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
|
||||
// data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
|
||||
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x, size %u\n", packet_type, packet[0], size);
|
||||
|
||||
bt_flip_addr(event_addr, &packet[3]);
|
||||
context = get_hfp_connection_context_for_bd_addr(event_addr);
|
||||
if (!context || context->state != HFP_W4_RFCOMM_CONNECTED) return;
|
||||
@ -479,6 +492,8 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
remove_hfp_connection_context(context);
|
||||
} else {
|
||||
context->con_handle = READ_BT_16(packet, 9);
|
||||
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE con_handle 0x%02x\n", context->con_handle);
|
||||
|
||||
context->rfcomm_cid = READ_BT_16(packet, 12);
|
||||
uint16_t mtu = READ_BT_16(packet, 14);
|
||||
printf("RFCOMM channel open succeeded. Context %p, RFCOMM Channel ID 0x%02x, max frame size %u\n", context, context->rfcomm_cid, mtu);
|
||||
@ -494,17 +509,27 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// forward event to app, to learn about con_handle
|
||||
(*callback)(packet, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
|
||||
bt_flip_addr(event_addr, &packet[5]);
|
||||
int index = 2;
|
||||
uint8_t status = packet[index++];
|
||||
|
||||
if (status != 0){
|
||||
log_error("(e)SCO Connection is not established, status %u", status);
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t sco_handle = READ_BT_16(packet, index);
|
||||
index+=2;
|
||||
bd_addr_t address;
|
||||
memcpy(address, &packet[index], 6);
|
||||
|
||||
bt_flip_addr(event_addr, &packet[index]);
|
||||
index+=6;
|
||||
|
||||
uint8_t link_type = packet[index++];
|
||||
uint8_t transmission_interval = packet[index++]; // measured in slots
|
||||
uint8_t retransmission_interval = packet[index++];// measured in slots
|
||||
@ -514,39 +539,41 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
index+=2;
|
||||
uint8_t air_mode = packet[index];
|
||||
|
||||
if (status != 0){
|
||||
log_error("(e)SCO Connection is not established, status %u", status);
|
||||
break;
|
||||
}
|
||||
switch (link_type){
|
||||
case 0x00:
|
||||
printf("SCO Connection established. \n");
|
||||
log_info("SCO Connection established.");
|
||||
if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
|
||||
if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
|
||||
if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
|
||||
if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
|
||||
break;
|
||||
case 0x02:
|
||||
printf("eSCO Connection established. \n");
|
||||
log_info("eSCO Connection established. \n");
|
||||
break;
|
||||
default:
|
||||
log_error("(e)SCO reserved link_type 0x%2x", link_type);
|
||||
break;
|
||||
}
|
||||
log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, "
|
||||
" 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);
|
||||
" rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)\n", sco_handle,
|
||||
bd_addr_to_str(event_addr), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);
|
||||
|
||||
context = get_hfp_connection_context_for_bd_addr(address);
|
||||
context = get_hfp_connection_context_for_bd_addr(event_addr);
|
||||
|
||||
if (!context) {
|
||||
log_error("SCO link created, context for address %s not found.", bd_addr_to_str(event_addr));
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
|
||||
log_info("SCO about to disconnect: HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN");
|
||||
context->state = HFP_W2_DISCONNECT_SCO;
|
||||
break;
|
||||
}
|
||||
|
||||
context->sco_handle = sco_handle;
|
||||
context->establish_audio_connection = 0;
|
||||
context->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
|
||||
hfp_emit_audio_connection_established_event(callback, packet[2], sco_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -566,15 +593,23 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
|
||||
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
||||
handle = READ_BT_16(packet,3);
|
||||
context = get_hfp_connection_context_for_handle(handle);
|
||||
context = get_hfp_connection_context_for_sco_handle(handle);
|
||||
|
||||
if (!context) break;
|
||||
if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
|
||||
context->state = HFP_IDLE;
|
||||
hfp_establish_service_level_connection(context->remote_addr, context->service_uuid);
|
||||
|
||||
if (context->state != HFP_W4_SCO_DISCONNECTED){
|
||||
log_info("Received gap disconnect in wrong hfp state");
|
||||
}
|
||||
log_info("Check SCO handle: incoming 0x%02x, context 0x%02x\n", handle,context->sco_handle);
|
||||
|
||||
if (handle == context->sco_handle){
|
||||
log_info("SCO disconnected, w2 disconnect RFCOMM\n");
|
||||
context->sco_handle = 0;
|
||||
context->release_audio_connection = 0;
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED, 0);
|
||||
break;
|
||||
}
|
||||
hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, packet[2]);
|
||||
remove_hfp_connection_context(context);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -582,145 +617,171 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
// translates command string into hfp_command_t CMD and flags to distinguish between CMD=, CMD?, CMD=?
|
||||
static void process_command(hfp_connection_t * context){
|
||||
if (context->line_size < 2) return;
|
||||
// printf("process_command %s\n", context->line_buffer);
|
||||
context->command = HFP_CMD_NONE;
|
||||
int offset = 0;
|
||||
int isHandsFree = 1;
|
||||
// translates command string into hfp_command_t CMD
|
||||
static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
int offset = isHandsFree ? 0 : 2;
|
||||
|
||||
if (strncmp((char *)context->line_buffer, "AT", 2) == 0){
|
||||
offset = 2;
|
||||
isHandsFree = 0;
|
||||
if (strncmp(line_buffer+offset, HFP_PHONE_NUMBER_FOR_VOICE_TAG, strlen(HFP_PHONE_NUMBER_FOR_VOICE_TAG)) == 0){
|
||||
if (isHandsFree) return HFP_CMD_AG_SEND_PHONE_NUMBER;
|
||||
return HFP_CMD_HF_REQUEST_PHONE_NUMBER;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_TRANSMIT_DTMF_CODES, strlen(HFP_TRANSMIT_DTMF_CODES)) == 0){
|
||||
return HFP_CMD_TRANSMIT_DTMF_CODES;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_SET_MICROPHONE_GAIN, strlen(HFP_SET_MICROPHONE_GAIN)) == 0){
|
||||
return HFP_CMD_SET_MICROPHONE_GAIN;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_SET_SPEAKER_GAIN, strlen(HFP_SET_SPEAKER_GAIN)) == 0){
|
||||
return HFP_CMD_SET_SPEAKER_GAIN;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_ERROR, strlen(HFP_ERROR)) == 0){
|
||||
context->command = HFP_CMD_ERROR;
|
||||
return;
|
||||
if (strncmp(line_buffer+offset, HFP_ACTIVATE_VOICE_RECOGNITION, strlen(HFP_ACTIVATE_VOICE_RECOGNITION)) == 0){
|
||||
if (isHandsFree) return HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION;
|
||||
return HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION;
|
||||
}
|
||||
|
||||
if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_OK, strlen(HFP_OK)) == 0){
|
||||
//printf("parsed HFP_CMD_OK \n");
|
||||
context->command = HFP_CMD_OK;
|
||||
return;
|
||||
if (strncmp(line_buffer+offset, HFP_TURN_OFF_EC_AND_NR, strlen(HFP_TURN_OFF_EC_AND_NR)) == 0){
|
||||
return HFP_CMD_TURN_OFF_EC_AND_NR;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORTED_FEATURES, strlen(HFP_SUPPORTED_FEATURES)) == 0){
|
||||
context->command = HFP_CMD_SUPPORTED_FEATURES;
|
||||
return;
|
||||
if (strncmp(line_buffer, HFP_CALL_ANSWERED, strlen(HFP_CALL_ANSWERED)) == 0){
|
||||
return HFP_CMD_CALL_ANSWERED;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
|
||||
//printf("parsed HFP_INDICATOR \n");
|
||||
context->command = HFP_CMD_INDICATOR;
|
||||
if (isHandsFree) return;
|
||||
if (strncmp(line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0){
|
||||
return HFP_CMD_CALL_PHONE_NUMBER;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer, HFP_REDIAL_LAST_NUMBER, strlen(HFP_REDIAL_LAST_NUMBER)) == 0){
|
||||
return HFP_CMD_REDIAL_LAST_NUMBER;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_CHANGE_IN_BAND_RING_TONE_SETTING, strlen(HFP_CHANGE_IN_BAND_RING_TONE_SETTING)) == 0){
|
||||
return HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_HANG_UP_CALL, strlen(HFP_HANG_UP_CALL)) == 0){
|
||||
return HFP_CMD_HANG_UP_CALL;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_ERROR, strlen(HFP_ERROR)) == 0){
|
||||
return HFP_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (isHandsFree && strncmp(line_buffer+offset, HFP_OK, strlen(HFP_OK)) == 0){
|
||||
return HFP_CMD_OK;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_SUPPORTED_FEATURES, strlen(HFP_SUPPORTED_FEATURES)) == 0){
|
||||
return HFP_CMD_SUPPORTED_FEATURES;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
|
||||
if (strncmp(line_buffer+strlen(HFP_INDICATOR)+offset, "?", 1) == 0){
|
||||
return HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+strlen(HFP_INDICATOR)+offset, "=?", 2) == 0){
|
||||
return HFP_CMD_RETRIEVE_AG_INDICATORS;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){
|
||||
return HFP_CMD_AVAILABLE_CODECS;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){
|
||||
return HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_ENABLE_CLIP, strlen(HFP_ENABLE_CLIP)) == 0){
|
||||
return HFP_CMD_ENABLE_CLIP;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_ENABLE_CALL_WAITING_NOTIFICATION, strlen(HFP_ENABLE_CALL_WAITING_NOTIFICATION)) == 0){
|
||||
return HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){
|
||||
|
||||
if (strncmp((char *)context->line_buffer+strlen(HFP_INDICATOR)+offset, "?", 1) == 0){
|
||||
context->retrieve_ag_indicators_status = 1;
|
||||
context->retrieve_ag_indicators = 0;
|
||||
} else {
|
||||
context->retrieve_ag_indicators = 1;
|
||||
context->retrieve_ag_indicators_status = 0;
|
||||
if (isHandsFree) return HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
|
||||
|
||||
if (strncmp(line_buffer+strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)+offset, "=?", 2) == 0){
|
||||
return HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){
|
||||
context->command = HFP_CMD_AVAILABLE_CODECS;
|
||||
context->notify_ag_on_new_codecs = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){
|
||||
context->command = HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){
|
||||
context->command = HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){
|
||||
context->command = HFP_CMD_GENERIC_STATUS_INDICATOR;
|
||||
if (isHandsFree) return;
|
||||
|
||||
if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=?", 2) == 0){
|
||||
context->list_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators = 1;
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
} else if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=", 1) == 0){
|
||||
context->list_generic_status_indicators = 1;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
} else {
|
||||
context->list_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators_state = 1;
|
||||
if (strncmp(line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=", 1) == 0){
|
||||
return HFP_CMD_CALL_HOLD;
|
||||
}
|
||||
return;
|
||||
|
||||
return HFP_CMD_UNKNOWN;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
|
||||
context->command = HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){
|
||||
if (isHandsFree) return HFP_CMD_UNKNOWN;
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_QUERY_OPERATOR_SELECTION, strlen(HFP_QUERY_OPERATOR_SELECTION)) == 0){
|
||||
context->command = HFP_CMD_QUERY_OPERATOR_SELECTION;
|
||||
context->operator_name = 1;
|
||||
context->operator_name_format = 0;
|
||||
if (isHandsFree) return;
|
||||
|
||||
context->operator_name = 0;
|
||||
if (strncmp((char *)context->line_buffer+strlen(HFP_QUERY_OPERATOR_SELECTION)+offset, "=", 1) == 0){
|
||||
context->operator_name_format = 1;
|
||||
if (strncmp(line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=?", 2) == 0){
|
||||
return HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_TRANSFER_AG_INDICATOR_STATUS)) == 0){
|
||||
context->command = HFP_CMD_TRANSFER_AG_INDICATOR_STATUS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
|
||||
context->command = HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
|
||||
context->command = HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_TRIGGER_CODEC_CONNECTION_SETUP, strlen(HFP_TRIGGER_CODEC_CONNECTION_SETUP)) == 0){
|
||||
context->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP;
|
||||
// printf("HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP update command\n");
|
||||
if (isHandsFree){
|
||||
context->hf_trigger_codec_connection_setup = 1;
|
||||
printf("update command: hf_trigger_codec_connection_setup = 1\n");
|
||||
} else {
|
||||
context->hf_trigger_codec_connection_setup = 1;
|
||||
printf("update command: hf_trigger_codec_connection_setup = 1\n");
|
||||
if (strncmp(line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=", 1) == 0){
|
||||
return HFP_CMD_LIST_GENERIC_STATUS_INDICATORS;
|
||||
}
|
||||
return;
|
||||
return HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){
|
||||
if (!isHandsFree){
|
||||
context->command = HFP_CMD_HF_CONFIRMED_CODEC;
|
||||
} else {
|
||||
context->command = HFP_CMD_AG_SUGGESTED_CODEC;
|
||||
}
|
||||
return;
|
||||
if (strncmp(line_buffer+offset, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
|
||||
return HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, "NOP", 3) == 0) return;
|
||||
|
||||
printf(" process unknown command 3 %s \n", context->line_buffer);
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_QUERY_OPERATOR_SELECTION, strlen(HFP_QUERY_OPERATOR_SELECTION)) == 0){
|
||||
if (strncmp(line_buffer+strlen(HFP_QUERY_OPERATOR_SELECTION)+offset, "=", 1) == 0){
|
||||
return HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT;
|
||||
}
|
||||
return HFP_CMD_QUERY_OPERATOR_SELECTION_NAME;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_TRANSFER_AG_INDICATOR_STATUS)) == 0){
|
||||
return HFP_CMD_TRANSFER_AG_INDICATOR_STATUS;
|
||||
}
|
||||
|
||||
if (isHandsFree && strncmp(line_buffer+offset, HFP_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
|
||||
return HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR;
|
||||
}
|
||||
|
||||
if (!isHandsFree && strncmp(line_buffer+offset, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
|
||||
return HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_TRIGGER_CODEC_CONNECTION_SETUP, strlen(HFP_TRIGGER_CODEC_CONNECTION_SETUP)) == 0){
|
||||
return HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){
|
||||
if (isHandsFree){
|
||||
return HFP_CMD_AG_SUGGESTED_CODEC;
|
||||
} else {
|
||||
return HFP_CMD_HF_CONFIRMED_CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, "AT+", 3) == 0){
|
||||
printf(" process unknown HF command %s \n", line_buffer);
|
||||
return HFP_CMD_UNKNOWN;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, "+", 1) == 0){
|
||||
printf(" process unknown AG command %s \n", line_buffer);
|
||||
return HFP_CMD_UNKNOWN;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, "NOP", 3) == 0){
|
||||
return HFP_CMD_NONE;
|
||||
}
|
||||
|
||||
return HFP_CMD_NONE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -773,20 +834,15 @@ static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
|
||||
case HFP_PARSER_CMD_SEQUENCE:
|
||||
switch (context->command){
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
case HFP_CMD_INDICATOR:
|
||||
if (context->retrieve_ag_indicators == 1){
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
}
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
case HFP_CMD_GENERIC_STATUS_INDICATOR:
|
||||
if (context->retrieve_generic_status_indicators_state == 1){
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
}
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -796,7 +852,7 @@ static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
|
||||
context->parser_state = HFP_PARSER_THIRD_ITEM;
|
||||
break;
|
||||
case HFP_PARSER_THIRD_ITEM:
|
||||
if (context->command == HFP_CMD_INDICATOR && context->retrieve_ag_indicators){
|
||||
if (context->command == HFP_CMD_RETRIEVE_AG_INDICATORS){
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
break;
|
||||
}
|
||||
@ -805,9 +861,22 @@ static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
int value;
|
||||
|
||||
// handle ATD<dial_string>;
|
||||
if (strncmp((const char*)context->line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0){
|
||||
// check for end-of-line or ';'
|
||||
if (byte == ';' || hfp_parser_is_end_of_line(byte)){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
context->command = HFP_CMD_CALL_PHONE_NUMBER;
|
||||
} else {
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: handle space inside word
|
||||
if (byte == ' ' && context->parser_state > HFP_PARSER_CMD_HEADER) return;
|
||||
|
||||
@ -839,12 +908,61 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
// printf(" parse header 2 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
|
||||
if (hfp_parser_is_end_of_header(byte) || context->keep_separator == 1){
|
||||
// printf(" parse header 3 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
|
||||
process_command(context);
|
||||
char * line_buffer = (char *)context->line_buffer;
|
||||
context->command = parse_command(line_buffer, isHandsFree);
|
||||
|
||||
/* resolve command name according to context */
|
||||
if (context->command == HFP_CMD_UNKNOWN){
|
||||
switch(context->state){
|
||||
case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
|
||||
context->command = HFP_CMD_LIST_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
context->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
context->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
context->command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS:
|
||||
context->command = HFP_CMD_RETRIEVE_AG_INDICATORS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes
|
||||
switch (context->command){
|
||||
case HFP_CMD_SET_MICROPHONE_GAIN:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->microphone_gain = value;
|
||||
log_info("hfp parse HFP_CMD_SET_MICROPHONE_GAIN %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_SET_SPEAKER_GAIN:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->speaker_gain = value;
|
||||
log_info("hfp parse HFP_CMD_SET_SPEAKER_GAIN %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->ag_activate_voice_recognition = value;
|
||||
log_info("hfp parse HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_TURN_OFF_EC_AND_NR:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->ag_echo_and_noise_reduction = value;
|
||||
log_info("hfp parse HFP_CMD_TURN_OFF_EC_AND_NR %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->remote_supported_features = store_bit(context->remote_supported_features, HFP_AGSF_IN_BAND_RING_TONE, value);
|
||||
log_info("hfp parse HFP_CHANGE_IN_BAND_RING_TONE_SETTING %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_HF_CONFIRMED_CODEC:
|
||||
context->codec_confirmed = atoi((char*)context->line_buffer);
|
||||
log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", context->codec_confirmed);
|
||||
@ -863,19 +981,15 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
context->parser_item_index++;
|
||||
context->remote_codecs_nr = context->parser_item_index;
|
||||
break;
|
||||
case HFP_CMD_INDICATOR:
|
||||
if (context->retrieve_ag_indicators == 1){
|
||||
strcpy((char *)context->ag_indicators[context->parser_item_index].name, (char *)context->line_buffer);
|
||||
context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1;
|
||||
log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer);
|
||||
}
|
||||
|
||||
if (context->retrieve_ag_indicators_status == 1){
|
||||
log_info("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer);
|
||||
context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
break;
|
||||
}
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
strcpy((char *)context->ag_indicators[context->parser_item_index].name, (char *)context->line_buffer);
|
||||
context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1;
|
||||
log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
|
||||
log_info("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer);
|
||||
context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
break;
|
||||
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
||||
context->parser_item_index++;
|
||||
@ -890,27 +1004,18 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer);
|
||||
context->remote_call_services_nr++;
|
||||
break;
|
||||
case HFP_CMD_GENERIC_STATUS_INDICATOR:
|
||||
log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 1 (%d, %d, %d)\n",
|
||||
context->list_generic_status_indicators,
|
||||
context->retrieve_generic_status_indicators,
|
||||
context->retrieve_generic_status_indicators_state);
|
||||
if (context->retrieve_generic_status_indicators == 1 || context->list_generic_status_indicators == 1){
|
||||
log_info("Parsed Generic status indicator: %s\n", context->line_buffer);
|
||||
context->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
context->generic_status_indicators_nr = context->parser_item_index;
|
||||
break;
|
||||
}
|
||||
log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 2\n");
|
||||
if (context->retrieve_generic_status_indicators_state == 1){
|
||||
// HF parses inital AG gen. ind. state
|
||||
log_info("Parsed List generic status indicator %s state: ", context->line_buffer);
|
||||
context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
}
|
||||
case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
log_info("Parsed Generic status indicator: %s\n", context->line_buffer);
|
||||
context->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
context->generic_status_indicators_nr = context->parser_item_index;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
// HF parses inital AG gen. ind. state
|
||||
log_info("Parsed List generic status indicator %s state: ", context->line_buffer);
|
||||
context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
|
||||
case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
|
||||
// AG parses new gen. ind. state
|
||||
log_info("Parsed Enable ag indicator state: %s\n", context->line_buffer);
|
||||
@ -925,22 +1030,17 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1;
|
||||
log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION:
|
||||
if (context->operator_name_format == 1){
|
||||
if (context->line_buffer[0] == '3'){
|
||||
log_info("Parsed Set network operator format : %s, ", context->line_buffer);
|
||||
break;
|
||||
}
|
||||
// TODO emit ERROR, wrong format
|
||||
log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->operator_name == 1) {
|
||||
context->network_operator.mode = atoi((char *)&context->line_buffer[0]);
|
||||
log_info("Parsed network operator mode: %d, ", context->network_operator.mode);
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
context->network_operator.mode = atoi((char *)&context->line_buffer[0]);
|
||||
log_info("Parsed network operator mode: %d, ", context->network_operator.mode);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
if (context->line_buffer[0] == '3'){
|
||||
log_info("Parsed Set network operator format : %s, ", context->line_buffer);
|
||||
break;
|
||||
}
|
||||
// TODO emit ERROR, wrong format
|
||||
log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_ERROR:
|
||||
break;
|
||||
@ -949,7 +1049,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
break;
|
||||
case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
context->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)context->line_buffer);
|
||||
context->send_ok = 1;
|
||||
context->ok_pending = 1;
|
||||
context->extended_audio_gateway_error = 0;
|
||||
break;
|
||||
default:
|
||||
@ -959,29 +1059,27 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
|
||||
case HFP_PARSER_SECOND_ITEM:
|
||||
switch (context->command){
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION:
|
||||
if (context->operator_name_format == 1) {
|
||||
log_info("format %s \n", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
break;
|
||||
}
|
||||
if (context->operator_name == 1){
|
||||
log_info("format %s, ", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
}
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
printf("format %s, ", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
break;
|
||||
case HFP_CMD_GENERIC_STATUS_INDICATOR:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
printf("format %s \n", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
break;
|
||||
case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
context->generic_status_indicators[context->parser_item_index].state = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
context->ag_indicators[context->parser_item_index].status = (uint8_t)atoi((char*)context->line_buffer);
|
||||
printf("%d \n", context->ag_indicators[context->parser_item_index].status);
|
||||
context->ag_indicators[context->parser_item_index].status_changed = 1;
|
||||
break;
|
||||
case HFP_CMD_INDICATOR:
|
||||
if (context->retrieve_ag_indicators == 1){
|
||||
context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer);
|
||||
log_info("%s, ", context->line_buffer);
|
||||
}
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer);
|
||||
log_info("%s, ", context->line_buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -990,19 +1088,15 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
|
||||
case HFP_PARSER_THIRD_ITEM:
|
||||
switch (context->command){
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION:
|
||||
if (context->operator_name == 1){
|
||||
strcpy(context->network_operator.name, (char *)context->line_buffer);
|
||||
log_info("name %s\n", context->line_buffer);
|
||||
}
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
strcpy(context->network_operator.name, (char *)context->line_buffer);
|
||||
log_info("name %s\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_INDICATOR:
|
||||
if (context->retrieve_ag_indicators == 1){
|
||||
context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
context->ag_indicators_nr = context->parser_item_index;
|
||||
log_info("%s)\n", context->line_buffer);
|
||||
}
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
context->ag_indicators_nr = context->parser_item_index;
|
||||
log_info("%s)\n", context->line_buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1025,6 +1119,7 @@ void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_
|
||||
log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (context->state){
|
||||
case HFP_W2_DISCONNECT_RFCOMM:
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
@ -1057,7 +1152,7 @@ void hfp_release_service_level_connection(hfp_connection_t * context){
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->state < HFP_CCE_W4_SCO_CONNECTION_ESTABLISHED){
|
||||
if (context->state < HFP_W4_SCO_CONNECTED){
|
||||
context->state = HFP_W2_DISCONNECT_RFCOMM;
|
||||
return;
|
||||
}
|
||||
@ -1070,10 +1165,10 @@ void hfp_release_service_level_connection(hfp_connection_t * context){
|
||||
return;
|
||||
}
|
||||
|
||||
void hfp_release_audio_connection(hfp_connection_t * connection){
|
||||
if (!connection) return;
|
||||
if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
|
||||
connection->release_audio_connection = 1;
|
||||
void hfp_release_audio_connection(hfp_connection_t * context){
|
||||
if (!context) return;
|
||||
if (context->state >= HFP_W2_DISCONNECT_SCO) return;
|
||||
context->release_audio_connection = 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,8 +66,9 @@ extern "C" {
|
||||
9: eSCO S4 (and T2) Settings Supported
|
||||
10-31: Reserved for future definition
|
||||
*/
|
||||
#define HFP_HFSF_THREE_WAY_CALLING 1
|
||||
#define HFP_HFSF_EC_NR_FUNCTION 0
|
||||
#define HFP_HFSF_THREE_WAY_CALLING 1
|
||||
#define HFP_HFSF_VOICE_RECOGNITION_FUNCTION 3
|
||||
#define HFP_HFSF_CODEC_NEGOTIATION 7
|
||||
#define HFP_HFSF_HF_INDICATORS 8
|
||||
#define HFP_HFSF_ESCO 9
|
||||
@ -89,6 +90,8 @@ extern "C" {
|
||||
*/
|
||||
#define HFP_AGSF_THREE_WAY_CALLING 0
|
||||
#define HFP_AGSF_EC_NR_FUNCTION 1
|
||||
#define HFP_AGSF_VOICE_RECOGNITION_FUNCTION 2
|
||||
#define HFP_AGSF_IN_BAND_RING_TONE 3
|
||||
#define HFP_AGSF_CODEC_NEGOTIATION 9
|
||||
#define HFP_AGSF_HF_INDICATORS 10
|
||||
#define HFP_AGSF_ESCO 11
|
||||
@ -105,6 +108,8 @@ extern "C" {
|
||||
#define HFP_AVAILABLE_CODECS "+BAC"
|
||||
#define HFP_INDICATOR "+CIND"
|
||||
#define HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS "+CMER"
|
||||
#define HFP_ENABLE_CLIP "+CLIP"
|
||||
#define HFP_ENABLE_CALL_WAITING_NOTIFICATION "+CCWA"
|
||||
#define HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS "+BIA" // +BIA:<enabled>,,<enabled>,,,<enabled>
|
||||
#define HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD"
|
||||
#define HFP_GENERIC_STATUS_INDICATOR "+BIND"
|
||||
@ -114,6 +119,19 @@ extern "C" {
|
||||
#define HFP_EXTENDED_AUDIO_GATEWAY_ERROR "+CME ERROR"
|
||||
#define HFP_TRIGGER_CODEC_CONNECTION_SETUP "+BCC"
|
||||
#define HFP_CONFIRM_COMMON_CODEC "+BCS"
|
||||
#define HFP_CALL_ANSWERED "ATA"
|
||||
#define HFP_HANG_UP_CALL "+CHUP"
|
||||
#define HFP_CHANGE_IN_BAND_RING_TONE_SETTING "+BSIR"
|
||||
#define HFP_CALL_PHONE_NUMBER "ATD"
|
||||
#define HFP_REDIAL_LAST_NUMBER "AT+BLDN"
|
||||
#define HFP_TURN_OFF_EC_AND_NR "+NREC" // EC (Echo CAnceling), NR (Noise Reduction)
|
||||
#define HFP_ACTIVATE_VOICE_RECOGNITION "+BVRA" // EC (Echo CAnceling), NR (Noise Reduction)
|
||||
#define HFP_SET_MICROPHONE_GAIN "+VGM"
|
||||
#define HFP_SET_SPEAKER_GAIN "+VGS"
|
||||
|
||||
#define HFP_PHONE_NUMBER_FOR_VOICE_TAG "+BINP"
|
||||
#define HFP_TRANSMIT_DTMF_CODES "+VTS"
|
||||
|
||||
|
||||
#define HFP_OK "OK"
|
||||
#define HFP_ERROR "ERROR"
|
||||
@ -125,26 +143,52 @@ extern "C" {
|
||||
typedef enum {
|
||||
HFP_CMD_NONE = 0,
|
||||
HFP_CMD_ERROR,
|
||||
HFP_CMD_UNKNOWN,
|
||||
HFP_CMD_OK,
|
||||
HFP_CMD_SUPPORTED_FEATURES,
|
||||
HFP_CMD_AVAILABLE_CODECS,
|
||||
HFP_CMD_INDICATOR, // 5
|
||||
|
||||
HFP_CMD_RETRIEVE_AG_INDICATORS,
|
||||
HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS,
|
||||
|
||||
HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE,
|
||||
HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE,
|
||||
HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES,
|
||||
HFP_CMD_ENABLE_CLIP,
|
||||
HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION,
|
||||
|
||||
HFP_CMD_GENERIC_STATUS_INDICATOR,
|
||||
|
||||
HFP_CMD_LIST_GENERIC_STATUS_INDICATORS,
|
||||
HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS,
|
||||
HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE,
|
||||
|
||||
HFP_CMD_TRANSFER_AG_INDICATOR_STATUS,
|
||||
HFP_CMD_QUERY_OPERATOR_SELECTION,
|
||||
|
||||
HFP_CMD_QUERY_OPERATOR_SELECTION_NAME,
|
||||
HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT,
|
||||
|
||||
HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR,
|
||||
HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR,
|
||||
HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP,
|
||||
HFP_CMD_AG_SEND_COMMON_CODEC,
|
||||
HFP_CMD_AG_SUGGESTED_CODEC,
|
||||
HFP_CMD_HF_CONFIRMED_CODEC
|
||||
|
||||
HFP_CMD_HF_CONFIRMED_CODEC,
|
||||
HFP_CMD_CALL_ANSWERED,
|
||||
HFP_CMD_CALL_HOLD,
|
||||
HFP_CMD_AG_ANSWER_CALL,
|
||||
HFP_CMD_HANG_UP_CALL,
|
||||
HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING,
|
||||
HFP_CMD_CALL_PHONE_NUMBER,
|
||||
HFP_CMD_REDIAL_LAST_NUMBER,
|
||||
HFP_CMD_TURN_OFF_EC_AND_NR,
|
||||
HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION,
|
||||
HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION,
|
||||
HFP_CMD_HF_REQUEST_PHONE_NUMBER,
|
||||
HFP_CMD_AG_SEND_PHONE_NUMBER,
|
||||
HFP_CMD_TRANSMIT_DTMF_CODES,
|
||||
HFP_CMD_SET_MICROPHONE_GAIN,
|
||||
HFP_CMD_SET_SPEAKER_GAIN
|
||||
} hfp_command_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
HFP_CME_ERROR_AG_FAILURE = 0,
|
||||
@ -195,11 +239,28 @@ typedef enum {
|
||||
} hfp_callsetup_status_t;
|
||||
|
||||
typedef enum {
|
||||
HFP_HELDCALL_STATUS_NO_CALLS_HELD = 0,
|
||||
HFP_HELDCALL_STATUS_CALL_ON_HOLD_OR_SWAPPED,
|
||||
HFP_HELDCALL_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS
|
||||
HFP_CALLHELD_STATUS_NO_CALLS_HELD = 0,
|
||||
HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED,
|
||||
HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS
|
||||
} hfp_callheld_status_t;
|
||||
|
||||
typedef enum {
|
||||
HFP_AG_INCOMING_CALL,
|
||||
HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG,
|
||||
HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF,
|
||||
HFP_AG_AUDIO_CONNECTION_ESTABLISHED,
|
||||
HFP_AG_OUTGOING_CALL_INITIATED,
|
||||
HFP_AG_OUTGOING_CALL_REJECTED,
|
||||
HFP_AG_OUTGOING_CALL_ACCEPTED,
|
||||
HFP_AG_OUTGOING_CALL_RINGING,
|
||||
HFP_AG_OUTGOING_CALL_ESTABLISHED,
|
||||
HFP_AG_OUTGOING_REDIAL_INITIATED,
|
||||
HFP_AG_TERMINATE_CALL_BY_AG,
|
||||
HFP_AG_TERMINATE_CALL_BY_HF,
|
||||
HFP_AG_CALL_DROPPED,
|
||||
} hfp_ag_call_event_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
HFP_PARSER_CMD_HEADER = 0,
|
||||
HFP_PARSER_CMD_SEQUENCE,
|
||||
@ -238,30 +299,59 @@ typedef enum {
|
||||
HFP_RETRIEVE_GENERIC_STATUS_INDICATORS,
|
||||
HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS,
|
||||
|
||||
HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS, // 20
|
||||
HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS,
|
||||
HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS,
|
||||
|
||||
HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED, // 22
|
||||
HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED,
|
||||
|
||||
HFP_SLE_W2_EXCHANGE_COMMON_CODEC,
|
||||
HFP_SLE_W4_EXCHANGE_COMMON_CODEC,
|
||||
HFP_W2_CONNECT_SCO,
|
||||
HFP_W4_SCO_CONNECTED,
|
||||
|
||||
HFP_CODECS_CONNECTION_ESTABLISHED, // 25
|
||||
|
||||
HFP_CCE_W2_ESTABLISH_SCO,
|
||||
HFP_CCE_W4_SCO_CONNECTION_ESTABLISHED,
|
||||
|
||||
HFP_AUDIO_CONNECTION_ESTABLISHED,
|
||||
HFP_AUDIO_CONNECTION_ESTABLISHED,
|
||||
|
||||
HFP_W2_DISCONNECT_SCO,
|
||||
HFP_W4_SCO_DISCONNECTED, // 30
|
||||
HFP_W4_SCO_DISCONNECTED,
|
||||
|
||||
HFP_W2_DISCONNECT_RFCOMM,
|
||||
HFP_W4_RFCOMM_DISCONNECTED,
|
||||
HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART,
|
||||
HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART,
|
||||
HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
|
||||
} hfp_state_t;
|
||||
|
||||
typedef enum {
|
||||
HFP_CODECS_IDLE,
|
||||
HFP_CODECS_RECEIVED_LIST,
|
||||
HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE,
|
||||
HFP_CODECS_W4_AG_COMMON_CODEC,
|
||||
HFP_CODECS_AG_SENT_COMMON_CODEC,
|
||||
HFP_CODECS_AG_RESEND_COMMON_CODEC,
|
||||
HFP_CODECS_EXCHANGED,
|
||||
HFP_CODECS_ERROR
|
||||
} hfp_codecs_state_t;
|
||||
|
||||
typedef enum {
|
||||
HFP_CALL_IDLE,
|
||||
HFP_CALL_TRIGGER_AUDIO_CONNECTION,
|
||||
HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING,
|
||||
HFP_CALL_RINGING,
|
||||
HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE,
|
||||
HFP_CALL_ACTIVE,
|
||||
HFP_CALL_W2_SEND_CALL_WAITING,
|
||||
HFP_CALL_W4_CHLD,
|
||||
HFP_CALL_OUTGOING_INITIATED,
|
||||
HFP_CALL_OUTGOING_DIALING,
|
||||
HFP_CALL_OUTGOING_RINGING
|
||||
} hfp_call_state_t;
|
||||
|
||||
typedef enum{
|
||||
HFP_NONE_SM,
|
||||
HFP_SLC_SM,
|
||||
HFP_SLC_QUERIES_SM,
|
||||
HFP_CODECS_CONNECTION_SM,
|
||||
HFP_AUDIO_CONNECTION_SM,
|
||||
HFP_CALL_SM
|
||||
} hfp_state_machine_t;
|
||||
|
||||
typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
|
||||
typedef struct{
|
||||
@ -291,7 +381,7 @@ typedef struct{
|
||||
char name[17]; // enabled
|
||||
} hfp_network_opearator_t;
|
||||
|
||||
|
||||
|
||||
typedef struct hfp_connection {
|
||||
linked_item_t item;
|
||||
|
||||
@ -301,7 +391,11 @@ typedef struct hfp_connection {
|
||||
uint16_t rfcomm_channel_nr;
|
||||
uint16_t rfcomm_cid;
|
||||
|
||||
hfp_state_machine_t state_machine;
|
||||
hfp_call_state_t call_state;
|
||||
hfp_state_t state;
|
||||
hfp_codecs_state_t codecs_state;
|
||||
|
||||
// needed for reestablishing connection
|
||||
uint16_t service_uuid;
|
||||
|
||||
@ -333,43 +427,44 @@ typedef struct hfp_connection {
|
||||
// Retrieved during service level connection establishment, not used yet
|
||||
uint8_t negotiated_codec;
|
||||
|
||||
// HF -> AG configuration
|
||||
uint8_t clip_enabled;
|
||||
uint8_t call_waiting_notification_enabled;
|
||||
|
||||
// TODO: put these bit flags in a bitmap
|
||||
uint8_t wait_ok;
|
||||
uint8_t send_ok;
|
||||
uint8_t ok_pending;
|
||||
// uint8_t send_ok;
|
||||
uint8_t send_error;
|
||||
|
||||
uint8_t keep_separator;
|
||||
|
||||
uint8_t retrieve_ag_indicators; // HFP_CMD_INDICATOR, check if needed
|
||||
uint8_t retrieve_ag_indicators_status;
|
||||
|
||||
uint8_t list_generic_status_indicators; // HFP_CMD_LIST_GENERIC_STATUS_INDICATOR
|
||||
uint8_t retrieve_generic_status_indicators; // HFP_CMD_GENERIC_STATUS_INDICATOR
|
||||
uint8_t retrieve_generic_status_indicators_state; // HFP_CMD_GENERIC_STATUS_INDICATOR_STATE
|
||||
|
||||
uint8_t change_status_update_for_individual_ag_indicators;
|
||||
|
||||
uint8_t operator_name_format;
|
||||
uint8_t operator_name;
|
||||
uint8_t operator_name_changed;
|
||||
|
||||
uint8_t enable_extended_audio_gateway_error_report;
|
||||
uint8_t extended_audio_gateway_error;
|
||||
|
||||
// can come any time (here taken into account only after SLE),
|
||||
// if codec negotiation feature is set
|
||||
uint8_t notify_ag_on_new_codecs;
|
||||
|
||||
// establish codecs connection
|
||||
uint8_t hf_trigger_codec_connection_setup;
|
||||
uint8_t ag_trigger_codec_connection_setup;
|
||||
uint8_t ag_ready_for_codecs_connection_setup;
|
||||
uint8_t suggested_codec;
|
||||
uint8_t codec_confirmed;
|
||||
|
||||
uint8_t establish_audio_connection;
|
||||
uint8_t release_audio_connection;
|
||||
|
||||
uint8_t change_in_band_ring_tone_setting;
|
||||
uint8_t ag_ring;
|
||||
uint8_t ag_send_clip;
|
||||
uint8_t ag_echo_and_noise_reduction;
|
||||
uint8_t ag_activate_voice_recognition;
|
||||
|
||||
uint8_t microphone_gain;
|
||||
uint8_t send_microphone_gain;
|
||||
|
||||
uint8_t speaker_gain;
|
||||
uint8_t send_speaker_gain;
|
||||
|
||||
uint8_t send_phone_number_for_voice_tag;
|
||||
timer_source_t hfp_timeout;
|
||||
} hfp_connection_t;
|
||||
|
||||
// UTILS_START : TODO move to utils
|
||||
@ -380,17 +475,21 @@ int get_bit(uint16_t bitmap, int position);
|
||||
int store_bit(uint32_t bitmap, int position, uint8_t value);
|
||||
// UTILS_END
|
||||
|
||||
void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
||||
void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name);
|
||||
void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t *packet, uint16_t size);
|
||||
void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value);
|
||||
void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const char * value);
|
||||
|
||||
hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid);
|
||||
hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr);
|
||||
hfp_connection_t * get_hfp_connection_context_for_sco_handle(uint16_t handle);
|
||||
|
||||
int get_hfp_generic_status_indicators_nr(void);
|
||||
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void);
|
||||
void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
|
||||
|
||||
linked_list_t * hfp_get_connections(void);
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree);
|
||||
|
||||
void hfp_init(uint16_t rfcomm_channel_nr);
|
||||
void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid);
|
||||
|
1627
src/classic/hfp_ag.c
1627
src/classic/hfp_ag.c
File diff suppressed because it is too large
Load Diff
@ -154,6 +154,9 @@ void hfp_ag_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t st
|
||||
*/
|
||||
void hfp_ag_negotiate_codecs(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_establish_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
@ -162,6 +165,102 @@ void hfp_ag_establish_audio_connection(bd_addr_t bd_addr);
|
||||
void hfp_ag_release_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable in-band ring tone
|
||||
*/
|
||||
void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_incoming_call(void);
|
||||
|
||||
/**
|
||||
* @brief number is stored.
|
||||
*/
|
||||
void hfp_ag_set_clip(uint8_t type, const char * number);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_outgoing_call_rejected(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_outgoing_call_accepted(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_outgoing_call_ringing(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_outgoing_call_established(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_call_dropped(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_answer_incoming_call(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_terminate_call(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_set_registration_status(int status);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_set_signal_strength(int strength);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_set_roaming_status(int status);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_set_battery_level(int level);
|
||||
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_activate_voice_recognition(bd_addr_t bd_addr, int activate);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * number);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr);
|
||||
|
||||
/* API_END */
|
||||
|
||||
#if defined __cplusplus
|
||||
|
@ -114,9 +114,11 @@ void hfp_hf_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const ch
|
||||
if (!name){
|
||||
name = default_hfp_hf_service_name;
|
||||
}
|
||||
hfp_create_sdp_record(service, SDP_Handsfree, rfcomm_channel_nr, name, supported_features);
|
||||
}
|
||||
hfp_create_sdp_record(service, SDP_Handsfree, rfcomm_channel_nr, name);
|
||||
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); // Hands-Free Profile - SupportedFeatures
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
|
||||
}
|
||||
|
||||
static int hfp_hf_cmd_exchange_supported_features(uint16_t cid){
|
||||
char buffer[20];
|
||||
@ -251,60 +253,48 @@ static void hfp_emit_network_operator_event(hfp_callback_t callback, int status,
|
||||
|
||||
static int hfp_hf_run_for_context_service_level_connection(hfp_connection_t * context){
|
||||
if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
||||
int done = 0;
|
||||
if (context->wait_ok) return done;
|
||||
|
||||
if (context->ok_pending) return 0;
|
||||
int done = 1;
|
||||
|
||||
switch (context->state){
|
||||
case HFP_EXCHANGE_SUPPORTED_FEATURES:
|
||||
hfp_hf_cmd_exchange_supported_features(context->rfcomm_cid);
|
||||
context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
|
||||
hfp_hf_cmd_exchange_supported_features(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_NOTIFY_ON_CODECS:
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
context->state = HFP_W4_NOTIFY_ON_CODECS;
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_RETRIEVE_INDICATORS:
|
||||
hfp_hf_cmd_retrieve_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INDICATORS;
|
||||
context->retrieve_ag_indicators = 1;
|
||||
context->retrieve_ag_indicators_status = 0;
|
||||
hfp_hf_cmd_retrieve_indicators(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_RETRIEVE_INDICATORS_STATUS:
|
||||
hfp_hf_cmd_retrieve_indicators_status(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
context->retrieve_ag_indicators_status = 1;
|
||||
context->retrieve_ag_indicators = 0;
|
||||
hfp_hf_cmd_retrieve_indicators_status(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_ENABLE_INDICATORS_STATUS_UPDATE:
|
||||
hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, 1);
|
||||
context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, 1);
|
||||
break;
|
||||
case HFP_RETRIEVE_CAN_HOLD_CALL:
|
||||
hfp_hf_cmd_retrieve_can_hold_call(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
|
||||
hfp_hf_cmd_retrieve_can_hold_call(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_LIST_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hf_cmd_list_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
|
||||
context->list_generic_status_indicators = 1;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
hfp_hf_cmd_list_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hf_cmd_retrieve_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
context->list_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators = 1;
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
hfp_hf_cmd_retrieve_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hf_cmd_list_initital_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
context->list_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators_state = 1;
|
||||
hfp_hf_cmd_list_initital_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
break;
|
||||
default:
|
||||
done = 0;
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
@ -327,12 +317,10 @@ static void hfp_hf_handle_ok_service_level_connection_establishment(hfp_connecti
|
||||
|
||||
case HFP_W4_RETRIEVE_INDICATORS:
|
||||
context->state = HFP_RETRIEVE_INDICATORS_STATUS;
|
||||
context->retrieve_ag_indicators = 0;
|
||||
break;
|
||||
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
context->retrieve_ag_indicators_status = 0;
|
||||
break;
|
||||
|
||||
case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE:
|
||||
@ -359,17 +347,14 @@ static void hfp_hf_handle_ok_service_level_connection_establishment(hfp_connecti
|
||||
|
||||
case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
|
||||
context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
break;
|
||||
|
||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
break;
|
||||
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
break;
|
||||
default:
|
||||
@ -377,39 +362,47 @@ static void hfp_hf_handle_ok_service_level_connection_establishment(hfp_connecti
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * context){
|
||||
if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return;
|
||||
if (context->wait_ok) return;
|
||||
static int hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * context){
|
||||
if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
||||
if (context->ok_pending) return 0;
|
||||
|
||||
int done = 0;
|
||||
if (context->enable_status_update_for_ag_indicators != 0xFF){
|
||||
context->ok_pending = 1;
|
||||
done = 1;
|
||||
hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, context->enable_status_update_for_ag_indicators);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
return done;
|
||||
};
|
||||
if (context->change_status_update_for_individual_ag_indicators){
|
||||
context->ok_pending = 1;
|
||||
done = 1;
|
||||
hfp_hf_cmd_activate_status_update_for_ag_indicator(context->rfcomm_cid,
|
||||
context->ag_indicators_status_update_bitmap,
|
||||
context->ag_indicators_nr);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
return done;
|
||||
}
|
||||
|
||||
if (context->operator_name_format){
|
||||
if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT){
|
||||
context->ok_pending = 1;
|
||||
done = 1;
|
||||
hfp_hf_cmd_query_operator_name_format(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
return done;
|
||||
}
|
||||
if (context->operator_name){
|
||||
if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME){
|
||||
context->ok_pending = 1;
|
||||
done = 1;
|
||||
hfp_hf_cmd_query_operator_name(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
return done;
|
||||
}
|
||||
|
||||
if (context->enable_extended_audio_gateway_error_report){
|
||||
context->ok_pending = 1;
|
||||
done = 1;
|
||||
hfp_hf_cmd_enable_extended_audio_gateway_error_report(context->rfcomm_cid, context->enable_extended_audio_gateway_error_report);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
return done;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static void hfp_hf_handle_ok_service_level_connection_queries(hfp_connection_t * context){
|
||||
@ -427,14 +420,12 @@ static void hfp_hf_handle_ok_service_level_connection_queries(hfp_connection_t *
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->operator_name_format){
|
||||
context->operator_name_format = 0;
|
||||
context->operator_name = 1;
|
||||
if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT){
|
||||
context->command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->operator_name){
|
||||
context->operator_name = 0;
|
||||
if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME){
|
||||
hfp_emit_network_operator_event(hfp_callback, 0, context->network_operator);
|
||||
return;
|
||||
}
|
||||
@ -444,141 +435,77 @@ static void hfp_hf_handle_ok_service_level_connection_queries(hfp_connection_t *
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hfp_hf_run_for_context_codecs_connection(hfp_connection_t * context){
|
||||
// if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED && context->state <= HFP_AUDIO_CONNECTION_ESTABLISHED){
|
||||
|
||||
// handle audio connection setup
|
||||
// printf("hfp_run_for_context state %d \n", context->state);
|
||||
if (context->wait_ok) return;
|
||||
|
||||
switch (context->state){
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
context->wait_ok = 1;
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->hf_trigger_codec_connection_setup){
|
||||
context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
|
||||
context->wait_ok = 1;
|
||||
hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->suggested_codec){
|
||||
context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
|
||||
context->codec_confirmed = 1;
|
||||
context->wait_ok = 1;
|
||||
hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->suggested_codec);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_SLE_W4_EXCHANGE_COMMON_CODEC:
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
context->wait_ok = 1;
|
||||
context->codec_confirmed = 0;
|
||||
context->suggested_codec = 0;
|
||||
context->negotiated_codec = 0;
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
if (context->suggested_codec){
|
||||
if (hfp_hf_supports_codec(context->suggested_codec)){
|
||||
context->codec_confirmed = context->suggested_codec;
|
||||
context->wait_ok = 1;
|
||||
hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->suggested_codec);
|
||||
} else {
|
||||
context->notify_ag_on_new_codecs = 1;
|
||||
context->wait_ok = 1;
|
||||
static int codecs_exchange_state_machine(hfp_connection_t * context){
|
||||
if (context->ok_pending) return 0;
|
||||
int done = 1;
|
||||
|
||||
switch(context->command){
|
||||
case HFP_CMD_AVAILABLE_CODECS:
|
||||
switch (context->codecs_state){
|
||||
case HFP_CODECS_W4_AG_COMMON_CODEC:
|
||||
context->codec_confirmed = 0;
|
||||
context->suggested_codec = 0;
|
||||
context->negotiated_codec = 0;
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
case HFP_CODECS_EXCHANGED:
|
||||
context->negotiated_codec = 0;
|
||||
context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
break;
|
||||
|
||||
case HFP_CODECS_CONNECTION_ESTABLISHED:
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
|
||||
context->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE;
|
||||
hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid);
|
||||
break;
|
||||
|
||||
case HFP_CMD_AG_SUGGESTED_CODEC:
|
||||
if (hfp_hf_supports_codec(context->suggested_codec)){
|
||||
context->codec_confirmed = context->suggested_codec;
|
||||
hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->suggested_codec);
|
||||
} else {
|
||||
context->codec_confirmed = 0;
|
||||
context->suggested_codec = 0;
|
||||
context->negotiated_codec = 0;
|
||||
context->wait_ok = 1;
|
||||
context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->hf_trigger_codec_connection_setup){
|
||||
context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
|
||||
context->wait_ok = 1;
|
||||
hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->establish_audio_connection){
|
||||
// TODO AUDIO CONNECTION
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (done){
|
||||
context->ok_pending = 1;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
static void hfp_hf_handle_ok_codecs_connection(hfp_connection_t * context){
|
||||
// handle audio connection setup
|
||||
switch (context->state){
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
context->notify_ag_on_new_codecs = 0;
|
||||
break;
|
||||
}
|
||||
case HFP_SLE_W2_EXCHANGE_COMMON_CODEC:
|
||||
if (context->hf_trigger_codec_connection_setup){
|
||||
context->hf_trigger_codec_connection_setup = 0;
|
||||
context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
|
||||
break;
|
||||
}
|
||||
// handle audio connection setup
|
||||
switch (context->codecs_state){
|
||||
case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE:
|
||||
context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC;
|
||||
break;
|
||||
case HFP_SLE_W4_EXCHANGE_COMMON_CODEC:
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
context->codec_confirmed = 0;
|
||||
context->suggested_codec = 0;
|
||||
context->notify_ag_on_new_codecs = 0;
|
||||
break;
|
||||
}
|
||||
if (context->codec_confirmed && context->suggested_codec){
|
||||
context->negotiated_codec = context->suggested_codec;
|
||||
context->codec_confirmed = 0;
|
||||
context->suggested_codec = 0;
|
||||
context->state = HFP_CODECS_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_AUDIO_CONNECTION_ESTABLISHED:
|
||||
printf("HFP_AUDIO_CONNECTION_ESTABLISHED \n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_run_for_context(hfp_connection_t * context){
|
||||
|
||||
if (!context) return;
|
||||
if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
|
||||
|
||||
hfp_hf_run_for_context_service_level_connection(context);
|
||||
hfp_hf_run_for_context_service_level_connection_queries(context);
|
||||
hfp_hf_run_for_context_codecs_connection(context);
|
||||
int done = hfp_hf_run_for_context_service_level_connection(context);
|
||||
if (!done){
|
||||
done = hfp_hf_run_for_context_service_level_connection_queries(context);
|
||||
}
|
||||
if (!done){
|
||||
done = codecs_exchange_state_machine(context);
|
||||
}
|
||||
|
||||
if (done) return;
|
||||
// deal with disconnect
|
||||
switch (context->state){
|
||||
case HFP_W2_DISCONNECT_RFCOMM:
|
||||
@ -593,12 +520,11 @@ static void hfp_run_for_context(hfp_connection_t * context){
|
||||
|
||||
static void hfp_hf_switch_on_ok(hfp_connection_t *context){
|
||||
// printf("switch on ok\n");
|
||||
context->wait_ok = 0;
|
||||
context->ok_pending = 0;
|
||||
|
||||
hfp_hf_handle_ok_service_level_connection_establishment(context);
|
||||
hfp_hf_handle_ok_service_level_connection_queries(context);
|
||||
hfp_hf_handle_ok_codecs_connection(context);
|
||||
|
||||
// done
|
||||
context->command = HFP_CMD_NONE;
|
||||
}
|
||||
@ -612,27 +538,27 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8
|
||||
int pos, i;
|
||||
//printf("\nHF received: %s", packet+2);
|
||||
for (pos = 0; pos < size ; pos++){
|
||||
hfp_parse(context, packet[pos]);
|
||||
hfp_parse(context, packet[pos], 1);
|
||||
|
||||
// emit indicators status changed
|
||||
for (i = 0; i < context->ag_indicators_nr; i++){
|
||||
if (context->ag_indicators[i].status_changed) {
|
||||
hfp_emit_ag_indicator_event(hfp_callback, 0, context->ag_indicators[i]);
|
||||
context->ag_indicators[i].status_changed = 0;
|
||||
hfp_emit_ag_indicator_event(hfp_callback, 0, context->ag_indicators[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->command == HFP_CMD_ERROR){
|
||||
context->wait_ok = 0;
|
||||
context->ok_pending = 0;
|
||||
hfp_reset_context_flags(context);
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 1);
|
||||
return;
|
||||
}
|
||||
if (context->command == HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR){
|
||||
context->wait_ok = 0;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, context->extended_audio_gateway_error);
|
||||
context->ok_pending = 0;
|
||||
context->extended_audio_gateway_error = 0;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, context->extended_audio_gateway_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -685,12 +611,14 @@ void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr){
|
||||
while (linked_list_iterator_has_next(&it)){
|
||||
hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
|
||||
if (!connection) continue;
|
||||
connection->notify_ag_on_new_codecs = 1;
|
||||
connection->command = HFP_CMD_AVAILABLE_CODECS;
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status){
|
||||
l2cap_init();
|
||||
l2cap_register_packet_handler(packet_handler);
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
|
||||
@ -745,7 +673,7 @@ void hfp_hf_query_operator_selection(bd_addr_t bd_addr){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
connection->operator_name_format = 1;
|
||||
connection->command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT;
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
@ -760,22 +688,6 @@ void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_negotiate_codecs(bd_addr_t bd_addr){
|
||||
hfp_hf_establish_service_level_connection(bd_addr);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!has_codec_negotiation_feature(connection)) return;
|
||||
if (connection->remote_codecs_nr == 0) return;
|
||||
|
||||
if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
|
||||
|
||||
if (connection->state != HFP_SLE_W2_EXCHANGE_COMMON_CODEC &&
|
||||
connection->state != HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
|
||||
connection->hf_trigger_codec_connection_setup = 1;
|
||||
}
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
|
||||
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr){
|
||||
hfp_hf_establish_service_level_connection(bd_addr);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
@ -785,9 +697,13 @@ void hfp_hf_establish_audio_connection(bd_addr_t bd_addr){
|
||||
if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
|
||||
|
||||
connection->establish_audio_connection = 1;
|
||||
if (connection->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
|
||||
connection->hf_trigger_codec_connection_setup = 1;
|
||||
}
|
||||
switch (connection->codecs_state){
|
||||
case HFP_CODECS_W4_AG_COMMON_CODEC:
|
||||
break;
|
||||
default:
|
||||
connection->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP;
|
||||
break;
|
||||
}
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
|
@ -141,8 +141,6 @@ void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_negotiate_codecs(bd_addr_t bd_addr);
|
||||
|
||||
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
|
@ -207,7 +207,7 @@ void hsp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char
|
||||
}
|
||||
|
||||
static int hsp_ag_send_str_over_rfcomm(uint16_t cid, char * command){
|
||||
if (!rfcomm_can_send_packet_now(rfcomm_cid)) return 1;
|
||||
if (!rfcomm_can_send_packet_now(cid)) return 1;
|
||||
int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
|
||||
if (err){
|
||||
printf("rfcomm_send_internal -> error 0X%02x", err);
|
||||
@ -337,16 +337,20 @@ static void hsp_run(void){
|
||||
int err;
|
||||
|
||||
if (ag_send_ok){
|
||||
ag_send_ok = 0;
|
||||
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, HSP_AG_OK);
|
||||
if (!err){
|
||||
ag_send_ok = 0;
|
||||
if (err){
|
||||
ag_send_ok = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ag_send_error){
|
||||
ag_send_error = 0;
|
||||
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, HSP_AG_ERROR);
|
||||
if (!err) ag_send_error = 0;
|
||||
if (err) {
|
||||
ag_send_error = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -359,18 +363,24 @@ static void hsp_run(void){
|
||||
|
||||
case HSP_W4_RING_ANSWER:
|
||||
if (ag_ring){
|
||||
ag_ring = 0;
|
||||
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, HSP_AG_RING);
|
||||
if (!err) ag_ring = 0;
|
||||
if (err) {
|
||||
ag_ring = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ag_num_button_press_received) break;
|
||||
|
||||
ag_send_ok = 0;
|
||||
|
||||
ag_num_button_press_received = 0;
|
||||
hsp_state = HSP_W2_CONNECT_SCO;
|
||||
|
||||
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, HSP_AG_OK);
|
||||
if (!err) {
|
||||
hsp_state = HSP_W2_CONNECT_SCO;
|
||||
ag_send_ok = 0;
|
||||
ag_num_button_press_received = 0;
|
||||
if (err) {
|
||||
hsp_state = HSP_W4_RING_ANSWER;
|
||||
ag_num_button_press_received = 1;
|
||||
}
|
||||
break;
|
||||
case HSP_W2_CONNECT_SCO:
|
||||
@ -393,18 +403,26 @@ static void hsp_run(void){
|
||||
case HSP_ACTIVE:
|
||||
|
||||
if (ag_microphone_gain >= 0){
|
||||
int gain = ag_microphone_gain;
|
||||
ag_microphone_gain = -1;
|
||||
char buffer[10];
|
||||
sprintf(buffer, "%s=%d\r\n", HSP_MICROPHONE_GAIN, ag_microphone_gain);
|
||||
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, buffer);
|
||||
if (!err) ag_microphone_gain = -1;
|
||||
if (err) {
|
||||
ag_microphone_gain = gain;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ag_speaker_gain >= 0){
|
||||
int gain = ag_speaker_gain;
|
||||
ag_speaker_gain = -1;
|
||||
char buffer[10];
|
||||
sprintf(buffer, "%s=%d\r\n", HSP_SPEAKER_GAIN, ag_speaker_gain);
|
||||
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, buffer);
|
||||
if (!err) ag_speaker_gain = -1;
|
||||
if (err) {
|
||||
ag_speaker_gain = gain;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -349,18 +349,26 @@ static void hsp_run(void){
|
||||
if (hs_ok_received) break;
|
||||
|
||||
if (hs_microphone_gain >= 0){
|
||||
int gain = hs_microphone_gain;
|
||||
hs_microphone_gain = -1;
|
||||
char buffer[20];
|
||||
sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain);
|
||||
err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
|
||||
if (!err) hs_microphone_gain = -1;
|
||||
if (err) {
|
||||
hs_microphone_gain = gain;
|
||||
}
|
||||
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, hs_speaker_gain);
|
||||
err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
|
||||
if (!err) hs_speaker_gain = -1;
|
||||
if (err) {
|
||||
hs_speaker_gain = gain;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2124,6 +2124,7 @@ int rfcomm_query_port_configuration(uint16_t rfcomm_cid){
|
||||
return rfcomm_send_uih_rpn_req(channel->multiplexer, channel->dlci);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t rfcomm_create_channel_internal(bd_addr_t addr, uint8_t server_channel, uint8_t incoming_flow_control, uint8_t initial_credits, uint16_t * out_rfcomm_cid){
|
||||
log_info("RFCOMM_CREATE_CHANNEL addr %s channel #%u init credits %u", bd_addr_to_str(addr), server_channel, initial_credits);
|
||||
|
||||
@ -2199,8 +2200,7 @@ void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
|
||||
rfcomm_run();
|
||||
}
|
||||
|
||||
static uint8_t rfcomm_register_service_internal(uint8_t channel, uint16_t max_frame_size, uint8_t incoming_flow_control, uint8_t initial_credits){
|
||||
log_info("RFCOMM_REGISTER_SERVICE channel #%u mtu %u flow_control %u credits %u",
|
||||
static uint8_t rfcomm_register_service_internal(uint8_t channel, uint16_t max_frame_size, uint8_t incoming_flow_control, uint8_t initial_credits){ log_info("RFCOMM_REGISTER_SERVICE channel #%u mtu %u flow_control %u credits %u",
|
||||
channel, max_frame_size, incoming_flow_control, initial_credits);
|
||||
|
||||
// check if already registered
|
||||
|
@ -53,6 +53,9 @@
|
||||
// called by test/sdp_client
|
||||
void sdp_query_rfcomm_init(void);
|
||||
|
||||
// called by test/sdp_client
|
||||
void sdp_query_rfcomm_init(void);
|
||||
|
||||
static void dummy_notify_app(sdp_query_event_t* event, void * context);
|
||||
|
||||
typedef enum {
|
||||
|
@ -43,7 +43,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include "btstack_defines.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
typedef enum {
|
||||
|
||||
// MITM protection not required
|
||||
|
@ -6,14 +6,12 @@ SUBDIRS = \
|
||||
ble_client \
|
||||
des_iterator \
|
||||
gatt_client \
|
||||
hfp \
|
||||
linked_list \
|
||||
remote_device_db \
|
||||
sdp_client \
|
||||
security_manager \
|
||||
|
||||
# hfp \
|
||||
|
||||
|
||||
subdirs:
|
||||
echo Building all tests
|
||||
@set -e; \
|
||||
|
@ -53,7 +53,8 @@
|
||||
#include "ble/att.h"
|
||||
#include "ble/att_db_util.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "bluetooth.h"
|
||||
|
||||
#include "le_counter.h"
|
||||
|
||||
#if 0
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bluetooth.h"
|
||||
|
||||
#include "classic/sdp_util.h"
|
||||
#include "CppUTest/TestHarness.h"
|
||||
#include "CppUTest/CommandLineTestRunner.h"
|
||||
|
@ -61,7 +61,7 @@ EXAMPLES = hfp_ag_parser_test hfp_ag_client_test hfp_hf_parser_test hfp_hf_clien
|
||||
all: ${BTSTACK_ROOT}/src/version.h ${EXAMPLES}
|
||||
|
||||
clean:
|
||||
rm -rf *.o $(PARSER_EXAMPLES) $(CLIENT_EXAMPLES) *.dSYM
|
||||
rm -rf *.o $(EXAMPLES) $(CLIENT_EXAMPLES) *.dSYM
|
||||
|
||||
hfp_ag_parser_test: ${COMMON_OBJ} hfp_ag.o hfp.o hfp_ag_parser_test.c
|
||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||
|
@ -84,6 +84,9 @@ static hfp_ag_indicator_t ag_indicators[] = {
|
||||
{7, "callheld", 0, 2, 0, 1, 1, 0}
|
||||
};
|
||||
|
||||
static int supported_features_with_codec_negotiation = 1007; // 0011 1110 1111
|
||||
static int supported_features_without_codec_negotiation = 495; // 0001 1110 1111
|
||||
|
||||
static int call_hold_services_nr = 5;
|
||||
static const char* call_hold_services[] = {"1", "1x", "2", "2x", "3"};
|
||||
|
||||
@ -97,8 +100,9 @@ static hfp_generic_status_indicator_t hf_indicators[] = {
|
||||
static uint8_t service_level_connection_established = 0;
|
||||
static uint8_t codecs_connection_established = 0;
|
||||
static uint8_t audio_connection_established = 0;
|
||||
static uint8_t service_level_connection_released = 0;
|
||||
|
||||
static uint8_t start_ringing = 0;
|
||||
static uint8_t stop_ringing = 0;
|
||||
static uint8_t call_termiated = 0;
|
||||
|
||||
int expected_rfcomm_command(const char * expected_cmd){
|
||||
char * ag_cmd = (char *)get_rfcomm_payload();
|
||||
@ -108,7 +112,7 @@ int expected_rfcomm_command(const char * expected_cmd){
|
||||
if ( (ag_cmd+i)[0] == '\r' || (ag_cmd+i)[0] == '\n' ) {
|
||||
continue;
|
||||
}
|
||||
if (memcmp(ag_cmd + i, expected_cmd, expected_len) == 0) return 1;
|
||||
if (strncmp(ag_cmd + i, expected_cmd, expected_len) == 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -119,9 +123,9 @@ void simulate_test_sequence(char ** test_steps, int nr_test_steps){
|
||||
for (i=0; i < nr_test_steps; i++){
|
||||
char * cmd = test_steps[i];
|
||||
printf("\n---> NEXT STEP %s\n", cmd);
|
||||
if (memcmp(cmd, "AT", 2) == 0){
|
||||
if (strncmp(cmd, "AT", 2) == 0){
|
||||
inject_rfcomm_command_to_ag((uint8_t*)cmd, strlen(cmd));
|
||||
} else if (memcmp(cmd, "NOP", 3) == 0){
|
||||
} else if (strncmp(cmd, "NOP", 3) == 0){
|
||||
inject_rfcomm_command_to_ag((uint8_t*)"NOP",3);
|
||||
} else {
|
||||
int expected_cmd = expected_rfcomm_command(cmd);
|
||||
@ -153,11 +157,29 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
codecs_connection_established = 1;
|
||||
audio_connection_established = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("\n** SLC released **\n\n");
|
||||
service_level_connection_established = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
|
||||
printf("\n** AC established **\n\n");
|
||||
audio_connection_established = 1;
|
||||
break;
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
service_level_connection_released = 1;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
|
||||
printf("\n** AC released **\n\n");
|
||||
audio_connection_established = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_START_RINGINIG:
|
||||
printf("\n** Start ringing **\n\n");
|
||||
start_ringing = 1;
|
||||
break;
|
||||
case HFP_SUBEVENT_STOP_RINGINIG:
|
||||
printf("\n** Stop ringing **\n\n");
|
||||
stop_ringing = 1;
|
||||
start_ringing = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_CALL_TERMINATED:
|
||||
call_termiated = 1;
|
||||
break;
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
@ -171,16 +193,24 @@ TEST_GROUP(HFPClient){
|
||||
service_level_connection_established = 0;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
service_level_connection_released = 0;
|
||||
start_ringing = 0;
|
||||
stop_ringing = 0;
|
||||
call_termiated = 0;
|
||||
|
||||
hfp_ag_init(rfcomm_channel_nr, supported_features_with_codec_negotiation,
|
||||
codecs, sizeof(codecs),
|
||||
ag_indicators, ag_indicators_nr,
|
||||
hf_indicators, hf_indicators_nr,
|
||||
call_hold_services, call_hold_services_nr);
|
||||
}
|
||||
|
||||
void teardown(void){
|
||||
if (service_level_connection_established){
|
||||
hfp_ag_release_service_level_connection(device_addr);
|
||||
CHECK_EQUAL(service_level_connection_released, 1);
|
||||
service_level_connection_established = 0;
|
||||
service_level_connection_released = 0;
|
||||
}
|
||||
hfp_ag_release_audio_connection(device_addr);
|
||||
hfp_ag_release_service_level_connection(device_addr);
|
||||
|
||||
service_level_connection_established = 0;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
}
|
||||
|
||||
void setup_hfp_service_level_connection(char ** test_steps, int nr_test_steps){
|
||||
@ -193,9 +223,78 @@ TEST_GROUP(HFPClient){
|
||||
codecs_connection_established = 0;
|
||||
simulate_test_sequence((char **) test_steps, nr_test_steps);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// TEST(HFPClient, HFAnswerIncomingCallWithInBandRingToneHFTermiantesCall){
|
||||
// setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
||||
// CHECK_EQUAL(service_level_connection_established, 1);
|
||||
|
||||
// hfp_ag_set_use_in_band_ring_tone(1);
|
||||
// hfp_ag_incoming_call();
|
||||
// simulate_test_sequence(default_ic_setup(), default_ic_setup_size());
|
||||
// CHECK_EQUAL(audio_connection_established, 1);
|
||||
|
||||
// simulate_test_sequence(alert_ic_setup(), alert_ic_setup_size());
|
||||
// CHECK_EQUAL(stop_ringing, 1);
|
||||
|
||||
// simulate_test_sequence(terminate_ic_hf_setup(), terminate_ic_hf_setup_size());
|
||||
// CHECK_EQUAL(call_termiated,1);
|
||||
// }
|
||||
|
||||
|
||||
// TEST(HFPClient, HFAnswerIncomingCallWithInBandRingToneAGTerminatesCall){
|
||||
// setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
||||
// CHECK_EQUAL(service_level_connection_established, 1);
|
||||
|
||||
// hfp_ag_set_use_in_band_ring_tone(1);
|
||||
// hfp_ag_incoming_call();
|
||||
// simulate_test_sequence(default_ic_setup(), default_ic_setup_size());
|
||||
// CHECK_EQUAL(audio_connection_established, 1);
|
||||
|
||||
// simulate_test_sequence(alert_ic_setup(), alert_ic_setup_size());
|
||||
// CHECK_EQUAL(stop_ringing, 1);
|
||||
|
||||
// // AG terminates call
|
||||
// hfp_ag_terminate_call();
|
||||
// simulate_test_sequence(terminate_ic_ag_setup(), terminate_ic_ag_setup_size());
|
||||
// CHECK_EQUAL(call_termiated,1);
|
||||
// }
|
||||
|
||||
|
||||
TEST(HFPClient, HFAudioConnectionEstablishedWithCodecNegotiation){
|
||||
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
|
||||
setup_hfp_codecs_connection(default_cc_setup(), default_cc_setup_size());
|
||||
CHECK_EQUAL(codecs_connection_established, 1);
|
||||
|
||||
hfp_ag_establish_audio_connection(device_addr);
|
||||
CHECK_EQUAL(audio_connection_established, 1);
|
||||
|
||||
hfp_ag_release_audio_connection(device_addr);
|
||||
CHECK_EQUAL(audio_connection_established, 0);
|
||||
}
|
||||
|
||||
TEST(HFPClient, HFAudioConnectionEstablishedWithoutCodecNegotiation){
|
||||
hfp_ag_init(rfcomm_channel_nr, supported_features_without_codec_negotiation,
|
||||
codecs, sizeof(codecs),
|
||||
ag_indicators, ag_indicators_nr,
|
||||
hf_indicators, hf_indicators_nr,
|
||||
call_hold_services, call_hold_services_nr);
|
||||
|
||||
setup_hfp_service_level_connection(hfp_slc_tests()[1].test, hfp_slc_tests()[1].len);
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
|
||||
setup_hfp_codecs_connection(default_cc_setup(), default_cc_setup_size());
|
||||
CHECK_EQUAL(codecs_connection_established, 1);
|
||||
|
||||
hfp_ag_establish_audio_connection(device_addr);
|
||||
CHECK_EQUAL(audio_connection_established, 1);
|
||||
|
||||
hfp_ag_release_audio_connection(device_addr);
|
||||
CHECK_EQUAL(audio_connection_established, 0);
|
||||
}
|
||||
|
||||
TEST(HFPClient, HFCodecsConnectionEstablished){
|
||||
for (int i = 0; i < cc_tests_size(); i++){
|
||||
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
||||
@ -215,20 +314,22 @@ TEST(HFPClient, HFServiceLevelConnectionCommands){
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPClient, HFServiceLevelConnectionEstablished){
|
||||
for (int i = 0; i < slc_tests_size(); i++){
|
||||
setup_hfp_service_level_connection(hfp_slc_tests()[i].test, hfp_slc_tests()[i].len);
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
hfp_ag_init(rfcomm_channel_nr, 1007, codecs, sizeof(codecs),
|
||||
TEST(HFPClient, HFServiceLevelConnectionEstablishedWithoutCodecNegotiation){
|
||||
hfp_ag_init(rfcomm_channel_nr, supported_features_without_codec_negotiation,
|
||||
codecs, sizeof(codecs),
|
||||
ag_indicators, ag_indicators_nr,
|
||||
hf_indicators, hf_indicators_nr,
|
||||
call_hold_services, call_hold_services_nr);
|
||||
setup_hfp_service_level_connection(hfp_slc_tests()[1].test, hfp_slc_tests()[1].len);
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
}
|
||||
|
||||
TEST(HFPClient, HFServiceLevelConnectionEstablishedWithCodecNegotiation){
|
||||
setup_hfp_service_level_connection(hfp_slc_tests()[0].test, hfp_slc_tests()[0].len);
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
}
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
hfp_ag_register_packet_handler(packet_handler);
|
||||
|
||||
return CommandLineTestRunner::RunAllTests(argc, argv);
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
#include "classic/hfp.h"
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree);
|
||||
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators();
|
||||
void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
|
||||
|
||||
@ -93,7 +93,7 @@ TEST(HFPParser, HFP_AG_SUPPORTED_FEATURES){
|
||||
sprintf(packet, "\r\nAT%s=159\r\n", HFP_SUPPORTED_FEATURES);
|
||||
context.keep_separator = 0;
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_SUPPORTED_FEATURES, context.command);
|
||||
CHECK_EQUAL(159, context.remote_supported_features);
|
||||
@ -102,7 +102,7 @@ TEST(HFPParser, HFP_AG_SUPPORTED_FEATURES){
|
||||
TEST(HFPParser, HFP_AG_AVAILABLE_CODECS){
|
||||
sprintf(packet, "\r\nAT%s=0,1,2\r\n", HFP_AVAILABLE_CODECS);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_AVAILABLE_CODECS, context.command);
|
||||
CHECK_EQUAL(3, context.remote_codecs_nr);
|
||||
@ -116,14 +116,10 @@ TEST(HFPParser, HFP_AG_GENERIC_STATUS_INDICATOR){
|
||||
sprintf(packet, "\r\nAT%s=0,1,2,3,4\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_GENERIC_STATUS_INDICATOR);
|
||||
CHECK_EQUAL(context.list_generic_status_indicators, 1);
|
||||
CHECK_EQUAL(context.retrieve_generic_status_indicators, 0);
|
||||
CHECK_EQUAL(context.retrieve_generic_status_indicators_state, 0);
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_LIST_GENERIC_STATUS_INDICATORS);
|
||||
CHECK_EQUAL(5, context.generic_status_indicators_nr);
|
||||
|
||||
for (pos = 0; pos < context.generic_status_indicators_nr; pos++){
|
||||
@ -135,7 +131,7 @@ TEST(HFPParser, HFP_AG_GENERIC_STATUS_INDICATOR){
|
||||
TEST(HFPParser, HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE){
|
||||
sprintf(packet, "\r\nAT%s=3,0,0,1\r\n", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE, context.command);
|
||||
CHECK_EQUAL(1, context.enable_status_update_for_ag_indicators);
|
||||
@ -157,7 +153,7 @@ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
|
||||
sprintf(packet, "\r\nAT%s=0,0,0,0,0,0,0\r\n",
|
||||
HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
|
||||
@ -175,7 +171,7 @@ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
|
||||
// sprintf(packet, "\r\nAT%s=1,,,1,1,1,\r\n",
|
||||
// HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
|
||||
// for (pos = 0; pos < strlen(packet); pos++){
|
||||
// hfp_parse(&context, packet[pos]);
|
||||
// hfp_parse(&context, packet[pos], 0);
|
||||
// }
|
||||
|
||||
// CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
|
||||
@ -191,23 +187,17 @@ TEST(HFPParser, HFP_AG_HF_QUERY_OPERATOR_SELECTION){
|
||||
sprintf(packet, "\r\nAT%s=3,0\r\n", HFP_QUERY_OPERATOR_SELECTION);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
CHECK_EQUAL(context.operator_name_format, 1);
|
||||
CHECK_EQUAL(context.operator_name, 0);
|
||||
CHECK_EQUAL(context.operator_name_changed, 0);
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_QUERY_OPERATOR_SELECTION, context.command);
|
||||
CHECK_EQUAL(context.network_operator.format, 0);
|
||||
CHECK_EQUAL(context.network_operator.mode, 0);
|
||||
CHECK_EQUAL(HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT, context.command);
|
||||
|
||||
sprintf(packet, "\r\nAT%s?\r\n", HFP_QUERY_OPERATOR_SELECTION);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
CHECK_EQUAL(context.operator_name_format, 0);
|
||||
CHECK_EQUAL(context.operator_name, 0);
|
||||
CHECK_EQUAL(context.operator_name_changed, 0);
|
||||
}
|
||||
|
||||
@ -215,7 +205,7 @@ TEST(HFPParser, HFP_AG_EXTENDED_AUDIO_GATEWAY_ERROR){
|
||||
sprintf(packet, "\r\nAT%s=1\r\n", HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR);
|
||||
@ -224,13 +214,10 @@ TEST(HFPParser, HFP_AG_EXTENDED_AUDIO_GATEWAY_ERROR){
|
||||
|
||||
TEST(HFPParser, HFP_AG_TRIGGER_CODEC_CONNECTION_SETUP){
|
||||
sprintf(packet, "\r\nAT%s\r\n", HFP_TRIGGER_CODEC_CONNECTION_SETUP);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP);
|
||||
CHECK_EQUAL(context.ag_trigger_codec_connection_setup, 1);
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_AG_CONFIRM_COMMON_CODEC){
|
||||
@ -238,7 +225,7 @@ TEST(HFPParser, HFP_AG_CONFIRM_COMMON_CODEC){
|
||||
sprintf(packet, "\r\nAT%s=%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_HF_CONFIRMED_CODEC);
|
||||
|
@ -75,15 +75,13 @@ static uint16_t indicators[1] = {0x01};
|
||||
|
||||
static uint8_t service_level_connection_established = 0;
|
||||
static uint8_t codecs_connection_established = 0;
|
||||
static uint8_t audio_connection_established = 0;
|
||||
static uint8_t service_level_connection_released = 0;
|
||||
|
||||
int expected_rfcomm_command(const char * cmd){
|
||||
char * ag_cmd = (char *)get_rfcomm_payload();
|
||||
int offset = 2;
|
||||
int cmd_size = strlen(cmd);
|
||||
|
||||
int cmd_found = memcmp(ag_cmd+offset, cmd, cmd_size) == 0;
|
||||
int cmd_found = strncmp(ag_cmd+offset, cmd, cmd_size) == 0;
|
||||
while (!cmd_found && get_rfcomm_payload_len() - cmd_size >= offset){
|
||||
offset++;
|
||||
cmd_found = strncmp(ag_cmd+offset, cmd, cmd_size) == 0;
|
||||
@ -91,31 +89,31 @@ int expected_rfcomm_command(const char * cmd){
|
||||
if (!cmd_found) return 0;
|
||||
|
||||
// AG cmds that are not followed by OK
|
||||
if (memcmp(ag_cmd+offset, "+BCS", 4) == 0){
|
||||
if (strncmp(ag_cmd+offset, "+BCS", 4) == 0){
|
||||
return cmd_found;
|
||||
}
|
||||
|
||||
offset += strlen(cmd)+4;
|
||||
// printf("cmd found, offset %d, cmd %s\n", offset, ag_cmd+offset);
|
||||
int ok_found = memcmp(ag_cmd+offset, "OK", 2) == 0;
|
||||
int ok_found = strncmp(ag_cmd+offset, "OK", 2) == 0;
|
||||
while (!ok_found && get_rfcomm_payload_len() - 2 >= offset){
|
||||
offset++;
|
||||
// printf("cmd found, offset %d, cmd %s\n", offset, ag_cmd+offset);
|
||||
ok_found = memcmp(ag_cmd+offset, "OK", 2) == 0;
|
||||
ok_found = strncmp(ag_cmd+offset, "OK", 2) == 0;
|
||||
}
|
||||
// printf("cmd found, ok found %d\n", ok_found);
|
||||
return cmd_found && ok_found;
|
||||
}
|
||||
|
||||
void hfp_hf_run_test_sequence(char ** test_steps, int nr_test_steps){
|
||||
void simulate_test_sequence(char ** test_steps, int nr_test_steps){
|
||||
int i = 0;
|
||||
for (i=0; i < nr_test_steps; i++){
|
||||
char * cmd = test_steps[i];
|
||||
printf("\n---> NEXT STEP %s\n", cmd);
|
||||
if (memcmp(cmd, "AT", 2) == 0){
|
||||
if (strncmp(cmd, "AT", 2) == 0){
|
||||
int parsed_codecs[2];
|
||||
uint8_t new_codecs[2];
|
||||
if (memcmp(cmd, "AT+BAC=", 7) == 0){
|
||||
if (strncmp(cmd, "AT+BAC=", 7) == 0){
|
||||
printf("Send BAC\n");
|
||||
sscanf(&cmd[7],"%d,%d", &parsed_codecs[0], &parsed_codecs[1]);
|
||||
new_codecs[0] = parsed_codecs[0];
|
||||
@ -143,19 +141,16 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
}
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
printf("\n** SLC established **\n\n");
|
||||
service_level_connection_established = 1;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE:
|
||||
printf("\n** CC established **\n\n");
|
||||
codecs_connection_established = 1;
|
||||
audio_connection_established = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
audio_connection_established = 1;
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
service_level_connection_released = 1;
|
||||
service_level_connection_established = 0;
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_COMPLETE:
|
||||
@ -184,31 +179,25 @@ TEST_GROUP(HFPClient){
|
||||
void setup(void){
|
||||
service_level_connection_established = 0;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
service_level_connection_released = 0;
|
||||
}
|
||||
|
||||
void teardown(void){
|
||||
if (service_level_connection_established){
|
||||
hfp_hf_release_service_level_connection(device_addr);
|
||||
CHECK_EQUAL(service_level_connection_released, 1);
|
||||
CHECK_EQUAL(service_level_connection_established, 0);
|
||||
}
|
||||
codecs_connection_established = 0;
|
||||
}
|
||||
|
||||
void verify_hfp_service_level_connection_established(char ** test_steps, int nr_test_steps){
|
||||
void setup_hfp_service_level_connection(char ** test_steps, int nr_test_steps){
|
||||
service_level_connection_established = 0;
|
||||
hfp_hf_establish_service_level_connection(device_addr);
|
||||
hfp_hf_run_test_sequence((char **) test_steps, nr_test_steps);
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
hfp_hf_set_codecs(codecs, 1);
|
||||
inject_rfcomm_command((uint8_t*)HFP_OK, strlen(HFP_OK));
|
||||
simulate_test_sequence((char **) test_steps, nr_test_steps);
|
||||
}
|
||||
|
||||
void verify_hfp_codecs_connection_established(char ** test_steps, int nr_test_steps){
|
||||
void setup_hfp_codecs_connection(char ** test_steps, int nr_test_steps){
|
||||
codecs_connection_established = 0;
|
||||
hfp_hf_negotiate_codecs(device_addr);
|
||||
hfp_hf_run_test_sequence((char **) test_steps, nr_test_steps);
|
||||
CHECK_EQUAL(codecs_connection_established, 1);
|
||||
simulate_test_sequence((char **) test_steps, nr_test_steps);
|
||||
}
|
||||
|
||||
};
|
||||
@ -220,17 +209,16 @@ TEST(HFPClient, HFCodecsConnectionEstablished){
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
|
||||
setup_hfp_codecs_connection(hfp_cc_tests()[i].test, hfp_cc_tests()[i].len);
|
||||
//CHECK_EQUAL(codecs_connection_established, 1);
|
||||
teardown();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPClient, HFServiceLevelConnectionCommands){
|
||||
verify_hfp_service_level_connection_established(default_slc_setup(), default_slc_setup_size());
|
||||
for (int i = 0; i < slc_cmds_tests_size(); i++){
|
||||
hfp_hf_run_test_sequence(hfp_slc_cmds_tests()[i].test, hfp_slc_cmds_tests()[i].len);
|
||||
}
|
||||
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
for (int i = 0; i < slc_cmds_tests_size(); i++){
|
||||
simulate_test_sequence(hfp_slc_cmds_tests()[i].test, hfp_slc_cmds_tests()[i].len);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPClient, HFServiceLevelConnectionEstablished){
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
#include "classic/hfp.h"
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree);
|
||||
|
||||
static hfp_connection_t context;
|
||||
static int hfp_ag_indicators_nr = 7;
|
||||
@ -84,7 +84,7 @@ TEST_GROUP(HFPParser){
|
||||
TEST(HFPParser, HFP_HF_OK){
|
||||
sprintf(packet, "\r\n%s\r\n", HFP_OK);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
}
|
||||
@ -92,7 +92,7 @@ TEST(HFPParser, HFP_HF_OK){
|
||||
TEST(HFPParser, HFP_HF_SUPPORTED_FEATURES){
|
||||
sprintf(packet, "\r\n%s:1007\r\n\r\nOK\r\n", HFP_SUPPORTED_FEATURES);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
CHECK_EQUAL(1007, context.remote_supported_features);
|
||||
@ -107,11 +107,11 @@ TEST(HFPParser, HFP_HF_INDICATORS){
|
||||
}
|
||||
offset += snprintf(packet+offset, sizeof(packet)-offset, "\"%s\", (%d, %d)\r\n\r\nOK\r\n", hfp_ag_indicators[pos].name, hfp_ag_indicators[pos].min_range, hfp_ag_indicators[pos].max_range);
|
||||
|
||||
context.retrieve_ag_indicators = 1;
|
||||
context.retrieve_ag_indicators_status = 0;
|
||||
//context.command = HFP_CMD_RETRIEVE_AG_INDICATORS;
|
||||
context.state = HFP_W4_RETRIEVE_INDICATORS;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
CHECK_EQUAL(hfp_ag_indicators_nr, context.ag_indicators_nr);
|
||||
@ -132,12 +132,11 @@ TEST(HFPParser, HFP_HF_INDICATOR_STATUS){
|
||||
}
|
||||
offset += snprintf(packet+offset, sizeof(packet)-offset, "%d\r\n\r\nOK\r\n", hfp_ag_indicators[pos].status);
|
||||
|
||||
context.command = HFP_CMD_INDICATOR;
|
||||
context.retrieve_ag_indicators_status = 1;
|
||||
context.retrieve_ag_indicators = 0;
|
||||
//context.command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
|
||||
context.state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
@ -150,7 +149,7 @@ TEST(HFPParser, HFP_HF_INDICATOR_STATUS){
|
||||
TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){
|
||||
sprintf(packet, "\r\n%s:(1,1x,2,2x,3)\r\n\r\nOK\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
CHECK_EQUAL(5, context.remote_call_services_nr);
|
||||
@ -164,12 +163,11 @@ TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){
|
||||
|
||||
TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR){
|
||||
sprintf(packet, "\r\n%s:0,1,2,3,4\r\n\r\nOK\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
context.list_generic_status_indicators = 0;
|
||||
context.retrieve_generic_status_indicators = 1;
|
||||
context.retrieve_generic_status_indicators_state = 0;
|
||||
|
||||
//context.command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
context.state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
@ -182,12 +180,11 @@ TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR){
|
||||
|
||||
TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR_STATE){
|
||||
sprintf(packet, "\r\n%s:0,1\r\n\r\nOK\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
context.list_generic_status_indicators = 0;
|
||||
context.retrieve_generic_status_indicators = 0;
|
||||
context.retrieve_generic_status_indicators_state = 1;
|
||||
|
||||
// context.command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
|
||||
context.state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
@ -203,7 +200,7 @@ TEST(HFPParser, HFP_HF_AG_INDICATOR_STATUS_UPDATE){
|
||||
|
||||
sprintf(packet, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
@ -213,13 +210,13 @@ TEST(HFPParser, HFP_HF_AG_INDICATOR_STATUS_UPDATE){
|
||||
TEST(HFPParser, HFP_HF_AG_QUERY_OPERATOR_SELECTION){
|
||||
sprintf(packet, "\r\n%s:1,0,\"sunrise\"\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION);
|
||||
|
||||
context.command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_OK);
|
||||
CHECK_EQUAL(context.operator_name_format, 0);
|
||||
CHECK_EQUAL(context.operator_name, 1);
|
||||
CHECK_EQUAL(context.operator_name_changed, 0);
|
||||
CHECK_EQUAL( strcmp("sunrise", context.network_operator.name), 0);
|
||||
}
|
||||
@ -228,7 +225,7 @@ TEST(HFPParser, HFP_HF_ERROR){
|
||||
sprintf(packet, "\r\n%s\r\n", HFP_ERROR);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_ERROR);
|
||||
@ -238,7 +235,7 @@ TEST(HFPParser, HFP_HF_EXTENDED_AUDIO_GATEWAY_ERROR){
|
||||
sprintf(packet, "\r\n%s:%d\r\n", HFP_EXTENDED_AUDIO_GATEWAY_ERROR, HFP_CME_ERROR_NO_NETWORK_SERVICE);
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR);
|
||||
@ -255,7 +252,7 @@ TEST(HFPParser, HFP_HF_AG_INDICATOR_CALLS_STATUS_UPDATE){
|
||||
uint8_t index = call_status_index;
|
||||
sprintf(packet, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
CHECK_EQUAL(context.ag_indicators[index - 1].status, status);
|
||||
@ -264,7 +261,7 @@ TEST(HFPParser, HFP_HF_AG_INDICATOR_CALLS_STATUS_UPDATE){
|
||||
index = callsetup_status_index;
|
||||
sprintf(packet, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
CHECK_EQUAL(context.ag_indicators[index - 1].status, status);
|
||||
@ -273,7 +270,7 @@ TEST(HFPParser, HFP_HF_AG_INDICATOR_CALLS_STATUS_UPDATE){
|
||||
index = callheld_status_index;
|
||||
sprintf(packet, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
hfp_parse(&context, packet[pos], 1);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
CHECK_EQUAL(context.ag_indicators[index - 1].status, status);
|
||||
|
@ -58,11 +58,14 @@ static void *registered_sdp_app_context;
|
||||
static uint8_t sdp_rfcomm_channel_nr = 1;
|
||||
const char sdp_rfcomm_service_name[] = "BTstackMock";
|
||||
static uint16_t rfcomm_cid = 1;
|
||||
static bd_addr_t dev_addr;
|
||||
static uint16_t sco_handle = 10;
|
||||
static uint8_t rfcomm_payload[200];
|
||||
static uint16_t rfcomm_payload_len;
|
||||
void * active_connection;
|
||||
hfp_connection_t * hfp_context;
|
||||
|
||||
void (*registered_rfcomm_packet_handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
void (*registered_rfcomm_packet_handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
void (*registered_sdp_app_callback)(sdp_query_event_t * event, void * context);
|
||||
|
||||
uint8_t * get_rfcomm_payload(){
|
||||
@ -119,6 +122,12 @@ static void print_without_newlines(uint8_t *data, uint16_t len){
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
extern "C" void l2cap_init(void){}
|
||||
|
||||
extern "C" void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
|
||||
}
|
||||
|
||||
|
||||
int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
|
||||
if (strncmp((char*)data, "AT", 2) == 0){
|
||||
printf("Verify HF state machine response: ");
|
||||
@ -132,8 +141,32 @@ int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hci_event_sco_complete(){
|
||||
uint8_t event[19];
|
||||
uint8_t pos = 0;
|
||||
event[pos++] = HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
|
||||
event[pos++] = 0; //status
|
||||
bt_store_16(event, pos, sco_handle); pos += 2; // sco handle
|
||||
bt_flip_addr(&event[pos], dev_addr); pos += 6;
|
||||
|
||||
event[pos++] = 0; // link_type
|
||||
event[pos++] = 0; // transmission_interval
|
||||
event[pos++] = 0; // retransmission_interval
|
||||
|
||||
bt_store_16(event, pos, 0); pos += 2; // rx_packet_length
|
||||
bt_store_16(event, pos, 0); pos += 2; // tx_packet_length
|
||||
|
||||
event[pos++] = 0; // air_mode
|
||||
(*registered_rfcomm_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
int hci_send_cmd(const hci_cmd_t *cmd, ...){
|
||||
printf("hci_send_cmd opcode 0x%02x\n", cmd->opcode);
|
||||
if (cmd->opcode == 0x428){
|
||||
hci_event_sco_complete();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -166,23 +199,30 @@ void sdp_query_rfcomm_channel_and_name_for_uuid(bd_addr_t remote, uint16_t uuid)
|
||||
sdp_query_complete_response(0);
|
||||
}
|
||||
|
||||
void rfcomm_create_channel_internal(void * connection, bd_addr_t addr, uint8_t channel){
|
||||
|
||||
uint8_t rfcomm_create_channel(bd_addr_t addr, uint8_t channel, uint16_t * out_cid){
|
||||
// RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE
|
||||
// printf("rfcomm_create_channel_internal\n");
|
||||
active_connection = connection;
|
||||
uint8_t event[16];
|
||||
uint8_t pos = 0;
|
||||
event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
event[pos++] = 0;
|
||||
|
||||
bt_flip_addr(&event[pos], addr); pos += 6;
|
||||
bt_flip_addr(&event[pos], addr);
|
||||
memcpy(dev_addr, addr, 6);
|
||||
pos += 6;
|
||||
|
||||
bt_store_16(event, pos, 1); pos += 2;
|
||||
event[pos++] = 0;
|
||||
|
||||
bt_store_16(event, pos, rfcomm_cid); pos += 2; // channel ID
|
||||
bt_store_16(event, pos, 200); pos += 2; // max frame size
|
||||
(*registered_rfcomm_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
|
||||
(*registered_rfcomm_packet_handler)(HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
|
||||
|
||||
if (out_cid){
|
||||
*out_cid = rfcomm_cid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rfcomm_can_send_packet_now(uint16_t rfcomm_cid){
|
||||
@ -194,15 +234,16 @@ void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
|
||||
event[0] = RFCOMM_EVENT_CHANNEL_CLOSED;
|
||||
event[1] = sizeof(event) - 2;
|
||||
bt_store_16(event, 2, rfcomm_cid);
|
||||
(*registered_rfcomm_packet_handler)(active_connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
||||
(*registered_rfcomm_packet_handler)(HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
||||
}
|
||||
|
||||
void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
|
||||
void rfcomm_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
|
||||
registered_rfcomm_packet_handler = handler;
|
||||
}
|
||||
|
||||
void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size){
|
||||
printf("rfcomm_register_service_internal\n");
|
||||
uint8_t rfcomm_register_service(uint8_t channel, uint16_t max_frame_size){
|
||||
printf("rfcomm_register_service\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -215,6 +256,37 @@ void rfcomm_accept_connection_internal(uint16_t rfcomm_cid){
|
||||
printf("rfcomm_accept_connection_internal \n");
|
||||
}
|
||||
|
||||
void run_loop_add_timer(timer_source_t *timer){
|
||||
}
|
||||
|
||||
int run_loop_remove_timer(timer_source_t *timer){
|
||||
return 0;
|
||||
}
|
||||
void run_loop_set_timer_handler(timer_source_t *ts, void (*process)(timer_source_t *_ts)){
|
||||
}
|
||||
|
||||
void run_loop_set_timer(timer_source_t *a, uint32_t timeout_in_ms){
|
||||
}
|
||||
|
||||
|
||||
void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason){
|
||||
uint8_t event[6];
|
||||
event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = 0; // status = OK
|
||||
bt_store_16(event, 3, handle);
|
||||
event[5] = reason;
|
||||
(*registered_rfcomm_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
uint8_t gap_disconnect(hci_con_handle_t handle){
|
||||
hci_emit_disconnection_complete(handle, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t hci_get_sco_voice_setting(){
|
||||
return 0x40;
|
||||
}
|
||||
|
||||
void inject_rfcomm_command_to_hf(uint8_t * data, int len){
|
||||
if (memcmp((char*)data, "AT", 2) == 0) return;
|
||||
@ -225,7 +297,7 @@ void inject_rfcomm_command_to_hf(uint8_t * data, int len){
|
||||
} else {
|
||||
printf("Trigger HF state machine - %s", data);
|
||||
}
|
||||
(*registered_rfcomm_packet_handler)(active_connection, RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &rfcomm_payload[0], rfcomm_payload_len);
|
||||
(*registered_rfcomm_packet_handler)(RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &rfcomm_payload[0], rfcomm_payload_len);
|
||||
}
|
||||
|
||||
void inject_rfcomm_command_to_ag(uint8_t * data, int len){
|
||||
@ -237,9 +309,8 @@ void inject_rfcomm_command_to_ag(uint8_t * data, int len){
|
||||
} else {
|
||||
printf("Trigger AG state machine - %s", data);
|
||||
}
|
||||
(*registered_rfcomm_packet_handler)(active_connection, RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &rfcomm_payload[0], rfcomm_payload_len);
|
||||
(*registered_rfcomm_packet_handler)( RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &rfcomm_payload[0], rfcomm_payload_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
|
||||
/* Service Level Connection (slc) test sequences */
|
||||
|
||||
// with codec negotiation feature
|
||||
const char * slc_test1[] = {
|
||||
"AT+BRSF=438",
|
||||
"+BRSF:1007",
|
||||
@ -72,8 +73,27 @@ const char * slc_test1[] = {
|
||||
"OK"
|
||||
};
|
||||
|
||||
// without codec negotiation feature
|
||||
const char * slc_test2[] = {
|
||||
"AT+BRSF=438",
|
||||
"+BRSF:495",
|
||||
"OK",
|
||||
"AT+CIND=?",
|
||||
"+CIND:(\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0,3)),(\"battchg\",(0,5)),(\"signal\",(0,5)),(\"roam\",(0,1)),(\"callheld\",(0,2))",
|
||||
"OK",
|
||||
"AT+CIND?",
|
||||
"+CIND:1,0,0,3,5,0,0",
|
||||
"OK",
|
||||
"AT+CMER=3,0,0,1",
|
||||
"OK",
|
||||
"AT+CHLD=?",
|
||||
"+CHLD:(1,1x,2,2x,3)",
|
||||
"OK"
|
||||
};
|
||||
|
||||
hfp_test_item_t slc_tests[] = {
|
||||
TEST_SEQUENCE(slc_test1)
|
||||
TEST_SEQUENCE(slc_test1),
|
||||
TEST_SEQUENCE(slc_test2)
|
||||
};
|
||||
|
||||
/* Service Level Connection (slc) common commands */
|
||||
@ -136,6 +156,7 @@ const char * cc_test4[] = {
|
||||
"OK"
|
||||
};
|
||||
|
||||
|
||||
hfp_test_item_t cc_tests[] = {
|
||||
TEST_SEQUENCE(cc_test1),
|
||||
TEST_SEQUENCE(cc_test2),
|
||||
@ -143,6 +164,44 @@ hfp_test_item_t cc_tests[] = {
|
||||
TEST_SEQUENCE(cc_test4)
|
||||
};
|
||||
|
||||
/* Incoming call sequence */
|
||||
const char * ic_test1[] = {
|
||||
"+CIEV:3,1",
|
||||
"NOP",
|
||||
"BCS:1",
|
||||
"AT+BCS=1",
|
||||
"OK",
|
||||
"NOP"
|
||||
};
|
||||
|
||||
const char * ic_alert_test1[] = {
|
||||
"NOP",
|
||||
"ATA",
|
||||
"OK",
|
||||
"NOP",
|
||||
"+CIEV:2,1", // call = 1
|
||||
"NOP",
|
||||
"+CIEV:3,0",
|
||||
};
|
||||
|
||||
const char * ic_ag_terminates_call[] = {
|
||||
// AG terminates call
|
||||
"+CIEV:2,0"
|
||||
};
|
||||
|
||||
const char * ic_hf_terminates_call[] = {
|
||||
// HF terminates call
|
||||
"NOP",
|
||||
"AT+CHUP",
|
||||
"OK",
|
||||
"NOP",
|
||||
"+CIEV:2,0"
|
||||
};
|
||||
|
||||
hfp_test_item_t ic_tests[] = {
|
||||
TEST_SEQUENCE(ic_test1)
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////
|
||||
@ -165,10 +224,22 @@ int default_slc_cmds_setup_size(){ return sizeof(slc_cmds_test1)/sizeof(char*);}
|
||||
|
||||
// CC
|
||||
hfp_test_item_t * hfp_cc_tests(){ return cc_tests;}
|
||||
int cc_tests_size(){ return sizeof(cc_tests) /test_item_size;
|
||||
}
|
||||
int cc_tests_size(){ return sizeof(cc_tests) /test_item_size;}
|
||||
|
||||
char ** default_cc_setup() { return (char **)cc_test1;}
|
||||
int default_cc_setup_size(){ return sizeof(cc_test1)/sizeof(char*);}
|
||||
|
||||
// IC
|
||||
char ** default_ic_setup() { return (char **)ic_test1;}
|
||||
int default_ic_setup_size(){ return sizeof(ic_test1)/sizeof(char*);}
|
||||
|
||||
char ** alert_ic_setup() { return (char **)ic_alert_test1;}
|
||||
int alert_ic_setup_size(){ return sizeof(ic_alert_test1)/sizeof(char*);}
|
||||
|
||||
|
||||
char ** terminate_ic_ag_setup() { return (char **)ic_ag_terminates_call;}
|
||||
int terminate_ic_ag_setup_size(){ return sizeof(ic_ag_terminates_call)/sizeof(char*);}
|
||||
|
||||
char ** terminate_ic_hf_setup() { return (char **)ic_hf_terminates_call;}
|
||||
int terminate_ic_hf_setup_size(){ return sizeof(ic_hf_terminates_call)/sizeof(char*);}
|
||||
|
@ -70,3 +70,16 @@ int cc_tests_size();
|
||||
char ** default_cc_setup();
|
||||
int default_cc_setup_size();
|
||||
|
||||
/* Incoming call (ic) test sequences */
|
||||
char ** default_ic_setup();
|
||||
int default_ic_setup_size();
|
||||
|
||||
char ** alert_ic_setup();
|
||||
int alert_ic_setup_size();
|
||||
|
||||
char ** terminate_ic_ag_setup();
|
||||
int terminate_ic_ag_setup_size();
|
||||
|
||||
char ** terminate_ic_hf_setup();
|
||||
int terminate_ic_hf_setup_size();
|
||||
|
||||
|
7
test/pts/.gitignore
vendored
7
test/pts/.gitignore
vendored
@ -1,6 +1,8 @@
|
||||
ancs_client
|
||||
ble_central_test
|
||||
ble_central_test.h
|
||||
ble_peripheral_test
|
||||
ble_peripheral_test.h
|
||||
bnep_test
|
||||
classic_test
|
||||
hfp_ag_test
|
||||
@ -9,7 +11,4 @@ hsp_ag_test
|
||||
hsp_hs_test
|
||||
l2cap_test
|
||||
profile.h
|
||||
|
||||
ble_peripheral_test.h
|
||||
ble_central_test.h
|
||||
sco_loopback
|
||||
sco_loopback
|
@ -75,6 +75,9 @@ static bd_addr_t device_addr;
|
||||
static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||
static bd_addr_t speaker_addr = {0x00, 0x21, 0x3C, 0xAC, 0xF7, 0x38};
|
||||
static uint8_t codecs[1] = {HFP_CODEC_CVSD};
|
||||
static uint16_t handle = -1;
|
||||
static int memory_1_enabled = 1;
|
||||
static int last_number_exists = 1;
|
||||
|
||||
static int ag_indicators_nr = 7;
|
||||
static hfp_ag_indicator_t ag_indicators[] = {
|
||||
@ -97,30 +100,63 @@ static hfp_generic_status_indicator_t hf_indicators[] = {
|
||||
{2, 1},
|
||||
};
|
||||
|
||||
|
||||
char cmd;
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
|
||||
static void reset_pst_flags(){
|
||||
}
|
||||
|
||||
// Testig User Interface
|
||||
static void show_usage(void){
|
||||
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
|
||||
printf("---\n");
|
||||
|
||||
printf("a - establish HFP connection to PTS module\n");
|
||||
printf("A - release HFP connection to PTS module\n");
|
||||
// printf("A - release HFP connection to PTS module\n");
|
||||
|
||||
printf("z - establish HFP connection to speaker\n");
|
||||
// printf("Z - release HFP connection to speaker\n");
|
||||
|
||||
printf("b - establish AUDIO connection\n");
|
||||
printf("B - release AUDIO connection\n");
|
||||
|
||||
printf("z - establish HFP connection to local mac\n");
|
||||
printf("Z - release HFP connection to local mac\n");
|
||||
printf("c - simulate incoming call from 1234567\n");
|
||||
printf("C - simulate call from 1234567 dropped\n");
|
||||
|
||||
printf("d - report AG failure\n");
|
||||
|
||||
printf("e - answer call on AG\n");
|
||||
printf("E - reject call on AG\n");
|
||||
|
||||
printf("r - disable in-band ring tone\n");
|
||||
printf("R - enable in-band ring tone\n");
|
||||
|
||||
printf("f - Disable cellular network\n");
|
||||
printf("F - Enable cellular network\n");
|
||||
|
||||
printf("g - Set signal strength to 0\n");
|
||||
printf("G - Set signal strength to 5\n");
|
||||
|
||||
printf("h - Disable roaming\n");
|
||||
printf("H - Enable roaming\n");
|
||||
|
||||
printf("i - Set battery level to 3\n");
|
||||
printf("I - Set battery level to 5\n");
|
||||
|
||||
printf("j - Answering call on remote side\n");
|
||||
|
||||
printf("k - Clear memory #1\n");
|
||||
printf("K - Set memory #1\n");
|
||||
|
||||
printf("l - Clear last number\n");
|
||||
printf("L - Set last number\n");
|
||||
|
||||
printf("m - simulate incoming call from 7654321\n");
|
||||
// printf("M - simulate call from 7654321 dropped\n");
|
||||
|
||||
printf("n - Disable Voice Regocnition\n");
|
||||
printf("N - Enable Voice Recognition\n");
|
||||
|
||||
printf("t - terminate connection\n");
|
||||
|
||||
printf("---\n");
|
||||
printf("Ctrl-c - exit\n");
|
||||
printf("---\n");
|
||||
@ -155,10 +191,103 @@ static int stdin_process(struct data_source *ds){
|
||||
printf("Release Audio connection.\n");
|
||||
hfp_ag_release_audio_connection(device_addr);
|
||||
break;
|
||||
case 'c':
|
||||
printf("Simulate incoming call from 1234567\n");
|
||||
hfp_ag_set_clip(129, "1234567");
|
||||
hfp_ag_incoming_call();
|
||||
break;
|
||||
case 'm':
|
||||
printf("Simulate incoming call from 7654321\n");
|
||||
hfp_ag_set_clip(129, "7654321");
|
||||
hfp_ag_incoming_call();
|
||||
break;
|
||||
case 'C':
|
||||
printf("Simulate terminate call\n");
|
||||
hfp_ag_call_dropped();
|
||||
break;
|
||||
case 'd':
|
||||
printf("Report AG failure\n");
|
||||
hfp_ag_report_extended_audio_gateway_error_result_code(device_addr, HFP_CME_ERROR_AG_FAILURE);
|
||||
|
||||
break;
|
||||
case 'e':
|
||||
printf("Answer call on AG\n");
|
||||
hfp_ag_answer_incoming_call();
|
||||
break;
|
||||
case 'E':
|
||||
printf("Reject call on AG\n");
|
||||
hfp_ag_terminate_call();
|
||||
break;
|
||||
case 'f':
|
||||
printf("Disable cellular network\n");
|
||||
hfp_ag_set_registration_status(0);
|
||||
break;
|
||||
case 'F':
|
||||
printf("Enable cellular network\n");
|
||||
hfp_ag_set_registration_status(1);
|
||||
break;
|
||||
case 'g':
|
||||
printf("Set signal strength to 0\n");
|
||||
hfp_ag_set_signal_strength(0);
|
||||
break;
|
||||
case 'G':
|
||||
printf("Set signal strength to 5\n");
|
||||
hfp_ag_set_signal_strength(5);
|
||||
break;
|
||||
case 'h':
|
||||
printf("Disable roaming\n");
|
||||
hfp_ag_set_roaming_status(0);
|
||||
break;
|
||||
case 'H':
|
||||
printf("Enable roaming\n");
|
||||
hfp_ag_set_roaming_status(1);
|
||||
break;
|
||||
case 'i':
|
||||
printf("Set battery level to 3\n");
|
||||
hfp_ag_set_battery_level(3);
|
||||
break;
|
||||
case 'I':
|
||||
printf("Set battery level to 5\n");
|
||||
hfp_ag_set_battery_level(5);
|
||||
break;
|
||||
case 'j':
|
||||
printf("Answering call on remote side\n");
|
||||
hfp_ag_outgoing_call_established();
|
||||
break;
|
||||
case 'r':
|
||||
printf("Disable in-band ring tone\n");
|
||||
hfp_ag_set_use_in_band_ring_tone(0);
|
||||
break;
|
||||
case 'k':
|
||||
printf("Memory 1 cleared\n");
|
||||
memory_1_enabled = 0;
|
||||
break;
|
||||
case 'K':
|
||||
printf("Memory 1 set\n");
|
||||
memory_1_enabled = 1;
|
||||
break;
|
||||
case 'l':
|
||||
printf("Last dialed number cleared\n");
|
||||
last_number_exists = 0;
|
||||
break;
|
||||
case 'L':
|
||||
printf("Last dialed number set\n");
|
||||
last_number_exists = 1;
|
||||
break;
|
||||
case 'n':
|
||||
printf("Disable Voice Recognition\n");
|
||||
hfp_ag_activate_voice_recognition(device_addr, 0);
|
||||
break;
|
||||
case 'N':
|
||||
printf("Enable Voice Recognition\n");
|
||||
hfp_ag_activate_voice_recognition(device_addr, 1);
|
||||
break;
|
||||
case 'R':
|
||||
printf("Enable in-band ring tone\n");
|
||||
hfp_ag_set_use_in_band_ring_tone(1);
|
||||
break;
|
||||
case 't':
|
||||
printf("Terminate HCI connection.\n");
|
||||
gap_disconnect(handle);
|
||||
default:
|
||||
show_usage();
|
||||
break;
|
||||
@ -169,22 +298,68 @@ static int stdin_process(struct data_source *ds){
|
||||
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
|
||||
if (event[0] == RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE){
|
||||
handle = READ_BT_16(event, 9);
|
||||
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE received for handle 0x%04x\n", handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
if (event[3]){
|
||||
if (event[3] && event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER){
|
||||
printf("ERROR, status: %u\n", event[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
printf("Service level connection established.\n\n");
|
||||
printf("Service level connection established.\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("Service level connection released.\n\n");
|
||||
reset_pst_flags();
|
||||
printf("Service level connection released.\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
|
||||
printf("\n** Audio connection established **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
|
||||
printf("\n** Audio connection released **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_START_RINGINIG:
|
||||
printf("\n** Start Ringing **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_STOP_RINGINIG:
|
||||
printf("\n** Stop Ringing **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER:
|
||||
printf("\n** Outgoing call '%s' **\n", &event[3]);
|
||||
// validate number
|
||||
if ( strcmp("1234567", (char*) &event[3]) == 0
|
||||
|| strcmp("7654321", (char*) &event[3]) == 0
|
||||
|| (memory_1_enabled && strcmp(">1", (char*) &event[3]) == 0)){
|
||||
printf("Dialstring valid: accept call\n");
|
||||
hfp_ag_outgoing_call_accepted();
|
||||
// TODO: calling ringing right away leads to callstatus=2 being skipped. don't call for now
|
||||
// hfp_ag_outgoing_call_ringing();
|
||||
} else {
|
||||
printf("Dialstring invalid: reject call\n");
|
||||
hfp_ag_outgoing_call_rejected();
|
||||
}
|
||||
break;
|
||||
case HFP_SUBEVENT_REDIAL_LAST_NUMBER:
|
||||
printf("\n** Redial last number\n");
|
||||
if (last_number_exists){
|
||||
hfp_ag_outgoing_call_accepted();
|
||||
printf("Last number exists: accept call\n");
|
||||
// TODO: calling ringing right away leads to callstatus=2 being skipped. don't call for now
|
||||
// hfp_ag_outgoing_call_ringing();
|
||||
} else {
|
||||
printf("Last number missing: reject call\n");
|
||||
hfp_ag_outgoing_call_rejected();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
// printf("event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -195,7 +370,7 @@ int btstack_main(int argc, const char * argv[]){
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
|
||||
hfp_ag_init(rfcomm_channel_nr, 1007, codecs, sizeof(codecs),
|
||||
hfp_ag_init(rfcomm_channel_nr, 0x3ef | (1<<HFP_AGSF_HF_INDICATORS), codecs, sizeof(codecs),
|
||||
ag_indicators, ag_indicators_nr,
|
||||
hf_indicators, hf_indicators_nr,
|
||||
call_hold_services, call_hold_services_nr);
|
||||
@ -206,7 +381,12 @@ int btstack_main(int argc, const char * argv[]){
|
||||
sdp_init();
|
||||
memset((uint8_t *)hfp_service_buffer, 0, sizeof(hfp_service_buffer));
|
||||
hfp_ag_create_sdp_record((uint8_t *)hfp_service_buffer, rfcomm_channel_nr, hfp_ag_service_name, 0, 0);
|
||||
sdp_register_service((uint8_t *)hfp_service_buffer);
|
||||
|
||||
sdp_register_service_internal(NULL, (uint8_t *)hfp_service_buffer);
|
||||
|
||||
|
||||
// pre-select pts
|
||||
memcpy(device_addr, pts_addr, 6);
|
||||
|
||||
// turn on!
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
@ -305,6 +305,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
setup_audio();
|
||||
hci_register_sco_packet_handler(&sco_packet_handler);
|
||||
|
||||
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
|
||||
hsp_hs_create_service((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_hs_service_name, 0);
|
||||
|
||||
hsp_hs_init(rfcomm_channel_nr);
|
||||
hsp_hs_register_packet_handler(packet_handler);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user