From ca6041f8467c012302dc8c2f061416e5e1f9c2fa Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Fri, 8 Jan 2016 17:16:29 +0100 Subject: [PATCH] hfp: start extracting gsm model --- src/hfp.h | 18 ++-- src/hfp_ag.c | 10 ++ src/hfp_ag.h | 1 + src/hfp_gsm_model.c | 173 +++++++++++++++++++++++++++++++++ src/hfp_gsm_model.h | 229 ++++++++++++++++++++++++++++++++++++++++++++ test/hfp/Makefile | 4 +- test/pts/Makefile | 2 +- 7 files changed, 425 insertions(+), 12 deletions(-) create mode 100644 src/hfp_gsm_model.c create mode 100644 src/hfp_gsm_model.h diff --git a/src/hfp.h b/src/hfp.h index b933b8156..07b348631 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -275,7 +275,7 @@ typedef enum { 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_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_event_t; @@ -404,14 +404,14 @@ typedef enum { } hfp_hf_query_operator_state_t; typedef enum { - HFP_LINK_SETTINGS_D0 = 0, - HFP_LINK_SETTINGS_D1, - HFP_LINK_SETTINGS_S1, - HFP_LINK_SETTINGS_S2, - HFP_LINK_SETTINGS_S3, - HFP_LINK_SETTINGS_S4, - HFP_LINK_SETTINGS_T1, - HFP_LINK_SETTINGS_T2 + HFP_LINK_SETTINGS_D0 = 0, + HFP_LINK_SETTINGS_D1, + HFP_LINK_SETTINGS_S1, + HFP_LINK_SETTINGS_S2, + HFP_LINK_SETTINGS_S3, + HFP_LINK_SETTINGS_S4, + HFP_LINK_SETTINGS_T1, + HFP_LINK_SETTINGS_T2 } hfp_link_setttings_t; typedef enum{ diff --git a/src/hfp_ag.c b/src/hfp_ag.c index bdb1475b2..25498986e 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -59,6 +59,7 @@ #include "sdp.h" #include "debug.h" #include "hfp.h" +#include "hfp_gsm_model.h" #include "hfp_ag.h" static const char default_hfp_ag_service_name[] = "Voice gateway"; @@ -1114,6 +1115,7 @@ static int call_setup_state_machine(hfp_connection_t * connection){ // connection is used to identify originating HF static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connection){ int indicator_index; + switch (event){ case HFP_AG_INCOMING_CALL: switch (hfp_ag_call_state){ @@ -1377,16 +1379,21 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect break; case HFP_AG_OUTGOING_CALL_INITIATED: + hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_INITIATED); connection->call_state = HFP_CALL_OUTGOING_INITIATED; + hfp_emit_string_event(hfp_callback, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, (const char *) &connection->line_buffer[3]); break; case HFP_AG_OUTGOING_REDIAL_INITIATED: + hfp_gsm_handle_event(HFP_AG_OUTGOING_REDIAL_INITIATED); connection->call_state = HFP_CALL_OUTGOING_INITIATED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_REDIAL_LAST_NUMBER, 0); break; 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); if (!connection){ log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); @@ -1398,6 +1405,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect break; case HFP_AG_OUTGOING_CALL_ACCEPTED: + // hfp_gsm_handle_event(); connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); if (!connection){ log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); @@ -1425,6 +1433,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect break; case HFP_AG_OUTGOING_CALL_RINGING: + // hfp_gsm_handle_event(); connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); if (!connection){ log_info("hfp_ag_call_sm: did not find outgoing connection in dialing state"); @@ -1436,6 +1445,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect break; case HFP_AG_OUTGOING_CALL_ESTABLISHED: + // hfp_gsm_handle_event(); // get outgoing call connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_RINGING); if (!connection){ diff --git a/src/hfp_ag.h b/src/hfp_ag.h index 863b2c40d..c40c32b79 100644 --- a/src/hfp_ag.h +++ b/src/hfp_ag.h @@ -48,6 +48,7 @@ #include "hci.h" #include "sdp_query_rfcomm.h" #include "hfp.h" +#include "hfp_gsm_model.h" #if defined __cplusplus extern "C" { diff --git a/src/hfp_gsm_model.c b/src/hfp_gsm_model.c new file mode 100644 index 000000000..77ab7b6c8 --- /dev/null +++ b/src/hfp_gsm_model.c @@ -0,0 +1,173 @@ +/* + * 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 HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!) +// +// ***************************************************************************** + +#include "btstack-config.h" + +#include +#include +#include +#include + +#include +#include + +#include "hci.h" +#include "btstack_memory.h" +#include "hci_dump.h" +#include "l2cap.h" +#include "sdp_query_rfcomm.h" +#include "sdp.h" +#include "debug.h" +#include "hfp.h" +#include "hfp_gsm_model.h" + +#define HFP_GSM_MAX_NR_CALLS 3 + +typedef enum{ + CALL_NONE, + CALL_ACTIVE, + CALL_HELD +} hfp_gsm_call_status_t; + + +typedef struct { + hfp_gsm_call_status_t status; +} hfp_gsm_call_t; + + +// +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 int get_number_calls_with_status(hfp_gsm_call_status_t status){ + int i, count = 0; + for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ + if (gsm_calls[i].status == status) count++; + } + return count; +} + +static int get_call_index_with_status(hfp_gsm_call_status_t status){ + int i ; + for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ + if (gsm_calls[i].status == status) return i; + } + return -1; +} + +static inline int get_none_call_index(){ + return get_call_index_with_status(CALL_NONE); +} + +static inline int get_active_call_index(){ + return get_call_index_with_status(CALL_ACTIVE); +} + +// static inline int get_number_none_calls(){ +// return get_number_calls_with_status(CALL_NONE); +// } + +static inline int get_number_active_calls(){ + return get_number_calls_with_status(CALL_ACTIVE); +} + +static inline int get_number_held_calls(){ + return get_number_calls_with_status(CALL_HELD); +} + +hfp_call_status_t hfp_gsm_call_status(){ + if (get_number_active_calls() + get_number_held_calls()){ + return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT; + } + return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; +} + +hfp_callheld_status_t hfp_gsm_callheld_status(){ + // @note: order is important + if (get_number_held_calls() == 0){ + return HFP_CALLHELD_STATUS_NO_CALLS_HELD; + } + if (get_number_active_calls() == 0) { + return HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS; + } + return HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED; +} + +hfp_callsetup_status_t hfp_gsm_callsetup_status(){ + return callsetup_status; +} + +void hfp_gsm_handle_event(hfp_ag_call_event_t event){ + int next_free_slot = get_none_call_index(); + int current_call_index = get_active_call_index(); + + switch (event){ + case HFP_AG_OUTGOING_CALL_INITIATED: + case HFP_AG_OUTGOING_REDIAL_INITIATED: + + if (next_free_slot == -1){ + log_error("max nr gsm call exceeded"); + return; + } + + if (current_call_index != -1){ + gsm_calls[current_call_index].status = CALL_HELD; + } + gsm_calls[next_free_slot].status = CALL_ACTIVE; + callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE; + break; + case HFP_AG_OUTGOING_CALL_REJECTED: + break; + case HFP_AG_OUTGOING_CALL_ACCEPTED: + break; + case HFP_AG_OUTGOING_CALL_RINGING: + break; + case HFP_AG_OUTGOING_CALL_ESTABLISHED: + break; + default: + break; + } +} \ No newline at end of file diff --git a/src/hfp_gsm_model.h b/src/hfp_gsm_model.h new file mode 100644 index 000000000..dd72c3d7b --- /dev/null +++ b/src/hfp_gsm_model.h @@ -0,0 +1,229 @@ +/* + * 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 + * + */ + +// ***************************************************************************** +// +// GSM model (!! UNDER DEVELOPMENT !!) +// +// ***************************************************************************** + + +#ifndef BTSTACK_HFP_GSM_MODEL_H +#define BTSTACK_HFP_GSM_MODEL_H + +#include "hci.h" +#include "sdp_query_rfcomm.h" +#include "hfp.h" + +#if defined __cplusplus +extern "C" { +#endif + +/* API_START */ + +/** + * @brief + */ + +hfp_callheld_status_t hfp_gsm_callheld_status(); +hfp_call_status_t hfp_gsm_call_status(); +hfp_callsetup_status_t hfp_gsm_callsetup_status(); + +void hfp_gsm_handle_event(hfp_ag_call_event_t event); + +// /** +// * @brief +// */ +// void hfp_gsm_incoming_call(void); + + +// / +// /** +// * @brief Report the change in AG's call status. +// * Call status: +// * - 0 = No calls (held or active) +// * - 1 = Call is present (active or held) +// */ +// void hfp_gsm_transfer_call_status(bd_addr_t bd_addr, hfp_call_status_t status); + +// /** +// * @brief Report the change in AG's call setup status. +// * Call setup status: +// * - 0 = No call setup in progress +// * - 1 = Incoming call setup in progress +// * - 2 = Outgoing call setup in dialing state +// * - 3 = Outgoing call setup in alerting state +// */ +// void hfp_gsm_transfer_callsetup_status(bd_addr_t bd_addr, hfp_callsetup_status_t status); + +// /** +// * @brief Report the change in AG's held call status. +// * Held call status: +// * - 0 = No calls held +// * - 1 = Call is placed on hold or active/held calls are swapped +// * - 2 = Call on hold, no active calls +// */ +// void hfp_gsm_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t status); + +// /** +// * @brief Enable in-band ring tone +// */ +// void hfp_gsm_set_use_in_band_ring_tone(int use_in_band_ring_tone); + + + +// /** +// * @brief number is stored. +// */ +// void hfp_gsm_set_clip(uint8_t type, const char * number); + +// /** +// * @brief +// */ +// void hfp_gsm_outgoing_call_rejected(void); + +// /** +// * @brief +// */ +// void hfp_gsm_outgoing_call_accepted(void); + +// /** +// * @brief +// */ +// void hfp_gsm_outgoing_call_ringing(void); + +// /** +// * @brief +// */ +// void hfp_gsm_outgoing_call_established(void); + +// * +// * @brief + +// void hfp_gsm_call_dropped(void); + +// /** +// * @brief +// */ +// void hfp_gsm_answer_incoming_call(void); + +// /** +// * @brief +// */ +// void hfp_gsm_join_held_call(void); + +// /** +// * @brief +// */ +// void hfp_gsm_terminate_call(void); + +// /* +// * @brief +// */ +// void hfp_gsm_set_registration_status(int status); + +// /* +// * @brief +// */ +// void hfp_gsm_set_signal_strength(int strength); + +// /* +// * @brief +// */ +// void hfp_gsm_set_roaming_status(int status); + + +// /* +// * @brief +// */ +// void hfp_gsm_activate_voice_recognition(bd_addr_t bd_addr, int activate); + + +// /* +// * @brief +// */ +// void hfp_gsm_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * number); + +// /* +// * @brief +// */ +// void hfp_gsm_reject_phone_number_for_voice_tag(bd_addr_t bd_addr); + +// /* +// * @brief +// */ +// void hfp_gsm_send_dtmf_code_done(bd_addr_t bd_addr); + +// /* +// * @brief +// */ +// void hfp_gsm_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count); + +// /* +// * @brief +// */ +// void hfp_gsm_send_current_call_status(bd_addr_t bd_addr, int idx, hfp_enhanced_call_dir_t dir, +// hfp_enhanced_call_status_t status, hfp_enhanced_call_mode_t mode, +// hfp_enhanced_call_mpty_t mpty, uint8_t type, const char * number); + +// /* +// * @brief +// */ +// void hfp_gsm_send_current_call_status_done(bd_addr_t bd_addr); + +// /* +// * @brief +// */ +// void hfp_gsm_hold_incoming_call(void); + +// /* +// * @brief +// */ +// void hfp_gsm_accept_held_incoming_call(void); + +// /* +// * @brief +// */ +// void hfp_gsm_reject_held_incoming_call(void); + +/* API_END */ + +#if defined __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/test/hfp/Makefile b/test/hfp/Makefile index cda1c48c7..aef870808 100644 --- a/test/hfp/Makefile +++ b/test/hfp/Makefile @@ -62,7 +62,7 @@ all: ${BTSTACK_ROOT}/include/btstack/version.h ${EXAMPLES} clean: rm -rf *.o $(EXAMPLES) $(CLIENT_EXAMPLES) *.dSYM -hfp_ag_parser_test: ${COMMON_OBJ} hfp_ag.o hfp.o hfp_ag_parser_test.c +hfp_ag_parser_test: ${COMMON_OBJ} hfp_gsm_model.o hfp_ag.o hfp.o hfp_ag_parser_test.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ hfp_hf_parser_test: ${COMMON_OBJ} hfp_hf.o hfp.o hfp_hf_parser_test.c @@ -71,7 +71,7 @@ hfp_hf_parser_test: ${COMMON_OBJ} hfp_hf.o hfp.o hfp_hf_parser_test.c hfp_hf_client_test: ${MOCK_OBJ} hfp_hf.o hfp.o hfp_hf_client_test.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ -hfp_ag_client_test: ${MOCK_OBJ} hfp_ag.o hfp.o hfp_ag_client_test.c +hfp_ag_client_test: ${MOCK_OBJ} hfp_gsm_model.o hfp_ag.o hfp.o hfp_ag_client_test.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ test: all diff --git a/test/pts/Makefile b/test/pts/Makefile index d904116fb..df54d5da5 100644 --- a/test/pts/Makefile +++ b/test/pts/Makefile @@ -55,7 +55,7 @@ hsp_hs_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hsp_hs.o hsp_hs_test.c hfp_hf_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hfp.o hfp_hf.o hfp_hf_test.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ -hfp_ag_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hfp.o hfp_ag.o hfp_ag_test.c +hfp_ag_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hfp.o hfp_ag_model.o hfp_ag.o hfp_ag_test.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ l2cap_test: ${CORE_OBJ} ${COMMON_OBJ} l2cap_test.c