mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-12-13 14:04:12 +08:00
c8fea98cba
This patch adds completion functions to handsfree methods.
785 lines
17 KiB
C
785 lines
17 KiB
C
/*
|
|
* Copyright (C) 2013 Intel Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include "if-main.h"
|
|
|
|
const bthf_interface_t *if_hf = NULL;
|
|
|
|
SINTMAP(bthf_at_response_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_AT_RESPONSE_ERROR),
|
|
DELEMENT(BTHF_AT_RESPONSE_OK),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_connection_state_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_CONNECTION_STATE_DISCONNECTED),
|
|
DELEMENT(BTHF_CONNECTION_STATE_CONNECTING),
|
|
DELEMENT(BTHF_CONNECTION_STATE_CONNECTED),
|
|
DELEMENT(BTHF_CONNECTION_STATE_SLC_CONNECTED),
|
|
DELEMENT(BTHF_CONNECTION_STATE_DISCONNECTING),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_audio_state_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_AUDIO_STATE_DISCONNECTED),
|
|
DELEMENT(BTHF_AUDIO_STATE_CONNECTING),
|
|
DELEMENT(BTHF_AUDIO_STATE_CONNECTED),
|
|
DELEMENT(BTHF_AUDIO_STATE_DISCONNECTING),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_vr_state_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_VR_STATE_STOPPED),
|
|
DELEMENT(BTHF_VR_STATE_STARTED),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_volume_type_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_VOLUME_TYPE_SPK),
|
|
DELEMENT(BTHF_VOLUME_TYPE_MIC),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_nrec_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_NREC_STOP),
|
|
DELEMENT(BTHF_NREC_START),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_chld_type_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_CHLD_TYPE_RELEASEHELD),
|
|
DELEMENT(BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD),
|
|
DELEMENT(BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD),
|
|
DELEMENT(BTHF_CHLD_TYPE_ADDHELDTOCONF),
|
|
ENDMAP
|
|
|
|
/* Network Status */
|
|
SINTMAP(bthf_network_state_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_NETWORK_STATE_NOT_AVAILABLE),
|
|
DELEMENT(BTHF_NETWORK_STATE_AVAILABLE),
|
|
ENDMAP
|
|
|
|
/* Service type */
|
|
SINTMAP(bthf_service_type_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_SERVICE_TYPE_HOME),
|
|
DELEMENT(BTHF_SERVICE_TYPE_ROAMING),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_call_state_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_CALL_STATE_ACTIVE),
|
|
DELEMENT(BTHF_CALL_STATE_HELD),
|
|
DELEMENT(BTHF_CALL_STATE_DIALING),
|
|
DELEMENT(BTHF_CALL_STATE_ALERTING),
|
|
DELEMENT(BTHF_CALL_STATE_INCOMING),
|
|
DELEMENT(BTHF_CALL_STATE_WAITING),
|
|
DELEMENT(BTHF_CALL_STATE_IDLE),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_call_direction_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_CALL_DIRECTION_OUTGOING),
|
|
DELEMENT(BTHF_CALL_DIRECTION_INCOMING),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_call_mode_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_CALL_TYPE_VOICE),
|
|
DELEMENT(BTHF_CALL_TYPE_DATA),
|
|
DELEMENT(BTHF_CALL_TYPE_FAX),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_call_mpty_type_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_CALL_MPTY_TYPE_SINGLE),
|
|
DELEMENT(BTHF_CALL_MPTY_TYPE_MULTI),
|
|
ENDMAP
|
|
|
|
SINTMAP(bthf_call_addrtype_t, -1, "(unknown)")
|
|
DELEMENT(BTHF_CALL_ADDRTYPE_UNKNOWN),
|
|
DELEMENT(BTHF_CALL_ADDRTYPE_INTERNATIONAL),
|
|
ENDMAP
|
|
|
|
/* Callbacks */
|
|
|
|
static char last_addr[MAX_ADDR_STR_LEN];
|
|
|
|
/*
|
|
* Callback for connection state change.
|
|
* state will have one of the values from BtHfConnectionState
|
|
*/
|
|
static void connection_state_cb(bthf_connection_state_t state,
|
|
bt_bdaddr_t *bd_addr)
|
|
{
|
|
haltest_info("%s: state=%s bd_addr=%s\n", __func__,
|
|
bthf_connection_state_t2str(state),
|
|
bt_bdaddr_t2str(bd_addr, last_addr));
|
|
}
|
|
|
|
/*
|
|
* Callback for audio connection state change.
|
|
* state will have one of the values from BtHfAudioState
|
|
*/
|
|
static void audio_state_cb(bthf_audio_state_t state, bt_bdaddr_t *bd_addr)
|
|
{
|
|
haltest_info("%s: state=%s bd_addr=%s\n", __func__,
|
|
bthf_audio_state_t2str(state),
|
|
bt_bdaddr_t2str(bd_addr, last_addr));
|
|
}
|
|
|
|
/*
|
|
* Callback for VR connection state change.
|
|
* state will have one of the values from BtHfVRState
|
|
*/
|
|
static void vr_cmd_cb(bthf_vr_state_t state)
|
|
{
|
|
haltest_info("%s: state=%s\n", __func__, bthf_vr_state_t2str(state));
|
|
}
|
|
|
|
/* Callback for answer incoming call (ATA) */
|
|
static void answer_call_cmd_cb(void)
|
|
{
|
|
haltest_info("%s\n", __func__);
|
|
}
|
|
|
|
/* Callback for disconnect call (AT+CHUP) */
|
|
static void hangup_call_cmd_cb(void)
|
|
{
|
|
haltest_info("%s\n", __func__);
|
|
}
|
|
|
|
/*
|
|
* Callback for disconnect call (AT+CHUP)
|
|
* type will denote Speaker/Mic gain (BtHfVolumeControl).
|
|
*/
|
|
static void volume_cmd_cb(bthf_volume_type_t type, int volume)
|
|
{
|
|
haltest_info("%s: type=%s volume=%d\n", __func__,
|
|
bthf_volume_type_t2str(type), volume);
|
|
}
|
|
|
|
/*
|
|
* Callback for dialing an outgoing call
|
|
* If number is NULL, redial
|
|
*/
|
|
static void dial_call_cmd_cb(char *number)
|
|
{
|
|
haltest_info("%s: number=%s\n", __func__, number);
|
|
}
|
|
|
|
/*
|
|
* Callback for sending DTMF tones
|
|
* tone contains the dtmf character to be sent
|
|
*/
|
|
static void dtmf_cmd_cb(char tone)
|
|
{
|
|
haltest_info("%s: tone=%d\n", __func__, tone);
|
|
}
|
|
|
|
/*
|
|
* Callback for enabling/disabling noise reduction/echo cancellation
|
|
* value will be 1 to enable, 0 to disable
|
|
*/
|
|
static void nrec_cmd_cb(bthf_nrec_t nrec)
|
|
{
|
|
haltest_info("%s: nrec=%s\n", __func__, bthf_nrec_t2str(nrec));
|
|
}
|
|
|
|
/*
|
|
* Callback for call hold handling (AT+CHLD)
|
|
* value will contain the call hold command (0, 1, 2, 3)
|
|
*/
|
|
static void chld_cmd_cb(bthf_chld_type_t chld)
|
|
{
|
|
haltest_info("%s: chld=%s\n", __func__, bthf_chld_type_t2str(chld));
|
|
}
|
|
|
|
/* Callback for CNUM (subscriber number) */
|
|
static void cnum_cmd_cb(void)
|
|
{
|
|
haltest_info("%s\n", __func__);
|
|
}
|
|
|
|
/* Callback for indicators (CIND) */
|
|
static void cind_cmd_cb(void)
|
|
{
|
|
haltest_info("%s\n", __func__);
|
|
}
|
|
|
|
/* Callback for operator selection (COPS) */
|
|
static void cops_cmd_cb(void)
|
|
{
|
|
haltest_info("%s\n", __func__);
|
|
}
|
|
|
|
/* Callback for call list (AT+CLCC) */
|
|
static void clcc_cmd_cb(void)
|
|
{
|
|
haltest_info("%s\n", __func__);
|
|
}
|
|
|
|
/*
|
|
* Callback for unknown AT command recd from HF
|
|
* at_string will contain the unparsed AT string
|
|
*/
|
|
static void unknown_at_cmd_cb(char *at_string)
|
|
{
|
|
haltest_info("%s: at_string=%s\n", __func__, at_string);
|
|
}
|
|
|
|
/* Callback for keypressed (HSP) event. */
|
|
static void key_pressed_cmd_cb(void)
|
|
{
|
|
haltest_info("%s\n", __func__);
|
|
}
|
|
|
|
static bthf_callbacks_t hf_cbacks = {
|
|
|
|
.size = sizeof(hf_cbacks),
|
|
.connection_state_cb = connection_state_cb,
|
|
.audio_state_cb = audio_state_cb,
|
|
.vr_cmd_cb = vr_cmd_cb,
|
|
.answer_call_cmd_cb = answer_call_cmd_cb,
|
|
.hangup_call_cmd_cb = hangup_call_cmd_cb,
|
|
.volume_cmd_cb = volume_cmd_cb,
|
|
.dial_call_cmd_cb = dial_call_cmd_cb,
|
|
.dtmf_cmd_cb = dtmf_cmd_cb,
|
|
.nrec_cmd_cb = nrec_cmd_cb,
|
|
.chld_cmd_cb = chld_cmd_cb,
|
|
.cnum_cmd_cb = cnum_cmd_cb,
|
|
.cind_cmd_cb = cind_cmd_cb,
|
|
.cops_cmd_cb = cops_cmd_cb,
|
|
.clcc_cmd_cb = clcc_cmd_cb,
|
|
.unknown_at_cmd_cb = unknown_at_cmd_cb,
|
|
.key_pressed_cmd_cb = key_pressed_cmd_cb,
|
|
};
|
|
|
|
/* init */
|
|
|
|
static void init_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
EXEC(if_hf->init, &hf_cbacks);
|
|
}
|
|
|
|
/* connect */
|
|
|
|
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = NULL;
|
|
*enum_func = enum_devices;
|
|
}
|
|
}
|
|
|
|
static void connect_p(int argc, const char **argv)
|
|
{
|
|
bt_bdaddr_t addr;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
VERIFY_ADDR_ARG(2, &addr);
|
|
|
|
EXEC(if_hf->connect, &addr);
|
|
}
|
|
|
|
/* disconnect */
|
|
|
|
/*
|
|
* This completion function will be used for several methods
|
|
* returning recently connected address
|
|
*/
|
|
static void connected_addr_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = last_addr;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
/* Map completion to connected_addr_c */
|
|
#define disconnect_c connected_addr_c
|
|
|
|
static void disconnect_p(int argc, const char **argv)
|
|
{
|
|
bt_bdaddr_t addr;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
VERIFY_ADDR_ARG(2, &addr);
|
|
|
|
EXEC(if_hf->disconnect, &addr);
|
|
}
|
|
|
|
/* create an audio connection */
|
|
|
|
/* Map completion to connected_addr_c */
|
|
#define connect_audio_c connected_addr_c
|
|
|
|
static void connect_audio_p(int argc, const char **argv)
|
|
{
|
|
bt_bdaddr_t addr;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
VERIFY_ADDR_ARG(2, &addr);
|
|
|
|
EXEC(if_hf->connect_audio, &addr);
|
|
}
|
|
|
|
/* close the audio connection */
|
|
|
|
/* Map completion to connected_addr_c */
|
|
#define disconnect_audio_c connected_addr_c
|
|
|
|
static void disconnect_audio_p(int argc, const char **argv)
|
|
{
|
|
bt_bdaddr_t addr;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
VERIFY_ADDR_ARG(2, &addr);
|
|
|
|
EXEC(if_hf->disconnect_audio, &addr);
|
|
}
|
|
|
|
/* start voice recognition */
|
|
|
|
static void start_voice_recognition_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
EXEC(if_hf->start_voice_recognition);
|
|
}
|
|
|
|
/* stop voice recognition */
|
|
|
|
static void stop_voice_recognition_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
EXEC(if_hf->stop_voice_recognition);
|
|
}
|
|
|
|
/* volume control */
|
|
|
|
static void volume_control_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = TYPE_ENUM(bthf_volume_type_t);
|
|
*enum_func = enum_defines;
|
|
}
|
|
}
|
|
|
|
static void volume_control_p(int argc, const char **argv)
|
|
{
|
|
bthf_volume_type_t type;
|
|
int volume;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* volume type */
|
|
if (argc <= 2) {
|
|
haltest_error("No volume type specified\n");
|
|
return;
|
|
}
|
|
type = str2bthf_volume_type_t(argv[2]);
|
|
|
|
/* volume */
|
|
if (argc <= 3) {
|
|
haltest_error("No volume specified\n");
|
|
return;
|
|
}
|
|
volume = atoi(argv[3]);
|
|
|
|
EXEC(if_hf->volume_control, type, volume);
|
|
}
|
|
|
|
/* Combined device status change notification */
|
|
|
|
static void device_status_notification_c(int argc, const char **argv,
|
|
enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = TYPE_ENUM(bthf_network_state_t);
|
|
*enum_func = enum_defines;
|
|
} else if (argc == 4) {
|
|
*user = TYPE_ENUM(bthf_service_type_t);
|
|
*enum_func = enum_defines;
|
|
}
|
|
}
|
|
|
|
static void device_status_notification_p(int argc, const char **argv)
|
|
{
|
|
bthf_network_state_t ntk_state;
|
|
bthf_service_type_t svc_type;
|
|
int signal;
|
|
int batt_chg;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* network state */
|
|
if (argc <= 2) {
|
|
haltest_error("No network state specified\n");
|
|
return;
|
|
}
|
|
ntk_state = str2bthf_network_state_t(argv[2]);
|
|
|
|
/* service type */
|
|
if (argc <= 3) {
|
|
haltest_error("No service type specified\n");
|
|
return;
|
|
}
|
|
svc_type = str2bthf_service_type_t(argv[3]);
|
|
|
|
/* signal */
|
|
if (argc <= 4) {
|
|
haltest_error("No signal specified\n");
|
|
return;
|
|
}
|
|
signal = atoi(argv[4]);
|
|
|
|
/* batt_chg */
|
|
if (argc <= 5) {
|
|
haltest_error("No batt_chg specified\n");
|
|
return;
|
|
}
|
|
batt_chg = atoi(argv[5]);
|
|
|
|
EXEC(if_hf->device_status_notification, ntk_state, svc_type, signal,
|
|
batt_chg);
|
|
}
|
|
|
|
/* Response for COPS command */
|
|
|
|
static void cops_response_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* response */
|
|
if (argc <= 2) {
|
|
haltest_error("No cops specified\n");
|
|
return;
|
|
}
|
|
|
|
EXEC(if_hf->cops_response, argv[2]);
|
|
}
|
|
|
|
/* Response for CIND command */
|
|
|
|
static void cind_response_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 6) {
|
|
*user = TYPE_ENUM(bthf_call_state_t);
|
|
*enum_func = enum_defines;
|
|
}
|
|
}
|
|
|
|
static void cind_response_p(int argc, const char **argv)
|
|
{
|
|
int svc;
|
|
int num_active;
|
|
int num_held;
|
|
bthf_call_state_t call_setup_state;
|
|
int signal;
|
|
int roam;
|
|
int batt_chg;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* svc */
|
|
if (argc <= 2) {
|
|
haltest_error("No service specified\n");
|
|
return;
|
|
}
|
|
svc = atoi(argv[2]);
|
|
|
|
/* num active */
|
|
if (argc <= 3) {
|
|
haltest_error("No num active specified\n");
|
|
return;
|
|
}
|
|
num_active = atoi(argv[3]);
|
|
|
|
/* num held */
|
|
if (argc <= 4) {
|
|
haltest_error("No num held specified\n");
|
|
return;
|
|
}
|
|
num_held = atoi(argv[4]);
|
|
|
|
/* call setup state */
|
|
if (argc <= 5) {
|
|
haltest_error("No call setup state specified\n");
|
|
return;
|
|
}
|
|
call_setup_state = str2bthf_call_state_t(argv[5]);
|
|
|
|
/* signal */
|
|
if (argc <= 6) {
|
|
haltest_error("No signal specified\n");
|
|
return;
|
|
}
|
|
signal = atoi(argv[6]);
|
|
|
|
/* roam */
|
|
if (argc <= 7) {
|
|
haltest_error("No roam specified\n");
|
|
return;
|
|
}
|
|
roam = atoi(argv[7]);
|
|
|
|
/* batt_chg */
|
|
if (argc <= 8) {
|
|
haltest_error("No batt_chg specified\n");
|
|
return;
|
|
}
|
|
batt_chg = atoi(argv[8]);
|
|
|
|
EXEC(if_hf->cind_response, svc, num_active, num_held, call_setup_state,
|
|
signal, roam, batt_chg);
|
|
}
|
|
|
|
/* Pre-formatted AT response, typically in response to unknown AT cmd */
|
|
|
|
static void formatted_at_response_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* response */
|
|
if (argc <= 2) {
|
|
haltest_error("No response specified\n");
|
|
return;
|
|
}
|
|
|
|
EXEC(if_hf->formatted_at_response, argv[2]);
|
|
}
|
|
|
|
/* at_response */
|
|
|
|
static void at_response_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = TYPE_ENUM(bthf_at_response_t);
|
|
*enum_func = enum_defines;
|
|
}
|
|
}
|
|
|
|
static void at_response_p(int argc, const char **argv)
|
|
{
|
|
bthf_at_response_t response_code;
|
|
int error_code = 0;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* response type */
|
|
if (argc <= 2) {
|
|
haltest_error("No response specified\n");
|
|
return;
|
|
}
|
|
response_code = str2bthf_at_response_t(argv[2]);
|
|
|
|
/* error code */
|
|
if (argc >= 3)
|
|
error_code = atoi(argv[3]);
|
|
|
|
EXEC(if_hf->at_response, response_code, error_code);
|
|
}
|
|
|
|
/* response for CLCC command */
|
|
|
|
static void clcc_response_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 4) {
|
|
*user = TYPE_ENUM(bthf_call_direction_t);
|
|
*enum_func = enum_defines;
|
|
} else if (argc == 5) {
|
|
*user = TYPE_ENUM(bthf_call_state_t);
|
|
*enum_func = enum_defines;
|
|
} else if (argc == 6) {
|
|
*user = TYPE_ENUM(bthf_call_mode_t);
|
|
*enum_func = enum_defines;
|
|
} else if (argc == 7) {
|
|
*user = TYPE_ENUM(bthf_call_mpty_type_t);
|
|
*enum_func = enum_defines;
|
|
} else if (argc == 9) {
|
|
*user = TYPE_ENUM(bthf_call_addrtype_t);
|
|
*enum_func = enum_defines;
|
|
}
|
|
}
|
|
|
|
static void clcc_response_p(int argc, const char **argv)
|
|
{
|
|
int index;
|
|
bthf_call_direction_t dir;
|
|
bthf_call_state_t state;
|
|
bthf_call_mode_t mode;
|
|
bthf_call_mpty_type_t mpty;
|
|
const char *number;
|
|
bthf_call_addrtype_t type;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* index */
|
|
if (argc <= 2) {
|
|
haltest_error("No index specified\n");
|
|
return;
|
|
}
|
|
index = atoi(argv[2]);
|
|
|
|
/* direction */
|
|
if (argc <= 3) {
|
|
haltest_error("No direction specified\n");
|
|
return;
|
|
}
|
|
dir = str2bthf_call_direction_t(argv[3]);
|
|
|
|
/* call state */
|
|
if (argc <= 4) {
|
|
haltest_error("No call state specified\n");
|
|
return;
|
|
}
|
|
state = str2bthf_call_state_t(argv[4]);
|
|
|
|
/* call mode */
|
|
if (argc <= 5) {
|
|
haltest_error("No mode specified\n");
|
|
return;
|
|
}
|
|
mode = str2bthf_call_mode_t(argv[5]);
|
|
|
|
/* call mpty type */
|
|
if (argc <= 6) {
|
|
haltest_error("No mpty type specified\n");
|
|
return;
|
|
}
|
|
mpty = str2bthf_call_mpty_type_t(argv[6]);
|
|
|
|
/* number */
|
|
if (argc <= 7) {
|
|
haltest_error("No number specified\n");
|
|
return;
|
|
}
|
|
number = argv[7];
|
|
|
|
/* call mpty type */
|
|
if (argc <= 8) {
|
|
haltest_error("No address type specified\n");
|
|
return;
|
|
}
|
|
type = str2bthf_call_addrtype_t(argv[8]);
|
|
|
|
EXEC(if_hf->clcc_response, index, dir, state, mode, mpty, number,
|
|
type);
|
|
}
|
|
|
|
/* phone state change */
|
|
|
|
static void phone_state_change_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 5) {
|
|
*user = TYPE_ENUM(bthf_call_state_t);
|
|
*enum_func = enum_defines;
|
|
} else if (argc == 7) {
|
|
*user = TYPE_ENUM(bthf_call_addrtype_t);
|
|
*enum_func = enum_defines;
|
|
}
|
|
}
|
|
|
|
static void phone_state_change_p(int argc, const char **argv)
|
|
{
|
|
int num_active;
|
|
int num_held;
|
|
bthf_call_state_t call_setup_state;
|
|
const char *number;
|
|
bthf_call_addrtype_t type;
|
|
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
/* num_active */
|
|
if (argc <= 2) {
|
|
haltest_error("No num_active specified\n");
|
|
return;
|
|
}
|
|
num_active = atoi(argv[2]);
|
|
|
|
/* num_held */
|
|
if (argc <= 3) {
|
|
haltest_error("No num_held specified\n");
|
|
return;
|
|
}
|
|
num_held = atoi(argv[3]);
|
|
|
|
/* setup state */
|
|
if (argc <= 4) {
|
|
haltest_error("No call setup state specified\n");
|
|
return;
|
|
}
|
|
call_setup_state = str2bthf_call_state_t(argv[4]);
|
|
|
|
/* number */
|
|
if (argc <= 5) {
|
|
haltest_error("No number specified\n");
|
|
return;
|
|
}
|
|
number = argv[5];
|
|
|
|
/* call mpty type */
|
|
if (argc <= 6) {
|
|
haltest_error("No address type specified\n");
|
|
return;
|
|
}
|
|
type = str2bthf_call_addrtype_t(argv[6]);
|
|
|
|
EXEC(if_hf->phone_state_change, num_active, num_held, call_setup_state,
|
|
number, type);
|
|
}
|
|
|
|
/* cleanup */
|
|
|
|
static void cleanup_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_hf);
|
|
|
|
EXECV(if_hf->cleanup);
|
|
if_hf = NULL;
|
|
}
|
|
|
|
static struct method methods[] = {
|
|
STD_METHOD(init),
|
|
STD_METHODCH(connect, "<addr>"),
|
|
STD_METHODCH(disconnect, "<addr>"),
|
|
STD_METHODCH(connect_audio, "<addr>"),
|
|
STD_METHODCH(disconnect_audio, "<addr>"),
|
|
STD_METHOD(start_voice_recognition),
|
|
STD_METHOD(stop_voice_recognition),
|
|
STD_METHODCH(volume_control, "<vol_type> <volume>"),
|
|
STD_METHODCH(device_status_notification,
|
|
"<ntk_state> <svt_type> <signal> <batt_chg>"),
|
|
STD_METHODH(cops_response, "<cops string>"),
|
|
STD_METHODCH(cind_response,
|
|
"<svc> <num_active> <num_held> <setup_state> <signal> <roam> <batt_chg>"),
|
|
STD_METHODH(formatted_at_response, "<at_response>"),
|
|
STD_METHODCH(at_response, "<response_code> [<error_code>]"),
|
|
STD_METHODCH(clcc_response,
|
|
"<index> <direction> <state> <mode> <mpty> <number> <type>"),
|
|
STD_METHODCH(phone_state_change,
|
|
"<num_active> <num_held> <setup_state> <number> <type>"),
|
|
STD_METHOD(cleanup),
|
|
END_METHOD
|
|
};
|
|
|
|
const struct interface hf_if = {
|
|
.name = "handsfree",
|
|
.methods = methods
|
|
};
|