Merge branch 'master' into ble-api-cleanup

This commit is contained in:
Matthias Ringwald 2016-01-14 19:59:05 +01:00
commit d210d9c4c0
18 changed files with 737 additions and 165 deletions

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2009-2012 by Matthias Ringwald
*
* 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 MATTHIAS RINGWALD 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 btstack@ringwald.ch
*
*/
/*
* bt_control_bcm.c
*
* Adapter to use Broadcom-based chipsets with BTstack
*/
#include "btstack-config.h"
#include "bt_control_bcm.h"
#include <stddef.h> /* NULL */
#include <stdio.h>
#include <string.h> /* memcpy */
#include "bt_control.h"
#include "debug.h"
// actual init script provided by separate bt_firmware_image.c from WICED SDK
extern const uint8_t brcm_patchram_buf[];
extern const int brcm_patch_ram_length;
extern const char brcm_patch_version[];
//
static uint32_t init_script_offset;
static int send_download_command;
static int bt_control_bcm_on(void *config){
log_info("Broadcom init script %s, len %u", brcm_patch_version, brcm_patch_ram_length);
init_script_offset = 0;
send_download_command = 1;
return 0;
}
// @note: Broadcom chips require higher UART clock for baud rate > 3000000 -> limit baud rate in hci.c
static int bcm_baudrate_cmd(void * config, uint32_t baudrate, uint8_t *hci_cmd_buffer){
hci_cmd_buffer[0] = 0x18;
hci_cmd_buffer[1] = 0xfc;
hci_cmd_buffer[2] = 0x06;
hci_cmd_buffer[3] = 0x00;
hci_cmd_buffer[4] = 0x00;
bt_store_32(hci_cmd_buffer, 5, baudrate);
return 0;
}
// @note: bd addr has to be set after sending init script (it might just get re-set)
static int bt_control_bcm_set_bd_addr_cmd(void * config, bd_addr_t addr, uint8_t *hci_cmd_buffer){
hci_cmd_buffer[0] = 0x01;
hci_cmd_buffer[1] = 0xfc;
hci_cmd_buffer[2] = 0x06;
bt_flip_addr(&hci_cmd_buffer[3], addr);
return 0;
}
static int bt_control_bcm_next_cmd(void *config, uint8_t *hci_cmd_buffer){
// send download firmware command
if (send_download_command){
send_download_command = 0;
hci_cmd_buffer[0] = 0x2e;
hci_cmd_buffer[1] = 0xfc;
hci_cmd_buffer[2] = 0x00;
return 1;
}
if (init_script_offset >= brcm_patch_ram_length) {
return 0;
}
// use memcpy with pointer
int cmd_len = 3 + brcm_patchram_buf[init_script_offset+2];
memcpy(&hci_cmd_buffer[0], &brcm_patchram_buf[init_script_offset], cmd_len);
init_script_offset += cmd_len;
return 1;
}
// MARK: const structs
static const bt_control_t bt_control_bcm = {
bt_control_bcm_on, // on
NULL, // off
NULL, // sleep
NULL, // wake
NULL, // valid
NULL, // name
bcm_baudrate_cmd, // baudrate_cmd
bt_control_bcm_next_cmd, // next_cmd
NULL, // register_for_power_notifications
NULL, // hw_error
bt_control_bcm_set_bd_addr_cmd, // set_bd_addr_cmd
};
// MARK: public API
bt_control_t * bt_control_bcm_instance(void){
return (bt_control_t*) &bt_control_bcm;
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2009-2012 by Matthias Ringwald
*
* 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 MATTHIAS RINGWALD 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 btstack@ringwald.ch
*
*/
/*
* bt_control_bcm.h
*
* Adapter to use Broadcom-based chipsets with BTstack
*/
#ifndef __BT_CONTROL_BCM_H
#define __BT_CONTROL_BCM_H
#if defined __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "bt_control.h"
bt_control_t * bt_control_bcm_instance(void);
#if defined __cplusplus
}
#endif
#endif // __BT_CONTROL_BCM_H

View File

@ -86,12 +86,21 @@ static uint32_t init_script_offset = 0;
static int16_t init_power_in_dB = 13; // 13 dBm static int16_t init_power_in_dB = 13; // 13 dBm
static int init_ehcill_enabled = 0; static int init_ehcill_enabled = 0;
static int init_send_route_sco_over_hci = 0;
static int bt_control_cc256x_on(void *config){ static int bt_control_cc256x_on(void *config){
init_script_offset = 0; init_script_offset = 0;
#ifdef HAVE_SCO_OVER_HCI
init_send_route_sco_over_hci = 1;
#endif
return 0; return 0;
} }
// route SCO over HCI (connection type=1, tx buffer size = 0x00 (don't change), tx buffer max latency=0x0000(don't chnage)), accept packets - 0)
static const uint8_t hci_route_sco_over_hci[] = {
0x10, 0xfe, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00
};
// UART Baud Rate control from: http://e2e.ti.com/support/low_power_rf/f/660/p/134850/484763.aspx // UART Baud Rate control from: http://e2e.ti.com/support/low_power_rf/f/660/p/134850/484763.aspx
static int cc256x_baudrate_cmd(void * config, uint32_t baudrate, uint8_t *hci_cmd_buffer){ static int cc256x_baudrate_cmd(void * config, uint32_t baudrate, uint8_t *hci_cmd_buffer){
hci_cmd_buffer[0] = 0x36; hci_cmd_buffer[0] = 0x36;
@ -213,6 +222,12 @@ static int bt_control_cc256x_update_command(uint8_t *hci_cmd_buffer){
static int bt_control_cc256x_next_cmd(void *config, uint8_t *hci_cmd_buffer){ static int bt_control_cc256x_next_cmd(void *config, uint8_t *hci_cmd_buffer){
if (init_script_offset >= cc256x_init_script_size) { if (init_script_offset >= cc256x_init_script_size) {
// append send route SCO over HCI if requested
if (init_send_route_sco_over_hci){
init_send_route_sco_over_hci = 0;
memcpy(hci_cmd_buffer, hci_route_sco_over_hci, sizeof(hci_route_sco_over_hci));
return 1;
}
return 0; return 0;
} }

View File

@ -72,6 +72,7 @@ EXAMPLES = \
spp_counter \ spp_counter \
spp_streamer \ spp_streamer \
gap_le_advertisements \ gap_le_advertisements \
hsp_hs_test \
EXAMPLES_USING_LE = \ EXAMPLES_USING_LE = \
ancs_client \ ancs_client \
@ -164,10 +165,9 @@ led_counter: ${CORE_OBJ} ${COMMON_OBJ} led_counter.c
gap_le_advertisements: ${CORE_OBJ} ${COMMON_OBJ} ad_parser.c gap_le_advertisements.c gap_le_advertisements: ${CORE_OBJ} ${COMMON_OBJ} ad_parser.c gap_le_advertisements.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
hsp_hs_test: ${CORE_OBJ} ${COMMON_OBJ} sdp_query_rfcomm.o sdp_parser.o sdp_client.o hsp_hs.o hsp_hs_test.c hsp_hs_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hsp_hs.o hsp_hs_test.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
clean: clean:
rm -f ${EXAMPLES} rm -f ${EXAMPLES}
rm -f *.o *.out *.hex rm -f *.o *.out *.hex

View File

@ -39,6 +39,8 @@
// //
// Minimal test for HSP Headset (!! UNDER DEVELOPMENT !!) // Minimal test for HSP Headset (!! UNDER DEVELOPMENT !!)
// //
// Requires HAVE_SCO and HAVE_SCO_OVER_HCI to be defined
//
// Tested working setups: // Tested working setups:
// - Ubuntu 14 64-bit, CC2564B connected via FTDI USB-2-UART adapter, 921600 baud // - Ubuntu 14 64-bit, CC2564B connected via FTDI USB-2-UART adapter, 921600 baud
// //
@ -57,12 +59,11 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "hci_cmds.h"
#include "run_loop.h" #include "run_loop.h"
#include "sdp_util.h"
#include "classic/sdp_util.h" #include "sdp.h"
#include "classic/sdp.h" #include "hsp_hs.h"
#include "classic/hsp_hs.h"
#include "hci.h" #include "hci.h"
#include "l2cap.h" #include "l2cap.h"
@ -140,7 +141,7 @@ static void sco_packet_handler(uint8_t packet_type, uint8_t * packet, uint16_t s
// hexdumpf(packet, size); // hexdumpf(packet, size);
} }
void packet_handler(uint8_t * event, uint16_t event_size){ static void packet_handler(uint8_t * event, uint16_t event_size){
// printf("Packet handler event 0x%02x\n", event[0]); // printf("Packet handler event 0x%02x\n", event[0]);
@ -149,8 +150,7 @@ void packet_handler(uint8_t * event, uint16_t event_size){
switch (event[0]) { switch (event[0]) {
case BTSTACK_EVENT_STATE: case BTSTACK_EVENT_STATE:
if (event[2] != HCI_STATE_WORKING) break; if (event[2] != HCI_STATE_WORKING) break;
// request num completed events for SCO packets printf("Working!\n");
hci_send_cmd(&hci_write_synchronous_flow_control_enable, 1);
break; break;
case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
// printf("HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS\n"); // printf("HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS\n");
@ -208,6 +208,7 @@ void packet_handler(uint8_t * event, uint16_t event_size){
} }
} }
int btstack_main(int argc, const char * argv[]);
int btstack_main(int argc, const char * argv[]){ int btstack_main(int argc, const char * argv[]){
#ifdef TABLE_SIZE #ifdef TABLE_SIZE

View File

@ -3,23 +3,24 @@
#ifndef __BTSTACK_CONFIG #ifndef __BTSTACK_CONFIG
#define __BTSTACK_CONFIG #define __BTSTACK_CONFIG
#define HAVE_TRANSPORT_USB #define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO
#define HAVE_BLE #define HAVE_BLE
#define USE_POSIX_RUN_LOOP #define HAVE_BZERO
#define HAVE_SDP #define HAVE_HCI_DUMP
#define HAVE_MALLOC
#define HAVE_RFCOMM #define HAVE_RFCOMM
#define REMOTE_DEVICE_DB remote_device_db_iphone #define HAVE_SDP
#define HAVE_SO_NOSIGPIPE #define HAVE_SO_NOSIGPIPE
#define HAVE_TIME #define HAVE_TIME
#define HAVE_MALLOC #define HAVE_SCO
#define HAVE_BZERO #define HAVE_SCO_OVER_HCI
#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 HCI_ACL_PAYLOAD_SIZE (1691 + 4)
#define HAVE_HCI_DUMP #define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof BNEP header, avoid memcpy
#define REMOTE_DEVICE_DB remote_device_db_iphone
#define SDP_DES_DUMP #define SDP_DES_DUMP
#define SDP_DES_DUMP
#define USE_POSIX_RUN_LOOP
#define HAVE_SCO #define HAVE_SCO

View File

@ -14,9 +14,10 @@ include ${BTSTACK_ROOT}/chipset/cc256x/Makefile.inc
CFLAGS += -I$(BTSTACK_ROOT)/chipset/cc256x \ CFLAGS += -I$(BTSTACK_ROOT)/chipset/cc256x \
-I$(BTSTACK_ROOT)/platform/embedded -I$(BTSTACK_ROOT)/platform/embedded
# CC = gcc-fsf-4.9
CFLAGS += -g -Wall CFLAGS += -g -Wall
# CFLAGS += -Werror
#
CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Werror
VPATH += ${BTSTACK_ROOT}/platform/posix/src VPATH += ${BTSTACK_ROOT}/platform/posix/src
VPATH += ${BTSTACK_ROOT}/platform/embedded VPATH += ${BTSTACK_ROOT}/platform/embedded

View File

@ -63,10 +63,10 @@
int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]);
static hci_transport_config_uart_t config = { static hci_transport_config_uart_t hci_uart_config_cc256x = {
HCI_TRANSPORT_CONFIG_UART, HCI_TRANSPORT_CONFIG_UART,
115200, 115200,
0, // main baudrate 921600, // main baudrate
1, // flow control 1, // flow control
NULL, NULL,
}; };
@ -97,18 +97,30 @@ int main(int argc, const char * argv[]){
btstack_memory_init(); btstack_memory_init();
run_loop_init(run_loop_posix_get_instance()); run_loop_init(run_loop_posix_get_instance());
#if 0
// Ubuntu
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
// pick serial port
hci_uart_config_cc256x.device_name = "/dev/ttyUSB0";
#else
// OS X
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT // use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER); hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
// pick serial port // pick serial port
config.device_name = "/dev/tty.usbserial-A900K0VK"; hci_uart_config_cc256x.device_name = "/dev/tty.usbserial-A900K0VK";
#endif
// init HCI // init HCI
hci_transport_t * transport = hci_transport_h4_posix_instance(); hci_transport_t * transport = hci_transport_h4_posix_instance();
bt_control_t * control = bt_control_cc256x_instance(); bt_control_t * control = bt_control_cc256x_instance();
remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_fs; remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_fs;
hci_init(transport, &config, control, remote_db); hci_init(transport, &hci_uart_config_cc256x, control, remote_db);
// handle CTRL-c // handle CTRL-c
signal(SIGINT, sigint_handler); signal(SIGINT, sigint_handler);

View File

@ -255,6 +255,7 @@ typedef enum {
HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS
} hfp_callheld_status_t; } hfp_callheld_status_t;
typedef enum { typedef enum {
HFP_AG_INCOMING_CALL, HFP_AG_INCOMING_CALL,
HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG,
@ -275,7 +276,12 @@ typedef enum {
HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG, HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG,
HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF,
HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF, HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF,
HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF,
HFP_AG_CALL_HOLD_USER_BUSY,
HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL,
HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL,
HFP_AG_CALL_HOLD_ADD_HELD_CALL,
HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS
} hfp_ag_call_event_t; } hfp_ag_call_event_t;

View File

@ -76,8 +76,6 @@ static int hfp_ag_call_hold_services_nr = 0;
static char *hfp_ag_call_hold_services[6]; static char *hfp_ag_call_hold_services[6];
static hfp_callback_t hfp_callback; static hfp_callback_t hfp_callback;
static hfp_call_status_t hfp_ag_call_state;
static hfp_callsetup_status_t hfp_ag_callsetup_state; static hfp_callsetup_status_t hfp_ag_callsetup_state;
static hfp_callheld_status_t hfp_ag_callheld_state; static hfp_callheld_status_t hfp_ag_callheld_state;
static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state; static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state;
@ -96,6 +94,20 @@ static void hfp_run_for_context(hfp_connection_t *context);
static void hfp_ag_setup_audio_connection(hfp_connection_t * connection); static void hfp_ag_setup_audio_connection(hfp_connection_t * connection);
static void hfp_ag_hf_start_ringing(hfp_connection_t * context); static void hfp_ag_hf_start_ringing(hfp_connection_t * context);
static hfp_call_status_t get_hfp_ag_call_state(void){
return hfp_gsm_call_status();
}
static hfp_callsetup_status_t get_hfp_ag_callsetup_state(void){
return hfp_ag_callsetup_state;
//return hfp_gsm_callsetup_status();
}
static hfp_callheld_status_t get_hfp_ag_callheld_state(void){
return hfp_ag_callheld_state;
// return hfp_gsm_callheld_status();
}
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(); hfp_generic_status_indicator_t * get_hfp_generic_status_indicators();
int get_hfp_generic_status_indicators_nr(); int get_hfp_generic_status_indicators_nr();
void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr); void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
@ -626,12 +638,12 @@ static void hfp_ag_slc_established(hfp_connection_t * context){
hfp_init_link_settings(context); hfp_init_link_settings(context);
// if active call exist, set per-connection state active, too (when audio is on) // if active call exist, set per-connection state active, too (when audio is on)
if (hfp_ag_call_state == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ if (get_hfp_ag_call_state() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE; context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE;
} }
// if AG is ringing, also start ringing on the HF // if AG is ringing, also start ringing on the HF
if (hfp_ag_call_state == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS && if (get_hfp_ag_call_state() == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS &&
hfp_ag_callsetup_state == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ get_hfp_ag_callsetup_state() == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
hfp_ag_hf_start_ringing(context); hfp_ag_hf_start_ringing(context);
} }
} }
@ -1044,13 +1056,20 @@ static void hfp_ag_set_callheld_state(hfp_callheld_status_t state){
indicator->status = state; indicator->status = state;
} }
static void hfp_ag_set_call_state(hfp_call_status_t state){ static void hfp_ag_set_callheld_indicator(){
hfp_ag_call_state = state; hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callheld");
if (!indicator){
log_error("hfp_ag_set_callheld_state: callheld indicator is missing");
};
indicator->status = hfp_gsm_callheld_status();
}
static void hfp_ag_set_call_indicator(){
hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("call"); hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("call");
if (!indicator){ if (!indicator){
log_error("hfp_ag_set_call_state: call indicator is missing"); log_error("hfp_ag_set_call_state: call indicator is missing");
}; };
indicator->status = state; indicator->status = hfp_gsm_call_status();
} }
static void hfp_ag_stop_ringing(void){ static void hfp_ag_stop_ringing(void){
@ -1115,13 +1134,18 @@ static int call_setup_state_machine(hfp_connection_t * connection){
// connection is used to identify originating HF // connection is used to identify originating HF
static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connection){ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connection){
int indicator_index; int indicator_index;
int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup");
int callheld_indicator_index = get_ag_indicator_index_for_name("callheld");
int call_indicator_index = get_ag_indicator_index_for_name("call");
//printf("hfp_ag_call_sm event %d \n", event);
switch (event){ switch (event){
case HFP_AG_INCOMING_CALL: case HFP_AG_INCOMING_CALL:
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS:
hfp_gsm_handle_event(HFP_AG_INCOMING_CALL);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS);
hfp_ag_trigger_incoming_call(); hfp_ag_trigger_incoming_call();
printf("AG rings\n"); printf("AG rings\n");
@ -1131,8 +1155,9 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
} }
break; break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS:
hfp_gsm_handle_event(HFP_AG_INCOMING_CALL);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS);
hfp_ag_trigger_incoming_call(); hfp_ag_trigger_incoming_call();
printf("AG call waiting\n"); printf("AG call waiting\n");
@ -1146,11 +1171,12 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
// clear CLIP // clear CLIP
clip_type = 0; clip_type = 0;
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); hfp_gsm_handle_event(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG);
hfp_ag_set_call_indicator();
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_ag_accept_call(); hfp_ag_ag_accept_call();
printf("AG answers call, accept call by GSM\n"); printf("AG answers call, accept call by GSM\n");
@ -1160,9 +1186,10 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
} }
break; break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
printf("AG: current call is placed on hold, incoming call gets active\n"); printf("AG: current call is placed on hold, incoming call gets active\n");
hfp_gsm_handle_event(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED);
hfp_ag_transfer_callsetup_state(); hfp_ag_transfer_callsetup_state();
@ -1176,11 +1203,12 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_HELD_CALL_JOINED_BY_AG: case HFP_AG_HELD_CALL_JOINED_BY_AG:
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
switch (hfp_ag_callheld_state){ switch (get_hfp_ag_callheld_state()){
case HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED: case HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED:
printf("AG: joining held call with active call\n"); printf("AG: joining held call with active call\n");
hfp_gsm_handle_event(HFP_AG_HELD_CALL_JOINED_BY_AG);
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
hfp_ag_transfer_callheld_state(); hfp_ag_transfer_callheld_state();
hfp_emit_event(hfp_callback, HFP_SUBEVENT_CONFERENCE_CALL, 0); hfp_emit_event(hfp_callback, HFP_SUBEVENT_CONFERENCE_CALL, 0);
@ -1197,12 +1225,13 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
// clear CLIP // clear CLIP
clip_type = 0; clip_type = 0;
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_gsm_handle_event(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); hfp_ag_set_call_indicator();
hfp_ag_hf_accept_call(connection); hfp_ag_hf_accept_call(connection);
printf("HF answers call, accept call by GSM\n"); printf("HF answers call, accept call by GSM\n");
hfp_emit_event(hfp_callback, HFP_CMD_CALL_ANSWERED, 0); hfp_emit_event(hfp_callback, HFP_CMD_CALL_ANSWERED, 0);
@ -1217,17 +1246,18 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG: case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG:
// clear CLIP // clear CLIP
clip_type = 0; clip_type = 0;
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_gsm_handle_event(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG);
hfp_ag_response_and_hold_active = 1; hfp_ag_response_and_hold_active = 1;
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD; hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD;
hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
// as with regualr call // as with regualr call
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); hfp_ag_set_call_indicator();
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_ag_accept_call(); hfp_ag_ag_accept_call();
printf("AG response and hold - hold by AG\n"); printf("AG response and hold - hold by AG\n");
@ -1242,17 +1272,18 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF: case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF:
// clear CLIP // clear CLIP
clip_type = 0; clip_type = 0;
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_gsm_handle_event(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF);
hfp_ag_response_and_hold_active = 1; hfp_ag_response_and_hold_active = 1;
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD; hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD;
hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
// as with regualr call // as with regualr call
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); hfp_ag_set_call_indicator();
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_hf_accept_call(connection); hfp_ag_hf_accept_call(connection);
printf("AG response and hold - hold by HF\n"); printf("AG response and hold - hold by HF\n");
@ -1270,6 +1301,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF: case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF:
if (!hfp_ag_response_and_hold_active) break; if (!hfp_ag_response_and_hold_active) break;
if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break; if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break;
hfp_gsm_handle_event(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG);
hfp_ag_response_and_hold_active = 0; hfp_ag_response_and_hold_active = 0;
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED; hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED;
hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
@ -1280,21 +1312,23 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF: case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF:
if (!hfp_ag_response_and_hold_active) break; if (!hfp_ag_response_and_hold_active) break;
if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break; if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break;
hfp_gsm_handle_event(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG);
hfp_ag_response_and_hold_active = 0; hfp_ag_response_and_hold_active = 0;
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED; hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED;
hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
// from terminate by ag // from terminate by ag
hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); hfp_ag_set_call_indicator();
hfp_ag_trigger_terminate_call(); hfp_ag_trigger_terminate_call();
break; break;
case HFP_AG_TERMINATE_CALL_BY_HF: case HFP_AG_TERMINATE_CALL_BY_HF:
// clear CLIP // clear CLIP
clip_type = 0; clip_type = 0;
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_gsm_handle_event(HFP_AG_TERMINATE_CALL_BY_HF);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_transfer_callsetup_state(); hfp_ag_transfer_callsetup_state();
hfp_ag_trigger_reject_call(); hfp_ag_trigger_reject_call();
@ -1302,6 +1336,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE: case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE:
case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE:
hfp_gsm_handle_event(HFP_AG_TERMINATE_CALL_BY_HF);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_transfer_callsetup_state(); hfp_ag_transfer_callsetup_state();
printf("AG terminate outgoing call process\n"); printf("AG terminate outgoing call process\n");
@ -1310,7 +1345,8 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
} }
break; break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); hfp_gsm_handle_event(HFP_AG_TERMINATE_CALL_BY_HF);
hfp_ag_set_call_indicator();
hfp_ag_transfer_call_state(); hfp_ag_transfer_call_state();
connection->call_state = HFP_CALL_IDLE; connection->call_state = HFP_CALL_IDLE;
printf("AG terminate call\n"); printf("AG terminate call\n");
@ -1321,10 +1357,11 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
case HFP_AG_TERMINATE_CALL_BY_AG: case HFP_AG_TERMINATE_CALL_BY_AG:
// clear CLIP // clear CLIP
clip_type = 0; clip_type = 0;
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_gsm_handle_event(HFP_AG_TERMINATE_CALL_BY_AG);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_trigger_reject_call(); hfp_ag_trigger_reject_call();
printf("AG Rejected Incoming call, AG terminate call\n"); printf("AG Rejected Incoming call, AG terminate call\n");
@ -1333,8 +1370,9 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
} }
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
hfp_gsm_handle_event(HFP_AG_TERMINATE_CALL_BY_AG);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); hfp_ag_set_call_indicator();
hfp_ag_trigger_terminate_call(); hfp_ag_trigger_terminate_call();
printf("AG terminate call\n"); printf("AG terminate call\n");
break; break;
@ -1345,9 +1383,9 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
case HFP_AG_CALL_DROPPED: case HFP_AG_CALL_DROPPED:
// clear CLIP // clear CLIP
clip_type = 0; clip_type = 0;
switch (hfp_ag_call_state){ switch (get_hfp_ag_call_state()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (get_hfp_ag_callsetup_state()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_ag_stop_ringing(); hfp_ag_stop_ringing();
printf("Incoming call interrupted\n"); printf("Incoming call interrupted\n");
@ -1360,16 +1398,19 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
default: default:
break; break;
} }
hfp_gsm_handle_event(HFP_AG_CALL_DROPPED);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_transfer_callsetup_state(); hfp_ag_transfer_callsetup_state();
break; break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
if (hfp_ag_response_and_hold_active) { if (hfp_ag_response_and_hold_active) {
hfp_gsm_handle_event(HFP_AG_CALL_DROPPED);
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED; hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED;
hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
} }
hfp_gsm_handle_event(HFP_AG_CALL_DROPPED);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); hfp_ag_set_call_indicator();
hfp_ag_trigger_terminate_call(); hfp_ag_trigger_terminate_call();
printf("AG notify call dropped\n"); printf("AG notify call dropped\n");
break; break;
@ -1379,6 +1420,12 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_OUTGOING_CALL_INITIATED: case HFP_AG_OUTGOING_CALL_INITIATED:
// directly reject call if number of free slots is exceeded
if (!hfp_gsm_call_possible()){
connection->send_error = 1;
hfp_run_for_context(connection);
break;
}
hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_INITIATED); hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_INITIATED);
connection->call_state = HFP_CALL_OUTGOING_INITIATED; connection->call_state = HFP_CALL_OUTGOING_INITIATED;
@ -1386,6 +1433,13 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_OUTGOING_REDIAL_INITIATED: case HFP_AG_OUTGOING_REDIAL_INITIATED:
// directly reject call if number of free slots is exceeded
if (!hfp_gsm_call_possible()){
connection->send_error = 1;
hfp_run_for_context(connection);
break;
}
hfp_gsm_handle_event(HFP_AG_OUTGOING_REDIAL_INITIATED); hfp_gsm_handle_event(HFP_AG_OUTGOING_REDIAL_INITIATED);
connection->call_state = HFP_CALL_OUTGOING_INITIATED; connection->call_state = HFP_CALL_OUTGOING_INITIATED;
@ -1393,35 +1447,38 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_OUTGOING_CALL_REJECTED: case HFP_AG_OUTGOING_CALL_REJECTED:
hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_REJECTED);
connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED);
if (!connection){ if (!connection){
log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state");
break; break;
} }
hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_REJECTED);
connection->call_state = HFP_CALL_IDLE; connection->call_state = HFP_CALL_IDLE;
connection->send_error = 1; connection->send_error = 1;
hfp_run_for_context(connection); hfp_run_for_context(connection);
break; break;
case HFP_AG_OUTGOING_CALL_ACCEPTED: case HFP_AG_OUTGOING_CALL_ACCEPTED:{
// hfp_gsm_handle_event();
connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED);
if (!connection){ if (!connection){
log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state");
break; break;
} }
connection->ok_pending = 1; connection->ok_pending = 1;
connection->call_state = HFP_CALL_OUTGOING_DIALING; connection->call_state = HFP_CALL_OUTGOING_DIALING;
// trigger callsetup to be // trigger callsetup to be
int put_call_on_hold = get_hfp_ag_call_state() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT;
hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_ACCEPTED);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE);
indicator_index = get_ag_indicator_index_for_name("callsetup"); indicator_index = get_ag_indicator_index_for_name("callsetup");
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1);
// put current call on hold if active // put current call on hold if active
if (hfp_ag_call_state == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ if (put_call_on_hold){
printf("AG putting current call on hold for new outgoing call\n"); printf("AG putting current call on hold for new outgoing call\n");
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS); hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS);
indicator_index = get_ag_indicator_index_for_name("callheld"); indicator_index = get_ag_indicator_index_for_name("callheld");
@ -1431,7 +1488,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
// start audio if needed // start audio if needed
hfp_ag_establish_audio_connection(connection->remote_addr); hfp_ag_establish_audio_connection(connection->remote_addr);
break; break;
}
case HFP_AG_OUTGOING_CALL_RINGING: case HFP_AG_OUTGOING_CALL_RINGING:
// hfp_gsm_handle_event(); // hfp_gsm_handle_event();
connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING);
@ -1439,13 +1496,14 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
log_info("hfp_ag_call_sm: did not find outgoing connection in dialing state"); log_info("hfp_ag_call_sm: did not find outgoing connection in dialing state");
break; break;
} }
hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_RINGING);
connection->call_state = HFP_CALL_OUTGOING_RINGING; connection->call_state = HFP_CALL_OUTGOING_RINGING;
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE);
hfp_ag_transfer_callsetup_state(); hfp_ag_transfer_callsetup_state();
break; break;
case HFP_AG_OUTGOING_CALL_ESTABLISHED: case HFP_AG_OUTGOING_CALL_ESTABLISHED:{
// hfp_gsm_handle_event();
// get outgoing call // get outgoing call
connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_RINGING); connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_RINGING);
if (!connection){ if (!connection){
@ -1455,20 +1513,94 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
log_info("hfp_ag_call_sm: did not find outgoing connection"); log_info("hfp_ag_call_sm: did not find outgoing connection");
break; break;
} }
int CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS = get_hfp_ag_callheld_state() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS;
hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_ESTABLISHED);
connection->call_state = HFP_CALL_ACTIVE; connection->call_state = HFP_CALL_ACTIVE;
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); hfp_ag_set_call_indicator();
hfp_ag_transfer_call_state(); hfp_ag_transfer_call_state();
hfp_ag_transfer_callsetup_state(); hfp_ag_transfer_callsetup_state();
if (hfp_ag_callheld_state == HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS){ if (CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS){
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED);
hfp_ag_transfer_callheld_state(); hfp_ag_transfer_callheld_state();
} }
break; break;
}
case HFP_AG_CALL_HOLD_USER_BUSY:
hfp_gsm_handle_event(HFP_AG_CALL_HOLD_USER_BUSY);
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
connection->call_state = HFP_CALL_ACTIVE;
printf("AG: Call Waiting, User Busy\n");
break;
case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
int call_setup_in_progress = get_hfp_ag_callsetup_state() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
int call_held = get_hfp_ag_callheld_state() != HFP_CALLHELD_STATUS_NO_CALLS_HELD;
// Releases all active calls (if any exist) and accepts the other (held or waiting) call.
if (call_setup_in_progress){
printf("AG: Call Dropped, Accept new call\n");
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
} else {
printf("AG: Call Dropped, Resume held call\n");
}
if (call_held){
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
}
if (call_held || call_setup_in_progress){
hfp_gsm_handle_event(HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL);
}
connection->call_state = HFP_CALL_ACTIVE;
break;
}
case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
int call_setup_in_progress = get_hfp_ag_callsetup_state() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
// Places all active calls (if any exist) on hold and accepts the other (held or waiting) call.
// only update if callsetup changed
if (call_setup_in_progress){
printf("AG: Call on Hold, Accept new call\n");
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
} else {
printf("AG: Swap calls\n");
}
hfp_gsm_handle_event(HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL);
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
connection->call_state = HFP_CALL_ACTIVE;
break;
}
case HFP_AG_CALL_HOLD_ADD_HELD_CALL:
// Adds a held call to the conversation.
if (get_hfp_ag_callheld_state() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
printf("AG: Join 3-way-call\n");
hfp_gsm_handle_event(HFP_AG_CALL_HOLD_ADD_HELD_CALL);
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
hfp_emit_event(hfp_callback, HFP_SUBEVENT_CONFERENCE_CALL, 0);
}
connection->call_state = HFP_CALL_ACTIVE;
break;
case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS:
// Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)
hfp_gsm_handle_event(HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS);
printf("AG: Transfer call -> Connect two calls and disconnect\n");
hfp_ag_set_call_indicator();
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
connection->call_state = HFP_CALL_IDLE;
break;
default: default:
break; break;
} }
} }
static void hfp_run_for_context(hfp_connection_t *context){ static void hfp_run_for_context(hfp_connection_t *context){
@ -1739,73 +1871,24 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
case HFP_CMD_CALL_HOLD: { case HFP_CMD_CALL_HOLD: {
// TODO: fully implement this // TODO: fully implement this
log_error("HFP: unhandled call hold type %c", context->line_buffer[0]); log_error("HFP: unhandled call hold type %c", context->line_buffer[0]);
int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); context->command = HFP_CMD_NONE;
int callheld_indicator_index = get_ag_indicator_index_for_name("callheld"); context->ok_pending = 1;
int call_indicator_index = get_ag_indicator_index_for_name("call");
switch (context->line_buffer[0]){ switch (context->line_buffer[0]){
case '0': case '0':
context->command = HFP_CMD_NONE; hfp_ag_call_sm(HFP_AG_CALL_HOLD_USER_BUSY, context);
context->ok_pending = 1;
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
context->call_state = HFP_CALL_ACTIVE;
printf("AG: Call Waiting, User Busy\n");
break; break;
case '1': case '1':
// Releases all active calls (if any exist) and accepts the other (held or waiting) call. hfp_ag_call_sm(HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, context);
context->command = HFP_CMD_NONE;
context->ok_pending = 1;
if (hfp_ag_callsetup_state != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
printf("AG: Call Dropped, Accept new call\n");
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
} else {
printf("AG: Call Dropped, Resume held call\n");
}
if (hfp_ag_callheld_state != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
}
context->call_state = HFP_CALL_ACTIVE;
break; break;
case '2': case '2':
// Places all active calls (if any exist) on hold and accepts the other (held or waiting) call. hfp_ag_call_sm(HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, context);
context->command = HFP_CMD_NONE;
context->ok_pending = 1;
// only update if callsetup changed
if (hfp_ag_callsetup_state != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
printf("AG: Call on Hold, Accept new call\n");
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
} else {
printf("AG: Swap calls\n");
}
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
context->call_state = HFP_CALL_ACTIVE;
break; break;
case '3': case '3':
// Adds a held call to the conversation. hfp_ag_call_sm(HFP_AG_CALL_HOLD_ADD_HELD_CALL, context);
context->command = HFP_CMD_NONE;
context->ok_pending = 1;
if (hfp_ag_callheld_state != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
printf("AG: Join 3-way-call\n");
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
hfp_emit_event(hfp_callback, HFP_SUBEVENT_CONFERENCE_CALL, 0);
}
context->call_state = HFP_CALL_ACTIVE;
break; break;
case '4': case '4':
// Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer) hfp_ag_call_sm(HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS, context);
context->command = HFP_CMD_NONE;
context->ok_pending = 1;
printf("AG: Transfer call -> Connect two calls and disconnect\n");
hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS);
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, call_indicator_index, 1);
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
context->call_state = HFP_CALL_IDLE;
break; break;
default: default:
break; break;
@ -1907,9 +1990,17 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
hfp_ag_call_hold_services_nr = call_hold_services_nr; hfp_ag_call_hold_services_nr = call_hold_services_nr;
memcpy(hfp_ag_call_hold_services, call_hold_services, call_hold_services_nr * sizeof(char *)); memcpy(hfp_ag_call_hold_services, call_hold_services, call_hold_services_nr * sizeof(char *));
hfp_ag_call_state = HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS;
hfp_ag_callsetup_state = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; hfp_ag_callsetup_state = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
hfp_ag_callheld_state = HFP_CALLHELD_STATUS_NO_CALLS_HELD; hfp_ag_callheld_state = HFP_CALLHELD_STATUS_NO_CALLS_HELD;
hfp_ag_response_and_hold_active = 0;
clip_type = 0; // 0 == not set
memset(clip_number,0,sizeof(clip_number));
subscriber_numbers = NULL;
subscriber_numbers_count = 0;
hfp_gsm_init();
} }
void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){ void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){

View File

@ -64,6 +64,8 @@
typedef enum{ typedef enum{
CALL_NONE, CALL_NONE,
CALL_INITIATED,
CALL_RESPONSE_HOLD,
CALL_ACTIVE, CALL_ACTIVE,
CALL_HELD CALL_HELD
} hfp_gsm_call_status_t; } hfp_gsm_call_status_t;
@ -71,15 +73,21 @@ typedef enum{
typedef struct { typedef struct {
hfp_gsm_call_status_t status; hfp_gsm_call_status_t status;
uint8_t clip_type;
char clip_number[25];
} hfp_gsm_call_t; } hfp_gsm_call_t;
//
static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS]; static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS];
//
static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
void hfp_gsm_init(void){
memset(gsm_calls, 0, sizeof(gsm_calls));
int i;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
gsm_calls[i].status = CALL_NONE;
}
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
}
static int get_number_calls_with_status(hfp_gsm_call_status_t status){ static int get_number_calls_with_status(hfp_gsm_call_status_t status){
int i, count = 0; int i, count = 0;
@ -105,9 +113,21 @@ static inline int get_active_call_index(){
return get_call_index_with_status(CALL_ACTIVE); return get_call_index_with_status(CALL_ACTIVE);
} }
// static inline int get_number_none_calls(){ static inline int get_initiated_call_index(){
// return get_number_calls_with_status(CALL_NONE); return get_call_index_with_status(CALL_INITIATED);
// } }
static inline int get_held_call_index(){
return get_call_index_with_status(CALL_HELD);
}
static inline int get_response_held_call_index(){
return get_call_index_with_status(CALL_RESPONSE_HOLD);
}
static inline int get_number_none_calls(){
return get_number_calls_with_status(CALL_NONE);
}
static inline int get_number_active_calls(){ static inline int get_number_active_calls(){
return get_number_calls_with_status(CALL_ACTIVE); return get_number_calls_with_status(CALL_ACTIVE);
@ -117,8 +137,12 @@ static inline int get_number_held_calls(){
return get_number_calls_with_status(CALL_HELD); return get_number_calls_with_status(CALL_HELD);
} }
static inline int get_number_response_held_calls(){
return get_number_calls_with_status(CALL_RESPONSE_HOLD);
}
hfp_call_status_t hfp_gsm_call_status(){ hfp_call_status_t hfp_gsm_call_status(){
if (get_number_active_calls() + get_number_held_calls()){ if (get_number_active_calls() + get_number_held_calls() + get_number_response_held_calls()){
return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT; return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT;
} }
return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS;
@ -139,33 +163,224 @@ hfp_callsetup_status_t hfp_gsm_callsetup_status(){
return callsetup_status; return callsetup_status;
} }
int hfp_gsm_response_held_active(){
return get_response_held_call_index() != -1 ;
}
int hfp_gsm_call_possible(void){
return get_number_none_calls() > 0;
}
void hfp_gsm_handle_event(hfp_ag_call_event_t event){ void hfp_gsm_handle_event(hfp_ag_call_event_t event){
int next_free_slot = get_none_call_index(); int next_free_slot = get_none_call_index();
int current_call_index = get_active_call_index(); int current_call_index = get_active_call_index();
int initiated_call_index = get_initiated_call_index();
int held_call_index = get_held_call_index();
printf("hfp_gsm_handle_event %d \n", event);
switch (event){ switch (event){
case HFP_AG_OUTGOING_CALL_INITIATED: case HFP_AG_OUTGOING_CALL_INITIATED:
case HFP_AG_OUTGOING_REDIAL_INITIATED: case HFP_AG_OUTGOING_REDIAL_INITIATED:
if (next_free_slot == -1){ if (next_free_slot == -1){
log_error("max nr gsm call exceeded"); log_error("gsm: max call nr exceeded");
return; return;
} }
break;
case HFP_AG_OUTGOING_CALL_REJECTED:
if (current_call_index != -1){
gsm_calls[current_call_index].status = CALL_NONE;
}
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
break;
case HFP_AG_OUTGOING_CALL_ACCEPTED:
if (current_call_index != -1){ if (current_call_index != -1){
gsm_calls[current_call_index].status = CALL_HELD; gsm_calls[current_call_index].status = CALL_HELD;
} }
gsm_calls[next_free_slot].status = CALL_ACTIVE; gsm_calls[next_free_slot].status = CALL_INITIATED;
callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE; callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE;
break; break;
case HFP_AG_OUTGOING_CALL_REJECTED:
break;
case HFP_AG_OUTGOING_CALL_ACCEPTED:
break;
case HFP_AG_OUTGOING_CALL_RINGING: case HFP_AG_OUTGOING_CALL_RINGING:
if (current_call_index == -1){
log_error("gsm: no active call");
return;
}
callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE;
break; break;
case HFP_AG_OUTGOING_CALL_ESTABLISHED: case HFP_AG_OUTGOING_CALL_ESTABLISHED:
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
break; break;
case HFP_AG_INCOMING_CALL:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break;
callsetup_status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS;
gsm_calls[next_free_slot].status = CALL_INITIATED;
gsm_calls[next_free_slot].clip_type = 0;
break;
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
gsm_calls[current_call_index].status = CALL_HELD;
}
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
break;
case HFP_AG_HELD_CALL_JOINED_BY_AG:
if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break;
// TODO: mark joined calls with "multiparty flag" (if we cannot calculate it otherwise)
// TODO: is following condition correct? Can we join incoming call before it is answered?
if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
break;
}
if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) {
gsm_calls[held_call_index].status = CALL_ACTIVE;
break;
}
break;
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
break;
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG:
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_RESPONSE_HOLD;
break;
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG:
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF:
if (!hfp_gsm_response_held_active()) break;
gsm_calls[get_response_held_call_index()].status = CALL_ACTIVE;
break;
case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG:
case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF:
if (!hfp_gsm_response_held_active()) break;
gsm_calls[get_response_held_call_index()].status = CALL_NONE;
break;
case HFP_AG_TERMINATE_CALL_BY_HF:
switch (hfp_gsm_call_status()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
gsm_calls[current_call_index].status = CALL_NONE;
break;
}
break;
case HFP_AG_TERMINATE_CALL_BY_AG:
switch (hfp_gsm_call_status()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[current_call_index].status = CALL_NONE;
break;
default:
break;
}
break;
case HFP_AG_CALL_DROPPED:{
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break;
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
gsm_calls[i].status = CALL_NONE;
gsm_calls[i].clip_type = 0;
gsm_calls[i].clip_number[0] = '\0';
}
}
break;
case HFP_AG_CALL_HOLD_USER_BUSY:
// Held or waiting call gets active,
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_NONE;
gsm_calls[held_call_index].status = CALL_ACTIVE;
break;
case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == CALL_ACTIVE){
gsm_calls[i].clip_type = 0;
gsm_calls[i].clip_number[0] = '\0';
gsm_calls[i].status = CALL_NONE;
}
}
if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
} else {
gsm_calls[held_call_index].status = CALL_ACTIVE;
}
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
break;
}
case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == CALL_ACTIVE){
gsm_calls[i].clip_type = 0;
gsm_calls[i].clip_number[0] = '\0';
gsm_calls[i].status = CALL_HELD;
}
}
if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
} else {
gsm_calls[held_call_index].status = CALL_ACTIVE;
}
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
break;
}
case HFP_AG_CALL_HOLD_ADD_HELD_CALL:{
if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == CALL_HELD){
gsm_calls[i].clip_type = 0;
gsm_calls[i].clip_number[0] = '\0';
gsm_calls[i].status = CALL_ACTIVE;
}
}
}
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
break;
}
case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS:{
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
gsm_calls[i].clip_type = 0;
gsm_calls[i].clip_number[0] = '\0';
gsm_calls[i].status = CALL_NONE;
}
break;
}
default: default:
break; break;
} }

View File

@ -63,6 +63,10 @@ hfp_callheld_status_t hfp_gsm_callheld_status();
hfp_call_status_t hfp_gsm_call_status(); hfp_call_status_t hfp_gsm_call_status();
hfp_callsetup_status_t hfp_gsm_callsetup_status(); hfp_callsetup_status_t hfp_gsm_callsetup_status();
int hfp_gsm_call_possible(void);
void hfp_gsm_init(void);
void hfp_gsm_handle_event(hfp_ag_call_event_t event); void hfp_gsm_handle_event(hfp_ag_call_event_t event);
// /** // /**

View File

@ -168,7 +168,7 @@ void hsp_hs_create_service(uint8_t * service, uint32_t service_record_handle, in
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
attribute = de_push_sequence(service); attribute = de_push_sequence(service);
{ {
// "UUID for PAN Service" / see Bluetooth Erratum #3507 // see Bluetooth Erratum #3507
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_HSP); // 0x1108 de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_HSP); // 0x1108
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_Headset_HS); // 0x1131 de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_Headset_HS); // 0x1131
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio); // 0x1203 de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio); // 0x1203
@ -206,12 +206,12 @@ void hsp_hs_create_service(uint8_t * service, uint32_t service_record_handle, in
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList); de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
attribute = de_push_sequence(service); attribute = de_push_sequence(service);
{ {
uint8_t *sppProfile = de_push_sequence(attribute); uint8_t *hsp_profile = de_push_sequence(attribute);
{ {
de_add_number(sppProfile, DE_UUID, DE_SIZE_16, SDP_HSP); de_add_number(hsp_profile, DE_UUID, DE_SIZE_16, SDP_HSP);
de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0102); // Verision 1.2 de_add_number(hsp_profile, DE_UINT, DE_SIZE_16, 0x0102); // Verision 1.2
} }
de_pop_sequence(attribute, sppProfile); de_pop_sequence(attribute, hsp_profile);
} }
de_pop_sequence(service, attribute); de_pop_sequence(service, attribute);

View File

@ -1050,6 +1050,10 @@ static void hci_initializing_run(void){
hci_send_cmd(&hci_write_scan_enable, (hci_stack->connectable << 1) | hci_stack->discoverable); // page scan hci_send_cmd(&hci_write_scan_enable, (hci_stack->connectable << 1) | hci_stack->discoverable); // page scan
hci_stack->substate = HCI_INIT_W4_WRITE_SCAN_ENABLE; hci_stack->substate = HCI_INIT_W4_WRITE_SCAN_ENABLE;
break; break;
case HCI_INIT_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE:
hci_stack->substate = HCI_INIT_W4_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE;
hci_send_cmd(&hci_write_synchronous_flow_control_enable, 1); // SCO tracking enabled
break;
#ifdef HAVE_BLE #ifdef HAVE_BLE
// LE INIT // LE INIT
case HCI_INIT_LE_READ_BUFFER_SIZE: case HCI_INIT_LE_READ_BUFFER_SIZE:
@ -1249,17 +1253,34 @@ static void hci_initializing_event_handler(uint8_t * packet, uint16_t size){
return; return;
} }
break; break;
case HCI_INIT_W4_WRITE_PAGE_TIMEOUT:
break;
case HCI_INIT_W4_LE_READ_BUFFER_SIZE: case HCI_INIT_W4_LE_READ_BUFFER_SIZE:
// skip write le host if not supported (e.g. on LE only EM9301) // skip write le host if not supported (e.g. on LE only EM9301)
if (hci_stack->local_supported_commands[0] & 0x02) break; if (hci_stack->local_supported_commands[0] & 0x02) break;
hci_stack->substate = HCI_INIT_LE_SET_SCAN_PARAMETERS; hci_stack->substate = HCI_INIT_LE_SET_SCAN_PARAMETERS;
return; return;
#ifdef HAVE_SCO_OVER_HCI
case HCI_INIT_W4_WRITE_SCAN_ENABLE:
// just go to next state
break;
case HCI_INIT_W4_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE:
if (!hci_le_supported()){
// SKIP LE init for Classic only configuration
hci_stack->substate = HCI_INIT_DONE;
return;
}
break;
#else
case HCI_INIT_W4_WRITE_SCAN_ENABLE: case HCI_INIT_W4_WRITE_SCAN_ENABLE:
if (!hci_le_supported()){ if (!hci_le_supported()){
// SKIP LE init for Classic only configuration // SKIP LE init for Classic only configuration
hci_stack->substate = HCI_INIT_DONE; hci_stack->substate = HCI_INIT_DONE;
return; return;
} }
#endif
break;
default: default:
break; break;
} }
@ -1366,10 +1387,9 @@ static void event_handler(uint8_t *packet, int size){
} }
if (COMMAND_COMPLETE_EVENT(packet, hci_write_synchronous_flow_control_enable)){ if (COMMAND_COMPLETE_EVENT(packet, hci_write_synchronous_flow_control_enable)){
if (packet[5] == 0){ if (packet[5] == 0){
// @TODO cache value from hci_write_synchronous_flow_control_enable instead of assuming == 1
hci_stack->synchronous_flow_control_enabled = 1; hci_stack->synchronous_flow_control_enabled = 1;
} }
} }
break; break;
case HCI_EVENT_COMMAND_STATUS: case HCI_EVENT_COMMAND_STATUS:

View File

@ -458,15 +458,16 @@ typedef enum hci_init_state{
HCI_INIT_W4_WRITE_SIMPLE_PAIRING_MODE, HCI_INIT_W4_WRITE_SIMPLE_PAIRING_MODE,
HCI_INIT_WRITE_PAGE_TIMEOUT, HCI_INIT_WRITE_PAGE_TIMEOUT,
HCI_INIT_W4_WRITE_PAGE_TIMEOUT, HCI_INIT_W4_WRITE_PAGE_TIMEOUT,
// HCI_INIT_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE,
// HCI_INIT_W4_SYNCHRONOUS_FLOW_CONTROL_ENABLE,
HCI_INIT_WRITE_CLASS_OF_DEVICE, HCI_INIT_WRITE_CLASS_OF_DEVICE,
HCI_INIT_W4_WRITE_CLASS_OF_DEVICE, HCI_INIT_W4_WRITE_CLASS_OF_DEVICE,
HCI_INIT_WRITE_LOCAL_NAME, HCI_INIT_WRITE_LOCAL_NAME,
HCI_INIT_W4_WRITE_LOCAL_NAME, HCI_INIT_W4_WRITE_LOCAL_NAME,
HCI_INIT_WRITE_SCAN_ENABLE, HCI_INIT_WRITE_SCAN_ENABLE,
HCI_INIT_W4_WRITE_SCAN_ENABLE, HCI_INIT_W4_WRITE_SCAN_ENABLE,
HCI_INIT_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE,
HCI_INIT_W4_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE,
HCI_INIT_LE_READ_BUFFER_SIZE, HCI_INIT_LE_READ_BUFFER_SIZE,
HCI_INIT_W4_LE_READ_BUFFER_SIZE, HCI_INIT_W4_LE_READ_BUFFER_SIZE,
HCI_INIT_WRITE_LE_HOST_SUPPORTED, HCI_INIT_WRITE_LE_HOST_SUPPORTED,

View File

@ -337,7 +337,8 @@ static void simulate_test_sequence(hfp_test_item_t * test_item){
int previous_step = -1; int previous_step = -1;
while ( i < test_item->len){ while ( i < test_item->len){
previous_step++; previous_step++;
if (i < previous_step) exit(0); CHECK_EQUAL(i >= previous_step, 1);
char * expected_cmd = test_steps[i]; char * expected_cmd = test_steps[i];
int expected_cmd_len = strlen(expected_cmd); int expected_cmd_len = strlen(expected_cmd);
printf("\nStep %d, %s \n", i, expected_cmd); printf("\nStep %d, %s \n", i, expected_cmd);
@ -527,6 +528,7 @@ TEST_GROUP(HFPClient){
TEST(HFPClient, PTSRHHTests){ TEST(HFPClient, PTSRHHTests){
for (int i = 0; i < hfp_pts_ag_rhh_tests_size(); i++){ for (int i = 0; i < hfp_pts_ag_rhh_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_ag_rhh_tests()[i]); simulate_test_sequence(&hfp_pts_ag_rhh_tests()[i]);
teardown(); teardown();
} }
@ -534,6 +536,7 @@ TEST(HFPClient, PTSRHHTests){
TEST(HFPClient, PTSECCTests){ TEST(HFPClient, PTSECCTests){
for (int i = 0; i < hfp_pts_ag_ecc_tests_size(); i++){ for (int i = 0; i < hfp_pts_ag_ecc_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_ag_ecc_tests()[i]); simulate_test_sequence(&hfp_pts_ag_ecc_tests()[i]);
teardown(); teardown();
} }
@ -541,6 +544,7 @@ TEST(HFPClient, PTSECCTests){
TEST(HFPClient, PTSECSTests){ TEST(HFPClient, PTSECSTests){
for (int i = 0; i < hfp_pts_ag_ecs_tests_size(); i++){ for (int i = 0; i < hfp_pts_ag_ecs_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_ag_ecs_tests()[i]); simulate_test_sequence(&hfp_pts_ag_ecs_tests()[i]);
teardown(); teardown();
} }
@ -548,6 +552,7 @@ TEST(HFPClient, PTSECSTests){
TEST(HFPClient, PTSTWCTests){ TEST(HFPClient, PTSTWCTests){
for (int i = 0; i < hfp_pts_ag_twc_tests_size(); i++){ for (int i = 0; i < hfp_pts_ag_twc_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_ag_twc_tests()[i]); simulate_test_sequence(&hfp_pts_ag_twc_tests()[i]);
teardown(); teardown();
} }
@ -555,6 +560,7 @@ TEST(HFPClient, PTSTWCTests){
TEST(HFPClient, PTSATATests){ TEST(HFPClient, PTSATATests){
for (int i = 0; i < hfp_pts_ag_ata_tests_size(); i++){ for (int i = 0; i < hfp_pts_ag_ata_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_ag_ata_tests()[i]); simulate_test_sequence(&hfp_pts_ag_ata_tests()[i]);
teardown(); teardown();
} }
@ -562,6 +568,7 @@ TEST(HFPClient, PTSATATests){
TEST(HFPClient, PTSSLCTests){ TEST(HFPClient, PTSSLCTests){
for (int i = 0; i < hfp_pts_ag_slc_tests_size(); i++){ for (int i = 0; i < hfp_pts_ag_slc_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_ag_slc_tests()[i]); simulate_test_sequence(&hfp_pts_ag_slc_tests()[i]);
teardown(); teardown();
} }

View File

@ -318,7 +318,8 @@ void simulate_test_sequence(hfp_test_item_t * test_item){
int previous_step = -1; int previous_step = -1;
while ( i < test_item->len){ while ( i < test_item->len){
previous_step++; previous_step++;
if (i < previous_step) exit(0); CHECK_EQUAL(i >= previous_step, 1);
char * expected_cmd = test_steps[i]; char * expected_cmd = test_steps[i];
int expected_cmd_len = strlen(expected_cmd); int expected_cmd_len = strlen(expected_cmd);
printf("\nStep %d, %s \n", i, expected_cmd); printf("\nStep %d, %s \n", i, expected_cmd);
@ -495,6 +496,7 @@ TEST_GROUP(HFPClient){
TEST(HFPClient, PTSRHHTests){ TEST(HFPClient, PTSRHHTests){
for (int i = 0; i < hfp_pts_hf_rhh_tests_size(); i++){ for (int i = 0; i < hfp_pts_hf_rhh_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_hf_rhh_tests()[i]); simulate_test_sequence(&hfp_pts_hf_rhh_tests()[i]);
teardown(); teardown();
} }
@ -502,6 +504,7 @@ TEST(HFPClient, PTSRHHTests){
TEST(HFPClient, PTSECCTests){ TEST(HFPClient, PTSECCTests){
for (int i = 0; i < hfp_pts_hf_ecc_tests_size(); i++){ for (int i = 0; i < hfp_pts_hf_ecc_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_hf_ecc_tests()[i]); simulate_test_sequence(&hfp_pts_hf_ecc_tests()[i]);
teardown(); teardown();
} }
@ -509,6 +512,7 @@ TEST(HFPClient, PTSECCTests){
TEST(HFPClient, PTSECSTests){ TEST(HFPClient, PTSECSTests){
for (int i = 0; i < hfp_pts_hf_ecs_tests_size(); i++){ for (int i = 0; i < hfp_pts_hf_ecs_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_hf_ecs_tests()[i]); simulate_test_sequence(&hfp_pts_hf_ecs_tests()[i]);
teardown(); teardown();
} }
@ -516,6 +520,7 @@ TEST(HFPClient, PTSECSTests){
TEST(HFPClient, PTSTWCTests){ TEST(HFPClient, PTSTWCTests){
for (int i = 0; i < hfp_pts_hf_twc_tests_size(); i++){ for (int i = 0; i < hfp_pts_hf_twc_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_hf_twc_tests()[i]); simulate_test_sequence(&hfp_pts_hf_twc_tests()[i]);
teardown(); teardown();
} }
@ -523,6 +528,7 @@ TEST(HFPClient, PTSTWCTests){
TEST(HFPClient, PTSATATests){ TEST(HFPClient, PTSATATests){
for (int i = 0; i < hfp_pts_hf_ata_tests_size(); i++){ for (int i = 0; i < hfp_pts_hf_ata_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_hf_ata_tests()[i]); simulate_test_sequence(&hfp_pts_hf_ata_tests()[i]);
teardown(); teardown();
} }
@ -530,6 +536,7 @@ TEST(HFPClient, PTSATATests){
TEST(HFPClient, PTSSLCTests){ TEST(HFPClient, PTSSLCTests){
for (int i = 0; i < hfp_pts_hf_slc_tests_size(); i++){ for (int i = 0; i < hfp_pts_hf_slc_tests_size(); i++){
setup();
simulate_test_sequence(&hfp_pts_hf_slc_tests()[i]); simulate_test_sequence(&hfp_pts_hf_slc_tests()[i]);
teardown(); teardown();
} }

View File

@ -1883,7 +1883,8 @@ const char * TC_AG_ECS_BV_03_I[] = {
"OK" , "OK" ,
"AT+CMEE=1" , "AT+CMEE=1" ,
"OK" , "OK" ,
"USER:c" , // "+CIEV:3,1" , "USER:c" ,
"+CIEV:3,1" ,
"RING" , "RING" ,
"+CLIP: \"1234567\",129" , "+CLIP: \"1234567\",129" ,
"ATA" , "ATA" ,
@ -1902,7 +1903,7 @@ const char * TC_AG_ECS_BV_03_I[] = {
hfp_test_item_t pts_ag_ecs_tests[] = { hfp_test_item_t pts_ag_ecs_tests[] = {
TEST_SEQUENCE(TC_AG_ECS_BV_01_I), TEST_SEQUENCE(TC_AG_ECS_BV_01_I),
TEST_SEQUENCE(TC_AG_ECS_BV_02_I), TEST_SEQUENCE(TC_AG_ECS_BV_02_I),
// TEST_SEQUENCE(TC_AG_ECS_BV_03_I) TEST_SEQUENCE(TC_AG_ECS_BV_03_I)
}; };