/* * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include <stdint.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <inttypes.h> #include "esp_log.h" #include "bt_app_core.h" #include "bt_app_hf.h" #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gap_bt_api.h" #include "esp_hf_client_api.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" #include "freertos/ringbuf.h" #include "time.h" #include "sys/time.h" #include "sdkconfig.h" #include "app_BT_User.h" // #include "app_hf_msg_set.h" #include "esp_console.h" #include "argtable3/argtable3.h" const char *c_hf_evt_str[] = { "CONNECTION_STATE_EVT", /*!< connection state changed event */ "AUDIO_STATE_EVT", /*!< audio connection state change event */ "VR_STATE_CHANGE_EVT", /*!< voice recognition state changed */ "CALL_IND_EVT", /*!< call indication event */ "CALL_SETUP_IND_EVT", /*!< call setup indication event */ "CALL_HELD_IND_EVT", /*!< call held indicator event */ "NETWORK_STATE_EVT", /*!< network state change event */ "SIGNAL_STRENGTH_IND_EVT", /*!< signal strength indication event */ "ROAMING_STATUS_IND_EVT", /*!< roaming status indication event */ "BATTERY_LEVEL_IND_EVT", /*!< battery level indication event */ "CURRENT_OPERATOR_EVT", /*!< current operator name event */ "RESP_AND_HOLD_EVT", /*!< response and hold event */ "CLIP_EVT", /*!< Calling Line Identification notification event */ "CALL_WAITING_EVT", /*!< call waiting notification */ "CLCC_EVT", /*!< listing current calls event */ "VOLUME_CONTROL_EVT", /*!< audio volume control event */ "AT_RESPONSE", /*!< audio volume control event */ "SUBSCRIBER_INFO_EVT", /*!< subscriber information event */ "INBAND_RING_TONE_EVT", /*!< in-band ring tone settings */ "LAST_VOICE_TAG_NUMBER_EVT", /*!< requested number from AG event */ "RING_IND_EVT", /*!< ring indication event */ "PKT_STAT_EVT", /*!< requested number of packet status event */ }; // esp_hf_client_connection_state_t const char *c_connection_state_str[] = { "disconnected", "connecting", "connected", "slc_connected", "disconnecting", }; // esp_hf_client_audio_state_t const char *c_audio_state_str[] = { "disconnected", "connecting", "connected", "connected_msbc", }; /// esp_hf_vr_state_t const char *c_vr_state_str[] = { "disabled", "enabled", }; // esp_hf_service_availability_status_t const char *c_service_availability_status_str[] = { "unavailable", "available", }; // esp_hf_roaming_status_t const char *c_roaming_status_str[] = { "inactive", "active", }; // esp_hf_client_call_state_t const char *c_call_str[] = { "NO call in progress", "call in progress", }; // esp_hf_client_callsetup_t const char *c_call_setup_str[] = { "NONE", "INCOMING", "OUTGOING_DIALING", "OUTGOING_ALERTING" }; // esp_hf_client_callheld_t const char *c_call_held_str[] = { "NONE held", "Held and Active", "Held", }; // esp_hf_response_and_hold_status_t const char *c_resp_and_hold_str[] = { "HELD", "HELD ACCEPTED", "HELD REJECTED", }; // esp_hf_client_call_direction_t const char *c_call_dir_str[] = { "outgoing", "incoming", }; // esp_hf_client_call_state_t const char *c_call_state_str[] = { "active", "held", "dialing", "alerting", "incoming", "waiting", "held_by_resp_hold", }; // esp_hf_current_call_mpty_type_t const char *c_call_mpty_type_str[] = { "single", "multi", }; // esp_hf_volume_control_target_t const char *c_volume_control_target_str[] = { "SPEAKER", "MICROPHONE" }; // esp_hf_at_response_code_t const char *c_at_response_code_str[] = { "OK", "ERROR" "ERR_NO_CARRIER", "ERR_BUSY", "ERR_NO_ANSWER", "ERR_DELAYED", "ERR_BLACKLILSTED", "ERR_CME", }; // esp_hf_subscriber_service_type_t const char *c_subscriber_service_type_str[] = { "unknown", "voice", "fax", }; // esp_hf_client_in_band_ring_state_t const char *c_inband_ring_state_str[] = { "NOT provided", "Provided", }; extern esp_bd_addr_t peer_addr; //static uint8_t call_timer; // If you want to connect a specific device, add it's address here // esp_bd_addr_t peer_addr = {0xac, 0x67, 0xb2, 0x53, 0x77, 0xbe}; #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI #define ESP_HFP_RINGBUF_SIZE 3600 static RingbufHandle_t m_rb = NULL; static void bt_app_hf_client_audio_open(void) { m_rb = xRingbufferCreate(ESP_HFP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF); } static void bt_app_hf_client_audio_close(void) { if (!m_rb) { return ; } vRingbufferDelete(m_rb); } static uint32_t bt_app_hf_client_outgoing_cb(uint8_t *p_buf, uint32_t sz) { if (!m_rb) { return 0; } size_t item_size = 0; uint8_t *data = xRingbufferReceiveUpTo(m_rb, &item_size, 0, sz); if (item_size == sz) { memcpy(p_buf, data, item_size); vRingbufferReturnItem(m_rb, data); return sz; } else if (0 < item_size) { vRingbufferReturnItem(m_rb, data); return 0; } else { // data not enough, do not read return 0; } } static void bt_app_hf_client_incoming_cb(const uint8_t *buf, uint32_t sz) { if (! m_rb) { return; } BaseType_t done = xRingbufferSend(m_rb, (uint8_t *)buf, sz, 0); if (! done) { ESP_LOGE(BT_HF_TAG, "rb send fail"); } esp_hf_client_outgoing_data_ready(); } #endif /* #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI */ /* callback for HF_CLIENT */ void bt_app_hf_client_cb(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param) { if (event <= ESP_HF_CLIENT_PKT_STAT_NUMS_GET_EVT) { ESP_LOGI(BT_HF_TAG, "APP HFP event: %s", c_hf_evt_str[event]); } else { ESP_LOGE(BT_HF_TAG, "APP HFP invalid event %d", event); } switch (event) { case ESP_HF_CLIENT_CONNECTION_STATE_EVT: { ESP_LOGI(BT_HF_TAG, "--connection state %s, peer feats 0x%"PRIx32", chld_feats 0x%"PRIx32, c_connection_state_str[param->conn_stat.state], param->conn_stat.peer_feat, param->conn_stat.chld_feat); memcpy(peer_addr,param->conn_stat.remote_bda,ESP_BD_ADDR_LEN); if(param->conn_stat.state == 0) { BT_DisConnect_Event_Pro(); } else if(param->conn_stat.state == 2) { BT_Connect_Event_Pro(); } break; } case ESP_HF_CLIENT_AUDIO_STATE_EVT: { ESP_LOGI(BT_HF_TAG, "--audio state %s", c_audio_state_str[param->audio_stat.state]); #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED || param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC) { esp_hf_client_register_data_callback(bt_app_hf_client_incoming_cb, bt_app_hf_client_outgoing_cb); bt_app_hf_client_audio_open(); } else if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED) { bt_app_hf_client_audio_close(); } #endif /* #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI */ if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED || param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC) { hf_disc_audio_handler(); } break; } case ESP_HF_CLIENT_BVRA_EVT: { ESP_LOGI(BT_HF_TAG, "--VR state %s", c_vr_state_str[param->bvra.value]); break; } case ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT: { ESP_LOGI(BT_HF_TAG, "--NETWORK STATE %s", c_service_availability_status_str[param->service_availability.status]); break; } case ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT: { ESP_LOGI(BT_HF_TAG, "--ROAMING: %s", c_roaming_status_str[param->roaming.status]); break; } case ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT: { ESP_LOGI(BT_HF_TAG, "-- signal strength: %d", param->signal_strength.value); break; } case ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT: { ESP_LOGI(BT_HF_TAG, "--battery level %d", param->battery_level.value); break; } case ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT: { ESP_LOGI(BT_HF_TAG, "--operator name: %s", param->cops.name); break; } case ESP_HF_CLIENT_CIND_CALL_EVT: { ESP_LOGI(BT_HF_TAG, "--Call indicator %s", c_call_str[param->call.status]); if(param->call.status == 0) { BT_User.Call_Sts = Call_Idle; // call_timer = 0; //printf("call Hangup\r\n"); } else if(param->call.status == 1) { BT_User.Call_Sts = Call_InProcess; // printf("call Call_InProcess\r\n"); } break; } case ESP_HF_CLIENT_CIND_CALL_SETUP_EVT: { ESP_LOGI(BT_HF_TAG, "--Call setup indicator %s", c_call_setup_str[param->call_setup.status]); switch(param->call_setup.status) { case 0: { if(BT_User.Call_Sts == Call_IncomeCalling || BT_User.Call_Sts == Call_OutCalling) { BT_User.Call_Sts = Call_Idle; } // BT_User.Call_Sts = Call_Idle; // call_timer = 0; // printf("call Miss\r\n"); break; } case 1: { BT_User.Call_Sts = Call_IncomeCalling; //printf("call income\r\n"); break; } case 2: { BT_User.Call_Sts = Call_OutCalling; // printf("call outcall\r\n"); break; } case 3: { BT_User.Call_Sts = Call_OutCalling; // printf("call outcall\r\n"); break; } } if(param->call_setup.status == 0) break; } case ESP_HF_CLIENT_CIND_CALL_HELD_EVT: { ESP_LOGI(BT_HF_TAG, "--Call held indicator %s", c_call_held_str[param->call_held.status]); break; } case ESP_HF_CLIENT_BTRH_EVT: { ESP_LOGI(BT_HF_TAG, "--response and hold %s", c_resp_and_hold_str[param->btrh.status]); break; } case ESP_HF_CLIENT_CLIP_EVT: { ESP_LOGI(BT_HF_TAG, "--clip number %s", (param->clip.number == NULL) ? "NULL" : (param->clip.number)); // if(param->clip.number != NULL) // { // for(int i = 0 ; i < 11 ; i++) // { // BT_User.Number[i] = param->clip.number[i]; // } // } // if(BT_User.Call_Sts != Call_InProcess) // BT_User.Call_Sts = Call_IncomeCalling; // printf("call income\r\n"); // printf("%s\n",param->clip.number); // // printf("1\n"); break; } case ESP_HF_CLIENT_CCWA_EVT: { ESP_LOGI(BT_HF_TAG, "--call_waiting %s", (param->ccwa.number == NULL) ? "NULL" : (param->ccwa.number)); break; } case ESP_HF_CLIENT_CLCC_EVT: { ESP_LOGI(BT_HF_TAG, "--Current call: idx %d, dir %s, state %s, mpty %s, number %s", param->clcc.idx, c_call_dir_str[param->clcc.dir], c_call_state_str[param->clcc.status], c_call_mpty_type_str[param->clcc.mpty], (param->clcc.number == NULL) ? "NULL" : (param->clcc.number)); // if((strstr(param->clcc.number,"10000000") == NULL) && (BT_User.Call_Sts != Call_IncomeCalling) && (BT_User.Call_Sts != Call_InProcess)) // { // if(call_timer == 7) // { // BT_User.Call_Sts = Call_OutCalling; // printf("call outcall\r\n"); // printf("%s\n",param->clcc.number); // } // else // { // call_timer ++; // } // // call_timer ++; // } // else // { // call_timer = 0; // } // break; if((strstr(param->clcc.number,"10000000") == NULL) && (strstr(param->clcc.number,"00000000") == NULL)) { // printf("%s\n",param->clcc.number); BT_User.Get_Call_Num = 1; } } case ESP_HF_CLIENT_VOLUME_CONTROL_EVT: { ESP_LOGI(BT_HF_TAG, "--volume_target: %s, volume %d", c_volume_control_target_str[param->volume_control.type], param->volume_control.volume); break; } case ESP_HF_CLIENT_AT_RESPONSE_EVT: { ESP_LOGI(BT_HF_TAG, "--AT response event, code %d, cme %d", param->at_response.code, param->at_response.cme); break; } case ESP_HF_CLIENT_CNUM_EVT: { ESP_LOGI(BT_HF_TAG, "--subscriber type %s, number %s", c_subscriber_service_type_str[param->cnum.type], (param->cnum.number == NULL) ? "NULL" : param->cnum.number); break; } case ESP_HF_CLIENT_BSIR_EVT: { ESP_LOGI(BT_HF_TAG, "--inband ring state %s", c_inband_ring_state_str[param->bsir.state]); break; } case ESP_HF_CLIENT_BINP_EVT: { ESP_LOGI(BT_HF_TAG, "--last voice tag number: %s", (param->binp.number == NULL) ? "NULL" : param->binp.number); break; } case ESP_HF_CLIENT_PKT_STAT_NUMS_GET_EVT: { ESP_LOGE(BT_HF_TAG, "ESP_HF_CLIENT_PKT_STAT_NUMS_GET_EVT: %d", event); break; } default: ESP_LOGE(BT_HF_TAG, "HF_CLIENT EVT: %d", event); break; } } // uint8_t lasttest; void Get_Iphone_Fitter_callsts(void ) { if(BT_User.Call_Sts == Call_Idle) { BT_User.Get_Call_Num = 0; BT_User.Call_Fitter_sts = BT_User.Call_Sts; } else { if(BT_User.Get_Call_Num == 1) { BT_User.Call_Fitter_sts = BT_User.Call_Sts; } else { BT_User.Call_Fitter_sts = Call_Idle; } } // if(BT_User.Call_Fitter_sts != lasttest) // printf("%d\n",BT_User.Call_Fitter_sts); // lasttest = BT_User.Call_Fitter_sts; } #define HF_CMD_HANDLER(cmd) int hf_##cmd##_handler(void ) HF_CMD_HANDLER(conn) { // printf("connect\n"); esp_hf_client_connect(peer_addr); return 0; } HF_CMD_HANDLER(disc) { // printf("disconnect\n"); esp_hf_client_disconnect(peer_addr); return 0; } HF_CMD_HANDLER(conn_audio) { // printf("connect audio\n"); esp_hf_client_connect_audio(peer_addr); return 0; } HF_CMD_HANDLER(disc_audio) { // printf("disconnect audio\n"); esp_hf_client_disconnect_audio(peer_addr); return 0; } HF_CMD_HANDLER(query_op) { // printf("Query operator\n"); esp_hf_client_query_current_operator_name(); return 0; } HF_CMD_HANDLER(answer) { // printf("Answer call\n"); esp_hf_client_answer_call(); return 0; } HF_CMD_HANDLER(reject) { esp_err_t err; err = esp_hf_client_reject_call(); // printf("Reject call err %d\n",err); return 0; } const char test_dial_num[] = "17800536969"; HF_CMD_HANDLER(dial) { // printf("Dial number %s\n", test_dial_num); esp_hf_client_dial(test_dial_num); return 0; } HF_CMD_HANDLER(redial) { // printf("Dial number\n"); esp_hf_client_dial(NULL); return 0; } HF_CMD_HANDLER(dial_mem) { int index = 1; esp_hf_client_dial_memory(index); return 0; } HF_CMD_HANDLER(start_vr) { // printf("Start voice recognition\n"); esp_hf_client_start_voice_recognition(); return 0; } HF_CMD_HANDLER(stop_vr) { // printf("Stop voice recognition\n"); esp_hf_client_stop_voice_recognition(); return 0; } // HF_CMD_HANDLER(query_call) // { // // printf("Query current call status\n"); // esp_hf_client_query_current_calls(); // return 0; // } // HF_CMD_HANDLER(retrieve_subscriber) // { // // printf("Retrieve subscriber information\n"); // esp_hf_client_retrieve_subscriber_info(); // return 0; // } // HF_CMD_HANDLER(request_last_voice_tag) // { // // printf("Request last voice tag\n"); // esp_hf_client_request_last_voice_tag_number(); // return 0; // } // typedef enum { // ESP_HF_BTRH_CMD_HOLD = 0, /*!< put the incoming call on hold */ // ESP_HF_BTRH_CMD_ACCEPT = 1, /*!< accept a held incoming call */ // ESP_HF_BTRH_CMD_REJECT = 2, /*!< reject a held incoming call */ // } esp_hf_btrh_cmd_t; HF_CMD_HANDLER(btrh) { int btrh = ESP_HF_BTRH_CMD_HOLD; // printf("respond and hold command: %d\n", btrh); esp_hf_client_send_btrh_cmd(btrh); return 0; }