Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Data Structures | Macros | Enumerations | Functions | Variables
chan_mobile.c File Reference

Bluetooth Mobile Device channel driver. More...

#include "asterisk.h"
#include <pthread.h>
#include <signal.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sco.h>
#include <bluetooth/l2cap.h>
#include "asterisk/compat.h"
#include "asterisk/lock.h"
#include "asterisk/callerid.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
#include "asterisk/cli.h"
#include "asterisk/devicestate.h"
#include "asterisk/causes.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/io.h"
#include "asterisk/smoother.h"
#include "asterisk/format_cache.h"
Include dependency graph for chan_mobile.c:

Go to the source code of this file.

Data Structures

struct  adapter_pvt
 
struct  adapters
 
struct  cidinfo
 
struct  devices
 
struct  hfp_ag
 This struct holds HFP features the AG supports. More...
 
struct  hfp_cind
 This struct holds mappings for indications. More...
 
struct  hfp_hf
 This struct holds HFP features that we support. More...
 
struct  hfp_pvt
 This struct holds state information about the current hfp connection. More...
 
struct  mbl_pvt
 
struct  mbl_pvt::msg_queue
 
struct  msg_queue_entry
 

Macros

#define CHANNEL_FRAME_SIZE   320
 
#define DEVICE_FRAME_FORMAT   ast_format_slin
 
#define DEVICE_FRAME_SIZE   48
 
#define FORMAT1   "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-10.10s %-3.3s\n"
 
#define FORMAT1   "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n"
 
#define FORMAT2   "%-17.17s %-30.30s %-6.6s %-7.7s %d\n"
 
#define HFP_AG_CONTROL   (1 << 7)
 
#define HFP_AG_CW   (1 << 0)
 
#define HFP_AG_ECNR   (1 << 1)
 
#define HFP_AG_ERRORS   (1 << 8)
 
#define HFP_AG_REJECT   (1 << 5)
 
#define HFP_AG_RING   (1 << 3)
 
#define HFP_AG_STATUS   (1 << 6)
 
#define HFP_AG_TAG   (1 << 4)
 
#define HFP_AG_VOICE   (1 << 2)
 
#define HFP_CIND_BATTCHG   7
 
#define HFP_CIND_CALL   2
 
#define HFP_CIND_CALL_ACTIVE   1
 
#define HFP_CIND_CALL_NONE   0
 
#define HFP_CIND_CALLHELD   4
 
#define HFP_CIND_CALLSETUP   3
 
#define HFP_CIND_CALLSETUP_ALERTING   3
 
#define HFP_CIND_CALLSETUP_INCOMING   1
 
#define HFP_CIND_CALLSETUP_NONE   0
 
#define HFP_CIND_CALLSETUP_OUTGOING   2
 
#define HFP_CIND_NONE   0
 
#define HFP_CIND_ROAM   6
 
#define HFP_CIND_SERVICE   1
 
#define HFP_CIND_SERVICE_AVAILABLE   1
 
#define HFP_CIND_SERVICE_NONE   0
 
#define HFP_CIND_SIGNAL   5
 
#define HFP_CIND_UNKNOWN   -1
 
#define HFP_HF_CID   (1 << 2)
 
#define HFP_HF_CONTROL   (1 << 6)
 
#define HFP_HF_CW   (1 << 1)
 
#define HFP_HF_ECNR   (1 << 0)
 
#define HFP_HF_STATUS   (1 << 5)
 
#define HFP_HF_VOICE   (1 << 3)
 
#define HFP_HF_VOLUME   (1 << 4)
 
#define MBL_CONFIG   "chan_mobile.conf"
 
#define MBL_CONFIG_OLD   "mobile.conf"
 
#define rfcomm_read_debug(c)
 

Enumerations

enum  at_message_t {
  AT_PARSE_ERROR = -2 , AT_READ_ERROR = -1 , AT_UNKNOWN = 0 , AT_OK ,
  AT_ERROR , AT_RING , AT_BRSF , AT_CIND ,
  AT_CIEV , AT_CLIP , AT_CMTI , AT_CMGR ,
  AT_SMS_PROMPT , AT_CMS_ERROR , AT_A , AT_D ,
  AT_CHUP , AT_CKPD , AT_CMGS , AT_VGM ,
  AT_VGS , AT_VTS , AT_CMGF , AT_CNMI ,
  AT_CMER , AT_CIND_TEST , AT_CUSD , AT_BUSY ,
  AT_NO_DIALTONE , AT_NO_CARRIER , AT_ECAM
}
 
enum  mbl_type { MBL_TYPE_PHONE , MBL_TYPE_HEADSET }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int at_match_prefix (char *buf, char *prefix)
 Match the given buffer with the given prefix. More...
 
static const char * at_msg2str (at_message_t msg)
 Get the string representation of the given AT message. More...
 
static at_message_t at_read_full (int rsock, char *buf, size_t count)
 Read an AT message and classify it. More...
 
static int check_unloading ()
 Check if the module is unloading. More...
 
static void do_alignment_detection (struct mbl_pvt *pvt, char *buf, int buflen)
 
static void * do_discovery (void *data)
 
static void * do_monitor_headset (void *data)
 
static void * do_monitor_phone (void *data)
 
static void * do_sco_listen (void *data)
 Service new and existing SCO connections. This thread accepts new sco connections and handles audio data. There is one do_sco_listen thread for each adapter. More...
 
static char * handle_cli_mobile_cusd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_mobile_rfcomm (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_mobile_search (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_mobile_show_devices (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int handle_response_brsf (struct mbl_pvt *pvt, char *buf)
 Handle the BRSF response. More...
 
static int handle_response_busy (struct mbl_pvt *pvt)
 Handle BUSY messages. More...
 
static int handle_response_ciev (struct mbl_pvt *pvt, char *buf)
 Handle AT+CIEV messages. More...
 
static int handle_response_cind (struct mbl_pvt *pvt, char *buf)
 Handle the CIND response. More...
 
static int handle_response_clip (struct mbl_pvt *pvt, char *buf)
 Handle AT+CLIP messages. More...
 
static int handle_response_cmgr (struct mbl_pvt *pvt, char *buf)
 Handle AT+CMGR messages. More...
 
static int handle_response_cmti (struct mbl_pvt *pvt, char *buf)
 Handle AT+CMTI messages. More...
 
static int handle_response_cusd (struct mbl_pvt *pvt, char *buf)
 Handle CUSD messages. More...
 
static int handle_response_error (struct mbl_pvt *pvt, char *buf)
 Handle ERROR AT messages. More...
 
static int handle_response_no_carrier (struct mbl_pvt *pvt, char *buf)
 Handle NO CARRIER messages. More...
 
static int handle_response_no_dialtone (struct mbl_pvt *pvt, char *buf)
 Handle NO DIALTONE messages. More...
 
static int handle_response_ok (struct mbl_pvt *pvt, char *buf)
 Handle OK AT messages. More...
 
static int handle_response_ring (struct mbl_pvt *pvt, char *buf)
 Handle RING messages. More...
 
static int handle_sms_prompt (struct mbl_pvt *pvt, char *buf)
 Send an SMS message from the queue. More...
 
static int headset_send_ring (const void *data)
 
static int hfp_brsf2int (struct hfp_hf *hf)
 Convert a hfp_hf struct to a BRSF int. More...
 
static struct hfp_aghfp_int2brsf (int brsf, struct hfp_ag *ag)
 Convert a BRSF int to an hfp_ag struct. More...
 
static int hfp_parse_brsf (struct hfp_pvt *hfp, const char *buf)
 Parse BRSF data. More...
 
static int hfp_parse_ciev (struct hfp_pvt *hfp, char *buf, int *value)
 Parse a CIEV event. More...
 
static int hfp_parse_cind (struct hfp_pvt *hfp, char *buf)
 Read the result of the AT+CIND? command. More...
 
static int hfp_parse_cind_indicator (struct hfp_pvt *hfp, int group, char *indicator)
 Parse and store the given indicator. More...
 
static int hfp_parse_cind_test (struct hfp_pvt *hfp, char *buf)
 Parse the result of the AT+CIND=? command. More...
 
static struct cidinfo hfp_parse_clip (struct hfp_pvt *hfp, char *buf)
 Parse a CLIP event. More...
 
static int hfp_parse_cmgr (struct hfp_pvt *hfp, char *buf, char **from_number, char **text)
 Parse a CMGR message. More...
 
static int hfp_parse_cmti (struct hfp_pvt *hfp, char *buf)
 Parse a CMTI notification. More...
 
static char * hfp_parse_cusd (struct hfp_pvt *hfp, char *buf)
 Parse a CUSD answer. More...
 
static int hfp_parse_ecav (struct hfp_pvt *hfp, char *buf)
 Parse a ECAV event. More...
 
static int hfp_send_ata (struct hfp_pvt *hfp)
 Send ATA. More...
 
static int hfp_send_atd (struct hfp_pvt *hfp, const char *number)
 Send ATD. More...
 
static int hfp_send_brsf (struct hfp_pvt *hfp, struct hfp_hf *brsf)
 Send a BRSF request. More...
 
static int hfp_send_chup (struct hfp_pvt *hfp)
 Send AT+CHUP. More...
 
static int hfp_send_cind (struct hfp_pvt *hfp)
 Send the CIND read command. More...
 
static int hfp_send_cind_test (struct hfp_pvt *hfp)
 Send the CIND test command. More...
 
static int hfp_send_clip (struct hfp_pvt *hfp, int status)
 Enable or disable calling line identification. More...
 
static int hfp_send_cmer (struct hfp_pvt *hfp, int status)
 Enable or disable indicator events reporting. More...
 
static int hfp_send_cmgf (struct hfp_pvt *hfp, int mode)
 Set the SMS mode. More...
 
static int hfp_send_cmgr (struct hfp_pvt *hfp, int index)
 Read an SMS message. More...
 
static int hfp_send_cmgs (struct hfp_pvt *hfp, const char *number)
 Start sending an SMS message. More...
 
static int hfp_send_cnmi (struct hfp_pvt *hfp)
 Setup SMS new message indication. More...
 
static int hfp_send_cusd (struct hfp_pvt *hfp, const char *code)
 Send CUSD. More...
 
static int hfp_send_dtmf (struct hfp_pvt *hfp, char digit)
 Send a DTMF command. More...
 
static int hfp_send_ecam (struct hfp_pvt *hfp)
 Enable Sony Ericsson extensions / indications. More...
 
static int hfp_send_sms_text (struct hfp_pvt *hfp, const char *message)
 Send the text of an SMS message. More...
 
static int hfp_send_vgs (struct hfp_pvt *hfp, int value)
 Send the current speaker gain level. More...
 
static int hsp_send_error (int rsock)
 Send an ERROR AT response. More...
 
static int hsp_send_ok (int rsock)
 Send an OK AT response. More...
 
static int hsp_send_ring (int rsock)
 Send a RING unsolicited AT response. More...
 
static int hsp_send_vgm (int rsock, int gain)
 Send a microphone gain unsolicited AT response. More...
 
static int hsp_send_vgs (int rsock, int gain)
 Send a speaker gain unsolicited AT response. More...
 
static int load_module (void)
 
static int mbl_answer (struct ast_channel *ast)
 
static int mbl_ast_hangup (struct mbl_pvt *pvt)
 
static int mbl_call (struct ast_channel *ast, const char *dest, int timeout)
 
static int mbl_devicestate (const char *data)
 
static int mbl_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
 
static int mbl_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
 
static int mbl_hangup (struct ast_channel *ast)
 
static int mbl_has_service (struct mbl_pvt *pvt)
 Check if a mobile device has service. More...
 
static struct adapter_pvtmbl_load_adapter (struct ast_config *cfg, const char *cat)
 Load an adapter from the configuration file. More...
 
static int mbl_load_config (void)
 
static struct mbl_pvtmbl_load_device (struct ast_config *cfg, const char *cat)
 Load a device from the configuration file. More...
 
static struct ast_channelmbl_new (int state, struct mbl_pvt *pvt, struct cidinfo *cidinfo, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 
static int mbl_queue_control (struct mbl_pvt *pvt, enum ast_control_frame_type control)
 
static int mbl_queue_hangup (struct mbl_pvt *pvt)
 
static struct ast_framembl_read (struct ast_channel *ast)
 
static struct ast_channelmbl_request (const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
 
static int mbl_sendsms_exec (struct ast_channel *ast, const char *data)
 
static int mbl_status_exec (struct ast_channel *ast, const char *data)
 
static int mbl_write (struct ast_channel *ast, struct ast_frame *frame)
 
static void msg_queue_flush (struct mbl_pvt *pvt)
 Remove all items from the queue and free them. More...
 
static void msg_queue_free_and_pop (struct mbl_pvt *pvt)
 Remove an item from the front of the queue, and free it. More...
 
static struct msg_queue_entrymsg_queue_head (struct mbl_pvt *pvt)
 Get the head of a queue. More...
 
static struct msg_queue_entrymsg_queue_pop (struct mbl_pvt *pvt)
 Remove an item from the front of the queue. More...
 
static int msg_queue_push (struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
 Add an item to the back of the queue. More...
 
static int msg_queue_push_data (struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to, void *data)
 Add an item to the back of the queue with data. More...
 
static int parse_next_token (char string[], const int start, const char delim)
 Terminate current token and return an index to start of the next token. More...
 
static void rfcomm_append_buf (char **buf, size_t count, size_t *in_count, char c)
 Append the given character to the given buffer and increase the in_count. More...
 
static int rfcomm_connect (bdaddr_t src, bdaddr_t dst, int remote_channel)
 
static ssize_t rfcomm_read (int rsock, char *buf, size_t count)
 Read one Hayes AT message from an rfcomm socket. More...
 
static int rfcomm_read_and_append_char (int rsock, char **buf, size_t count, size_t *in_count, char *result, char expected)
 Read a character from the given stream and append it to the given buffer if it matches the expected character. More...
 
static int rfcomm_read_and_expect_char (int rsock, char *result, char expected)
 Read a character from the given stream and check if it matches what we expected. More...
 
static int rfcomm_read_cmgr (int rsock, char **buf, size_t count, size_t *in_count)
 Read the remainder of a +CMGR message. More...
 
static int rfcomm_read_command (int rsock, char **buf, size_t count, size_t *in_count)
 Read the remainder of an AT command. More...
 
static int rfcomm_read_result (int rsock, char **buf, size_t count, size_t *in_count)
 Read and AT result code. More...
 
static int rfcomm_read_sms_prompt (int rsock, char **buf, size_t count, size_t *in_count)
 Read the remainder of an AT SMS prompt. More...
 
static int rfcomm_read_until_crlf (int rsock, char **buf, size_t count, size_t *in_count)
 Read until. More...
 
static int rfcomm_read_until_ok (int rsock, char **buf, size_t count, size_t *in_count)
 Read until a. More...
 
static int rfcomm_wait (int rsock, int *ms)
 Wait for activity on an rfcomm socket. More...
 
static int rfcomm_write (int rsock, char *buf)
 Write to an rfcomm socket. More...
 
static int rfcomm_write_full (int rsock, char *buf, size_t count)
 Write to an rfcomm socket. More...
 
static int sco_accept (int *id, int fd, short events, void *data)
 Accept SCO connections. This function is an ast_io callback function used to accept incoming sco audio connections. More...
 
static int sco_bind (struct adapter_pvt *adapter)
 Bind an SCO listener socket for the given adapter. More...
 
static int sco_connect (bdaddr_t src, bdaddr_t dst)
 
static int sco_write (int s, char *buf, int len)
 
static sdp_session_t * sdp_register (void)
 
static int sdp_search (char *addr, int profile)
 
static void set_unloading ()
 Set the unloading flag. More...
 
static int start_monitor (struct mbl_pvt *pvt)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Bluetooth Mobile Device Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
 
static struct adapters adapters = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static char * app_mblsendsms = "MobileSendSMS"
 
static char * app_mblstatus = "MobileStatus"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct devices devices = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static int discovery_interval = 60
 
static pthread_t discovery_thread = AST_PTHREADT_NULL
 
static struct hfp_hf hfp_our_brsf
 
static struct ast_cli_entry mbl_cli []
 
static struct ast_channel_tech mbl_tech
 
static char * mblsendsms_desc
 
static char * mblsendsms_synopsis = "MobileSendSMS(Device,Dest,Message)"
 
static char * mblstatus_desc
 
static char * mblstatus_synopsis = "MobileStatus(Device,Variable)"
 
static sdp_session_t * sdp_session
 
static ast_mutex_t unload_mutex = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static int unloading_flag = 0
 

Detailed Description

Bluetooth Mobile Device channel driver.

Author
Dave Bowerman david.nosp@m..bow.nosp@m.erman.nosp@m.@gma.nosp@m.il.co.nosp@m.m

Definition in file chan_mobile.c.

Macro Definition Documentation

◆ CHANNEL_FRAME_SIZE

#define CHANNEL_FRAME_SIZE   320

Definition at line 83 of file chan_mobile.c.

◆ DEVICE_FRAME_FORMAT

#define DEVICE_FRAME_FORMAT   ast_format_slin

Definition at line 82 of file chan_mobile.c.

◆ DEVICE_FRAME_SIZE

#define DEVICE_FRAME_SIZE   48

Definition at line 81 of file chan_mobile.c.

◆ FORMAT1 [1/2]

#define FORMAT1   "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-10.10s %-3.3s\n"

◆ FORMAT1 [2/2]

#define FORMAT1   "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n"

◆ FORMAT2

#define FORMAT2   "%-17.17s %-30.30s %-6.6s %-7.7s %d\n"

◆ HFP_AG_CONTROL

#define HFP_AG_CONTROL   (1 << 7)

Definition at line 272 of file chan_mobile.c.

◆ HFP_AG_CW

#define HFP_AG_CW   (1 << 0)

Definition at line 265 of file chan_mobile.c.

◆ HFP_AG_ECNR

#define HFP_AG_ECNR   (1 << 1)

Definition at line 266 of file chan_mobile.c.

◆ HFP_AG_ERRORS

#define HFP_AG_ERRORS   (1 << 8)

Definition at line 273 of file chan_mobile.c.

◆ HFP_AG_REJECT

#define HFP_AG_REJECT   (1 << 5)

Definition at line 270 of file chan_mobile.c.

◆ HFP_AG_RING

#define HFP_AG_RING   (1 << 3)

Definition at line 268 of file chan_mobile.c.

◆ HFP_AG_STATUS

#define HFP_AG_STATUS   (1 << 6)

Definition at line 271 of file chan_mobile.c.

◆ HFP_AG_TAG

#define HFP_AG_TAG   (1 << 4)

Definition at line 269 of file chan_mobile.c.

◆ HFP_AG_VOICE

#define HFP_AG_VOICE   (1 << 2)

Definition at line 267 of file chan_mobile.c.

◆ HFP_CIND_BATTCHG

#define HFP_CIND_BATTCHG   7

Definition at line 283 of file chan_mobile.c.

◆ HFP_CIND_CALL

#define HFP_CIND_CALL   2

Definition at line 278 of file chan_mobile.c.

◆ HFP_CIND_CALL_ACTIVE

#define HFP_CIND_CALL_ACTIVE   1

Definition at line 287 of file chan_mobile.c.

◆ HFP_CIND_CALL_NONE

#define HFP_CIND_CALL_NONE   0

Definition at line 286 of file chan_mobile.c.

◆ HFP_CIND_CALLHELD

#define HFP_CIND_CALLHELD   4

Definition at line 280 of file chan_mobile.c.

◆ HFP_CIND_CALLSETUP

#define HFP_CIND_CALLSETUP   3

Definition at line 279 of file chan_mobile.c.

◆ HFP_CIND_CALLSETUP_ALERTING

#define HFP_CIND_CALLSETUP_ALERTING   3

Definition at line 293 of file chan_mobile.c.

◆ HFP_CIND_CALLSETUP_INCOMING

#define HFP_CIND_CALLSETUP_INCOMING   1

Definition at line 291 of file chan_mobile.c.

◆ HFP_CIND_CALLSETUP_NONE

#define HFP_CIND_CALLSETUP_NONE   0

Definition at line 290 of file chan_mobile.c.

◆ HFP_CIND_CALLSETUP_OUTGOING

#define HFP_CIND_CALLSETUP_OUTGOING   2

Definition at line 292 of file chan_mobile.c.

◆ HFP_CIND_NONE

#define HFP_CIND_NONE   0

Definition at line 276 of file chan_mobile.c.

◆ HFP_CIND_ROAM

#define HFP_CIND_ROAM   6

Definition at line 282 of file chan_mobile.c.

◆ HFP_CIND_SERVICE

#define HFP_CIND_SERVICE   1

Definition at line 277 of file chan_mobile.c.

◆ HFP_CIND_SERVICE_AVAILABLE

#define HFP_CIND_SERVICE_AVAILABLE   1

Definition at line 297 of file chan_mobile.c.

◆ HFP_CIND_SERVICE_NONE

#define HFP_CIND_SERVICE_NONE   0

Definition at line 296 of file chan_mobile.c.

◆ HFP_CIND_SIGNAL

#define HFP_CIND_SIGNAL   5

Definition at line 281 of file chan_mobile.c.

◆ HFP_CIND_UNKNOWN

#define HFP_CIND_UNKNOWN   -1

Definition at line 275 of file chan_mobile.c.

◆ HFP_HF_CID

#define HFP_HF_CID   (1 << 2)

Definition at line 259 of file chan_mobile.c.

◆ HFP_HF_CONTROL

#define HFP_HF_CONTROL   (1 << 6)

Definition at line 263 of file chan_mobile.c.

◆ HFP_HF_CW

#define HFP_HF_CW   (1 << 1)

Definition at line 258 of file chan_mobile.c.

◆ HFP_HF_ECNR

#define HFP_HF_ECNR   (1 << 0)

Definition at line 257 of file chan_mobile.c.

◆ HFP_HF_STATUS

#define HFP_HF_STATUS   (1 << 5)

Definition at line 262 of file chan_mobile.c.

◆ HFP_HF_VOICE

#define HFP_HF_VOICE   (1 << 3)

Definition at line 260 of file chan_mobile.c.

◆ HFP_HF_VOLUME

#define HFP_HF_VOLUME   (1 << 4)

Definition at line 261 of file chan_mobile.c.

◆ MBL_CONFIG

#define MBL_CONFIG   "chan_mobile.conf"

Definition at line 78 of file chan_mobile.c.

◆ MBL_CONFIG_OLD

#define MBL_CONFIG_OLD   "mobile.conf"

Definition at line 79 of file chan_mobile.c.

◆ rfcomm_read_debug

#define rfcomm_read_debug (   c)

Definition at line 1501 of file chan_mobile.c.

Enumeration Type Documentation

◆ at_message_t

Enumerator
AT_PARSE_ERROR 
AT_READ_ERROR 
AT_UNKNOWN 
AT_OK 
AT_ERROR 
AT_RING 
AT_BRSF 
AT_CIND 
AT_CIEV 
AT_CLIP 
AT_CMTI 
AT_CMGR 
AT_SMS_PROMPT 
AT_CMS_ERROR 
AT_A 
AT_D 
AT_CHUP 
AT_CKPD 
AT_CMGS 
AT_VGM 
AT_VGS 
AT_VTS 
AT_CMGF 
AT_CNMI 
AT_CMER 
AT_CIND_TEST 
AT_CUSD 
AT_BUSY 
AT_NO_DIALTONE 
AT_NO_CARRIER 
AT_ECAM 

Definition at line 419 of file chan_mobile.c.

419  {
420  /* errors */
421  AT_PARSE_ERROR = -2,
422  AT_READ_ERROR = -1,
423  AT_UNKNOWN = 0,
424  /* at responses */
425  AT_OK,
426  AT_ERROR,
427  AT_RING,
428  AT_BRSF,
429  AT_CIND,
430  AT_CIEV,
431  AT_CLIP,
432  AT_CMTI,
433  AT_CMGR,
435  AT_CMS_ERROR,
436  /* at commands */
437  AT_A,
438  AT_D,
439  AT_CHUP,
440  AT_CKPD,
441  AT_CMGS,
442  AT_VGM,
443  AT_VGS,
444  AT_VTS,
445  AT_CMGF,
446  AT_CNMI,
447  AT_CMER,
448  AT_CIND_TEST,
449  AT_CUSD,
450  AT_BUSY,
453  AT_ECAM,
454 } at_message_t;
at_message_t
Definition: chan_mobile.c:419
@ AT_VGS
Definition: chan_mobile.c:443
@ AT_NO_DIALTONE
Definition: chan_mobile.c:451
@ AT_CHUP
Definition: chan_mobile.c:439
@ AT_UNKNOWN
Definition: chan_mobile.c:423
@ AT_CMGF
Definition: chan_mobile.c:445
@ AT_CIND_TEST
Definition: chan_mobile.c:448
@ AT_ERROR
Definition: chan_mobile.c:426
@ AT_ECAM
Definition: chan_mobile.c:453
@ AT_CNMI
Definition: chan_mobile.c:446
@ AT_PARSE_ERROR
Definition: chan_mobile.c:421
@ AT_OK
Definition: chan_mobile.c:425
@ AT_CIND
Definition: chan_mobile.c:429
@ AT_CIEV
Definition: chan_mobile.c:430
@ AT_CLIP
Definition: chan_mobile.c:431
@ AT_CMGS
Definition: chan_mobile.c:441
@ AT_CMER
Definition: chan_mobile.c:447
@ AT_VGM
Definition: chan_mobile.c:442
@ AT_SMS_PROMPT
Definition: chan_mobile.c:434
@ AT_RING
Definition: chan_mobile.c:427
@ AT_A
Definition: chan_mobile.c:437
@ AT_D
Definition: chan_mobile.c:438
@ AT_VTS
Definition: chan_mobile.c:444
@ AT_READ_ERROR
Definition: chan_mobile.c:422
@ AT_CKPD
Definition: chan_mobile.c:440
@ AT_BUSY
Definition: chan_mobile.c:450
@ AT_CMS_ERROR
Definition: chan_mobile.c:435
@ AT_CMGR
Definition: chan_mobile.c:433
@ AT_BRSF
Definition: chan_mobile.c:428
@ AT_CMTI
Definition: chan_mobile.c:432
@ AT_CUSD
Definition: chan_mobile.c:449
@ AT_NO_CARRIER
Definition: chan_mobile.c:452

◆ mbl_type

enum mbl_type
Enumerator
MBL_TYPE_PHONE 
MBL_TYPE_HEADSET 

Definition at line 94 of file chan_mobile.c.

94  {
97 };
@ MBL_TYPE_PHONE
Definition: chan_mobile.c:95
@ MBL_TYPE_HEADSET
Definition: chan_mobile.c:96

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4840 of file chan_mobile.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 4840 of file chan_mobile.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 4840 of file chan_mobile.c.

◆ at_match_prefix()

static int at_match_prefix ( char *  buf,
char *  prefix 
)
static

Match the given buffer with the given prefix.

Parameters
bufthe buffer to match
prefixthe prefix to match

Definition at line 2003 of file chan_mobile.c.

2004 {
2005  return !strncmp(buf, prefix, strlen(prefix));
2006 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static char prefix[MAX_PREFIX]
Definition: http.c:144

References buf, and prefix.

Referenced by at_read_full().

◆ at_msg2str()

static const char * at_msg2str ( at_message_t  msg)
inlinestatic

Get the string representation of the given AT message.

Parameters
msgthe message to process
Returns
a string describing the given message

Definition at line 2076 of file chan_mobile.c.

2077 {
2078  switch (msg) {
2079  /* errors */
2080  case AT_PARSE_ERROR:
2081  return "PARSE ERROR";
2082  case AT_READ_ERROR:
2083  return "READ ERROR";
2084  default:
2085  case AT_UNKNOWN:
2086  return "UNKNOWN";
2087  /* at responses */
2088  case AT_OK:
2089  return "OK";
2090  case AT_ERROR:
2091  return "ERROR";
2092  case AT_RING:
2093  return "RING";
2094  case AT_BRSF:
2095  return "AT+BRSF";
2096  case AT_CIND:
2097  return "AT+CIND";
2098  case AT_CIEV:
2099  return "AT+CIEV";
2100  case AT_CLIP:
2101  return "AT+CLIP";
2102  case AT_CMTI:
2103  return "AT+CMTI";
2104  case AT_CMGR:
2105  return "AT+CMGR";
2106  case AT_SMS_PROMPT:
2107  return "SMS PROMPT";
2108  case AT_CMS_ERROR:
2109  return "+CMS ERROR";
2110  case AT_BUSY:
2111  return "BUSY";
2112  case AT_NO_DIALTONE:
2113  return "NO DIALTONE";
2114  case AT_NO_CARRIER:
2115  return "NO CARRIER";
2116  /* at commands */
2117  case AT_A:
2118  return "ATA";
2119  case AT_D:
2120  return "ATD";
2121  case AT_CHUP:
2122  return "AT+CHUP";
2123  case AT_CKPD:
2124  return "AT+CKPD";
2125  case AT_CMGS:
2126  return "AT+CMGS";
2127  case AT_VGM:
2128  return "AT+VGM";
2129  case AT_VGS:
2130  return "AT+VGS";
2131  case AT_VTS:
2132  return "AT+VTS";
2133  case AT_CMGF:
2134  return "AT+CMGF";
2135  case AT_CNMI:
2136  return "AT+CNMI";
2137  case AT_CMER:
2138  return "AT+CMER";
2139  case AT_CIND_TEST:
2140  return "AT+CIND=?";
2141  case AT_CUSD:
2142  return "AT+CUSD";
2143  case AT_ECAM:
2144  return "AT*ECAM";
2145  }
2146 }

References AT_A, AT_BRSF, AT_BUSY, AT_CHUP, AT_CIEV, AT_CIND, AT_CIND_TEST, AT_CKPD, AT_CLIP, AT_CMER, AT_CMGF, AT_CMGR, AT_CMGS, AT_CMS_ERROR, AT_CMTI, AT_CNMI, AT_CUSD, AT_D, AT_ECAM, AT_ERROR, AT_NO_CARRIER, AT_NO_DIALTONE, AT_OK, AT_PARSE_ERROR, AT_READ_ERROR, AT_RING, AT_SMS_PROMPT, AT_UNKNOWN, AT_VGM, AT_VGS, and AT_VTS.

Referenced by do_monitor_headset(), do_monitor_phone(), handle_response_brsf(), handle_response_cind(), handle_response_error(), and handle_response_ok().

◆ at_read_full()

static at_message_t at_read_full ( int  rsock,
char *  buf,
size_t  count 
)
static

Read an AT message and classify it.

Parameters
rsockan rfcomm socket
bufthe buffer to store the result in
countthe size of the buffer or the maximum number of characters to read
Returns
the type of message received, in addition buf will contain the message received and will be null terminated
See also
at_read()

Definition at line 2017 of file chan_mobile.c.

2018 {
2019  ssize_t s;
2020  if ((s = rfcomm_read(rsock, buf, count - 1)) < 1)
2021  return s;
2022  buf[s] = '\0';
2023 
2024  if (!strcmp("OK", buf)) {
2025  return AT_OK;
2026  } else if (!strcmp("ERROR", buf)) {
2027  return AT_ERROR;
2028  } else if (!strcmp("RING", buf)) {
2029  return AT_RING;
2030  } else if (!strcmp("AT+CKPD=200", buf)) {
2031  return AT_CKPD;
2032  } else if (!strcmp("> ", buf)) {
2033  return AT_SMS_PROMPT;
2034  } else if (at_match_prefix(buf, "+CMTI:")) {
2035  return AT_CMTI;
2036  } else if (at_match_prefix(buf, "+CIEV:")) {
2037  return AT_CIEV;
2038  } else if (at_match_prefix(buf, "+BRSF:")) {
2039  return AT_BRSF;
2040  } else if (at_match_prefix(buf, "+CIND:")) {
2041  return AT_CIND;
2042  } else if (at_match_prefix(buf, "+CLIP:")) {
2043  return AT_CLIP;
2044  } else if (at_match_prefix(buf, "+CMGR:")) {
2045  return AT_CMGR;
2046  } else if (at_match_prefix(buf, "+VGM:")) {
2047  return AT_VGM;
2048  } else if (at_match_prefix(buf, "+VGS:")) {
2049  return AT_VGS;
2050  } else if (at_match_prefix(buf, "+CMS ERROR:")) {
2051  return AT_CMS_ERROR;
2052  } else if (at_match_prefix(buf, "AT+VGM=")) {
2053  return AT_VGM;
2054  } else if (at_match_prefix(buf, "AT+VGS=")) {
2055  return AT_VGS;
2056  } else if (at_match_prefix(buf, "+CUSD:")) {
2057  return AT_CUSD;
2058  } else if (at_match_prefix(buf, "BUSY")) {
2059  return AT_BUSY;
2060  } else if (at_match_prefix(buf, "NO DIALTONE")) {
2061  return AT_NO_DIALTONE;
2062  } else if (at_match_prefix(buf, "NO CARRIER")) {
2063  return AT_NO_CARRIER;
2064  } else if (at_match_prefix(buf, "*ECAV:")) {
2065  return AT_ECAM;
2066  } else {
2067  return AT_UNKNOWN;
2068  }
2069 }
static ssize_t rfcomm_read(int rsock, char *buf, size_t count)
Read one Hayes AT message from an rfcomm socket.
Definition: chan_mobile.c:1808
static int at_match_prefix(char *buf, char *prefix)
Match the given buffer with the given prefix.
Definition: chan_mobile.c:2003

References AT_BRSF, AT_BUSY, AT_CIEV, AT_CIND, AT_CKPD, AT_CLIP, AT_CMGR, AT_CMS_ERROR, AT_CMTI, AT_CUSD, AT_ECAM, AT_ERROR, at_match_prefix(), AT_NO_CARRIER, AT_NO_DIALTONE, AT_OK, AT_RING, AT_SMS_PROMPT, AT_UNKNOWN, AT_VGM, AT_VGS, buf, and rfcomm_read().

Referenced by do_monitor_headset(), and do_monitor_phone().

◆ check_unloading()

static int check_unloading ( void  )
inlinestatic

Check if the module is unloading.

Return values
0not unloading
1unloading

Definition at line 4684 of file chan_mobile.c.

4685 {
4686  int res;
4688  res = unloading_flag;
4690 
4691  return res;
4692 }
static int unloading_flag
Definition: chan_mobile.c:90
static ast_mutex_t unload_mutex
Definition: chan_mobile.c:89
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:187

References ast_mutex_lock, ast_mutex_unlock, unload_mutex, and unloading_flag.

Referenced by do_discovery(), do_monitor_headset(), do_monitor_phone(), and do_sco_listen().

◆ do_alignment_detection()

static void do_alignment_detection ( struct mbl_pvt pvt,
char *  buf,
int  buflen 
)
static

Definition at line 1281 of file chan_mobile.c.

1282 {
1283 
1284  int i;
1285  short a, *s;
1286  char *p;
1287 
1288  if (pvt->alignment_detection_triggered) {
1289  for (i=buflen, p=buf+buflen-1; i>0; i--, p--)
1290  *p = *(p-1);
1291  *(p+1) = 0;
1292  return;
1293  }
1294 
1295  if (pvt->alignment_count < 4) {
1296  s = (short *)buf;
1297  for (i=0, a=0; i<buflen/2; i++) {
1298  a += *s++;
1299  a /= i+1;
1300  }
1301  pvt->alignment_samples[pvt->alignment_count++] = a;
1302  return;
1303  }
1304 
1305  ast_debug(1, "Alignment Detection result is [%-d %-d %-d %-d]\n", pvt->alignment_samples[0], pvt->alignment_samples[1], pvt->alignment_samples[2], pvt->alignment_samples[3]);
1306 
1307  a = abs(pvt->alignment_samples[1]) + abs(pvt->alignment_samples[2]) + abs(pvt->alignment_samples[3]);
1308  a /= 3;
1309  if (a > 100) {
1311  ast_debug(1, "Alignment Detection Triggered.\n");
1312  } else
1313  pvt->do_alignment_detection = 0;
1314 
1315 }
#define abs(x)
Definition: f2c.h:195
#define ast_debug(level,...)
Log a DEBUG message.
unsigned int do_alignment_detection
Definition: chan_mobile.c:142
short alignment_samples[4]
Definition: chan_mobile.c:145
int alignment_count
Definition: chan_mobile.c:146
unsigned int alignment_detection_triggered
Definition: chan_mobile.c:143
static struct test_val a

References a, abs, mbl_pvt::alignment_count, mbl_pvt::alignment_detection_triggered, mbl_pvt::alignment_samples, ast_debug, buf, and mbl_pvt::do_alignment_detection.

Referenced by mbl_read().

◆ do_discovery()

static void* do_discovery ( void *  data)
static

Definition at line 4284 of file chan_mobile.c.

4285 {
4286 
4287  struct adapter_pvt *adapter;
4288  struct mbl_pvt *pvt;
4289 
4290  while (!check_unloading()) {
4293  if (!adapter->inuse) {
4296  ast_mutex_lock(&pvt->lock);
4297  if (!adapter->inuse && !pvt->connected && !strcmp(adapter->id, pvt->adapter->id)) {
4298  if ((pvt->rfcomm_socket = rfcomm_connect(adapter->addr, pvt->addr, pvt->rfcomm_port)) > -1) {
4299  if (start_monitor(pvt)) {
4300  pvt->connected = 1;
4301  adapter->inuse = 1;
4302  manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Connect\r\nDevice: %s\r\n", pvt->id);
4303  ast_verb(3, "Bluetooth Device %s has connected, initializing...\n", pvt->id);
4304  }
4305  }
4306  }
4307  ast_mutex_unlock(&pvt->lock);
4308  }
4310  }
4311  }
4313 
4314 
4315  /* Go to sleep (only if we are not unloading) */
4316  if (!check_unloading())
4317  sleep(discovery_interval);
4318  }
4319 
4320  return NULL;
4321 }
static int discovery_interval
Definition: chan_mobile.c:85
static int check_unloading(void)
Check if the module is unloading.
Definition: chan_mobile.c:4684
static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel)
Definition: chan_mobile.c:1390
static int start_monitor(struct mbl_pvt *pvt)
Definition: chan_mobile.c:4263
#define ast_verb(level,...)
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:253
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define NULL
Definition: resample.c:96
unsigned int inuse
Definition: chan_mobile.c:104
bdaddr_t addr
Definition: chan_mobile.c:103
char id[31]
Definition: chan_mobile.c:102
Definition: search.h:40
bdaddr_t addr
Definition: chan_mobile.c:127
struct adapter_pvt * adapter
Definition: chan_mobile.c:128
char id[31]
Definition: chan_mobile.c:125
int rfcomm_socket
Definition: chan_mobile.c:132
unsigned int connected
Definition: chan_mobile.c:161
int rfcomm_port
Definition: chan_mobile.c:131
ast_mutex_t lock
Definition: chan_mobile.c:121

References mbl_pvt::adapter, adapter_pvt::addr, mbl_pvt::addr, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_verb, check_unloading(), mbl_pvt::connected, discovery_interval, EVENT_FLAG_SYSTEM, adapter_pvt::id, mbl_pvt::id, adapter_pvt::inuse, mbl_pvt::lock, manager_event, NULL, rfcomm_connect(), mbl_pvt::rfcomm_port, mbl_pvt::rfcomm_socket, and start_monitor().

◆ do_monitor_headset()

static void* do_monitor_headset ( void *  data)
static

Definition at line 4121 of file chan_mobile.c.

4122 {
4123 
4124  struct mbl_pvt *pvt = (struct mbl_pvt *)data;
4125  char buf[256];
4126  int t;
4127  at_message_t at_msg;
4128  struct ast_channel *chan = NULL;
4129 
4130  ast_verb(3, "Bluetooth Device %s initialised and ready.\n", pvt->id);
4131 
4132  while (!check_unloading()) {
4133 
4134  t = ast_sched_wait(pvt->sched);
4135  if (t == -1) {
4136  t = 6000;
4137  }
4138 
4139  ast_sched_runq(pvt->sched);
4140 
4141  if (rfcomm_wait(pvt->rfcomm_socket, &t) == 0)
4142  continue;
4143 
4144  if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
4145  ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
4146  goto e_cleanup;
4147  }
4148  ast_debug(1, "[%s] %s\n", pvt->id, buf);
4149 
4150  switch (at_msg) {
4151  case AT_VGS:
4152  case AT_VGM:
4153  /* XXX volume change requested, we will just
4154  * pretend to do something with it */
4155  if (hsp_send_ok(pvt->rfcomm_socket)) {
4156  ast_debug(1, "[%s] error sending AT message 'OK'\n", pvt->id);
4157  goto e_cleanup;
4158  }
4159  break;
4160  case AT_CKPD:
4161  ast_mutex_lock(&pvt->lock);
4162  if (pvt->outgoing) {
4163  pvt->needring = 0;
4164  hsp_send_ok(pvt->rfcomm_socket);
4165  if (pvt->answered) {
4166  /* we have an answered call up to the
4167  * HS, he wants to hangup */
4168  mbl_queue_hangup(pvt);
4169  } else {
4170  /* we have an outgoing call to the HS,
4171  * he wants to answer */
4172  if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
4173  ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
4174  mbl_queue_hangup(pvt);
4175  ast_mutex_unlock(&pvt->lock);
4176  goto e_cleanup;
4177  }
4178 
4179  ast_channel_set_fd(pvt->owner, 0, pvt->sco_socket);
4180 
4182  pvt->answered = 1;
4183 
4184  if (hsp_send_vgs(pvt->rfcomm_socket, 13) || hsp_send_vgm(pvt->rfcomm_socket, 13)) {
4185  ast_debug(1, "[%s] error sending VGS/VGM\n", pvt->id);
4186  mbl_queue_hangup(pvt);
4187  ast_mutex_unlock(&pvt->lock);
4188  goto e_cleanup;
4189  }
4190  }
4191  } else if (pvt->incoming) {
4192  /* we have an incoming call from the
4193  * HS, he wants to hang up */
4194  mbl_queue_hangup(pvt);
4195  } else {
4196  /* no call is up, HS wants to dial */
4197  hsp_send_ok(pvt->rfcomm_socket);
4198 
4199  if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
4200  ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
4201  ast_mutex_unlock(&pvt->lock);
4202  goto e_cleanup;
4203  }
4204 
4205  pvt->incoming = 1;
4206 
4207  if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL, NULL))) {
4208  ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
4209  ast_mutex_unlock(&pvt->lock);
4210  goto e_cleanup;
4211  }
4212 
4213  ast_channel_set_fd(chan, 0, pvt->sco_socket);
4214 
4215  ast_channel_exten_set(chan, "s");
4216  if (ast_pbx_start(chan)) {
4217  ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
4218  ast_hangup(chan);
4219  ast_mutex_unlock(&pvt->lock);
4220  goto e_cleanup;
4221  }
4222  }
4223  ast_mutex_unlock(&pvt->lock);
4224  break;
4225  default:
4226  ast_debug(1, "[%s] received unknown AT command: %s (%s)\n", pvt->id, buf, at_msg2str(at_msg));
4227  if (hsp_send_error(pvt->rfcomm_socket)) {
4228  ast_debug(1, "[%s] error sending AT message 'ERROR'\n", pvt->id);
4229  goto e_cleanup;
4230  }
4231  break;
4232  }
4233  }
4234 
4235 e_cleanup:
4236  ast_mutex_lock(&pvt->lock);
4237  if (pvt->owner) {
4238  ast_debug(1, "[%s] device disconnected, hanging up owner\n", pvt->id);
4239  mbl_queue_hangup(pvt);
4240  }
4241 
4242 
4243  close(pvt->rfcomm_socket);
4244  close(pvt->sco_socket);
4245  pvt->sco_socket = -1;
4246 
4247  pvt->connected = 0;
4248 
4249  pvt->needring = 0;
4250  pvt->outgoing = 0;
4251  pvt->incoming = 0;
4252 
4253  pvt->adapter->inuse = 0;
4254  ast_mutex_unlock(&pvt->lock);
4255 
4256  manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
4257  ast_verb(3, "Bluetooth Device %s has disconnected\n", pvt->id);
4258 
4259  return NULL;
4260 
4261 }
#define ast_log
Definition: astobj2.c:42
static const char * at_msg2str(at_message_t msg)
Get the string representation of the given AT message.
Definition: chan_mobile.c:2076
static int hsp_send_error(int rsock)
Send an ERROR AT response.
Definition: chan_mobile.c:2935
static int rfcomm_wait(int rsock, int *ms)
Wait for activity on an rfcomm socket.
Definition: chan_mobile.c:1479
static int mbl_queue_hangup(struct mbl_pvt *pvt)
Definition: chan_mobile.c:1334
static int hsp_send_vgm(int rsock, int gain)
Send a microphone gain unsolicited AT response.
Definition: chan_mobile.c:2957
static int hsp_send_ok(int rsock)
Send an OK AT response.
Definition: chan_mobile.c:2926
static struct ast_channel * mbl_new(int state, struct mbl_pvt *pvt, struct cidinfo *cidinfo, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
Definition: chan_mobile.c:847
static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
Definition: chan_mobile.c:1317
static at_message_t at_read_full(int rsock, char *buf, size_t count)
Read an AT message and classify it.
Definition: chan_mobile.c:2017
static int sco_connect(bdaddr_t src, bdaddr_t dst)
Definition: chan_mobile.c:1833
static int hsp_send_vgs(int rsock, int gain)
Send a speaker gain unsolicited AT response.
Definition: chan_mobile.c:2945
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2542
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2425
@ AST_STATE_UP
Definition: channelstate.h:42
@ AST_CONTROL_ANSWER
#define LOG_ERROR
int errno
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4715
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:433
Main Channel structure associated with a channel.
unsigned int needring
Definition: chan_mobile.c:159
struct ast_sched_context * sched
Definition: chan_mobile.c:149
unsigned int outgoing
Definition: chan_mobile.c:153
struct ast_channel * owner
Definition: chan_mobile.c:119
unsigned int incoming
Definition: chan_mobile.c:154
unsigned int answered
Definition: chan_mobile.c:160
int sco_socket
Definition: chan_mobile.c:137

References mbl_pvt::adapter, adapter_pvt::addr, mbl_pvt::addr, mbl_pvt::answered, ast_channel_exten_set(), ast_channel_set_fd(), AST_CONTROL_ANSWER, ast_debug, ast_hangup(), ast_log, ast_mutex_lock, ast_mutex_unlock, ast_pbx_start(), ast_sched_runq(), ast_sched_wait(), AST_STATE_UP, ast_verb, AT_CKPD, at_msg2str(), at_read_full(), AT_VGM, AT_VGS, buf, check_unloading(), mbl_pvt::connected, errno, EVENT_FLAG_SYSTEM, hsp_send_error(), hsp_send_ok(), hsp_send_vgm(), hsp_send_vgs(), mbl_pvt::id, mbl_pvt::incoming, adapter_pvt::inuse, mbl_pvt::lock, LOG_ERROR, manager_event, mbl_new(), mbl_queue_control(), mbl_queue_hangup(), mbl_pvt::needring, NULL, mbl_pvt::outgoing, mbl_pvt::owner, mbl_pvt::rfcomm_socket, rfcomm_wait(), mbl_pvt::sched, sco_connect(), and mbl_pvt::sco_socket.

Referenced by start_monitor().

◆ do_monitor_phone()

static void* do_monitor_phone ( void *  data)
static

Definition at line 3872 of file chan_mobile.c.

3873 {
3874  struct mbl_pvt *pvt = (struct mbl_pvt *)data;
3875  struct hfp_pvt *hfp = pvt->hfp;
3876  char buf[350];
3877  int t;
3878  at_message_t at_msg;
3879  struct msg_queue_entry *entry;
3880 
3881  /* Note: At one point the initialization procedure was neatly contained
3882  * in the hfp_init() function, but that initialization method did not
3883  * work with non standard devices. As a result, the initialization
3884  * procedure is not spread throughout the event handling loop.
3885  */
3886 
3887  /* start initialization with the BRSF request */
3888  ast_mutex_lock(&pvt->lock);
3889  pvt->timeout = 10000;
3890  if (hfp_send_brsf(hfp, &hfp_our_brsf) || msg_queue_push(pvt, AT_BRSF, AT_BRSF)) {
3891  ast_debug(1, "[%s] error sending BRSF\n", hfp->owner->id);
3892  goto e_cleanup;
3893  }
3894  ast_mutex_unlock(&pvt->lock);
3895 
3896  while (!check_unloading()) {
3897  ast_mutex_lock(&pvt->lock);
3898  t = pvt->timeout;
3899  ast_mutex_unlock(&pvt->lock);
3900 
3901  if (!rfcomm_wait(pvt->rfcomm_socket, &t)) {
3902  ast_debug(1, "[%s] timeout waiting for rfcomm data, disconnecting\n", pvt->id);
3903  ast_mutex_lock(&pvt->lock);
3904  if (!hfp->initialized) {
3905  if ((entry = msg_queue_head(pvt))) {
3906  switch (entry->response_to) {
3907  case AT_CIND_TEST:
3908  if (pvt->blackberry)
3909  ast_debug(1, "[%s] timeout during CIND test\n", hfp->owner->id);
3910  else
3911  ast_debug(1, "[%s] timeout during CIND test, try setting 'blackberry=yes'\n", hfp->owner->id);
3912  break;
3913  case AT_CMER:
3914  if (pvt->blackberry)
3915  ast_debug(1, "[%s] timeout after sending CMER, try setting 'blackberry=no'\n", hfp->owner->id);
3916  else
3917  ast_debug(1, "[%s] timeout after sending CMER\n", hfp->owner->id);
3918  break;
3919  default:
3920  ast_debug(1, "[%s] timeout while waiting for %s in response to %s\n", pvt->id, at_msg2str(entry->expected), at_msg2str(entry->response_to));
3921  break;
3922  }
3923  }
3924  }
3925  ast_mutex_unlock(&pvt->lock);
3926  goto e_cleanup;
3927  }
3928 
3929  if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) {
3930  ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
3931  break;
3932  }
3933 
3934  ast_debug(1, "[%s] read %s\n", pvt->id, buf);
3935 
3936  switch (at_msg) {
3937  case AT_BRSF:
3938  ast_mutex_lock(&pvt->lock);
3939  if (handle_response_brsf(pvt, buf)) {
3940  ast_mutex_unlock(&pvt->lock);
3941  goto e_cleanup;
3942  }
3943  ast_mutex_unlock(&pvt->lock);
3944  break;
3945  case AT_CIND:
3946  ast_mutex_lock(&pvt->lock);
3947  if (handle_response_cind(pvt, buf)) {
3948  ast_mutex_unlock(&pvt->lock);
3949  goto e_cleanup;
3950  }
3951  ast_mutex_unlock(&pvt->lock);
3952  break;
3953  case AT_OK:
3954  ast_mutex_lock(&pvt->lock);
3955  if (handle_response_ok(pvt, buf)) {
3956  ast_mutex_unlock(&pvt->lock);
3957  goto e_cleanup;
3958  }
3959  ast_mutex_unlock(&pvt->lock);
3960  break;
3961  case AT_CMS_ERROR:
3962  case AT_ERROR:
3963  ast_mutex_lock(&pvt->lock);
3964  if (handle_response_error(pvt, buf)) {
3965  ast_mutex_unlock(&pvt->lock);
3966  goto e_cleanup;
3967  }
3968  ast_mutex_unlock(&pvt->lock);
3969  break;
3970  case AT_RING:
3971  ast_mutex_lock(&pvt->lock);
3972  if (handle_response_ring(pvt, buf)) {
3973  ast_mutex_unlock(&pvt->lock);
3974  goto e_cleanup;
3975  }
3976  ast_mutex_unlock(&pvt->lock);
3977  break;
3978  case AT_CIEV:
3979  ast_mutex_lock(&pvt->lock);
3980  if (handle_response_ciev(pvt, buf)) {
3981  ast_mutex_unlock(&pvt->lock);
3982  goto e_cleanup;
3983  }
3984  ast_mutex_unlock(&pvt->lock);
3985  break;
3986  case AT_CLIP:
3987  ast_mutex_lock(&pvt->lock);
3988  if (handle_response_clip(pvt, buf)) {
3989  ast_mutex_unlock(&pvt->lock);
3990  goto e_cleanup;
3991  }
3992  ast_mutex_unlock(&pvt->lock);
3993  break;
3994  case AT_CMTI:
3995  ast_mutex_lock(&pvt->lock);
3996  if (handle_response_cmti(pvt, buf)) {
3997  ast_mutex_unlock(&pvt->lock);
3998  goto e_cleanup;
3999  }
4000  ast_mutex_unlock(&pvt->lock);
4001  break;
4002  case AT_CMGR:
4003  ast_mutex_lock(&pvt->lock);
4004  if (handle_response_cmgr(pvt, buf)) {
4005  ast_mutex_unlock(&pvt->lock);
4006  goto e_cleanup;
4007  }
4008  ast_mutex_unlock(&pvt->lock);
4009  break;
4010  case AT_SMS_PROMPT:
4011  ast_mutex_lock(&pvt->lock);
4012  if (handle_sms_prompt(pvt, buf)) {
4013  ast_mutex_unlock(&pvt->lock);
4014  goto e_cleanup;
4015  }
4016  ast_mutex_unlock(&pvt->lock);
4017  break;
4018  case AT_CUSD:
4019  ast_mutex_lock(&pvt->lock);
4020  if (handle_response_cusd(pvt, buf)) {
4021  ast_mutex_unlock(&pvt->lock);
4022  goto e_cleanup;
4023  }
4024  ast_mutex_unlock(&pvt->lock);
4025  break;
4026  case AT_BUSY:
4027  ast_mutex_lock(&pvt->lock);
4028  if (handle_response_busy(pvt)) {
4029  ast_mutex_unlock(&pvt->lock);
4030  goto e_cleanup;
4031  }
4032  ast_mutex_unlock(&pvt->lock);
4033  break;
4034  case AT_NO_DIALTONE:
4035  ast_mutex_lock(&pvt->lock);
4036  if (handle_response_no_dialtone(pvt, buf)) {
4037  ast_mutex_unlock(&pvt->lock);
4038  goto e_cleanup;
4039  }
4040  ast_mutex_unlock(&pvt->lock);
4041  break;
4042  case AT_NO_CARRIER:
4043  ast_mutex_lock(&pvt->lock);
4044  if (handle_response_no_carrier(pvt, buf)) {
4045  ast_mutex_unlock(&pvt->lock);
4046  goto e_cleanup;
4047  }
4048  ast_mutex_unlock(&pvt->lock);
4049  break;
4050  case AT_ECAM:
4051  ast_mutex_lock(&pvt->lock);
4052  if (hfp_parse_ecav(hfp, buf) == 7) {
4053  if (handle_response_busy(pvt)) {
4054  ast_mutex_unlock(&pvt->lock);
4055  goto e_cleanup;
4056  }
4057  }
4058  ast_mutex_unlock(&pvt->lock);
4059  break;
4060  case AT_UNKNOWN:
4061  ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
4062  break;
4063  case AT_PARSE_ERROR:
4064  ast_debug(1, "[%s] error parsing message\n", pvt->id);
4065  goto e_cleanup;
4066  case AT_READ_ERROR:
4067  ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
4068  goto e_cleanup;
4069  default:
4070  break;
4071  }
4072  }
4073 
4074 e_cleanup:
4075 
4076  if (!hfp->initialized)
4077  ast_verb(3, "Error initializing Bluetooth device %s.\n", pvt->id);
4078 
4079  ast_mutex_lock(&pvt->lock);
4080  if (pvt->owner) {
4081  ast_debug(1, "[%s] device disconnected, hanging up owner\n", pvt->id);
4082  pvt->needchup = 0;
4083  mbl_queue_hangup(pvt);
4084  }
4085 
4086  close(pvt->rfcomm_socket);
4087  close(pvt->sco_socket);
4088  pvt->sco_socket = -1;
4089 
4090  msg_queue_flush(pvt);
4091 
4092  pvt->connected = 0;
4093  hfp->initialized = 0;
4094 
4095  pvt->adapter->inuse = 0;
4096  ast_mutex_unlock(&pvt->lock);
4097 
4098  ast_verb(3, "Bluetooth Device %s has disconnected.\n", pvt->id);
4099  manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
4100 
4101  return NULL;
4102 }
static int handle_response_brsf(struct mbl_pvt *pvt, char *buf)
Handle the BRSF response.
Definition: chan_mobile.c:3198
static int hfp_send_brsf(struct hfp_pvt *hfp, struct hfp_hf *brsf)
Send a BRSF request.
Definition: chan_mobile.c:2516
static int handle_response_cmti(struct mbl_pvt *pvt, char *buf)
Handle AT+CMTI messages.
Definition: chan_mobile.c:3710
static int handle_response_clip(struct mbl_pvt *pvt, char *buf)
Handle AT+CLIP messages.
Definition: chan_mobile.c:3653
static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
Handle AT+CIEV messages.
Definition: chan_mobile.c:3561
static int handle_response_cind(struct mbl_pvt *pvt, char *buf)
Handle the CIND response.
Definition: chan_mobile.c:3233
static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf)
Handle AT+CMGR messages.
Definition: chan_mobile.c:3737
static void msg_queue_flush(struct mbl_pvt *pvt)
Remove all items from the queue and free them.
Definition: chan_mobile.c:3048
static int handle_response_ring(struct mbl_pvt *pvt, char *buf)
Handle RING messages.
Definition: chan_mobile.c:3693
static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
Add an item to the back of the queue.
Definition: chan_mobile.c:2984
static struct hfp_hf hfp_our_brsf
Definition: chan_mobile.c:361
static int handle_response_busy(struct mbl_pvt *pvt)
Handle BUSY messages.
Definition: chan_mobile.c:3833
static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
Handle OK AT messages.
Definition: chan_mobile.c:3275
static int handle_response_cusd(struct mbl_pvt *pvt, char *buf)
Handle CUSD messages.
Definition: chan_mobile.c:3813
static int handle_response_error(struct mbl_pvt *pvt, char *buf)
Handle ERROR AT messages.
Definition: chan_mobile.c:3444
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3060
static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf)
Send an SMS message from the queue.
Definition: chan_mobile.c:3782
static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf)
Parse a ECAV event.
Definition: chan_mobile.c:2166
static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf)
Handle NO CARRIER messages.
Definition: chan_mobile.c:3863
static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf)
Handle NO DIALTONE messages.
Definition: chan_mobile.c:3848
This struct holds state information about the current hfp connection.
Definition: chan_mobile.c:344
struct mbl_pvt * owner
Definition: chan_mobile.c:345
int initialized
Definition: chan_mobile.c:346
int rsock
Definition: chan_mobile.c:352
int timeout
Definition: chan_mobile.c:139
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
unsigned int needchup
Definition: chan_mobile.c:158
unsigned int blackberry
Definition: chan_mobile.c:144
Definition: chan_mobile.c:460
struct msg_queue_entry::@2 entry

References mbl_pvt::adapter, ast_debug, ast_mutex_lock, ast_mutex_unlock, ast_verb, AT_BRSF, AT_BUSY, AT_CIEV, AT_CIND, AT_CIND_TEST, AT_CLIP, AT_CMER, AT_CMGR, AT_CMS_ERROR, AT_CMTI, AT_CUSD, AT_ECAM, AT_ERROR, at_msg2str(), AT_NO_CARRIER, AT_NO_DIALTONE, AT_OK, AT_PARSE_ERROR, AT_READ_ERROR, at_read_full(), AT_RING, AT_SMS_PROMPT, AT_UNKNOWN, mbl_pvt::blackberry, buf, check_unloading(), mbl_pvt::connected, msg_queue_entry::entry, errno, EVENT_FLAG_SYSTEM, handle_response_brsf(), handle_response_busy(), handle_response_ciev(), handle_response_cind(), handle_response_clip(), handle_response_cmgr(), handle_response_cmti(), handle_response_cusd(), handle_response_error(), handle_response_no_carrier(), handle_response_no_dialtone(), handle_response_ok(), handle_response_ring(), handle_sms_prompt(), mbl_pvt::hfp, hfp_our_brsf, hfp_parse_ecav(), hfp_send_brsf(), mbl_pvt::id, hfp_pvt::initialized, adapter_pvt::inuse, mbl_pvt::lock, manager_event, mbl_queue_hangup(), msg_queue_flush(), msg_queue_head(), msg_queue_push(), mbl_pvt::needchup, NULL, mbl_pvt::owner, hfp_pvt::owner, mbl_pvt::rfcomm_socket, rfcomm_wait(), hfp_pvt::rsock, mbl_pvt::sco_socket, and mbl_pvt::timeout.

Referenced by start_monitor().

◆ do_sco_listen()

static void * do_sco_listen ( void *  data)
static

Service new and existing SCO connections. This thread accepts new sco connections and handles audio data. There is one do_sco_listen thread for each adapter.

Definition at line 4328 of file chan_mobile.c.

4329 {
4330  struct adapter_pvt *adapter = (struct adapter_pvt *) data;
4331 
4332  while (!check_unloading()) {
4333  /* check for new sco connections */
4334  if (ast_io_wait(adapter->accept_io, 0) == -1) {
4335  /* handle errors */
4336  ast_log(LOG_ERROR, "ast_io_wait() failed for adapter %s\n", adapter->id);
4337  break;
4338  }
4339 
4340  /* handle audio data */
4341  if (ast_io_wait(adapter->io, 1) == -1) {
4342  ast_log(LOG_ERROR, "ast_io_wait() failed for audio on adapter %s\n", adapter->id);
4343  break;
4344  }
4345  }
4346 
4347  return NULL;
4348 }
int ast_io_wait(struct io_context *ioc, int howlong)
Waits for IO.
Definition: io.c:278
struct io_context * accept_io
Definition: chan_mobile.c:107
struct io_context * io
Definition: chan_mobile.c:106

References adapter_pvt::accept_io, ast_io_wait(), ast_log, check_unloading(), adapter_pvt::id, adapter_pvt::io, LOG_ERROR, and NULL.

Referenced by mbl_load_adapter().

◆ handle_cli_mobile_cusd()

static char * handle_cli_mobile_cusd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 659 of file chan_mobile.c.

660 {
661  char buf[128];
662  struct mbl_pvt *pvt = NULL;
663 
664  switch (cmd) {
665  case CLI_INIT:
666  e->command = "mobile cusd";
667  e->usage =
668  "Usage: mobile cusd <device ID> <command>\n"
669  " Send cusd <command> to the rfcomm port on the device\n"
670  " with the specified <device ID>.\n";
671  return NULL;
672  case CLI_GENERATE:
673  return NULL;
674  }
675 
676  if (a->argc != 4)
677  return CLI_SHOWUSAGE;
678 
681  if (!strcmp(pvt->id, a->argv[2]))
682  break;
683  }
685 
686  if (!pvt) {
687  ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
688  goto e_return;
689  }
690 
691  ast_mutex_lock(&pvt->lock);
692  if (!pvt->connected) {
693  ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
694  goto e_unlock_pvt;
695  }
696 
697  snprintf(buf, sizeof(buf), "%s", a->argv[3]);
698  if (hfp_send_cusd(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CUSD)) {
699  ast_cli(a->fd, "[%s] error sending CUSD\n", pvt->id);
700  goto e_unlock_pvt;
701  }
702 
703 e_unlock_pvt:
704  ast_mutex_unlock(&pvt->lock);
705 e_return:
706  return CLI_SUCCESS;
707 }
static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code)
Send CUSD.
Definition: chan_mobile.c:2714
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177

References a, ast_cli(), ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AT_CUSD, AT_OK, buf, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mbl_pvt::connected, mbl_pvt::hfp, hfp_send_cusd(), mbl_pvt::id, mbl_pvt::lock, msg_queue_push(), NULL, and ast_cli_entry::usage.

◆ handle_cli_mobile_rfcomm()

static char * handle_cli_mobile_rfcomm ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 611 of file chan_mobile.c.

612 {
613  char buf[128];
614  struct mbl_pvt *pvt = NULL;
615 
616  switch (cmd) {
617  case CLI_INIT:
618  e->command = "mobile rfcomm";
619  e->usage =
620  "Usage: mobile rfcomm <device ID> <command>\n"
621  " Send <command> to the rfcomm port on the device\n"
622  " with the specified <device ID>.\n";
623  return NULL;
624  case CLI_GENERATE:
625  return NULL;
626  }
627 
628  if (a->argc != 4)
629  return CLI_SHOWUSAGE;
630 
633  if (!strcmp(pvt->id, a->argv[2]))
634  break;
635  }
637 
638  if (!pvt) {
639  ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
640  goto e_return;
641  }
642 
643  ast_mutex_lock(&pvt->lock);
644  if (!pvt->connected) {
645  ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
646  goto e_unlock_pvt;
647  }
648 
649  snprintf(buf, sizeof(buf), "%s\r", a->argv[3]);
652 
653 e_unlock_pvt:
654  ast_mutex_unlock(&pvt->lock);
655 e_return:
656  return CLI_SUCCESS;
657 }
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

References a, ast_cli(), ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AT_OK, AT_UNKNOWN, buf, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mbl_pvt::connected, mbl_pvt::id, mbl_pvt::lock, msg_queue_push(), NULL, mbl_pvt::rfcomm_socket, rfcomm_write(), and ast_cli_entry::usage.

◆ handle_cli_mobile_search()

static char * handle_cli_mobile_search ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 541 of file chan_mobile.c.

542 {
543  struct adapter_pvt *adapter;
544  inquiry_info *ii = NULL;
545  int max_rsp, num_rsp;
546  int len, flags;
547  int i, phport, hsport;
548  char addr[19] = {0};
549  char name[31] = {0};
550 
551 #define FORMAT1 "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n"
552 #define FORMAT2 "%-17.17s %-30.30s %-6.6s %-7.7s %d\n"
553 
554  switch (cmd) {
555  case CLI_INIT:
556  e->command = "mobile search";
557  e->usage =
558  "Usage: mobile search\n"
559  " Searches for Bluetooth Cell / Mobile devices in range.\n";
560  return NULL;
561  case CLI_GENERATE:
562  return NULL;
563  }
564 
565  if (a->argc != 2)
566  return CLI_SHOWUSAGE;
567 
568  /* find a free adapter */
570  AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
571  if (!adapter->inuse)
572  break;
573  }
575 
576  if (!adapter) {
577  ast_cli(a->fd, "All Bluetooth adapters are in use at this time.\n");
578  return CLI_SUCCESS;
579  }
580 
581  len = 8;
582  max_rsp = 255;
583  flags = IREQ_CACHE_FLUSH;
584 
585  ii = ast_alloca(max_rsp * sizeof(inquiry_info));
586  num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
587  if (num_rsp > 0) {
588  ast_cli(a->fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
589  for (i = 0; i < num_rsp; i++) {
590  ba2str(&(ii + i)->bdaddr, addr);
591  name[0] = 0x00;
592  if (hci_read_remote_name(adapter->hci_socket, &(ii + i)->bdaddr, sizeof(name) - 1, name, 0) < 0)
593  strcpy(name, "[unknown]");
594  phport = sdp_search(addr, HANDSFREE_AGW_PROFILE_ID);
595  if (!phport)
596  hsport = sdp_search(addr, HEADSET_PROFILE_ID);
597  else
598  hsport = 0;
599  ast_cli(a->fd, FORMAT2, addr, name, (phport > 0 || hsport > 0) ? "Yes" : "No",
600  (phport > 0) ? "Phone" : "Headset", (phport > 0) ? phport : hsport);
601  }
602  } else
603  ast_cli(a->fd, "No Bluetooth Cell / Mobile devices found.\n");
604 
605 #undef FORMAT1
606 #undef FORMAT2
607 
608  return CLI_SUCCESS;
609 }
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
static int sdp_search(char *addr, int profile)
Definition: chan_mobile.c:3073
#define FORMAT1
#define FORMAT2
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

References a, adapter_pvt::addr, ast_alloca, ast_cli(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, adapter_pvt::dev_id, FORMAT1, FORMAT2, adapter_pvt::hci_socket, adapter_pvt::inuse, len(), name, NULL, sdp_search(), and ast_cli_entry::usage.

◆ handle_cli_mobile_show_devices()

static char * handle_cli_mobile_show_devices ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 495 of file chan_mobile.c.

496 {
497  struct mbl_pvt *pvt;
498  char bdaddr[18];
499  char group[6];
500 
501 #define FORMAT1 "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-10.10s %-3.3s\n"
502 
503  switch (cmd) {
504  case CLI_INIT:
505  e->command = "mobile show devices";
506  e->usage =
507  "Usage: mobile show devices\n"
508  " Shows the state of Bluetooth Cell / Mobile devices.\n";
509  return NULL;
510  case CLI_GENERATE:
511  return NULL;
512  }
513 
514  if (a->argc != 3)
515  return CLI_SHOWUSAGE;
516 
517  ast_cli(a->fd, FORMAT1, "ID", "Address", "Group", "Adapter", "Connected", "State", "SMS");
520  ast_mutex_lock(&pvt->lock);
521  ba2str(&pvt->addr, bdaddr);
522  snprintf(group, sizeof(group), "%d", pvt->group);
523  ast_cli(a->fd, FORMAT1,
524  pvt->id,
525  bdaddr,
526  group,
527  pvt->adapter->id,
528  pvt->connected ? "Yes" : "No",
529  (!pvt->connected) ? "None" : (pvt->owner) ? "Busy" : (pvt->outgoing_sms || pvt->incoming_sms) ? "SMS" : (mbl_has_service(pvt)) ? "Free" : "No Service",
530  (pvt->has_sms) ? "Yes" : "No"
531  );
532  ast_mutex_unlock(&pvt->lock);
533  }
535 
536 #undef FORMAT1
537 
538  return CLI_SUCCESS;
539 }
static int mbl_has_service(struct mbl_pvt *pvt)
Check if a mobile device has service.
Definition: chan_mobile.c:1369
int group
Definition: chan_mobile.c:126
unsigned int outgoing_sms
Definition: chan_mobile.c:155
unsigned int has_sms
Definition: chan_mobile.c:141
unsigned int incoming_sms
Definition: chan_mobile.c:156

References a, mbl_pvt::adapter, mbl_pvt::addr, ast_cli(), ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mbl_pvt::connected, FORMAT1, mbl_pvt::group, mbl_pvt::has_sms, adapter_pvt::id, mbl_pvt::id, mbl_pvt::incoming_sms, mbl_pvt::lock, mbl_has_service(), NULL, mbl_pvt::outgoing_sms, mbl_pvt::owner, and ast_cli_entry::usage.

◆ handle_response_brsf()

static int handle_response_brsf ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle the BRSF response.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3198 of file chan_mobile.c.

3199 {
3200  struct msg_queue_entry *entry;
3201  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_BRSF) {
3202  if (hfp_parse_brsf(pvt->hfp, buf)) {
3203  ast_debug(1, "[%s] error parsing BRSF\n", pvt->id);
3204  goto e_return;
3205  }
3206 
3207  if (msg_queue_push(pvt, AT_OK, AT_BRSF)) {
3208  ast_debug(1, "[%s] error handling BRSF\n", pvt->id);
3209  goto e_return;
3210  }
3211 
3213  } else if (entry) {
3214  ast_debug(1, "[%s] received unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3215  } else {
3216  ast_debug(1, "[%s] received unexpected AT message 'BRSF'\n", pvt->id);
3217  }
3218 
3219  return 0;
3220 
3221 e_return:
3223  return -1;
3224 }
static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue, and free it.
Definition: chan_mobile.c:3034
static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf)
Parse BRSF data.
Definition: chan_mobile.c:2726

References ast_debug, AT_BRSF, at_msg2str(), AT_OK, buf, msg_queue_entry::entry, mbl_pvt::hfp, hfp_parse_brsf(), mbl_pvt::id, msg_queue_free_and_pop(), msg_queue_head(), and msg_queue_push().

Referenced by do_monitor_phone().

◆ handle_response_busy()

static int handle_response_busy ( struct mbl_pvt pvt)
static

Handle BUSY messages.

Parameters
pvta mbl_pvt structure
Return values
0success
-1error

Definition at line 3833 of file chan_mobile.c.

3834 {
3836  pvt->needchup = 1;
3838  return 0;
3839 }
#define AST_CAUSE_USER_BUSY
Definition: causes.h:107
@ AST_CONTROL_BUSY
int hangupcause
Definition: chan_mobile.c:150

References AST_CAUSE_USER_BUSY, AST_CONTROL_BUSY, mbl_pvt::hangupcause, mbl_queue_control(), and mbl_pvt::needchup.

Referenced by do_monitor_phone(), and handle_response_ciev().

◆ handle_response_ciev()

static int handle_response_ciev ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CIEV messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3561 of file chan_mobile.c.

3562 {
3563  int i;
3564  switch (hfp_parse_ciev(pvt->hfp, buf, &i)) {
3565  case HFP_CIND_CALL:
3566  switch (i) {
3567  case HFP_CIND_CALL_NONE:
3568  ast_debug(1, "[%s] line disconnected\n", pvt->id);
3569  if (pvt->owner) {
3570  ast_debug(1, "[%s] hanging up owner\n", pvt->id);
3571  if (mbl_queue_hangup(pvt)) {
3572  ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnecting...\n", pvt->id);
3573  return -1;
3574  }
3575  }
3576  pvt->needchup = 0;
3577  pvt->needcallerid = 0;
3578  pvt->incoming = 0;
3579  pvt->outgoing = 0;
3580  break;
3581  case HFP_CIND_CALL_ACTIVE:
3582  if (pvt->outgoing) {
3583  ast_debug(1, "[%s] remote end answered\n", pvt->id);
3585  } else if (pvt->incoming && pvt->answered) {
3587  } else if (pvt->incoming) {
3588  /* user answered from handset, disconnecting */
3589  ast_verb(3, "[%s] user answered bluetooth device from handset, disconnecting\n", pvt->id);
3590  mbl_queue_hangup(pvt);
3591  return -1;
3592  }
3593  break;
3594  }
3595  break;
3596 
3597  case HFP_CIND_CALLSETUP:
3598  switch (i) {
3600  if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
3601  if (pvt->owner) {
3602  if (pvt->hfp->sent_alerting == 1) {
3603  handle_response_busy(pvt);
3604  }
3605  if (mbl_queue_hangup(pvt)) {
3606  ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnecting...\n", pvt->id);
3607  return -1;
3608  }
3609  }
3610  pvt->needchup = 0;
3611  pvt->needcallerid = 0;
3612  pvt->incoming = 0;
3613  pvt->outgoing = 0;
3614  }
3615  break;
3617  ast_debug(1, "[%s] incoming call, waiting for caller id\n", pvt->id);
3618  pvt->needcallerid = 1;
3619  pvt->incoming = 1;
3620  break;
3622  if (pvt->outgoing) {
3623  pvt->hfp->sent_alerting = 0;
3624  ast_debug(1, "[%s] outgoing call\n", pvt->id);
3625  } else {
3626  ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
3627  return -1;
3628  }
3629  break;
3631  if (pvt->outgoing) {
3632  ast_debug(1, "[%s] remote alerting\n", pvt->id);
3634  pvt->hfp->sent_alerting = 1;
3635  }
3636  break;
3637  }
3638  break;
3639  case HFP_CIND_NONE:
3640  ast_debug(1, "[%s] error parsing CIND: %s\n", pvt->id, buf);
3641  break;
3642  }
3643  return 0;
3644 }
#define HFP_CIND_NONE
Definition: chan_mobile.c:276
#define HFP_CIND_CALL_ACTIVE
Definition: chan_mobile.c:287
#define HFP_CIND_CALLSETUP
Definition: chan_mobile.c:279
#define HFP_CIND_CALL_NONE
Definition: chan_mobile.c:286
#define HFP_CIND_CALL
Definition: chan_mobile.c:278
static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
Parse a CIEV event.
Definition: chan_mobile.c:2197
#define HFP_CIND_CALLSETUP_INCOMING
Definition: chan_mobile.c:291
#define HFP_CIND_CALLSETUP_OUTGOING
Definition: chan_mobile.c:292
#define HFP_CIND_CALLSETUP_NONE
Definition: chan_mobile.c:290
#define HFP_CIND_CALLSETUP_ALERTING
Definition: chan_mobile.c:293
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7469
@ AST_CONTROL_RINGING
int cind_state[16]
Definition: chan_mobile.c:350
struct hfp_cind cind_map
Definition: chan_mobile.c:351
int sent_alerting
Definition: chan_mobile.c:354
unsigned int needcallerid
Definition: chan_mobile.c:157

References mbl_pvt::answered, AST_CONTROL_ANSWER, AST_CONTROL_RINGING, ast_debug, ast_log, ast_setstate(), AST_STATE_UP, ast_verb, buf, hfp_cind::call, hfp_pvt::cind_map, hfp_pvt::cind_state, handle_response_busy(), mbl_pvt::hfp, HFP_CIND_CALL, HFP_CIND_CALL_ACTIVE, HFP_CIND_CALL_NONE, HFP_CIND_CALLSETUP, HFP_CIND_CALLSETUP_ALERTING, HFP_CIND_CALLSETUP_INCOMING, HFP_CIND_CALLSETUP_NONE, HFP_CIND_CALLSETUP_OUTGOING, HFP_CIND_NONE, hfp_parse_ciev(), mbl_pvt::id, mbl_pvt::incoming, LOG_ERROR, mbl_queue_control(), mbl_queue_hangup(), mbl_pvt::needcallerid, mbl_pvt::needchup, mbl_pvt::outgoing, mbl_pvt::owner, and hfp_pvt::sent_alerting.

Referenced by do_monitor_phone().

◆ handle_response_cind()

static int handle_response_cind ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle the CIND response.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3233 of file chan_mobile.c.

3234 {
3235  struct msg_queue_entry *entry;
3236  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_CIND) {
3237  switch (entry->response_to) {
3238  case AT_CIND_TEST:
3240  ast_debug(1, "[%s] error performing CIND test\n", pvt->id);
3241  goto e_return;
3242  }
3243  break;
3244  case AT_CIND:
3245  if (hfp_parse_cind(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND)) {
3246  ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3247  goto e_return;
3248  }
3249  break;
3250  default:
3251  ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3252  goto e_return;
3253  }
3255  } else if (entry) {
3256  ast_debug(1, "[%s] received unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3257  } else {
3258  ast_debug(1, "[%s] received unexpected AT message 'CIND'\n", pvt->id);
3259  }
3260 
3261  return 0;
3262 
3263 e_return:
3265  return -1;
3266 }
static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
Parse the result of the AT+CIND=? command.
Definition: chan_mobile.c:2820
static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf)
Read the result of the AT+CIND? command.
Definition: chan_mobile.c:2770

References ast_debug, AT_CIND, AT_CIND_TEST, at_msg2str(), AT_OK, buf, msg_queue_entry::entry, mbl_pvt::hfp, hfp_parse_cind(), hfp_parse_cind_test(), mbl_pvt::id, msg_queue_free_and_pop(), msg_queue_head(), and msg_queue_push().

Referenced by do_monitor_phone().

◆ handle_response_clip()

static int handle_response_clip ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CLIP messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3653 of file chan_mobile.c.

3654 {
3655  struct msg_queue_entry *msg;
3656  struct ast_channel *chan;
3657  struct cidinfo cidinfo;
3658 
3659  if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CLIP) {
3661 
3662  pvt->needcallerid = 0;
3663  cidinfo = hfp_parse_clip(pvt->hfp, buf);
3664 
3665  if (!(chan = mbl_new(AST_STATE_RING, pvt, &cidinfo, NULL, NULL))) {
3666  ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
3667  hfp_send_chup(pvt->hfp);
3668  msg_queue_push(pvt, AT_OK, AT_CHUP);
3669  return -1;
3670  }
3671 
3672  /* from this point on, we need to send a chup in the event of a
3673  * hangup */
3674  pvt->needchup = 1;
3675 
3676  if (ast_pbx_start(chan)) {
3677  ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
3678  mbl_ast_hangup(pvt);
3679  return -1;
3680  }
3681  }
3682 
3683  return 0;
3684 }
static int hfp_send_chup(struct hfp_pvt *hfp)
Send AT+CHUP.
Definition: chan_mobile.c:2683
static int mbl_ast_hangup(struct mbl_pvt *pvt)
Definition: chan_mobile.c:1354
static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
Parse a CLIP event.
Definition: chan_mobile.c:2226
@ AST_STATE_RING
Definition: channelstate.h:40
at_message_t expected
Definition: chan_mobile.c:461

References ast_log, ast_pbx_start(), AST_STATE_RING, AT_CHUP, AT_CLIP, AT_OK, buf, msg_queue_entry::expected, mbl_pvt::hfp, hfp_parse_clip(), hfp_send_chup(), mbl_pvt::id, LOG_ERROR, mbl_ast_hangup(), mbl_new(), msg_queue_free_and_pop(), msg_queue_head(), msg_queue_push(), mbl_pvt::needcallerid, mbl_pvt::needchup, and NULL.

Referenced by do_monitor_phone().

◆ handle_response_cmgr()

static int handle_response_cmgr ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CMGR messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3737 of file chan_mobile.c.

3738 {
3739  char *from_number = NULL, *text = NULL;
3740  struct ast_channel *chan;
3741  struct msg_queue_entry *msg;
3742 
3743  if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CMGR) {
3745 
3746  if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)) {
3747  ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
3748  return -1;
3749  }
3750 
3751  ast_debug(1, "[%s] successfully read sms message\n", pvt->id);
3752  pvt->incoming_sms = 0;
3753 
3754  /* XXX this channel probably does not need to be associated with this pvt */
3755  if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
3756  ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
3757  return -1;
3758  }
3759 
3760  ast_channel_exten_set(chan, "sms");
3761  pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
3762  pbx_builtin_setvar_helper(chan, "SMSTXT", text);
3763 
3764  if (ast_pbx_start(chan)) {
3765  ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming sms\n", pvt->id);
3766  mbl_ast_hangup(pvt);
3767  }
3768  } else {
3769  ast_debug(1, "[%s] got unexpected +CMGR message, ignoring\n", pvt->id);
3770  }
3771 
3772  return 0;
3773 }
char * text
Definition: app_queue.c:1641
static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text)
Parse a CMGR message.
Definition: chan_mobile.c:2354
@ AST_STATE_DOWN
Definition: channelstate.h:36
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.

References ast_channel_exten_set(), ast_debug, ast_log, ast_pbx_start(), AST_STATE_DOWN, AT_CMGR, buf, msg_queue_entry::expected, mbl_pvt::hfp, hfp_parse_cmgr(), mbl_pvt::id, mbl_pvt::incoming_sms, LOG_ERROR, mbl_ast_hangup(), mbl_new(), msg_queue_free_and_pop(), msg_queue_head(), NULL, pbx_builtin_setvar_helper(), and text.

Referenced by do_monitor_phone().

◆ handle_response_cmti()

static int handle_response_cmti ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CMTI messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3710 of file chan_mobile.c.

3711 {
3712  int index = hfp_parse_cmti(pvt->hfp, buf);
3713  if (index > 0) {
3714  ast_debug(1, "[%s] incoming sms message\n", pvt->id);
3715 
3716  if (hfp_send_cmgr(pvt->hfp, index)
3717  || msg_queue_push(pvt, AT_CMGR, AT_CMGR)) {
3718  ast_debug(1, "[%s] error sending CMGR to retrieve SMS message\n", pvt->id);
3719  return -1;
3720  }
3721 
3722  pvt->incoming_sms = 1;
3723  return 0;
3724  } else {
3725  ast_debug(1, "[%s] error parsing incoming sms message alert, disconnecting\n", pvt->id);
3726  return -1;
3727  }
3728 }
static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
Parse a CMTI notification.
Definition: chan_mobile.c:2328
static int hfp_send_cmgr(struct hfp_pvt *hfp, int index)
Read an SMS message.
Definition: chan_mobile.c:2648

References ast_debug, AT_CMGR, buf, mbl_pvt::hfp, hfp_parse_cmti(), hfp_send_cmgr(), mbl_pvt::id, mbl_pvt::incoming_sms, and msg_queue_push().

Referenced by do_monitor_phone().

◆ handle_response_cusd()

static int handle_response_cusd ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle CUSD messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3813 of file chan_mobile.c.

3814 {
3815  char *cusd;
3816 
3817  if (!(cusd = hfp_parse_cusd(pvt->hfp, buf))) {
3818  ast_verb(0, "[%s] error parsing CUSD: %s\n", pvt->id, buf);
3819  return 0;
3820  }
3821 
3822  ast_verb(0, "[%s] CUSD response: %s\n", pvt->id, cusd);
3823 
3824  return 0;
3825 }
static char * hfp_parse_cusd(struct hfp_pvt *hfp, char *buf)
Parse a CUSD answer.
Definition: chan_mobile.c:2418

References ast_verb, buf, mbl_pvt::hfp, hfp_parse_cusd(), and mbl_pvt::id.

Referenced by do_monitor_phone().

◆ handle_response_error()

static int handle_response_error ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle ERROR AT messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3444 of file chan_mobile.c.

3445 {
3446  struct msg_queue_entry *entry;
3447  if ((entry = msg_queue_head(pvt))
3448  && (entry->expected == AT_OK
3449  || entry->expected == AT_ERROR
3450  || entry->expected == AT_CMS_ERROR
3451  || entry->expected == AT_CMGR
3452  || entry->expected == AT_SMS_PROMPT)) {
3453  switch (entry->response_to) {
3454 
3455  /* initialization stuff */
3456  case AT_BRSF:
3457  ast_debug(1, "[%s] error reading BSRF\n", pvt->id);
3458  goto e_return;
3459  case AT_CIND_TEST:
3460  ast_debug(1, "[%s] error during CIND test\n", pvt->id);
3461  goto e_return;
3462  case AT_CIND:
3463  ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
3464  goto e_return;
3465  case AT_CMER:
3466  ast_debug(1, "[%s] error during CMER request\n", pvt->id);
3467  goto e_return;
3468  case AT_CLIP:
3469  ast_debug(1, "[%s] error enabling calling line indication\n", pvt->id);
3470  goto e_return;
3471  case AT_VGS:
3472  ast_debug(1, "[%s] volume level synchronization failed\n", pvt->id);
3473 
3474  /* this is not a fatal error, let's continue with initialization */
3475 
3476  /* set the SMS operating mode to text mode */
3477  if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
3478  ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
3479  goto e_return;
3480  }
3481  break;
3482  case AT_CMGF:
3483  pvt->has_sms = 0;
3484  ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
3485  ast_debug(1, "[%s] no SMS support\n", pvt->id);
3486  break;
3487  case AT_CNMI:
3488  pvt->has_sms = 0;
3489  ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
3490  ast_debug(1, "[%s] no SMS support\n", pvt->id);
3491  break;
3492  case AT_ECAM:
3493  ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id);
3494 
3495  /* this is not a fatal error, let's continue with the initialization */
3496 
3497  if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
3498  ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
3499  goto e_return;
3500  }
3501 
3502  pvt->timeout = -1;
3503  pvt->hfp->initialized = 1;
3504  ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
3505 
3506  break;
3507  /* end initialization stuff */
3508 
3509  case AT_A:
3510  ast_debug(1, "[%s] answer failed\n", pvt->id);
3511  mbl_queue_hangup(pvt);
3512  break;
3513  case AT_D:
3514  ast_debug(1, "[%s] dial failed\n", pvt->id);
3515  pvt->needchup = 0;
3517  break;
3518  case AT_CHUP:
3519  ast_debug(1, "[%s] error sending hangup, disconnecting\n", pvt->id);
3520  goto e_return;
3521  case AT_CMGR:
3522  ast_debug(1, "[%s] error reading sms message\n", pvt->id);
3523  pvt->incoming_sms = 0;
3524  break;
3525  case AT_CMGS:
3526  ast_debug(1, "[%s] error sending sms message\n", pvt->id);
3527  pvt->outgoing_sms = 0;
3528  break;
3529  case AT_VTS:
3530  ast_debug(1, "[%s] error sending digit\n", pvt->id);
3531  break;
3532  case AT_CUSD:
3533  ast_verb(0, "[%s] error sending CUSD command\n", pvt->id);
3534  break;
3535  case AT_UNKNOWN:
3536  default:
3537  ast_debug(1, "[%s] received ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
3538  break;
3539  }
3541  } else if (entry) {
3542  ast_debug(1, "[%s] received AT message 'ERROR' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3543  } else {
3544  ast_debug(1, "[%s] received unexpected AT message 'ERROR'\n", pvt->id);
3545  }
3546 
3547  return 0;
3548 
3549 e_return:
3551  return -1;
3552 }
static int hfp_send_cmgf(struct hfp_pvt *hfp, int mode)
Set the SMS mode.
Definition: chan_mobile.c:2627
static int hfp_send_vgs(struct hfp_pvt *hfp, int value)
Send the current speaker gain level.
Definition: chan_mobile.c:2558
@ AST_CONTROL_CONGESTION

References AST_CONTROL_CONGESTION, ast_debug, ast_verb, AT_A, AT_BRSF, AT_CHUP, AT_CIND, AT_CIND_TEST, AT_CLIP, AT_CMER, AT_CMGF, AT_CMGR, AT_CMGS, AT_CMS_ERROR, AT_CNMI, AT_CUSD, AT_D, AT_ECAM, AT_ERROR, at_msg2str(), AT_OK, AT_SMS_PROMPT, AT_UNKNOWN, AT_VGS, AT_VTS, msg_queue_entry::entry, mbl_pvt::has_sms, mbl_pvt::hfp, hfp_send_cmgf(), hfp_send_vgs(), mbl_pvt::id, mbl_pvt::incoming_sms, hfp_pvt::initialized, mbl_queue_control(), mbl_queue_hangup(), msg_queue_free_and_pop(), msg_queue_head(), msg_queue_push(), mbl_pvt::needchup, mbl_pvt::outgoing_sms, and mbl_pvt::timeout.

Referenced by do_monitor_phone().

◆ handle_response_no_carrier()

static int handle_response_no_carrier ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle NO CARRIER messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3863 of file chan_mobile.c.

3864 {
3865  ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
3866  pvt->needchup = 1;
3868  return 0;
3869 }

References AST_CONTROL_CONGESTION, ast_verb, mbl_pvt::id, mbl_queue_control(), and mbl_pvt::needchup.

Referenced by do_monitor_phone().

◆ handle_response_no_dialtone()

static int handle_response_no_dialtone ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle NO DIALTONE messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3848 of file chan_mobile.c.

3849 {
3850  ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
3851  pvt->needchup = 1;
3853  return 0;
3854 }

References AST_CONTROL_CONGESTION, ast_verb, mbl_pvt::id, mbl_queue_control(), and mbl_pvt::needchup.

Referenced by do_monitor_phone().

◆ handle_response_ok()

static int handle_response_ok ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle OK AT messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3275 of file chan_mobile.c.

3276 {
3277  struct msg_queue_entry *entry;
3278  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_OK) {
3279  switch (entry->response_to) {
3280 
3281  /* initialization stuff */
3282  case AT_BRSF:
3283  ast_debug(1, "[%s] BSRF sent successfully\n", pvt->id);
3284 
3285  /* If this is a blackberry do CMER now, otherwise
3286  * continue with CIND as normal. */
3287  if (pvt->blackberry) {
3288  if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
3289  ast_debug(1, "[%s] error sending CMER\n", pvt->id);
3290  goto e_return;
3291  }
3292  } else {
3294  ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
3295  goto e_return;
3296  }
3297  }
3298  break;
3299  case AT_CIND_TEST:
3300  ast_debug(1, "[%s] CIND test sent successfully\n", pvt->id);
3301 
3302  ast_debug(2, "[%s] call: %d\n", pvt->id, pvt->hfp->cind_map.call);
3303  ast_debug(2, "[%s] callsetup: %d\n", pvt->id, pvt->hfp->cind_map.callsetup);
3304  ast_debug(2, "[%s] service: %d\n", pvt->id, pvt->hfp->cind_map.service);
3305 
3306  if (hfp_send_cind(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND)) {
3307  ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
3308  goto e_return;
3309  }
3310  break;
3311  case AT_CIND:
3312  ast_debug(1, "[%s] CIND sent successfully\n", pvt->id);
3313 
3314  /* check if a call is active */
3315  if (pvt->hfp->cind_state[pvt->hfp->cind_map.call]) {
3316  ast_verb(3, "Bluetooth Device %s has a call in progress - delaying connection.\n", pvt->id);
3317  goto e_return;
3318  }
3319 
3320  /* If this is NOT a blackberry proceed with CMER,
3321  * otherwise send CLIP. */
3322  if (!pvt->blackberry) {
3323  if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
3324  ast_debug(1, "[%s] error sending CMER\n", pvt->id);
3325  goto e_return;
3326  }
3327  } else {
3328  if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
3329  ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
3330  goto e_return;
3331  }
3332  }
3333  break;
3334  case AT_CMER:
3335  ast_debug(1, "[%s] CMER sent successfully\n", pvt->id);
3336 
3337  /* If this is a blackberry proceed with the CIND test,
3338  * otherwise send CLIP. */
3339  if (pvt->blackberry) {
3341  ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
3342  goto e_return;
3343  }
3344  } else {
3345  if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
3346  ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
3347  goto e_return;
3348  }
3349  }
3350  break;
3351  case AT_CLIP:
3352  ast_debug(1, "[%s] calling line indication enabled\n", pvt->id);
3353  if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
3354  ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
3355  goto e_return;
3356  }
3357 
3358  break;
3359  case AT_ECAM:
3360  ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
3361  if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
3362  ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
3363  goto e_return;
3364  }
3365 
3366  pvt->timeout = -1;
3367  pvt->hfp->initialized = 1;
3368  ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
3369 
3370  break;
3371  case AT_VGS:
3372  ast_debug(1, "[%s] volume level synchronization successful\n", pvt->id);
3373 
3374  /* set the SMS operating mode to text mode */
3375  if (pvt->has_sms) {
3376  if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
3377  ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
3378  goto e_return;
3379  }
3380  }
3381  break;
3382  case AT_CMGF:
3383  ast_debug(1, "[%s] sms text mode enabled\n", pvt->id);
3384  /* turn on SMS new message indication */
3385  if (hfp_send_cnmi(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_CNMI)) {
3386  ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
3387  goto e_return;
3388  }
3389  break;
3390  case AT_CNMI:
3391  ast_debug(1, "[%s] sms new message indication enabled\n", pvt->id);
3392  pvt->has_sms = 1;
3393  break;
3394  /* end initialization stuff */
3395 
3396  case AT_A:
3397  ast_debug(1, "[%s] answer sent successfully\n", pvt->id);
3398  pvt->needchup = 1;
3399  break;
3400  case AT_D:
3401  ast_debug(1, "[%s] dial sent successfully\n", pvt->id);
3402  pvt->needchup = 1;
3403  pvt->outgoing = 1;
3405  break;
3406  case AT_CHUP:
3407  ast_debug(1, "[%s] successful hangup\n", pvt->id);
3408  break;
3409  case AT_CMGS:
3410  ast_debug(1, "[%s] successfully sent sms message\n", pvt->id);
3411  pvt->outgoing_sms = 0;
3412  break;
3413  case AT_VTS:
3414  ast_debug(1, "[%s] digit sent successfully\n", pvt->id);
3415  break;
3416  case AT_CUSD:
3417  ast_debug(1, "[%s] CUSD code sent successfully\n", pvt->id);
3418  break;
3419  case AT_UNKNOWN:
3420  default:
3421  ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
3422  break;
3423  }
3425  } else if (entry) {
3426  ast_debug(1, "[%s] received AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3427  } else {
3428  ast_debug(1, "[%s] received unexpected AT message 'OK'\n", pvt->id);
3429  }
3430  return 0;
3431 
3432 e_return:
3434  return -1;
3435 }
static int hfp_send_cind(struct hfp_pvt *hfp)
Send the CIND read command.
Definition: chan_mobile.c:2527
static int hfp_send_cnmi(struct hfp_pvt *hfp)
Setup SMS new message indication.
Definition: chan_mobile.c:2638
static int hfp_send_ecam(struct hfp_pvt *hfp)
Enable Sony Ericsson extensions / indications.
Definition: chan_mobile.c:2184
static int hfp_send_cind_test(struct hfp_pvt *hfp)
Send the CIND test command.
Definition: chan_mobile.c:2536
static int hfp_send_clip(struct hfp_pvt *hfp, int status)
Enable or disable calling line identification.
Definition: chan_mobile.c:2585
static int hfp_send_cmer(struct hfp_pvt *hfp, int status)
Enable or disable indicator events reporting.
Definition: chan_mobile.c:2546
@ AST_CONTROL_PROGRESS
int service
Definition: chan_mobile.c:331
int callsetup
Definition: chan_mobile.c:333

References AST_CONTROL_PROGRESS, ast_debug, ast_verb, AT_A, AT_BRSF, AT_CHUP, AT_CIND, AT_CIND_TEST, AT_CLIP, AT_CMER, AT_CMGF, AT_CMGS, AT_CNMI, AT_CUSD, AT_D, AT_ECAM, at_msg2str(), AT_OK, AT_UNKNOWN, AT_VGS, AT_VTS, mbl_pvt::blackberry, hfp_cind::call, hfp_cind::callsetup, hfp_pvt::cind_map, hfp_pvt::cind_state, msg_queue_entry::entry, mbl_pvt::has_sms, mbl_pvt::hfp, hfp_send_cind(), hfp_send_cind_test(), hfp_send_clip(), hfp_send_cmer(), hfp_send_cmgf(), hfp_send_cnmi(), hfp_send_ecam(), hfp_send_vgs(), mbl_pvt::id, hfp_pvt::initialized, mbl_queue_control(), msg_queue_free_and_pop(), msg_queue_head(), msg_queue_push(), mbl_pvt::needchup, mbl_pvt::outgoing, mbl_pvt::outgoing_sms, hfp_cind::service, and mbl_pvt::timeout.

Referenced by do_monitor_phone().

◆ handle_response_ring()

static int handle_response_ring ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle RING messages.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3693 of file chan_mobile.c.

3694 {
3695  if (pvt->needcallerid) {
3696  ast_debug(1, "[%s] got ring while waiting for caller id\n", pvt->id);
3697  return msg_queue_push(pvt, AT_CLIP, AT_UNKNOWN);
3698  } else {
3699  return 0;
3700  }
3701 }

References ast_debug, AT_CLIP, AT_UNKNOWN, mbl_pvt::id, msg_queue_push(), and mbl_pvt::needcallerid.

Referenced by do_monitor_phone().

◆ handle_sms_prompt()

static int handle_sms_prompt ( struct mbl_pvt pvt,
char *  buf 
)
static

Send an SMS message from the queue.

Parameters
pvta mbl_pvt structure
bufa null terminated buffer containing an AT message
Return values
0success
-1error

Definition at line 3782 of file chan_mobile.c.

3783 {
3784  struct msg_queue_entry *msg;
3785  if (!(msg = msg_queue_head(pvt))) {
3786  ast_debug(1, "[%s] error, got sms prompt with no pending sms messages\n", pvt->id);
3787  return 0;
3788  }
3789 
3790  if (msg->expected != AT_SMS_PROMPT) {
3791  ast_debug(1, "[%s] error, got sms prompt but no pending sms messages\n", pvt->id);
3792  return 0;
3793  }
3794 
3795  if (hfp_send_sms_text(pvt->hfp, msg->data)
3796  || msg_queue_push(pvt, AT_OK, AT_CMGS)) {
3798  ast_debug(1, "[%s] error sending sms message\n", pvt->id);
3799  return 0;
3800  }
3801 
3803  return 0;
3804 }
static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message)
Send the text of an SMS message.
Definition: chan_mobile.c:2672
void * data
Definition: chan_mobile.c:463

References ast_debug, AT_CMGS, AT_OK, AT_SMS_PROMPT, msg_queue_entry::data, msg_queue_entry::expected, mbl_pvt::hfp, hfp_send_sms_text(), mbl_pvt::id, msg_queue_free_and_pop(), msg_queue_head(), and msg_queue_push().

Referenced by do_monitor_phone().

◆ headset_send_ring()

static int headset_send_ring ( const void *  data)
static

Definition at line 4104 of file chan_mobile.c.

4105 {
4106  struct mbl_pvt *pvt = (struct mbl_pvt *) data;
4107  ast_mutex_lock(&pvt->lock);
4108  if (!pvt->needring) {
4109  ast_mutex_unlock(&pvt->lock);
4110  return 0;
4111  }
4112  ast_mutex_unlock(&pvt->lock);
4113 
4114  if (hsp_send_ring(pvt->rfcomm_socket)) {
4115  ast_debug(1, "[%s] error sending RING\n", pvt->id);
4116  return 0;
4117  }
4118  return 1;
4119 }
static int hsp_send_ring(int rsock)
Send a RING unsolicited AT response.
Definition: chan_mobile.c:2968

References ast_debug, ast_mutex_lock, ast_mutex_unlock, hsp_send_ring(), mbl_pvt::id, mbl_pvt::lock, mbl_pvt::needring, and mbl_pvt::rfcomm_socket.

Referenced by mbl_call().

◆ hfp_brsf2int()

static int hfp_brsf2int ( struct hfp_hf hf)
static

Convert a hfp_hf struct to a BRSF int.

Parameters
hfan hfp_hf brsf object
Returns
an integer representing the given brsf struct

Definition at line 2470 of file chan_mobile.c.

2471 {
2472  int brsf = 0;
2473 
2474  brsf |= hf->ecnr ? HFP_HF_ECNR : 0;
2475  brsf |= hf->cw ? HFP_HF_CW : 0;
2476  brsf |= hf->cid ? HFP_HF_CID : 0;
2477  brsf |= hf->voice ? HFP_HF_VOICE : 0;
2478  brsf |= hf->volume ? HFP_HF_VOLUME : 0;
2479  brsf |= hf->status ? HFP_HF_STATUS : 0;
2480  brsf |= hf->control ? HFP_HF_CONTROL : 0;
2481 
2482  return brsf;
2483 }
#define HFP_HF_STATUS
Definition: chan_mobile.c:262
#define HFP_HF_CW
Definition: chan_mobile.c:258
#define HFP_HF_CID
Definition: chan_mobile.c:259
#define HFP_HF_CONTROL
Definition: chan_mobile.c:263
#define HFP_HF_VOLUME
Definition: chan_mobile.c:261
#define HFP_HF_ECNR
Definition: chan_mobile.c:257
#define HFP_HF_VOICE
Definition: chan_mobile.c:260
int cw
Definition: chan_mobile.c:304
int control
Definition: chan_mobile.c:309
int ecnr
Definition: chan_mobile.c:303
int status
Definition: chan_mobile.c:308
int voice
Definition: chan_mobile.c:306
int cid
Definition: chan_mobile.c:305
int volume
Definition: chan_mobile.c:307

References hfp_hf::cid, hfp_hf::control, hfp_hf::cw, hfp_hf::ecnr, HFP_HF_CID, HFP_HF_CONTROL, HFP_HF_CW, HFP_HF_ECNR, HFP_HF_STATUS, HFP_HF_VOICE, HFP_HF_VOLUME, hfp_hf::status, hfp_hf::voice, and hfp_hf::volume.

Referenced by hfp_send_brsf().

◆ hfp_int2brsf()

static struct hfp_ag * hfp_int2brsf ( int  brsf,
struct hfp_ag ag 
)
static

Convert a BRSF int to an hfp_ag struct.

Parameters
brsfa brsf integer
aga AG (hfp_ag) brsf object
Returns
a pointer to the given hfp_ag object populated with the values from the given brsf integer

Definition at line 2492 of file chan_mobile.c.

2493 {
2494  ag->cw = brsf & HFP_AG_CW ? 1 : 0;
2495  ag->ecnr = brsf & HFP_AG_ECNR ? 1 : 0;
2496  ag->voice = brsf & HFP_AG_VOICE ? 1 : 0;
2497  ag->ring = brsf & HFP_AG_RING ? 1 : 0;
2498  ag->tag = brsf & HFP_AG_TAG ? 1 : 0;
2499  ag->reject = brsf & HFP_AG_REJECT ? 1 : 0;
2500  ag->status = brsf & HFP_AG_STATUS ? 1 : 0;
2501  ag->control = brsf & HFP_AG_CONTROL ? 1 : 0;
2502  ag->errors = brsf & HFP_AG_ERRORS ? 1 : 0;
2503 
2504  return ag;
2505 }
#define HFP_AG_ERRORS
Definition: chan_mobile.c:273
#define HFP_AG_CW
Definition: chan_mobile.c:265
#define HFP_AG_TAG
Definition: chan_mobile.c:269
#define HFP_AG_ECNR
Definition: chan_mobile.c:266
#define HFP_AG_VOICE
Definition: chan_mobile.c:267
#define HFP_AG_RING
Definition: chan_mobile.c:268
#define HFP_AG_CONTROL
Definition: chan_mobile.c:272
#define HFP_AG_STATUS
Definition: chan_mobile.c:271
#define HFP_AG_REJECT
Definition: chan_mobile.c:270
int cw
Definition: chan_mobile.c:316
int ring
Definition: chan_mobile.c:319
int reject
Definition: chan_mobile.c:321
int control
Definition: chan_mobile.c:323
int errors
Definition: chan_mobile.c:324
int ecnr
Definition: chan_mobile.c:317
int status
Definition: chan_mobile.c:322
int tag
Definition: chan_mobile.c:320
int voice
Definition: chan_mobile.c:318

References hfp_ag::control, hfp_ag::cw, hfp_ag::ecnr, hfp_ag::errors, HFP_AG_CONTROL, HFP_AG_CW, HFP_AG_ECNR, HFP_AG_ERRORS, HFP_AG_REJECT, HFP_AG_RING, HFP_AG_STATUS, HFP_AG_TAG, HFP_AG_VOICE, hfp_ag::reject, hfp_ag::ring, hfp_ag::status, hfp_ag::tag, and hfp_ag::voice.

Referenced by hfp_parse_brsf().

◆ hfp_parse_brsf()

static int hfp_parse_brsf ( struct hfp_pvt hfp,
const char *  buf 
)
static

Parse BRSF data.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)

Definition at line 2726 of file chan_mobile.c.

2727 {
2728  int brsf;
2729 
2730  if (!sscanf(buf, "+BRSF:%d", &brsf))
2731  return -1;
2732 
2733  hfp_int2brsf(brsf, &hfp->brsf);
2734 
2735  return 0;
2736 }
static struct hfp_ag * hfp_int2brsf(int brsf, struct hfp_ag *ag)
Convert a BRSF int to an hfp_ag struct.
Definition: chan_mobile.c:2492
struct hfp_ag brsf
Definition: chan_mobile.c:348

References hfp_pvt::brsf, buf, and hfp_int2brsf().

Referenced by handle_response_brsf().

◆ hfp_parse_ciev()

static int hfp_parse_ciev ( struct hfp_pvt hfp,
char *  buf,
int *  value 
)
static

Parse a CIEV event.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)
valuea pointer to an int to store the event value in (can be NULL)
Returns
0 on error (parse error, or unknown event) or a HFP_CIND_* value on success

Definition at line 2197 of file chan_mobile.c.

2198 {
2199  int i, v;
2200  if (!value)
2201  value = &v;
2202 
2203  if (!sscanf(buf, "+CIEV: %d,%d", &i, value)) {
2204  ast_debug(2, "[%s] error parsing CIEV event '%s'\n", hfp->owner->id, buf);
2205  return HFP_CIND_NONE;
2206  }
2207 
2208  if (i >= ARRAY_LEN(hfp->cind_state)) {
2209  ast_debug(2, "[%s] CIEV event index too high (%s)\n", hfp->owner->id, buf);
2210  return HFP_CIND_NONE;
2211  }
2212 
2213  hfp->cind_state[i] = *value;
2214  return hfp->cind_index[i];
2215 }
int cind_index[16]
Definition: chan_mobile.c:349
int value
Definition: syslog.c:37
#define ARRAY_LEN(a)
Definition: utils.h:661

References ARRAY_LEN, ast_debug, buf, hfp_pvt::cind_index, hfp_pvt::cind_state, HFP_CIND_NONE, mbl_pvt::id, hfp_pvt::owner, and value.

Referenced by handle_response_ciev().

◆ hfp_parse_cind()

static int hfp_parse_cind ( struct hfp_pvt hfp,
char *  buf 
)
static

Read the result of the AT+CIND? command.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)
Note
hfp_send_cind_test() and hfp_parse_cind_test() should be called at least once before this function is called.

Definition at line 2770 of file chan_mobile.c.

2771 {
2772  int i, state, group;
2773  size_t s;
2774  char *indicator = NULL;
2775 
2776  /* parse current state of all of our indicators. The list is in the
2777  * following format:
2778  * +CIND: 1,0,2,0,0,0,0
2779  */
2780  group = 0;
2781  state = 0;
2782  s = strlen(buf);
2783  for (i = 0; i < s; i++) {
2784  switch (state) {
2785  case 0: /* search for start of the status indicators (a space) */
2786  if (buf[i] == ' ') {
2787  group++;
2788  state++;
2789  }
2790  break;
2791  case 1: /* mark this indicator */
2792  indicator = &buf[i];
2793  state++;
2794  break;
2795  case 2: /* search for the start of the next indicator (a comma) */
2796  if (buf[i] == ',') {
2797  buf[i] = '\0';
2798 
2800 
2801  group++;
2802  state = 1;
2803  }
2804  break;
2805  }
2806  }
2807 
2808  /* store the last indicator */
2809  if (state == 2)
2811 
2812  return 0;
2813 }
static int hfp_parse_cind_indicator(struct hfp_pvt *hfp, int group, char *indicator)
Parse and store the given indicator.
Definition: chan_mobile.c:2744
enum sip_cc_notify_state state
Definition: chan_sip.c:966
static int indicator

References buf, hfp_parse_cind_indicator(), indicator, NULL, and state.

Referenced by handle_response_cind().

◆ hfp_parse_cind_indicator()

static int hfp_parse_cind_indicator ( struct hfp_pvt hfp,
int  group,
char *  indicator 
)
static

Parse and store the given indicator.

Parameters
hfpan hfp_pvt struct
groupthe indicator group
indicatorthe indicator to parse

Definition at line 2744 of file chan_mobile.c.

2745 {
2746  int value;
2747 
2748  /* store the current indicator */
2749  if (group >= ARRAY_LEN(hfp->cind_state)) {
2750  ast_debug(1, "ignoring CIND state '%s' for group %d, we only support up to %d indicators\n", indicator, group, (int) sizeof(hfp->cind_state));
2751  return -1;
2752  }
2753 
2754  if (!sscanf(indicator, "%d", &value)) {
2755  ast_debug(1, "error parsing CIND state '%s' for group %d\n", indicator, group);
2756  return -1;
2757  }
2758 
2759  hfp->cind_state[group] = value;
2760  return 0;
2761 }

References ARRAY_LEN, ast_debug, hfp_pvt::cind_state, indicator, and value.

Referenced by hfp_parse_cind().

◆ hfp_parse_cind_test()

static int hfp_parse_cind_test ( struct hfp_pvt hfp,
char *  buf 
)
static

Parse the result of the AT+CIND=? command.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)

Definition at line 2820 of file chan_mobile.c.

2821 {
2822  int i, state, group;
2823  size_t s;
2824  char *indicator = NULL;
2825 
2826  hfp->nocallsetup = 1;
2827 
2828  /* parse the indications list. It is in the follwing format:
2829  * +CIND: ("ind1",(0-1)),("ind2",(0-5))
2830  */
2831  group = 0;
2832  state = 0;
2833  s = strlen(buf);
2834  for (i = 0; i < s; i++) {
2835  switch (state) {
2836  case 0: /* search for start of indicator block */
2837  if (buf[i] == '(') {
2838  group++;
2839  state++;
2840  }
2841  break;
2842  case 1: /* search for '"' in indicator block */
2843  if (buf[i] == '"') {
2844  state++;
2845  }
2846  break;
2847  case 2: /* mark the start of the indicator name */
2848  indicator = &buf[i];
2849  state++;
2850  break;
2851  case 3: /* look for the end of the indicator name */
2852  if (buf[i] == '"') {
2853  buf[i] = '\0';
2854  state++;
2855  }
2856  break;
2857  case 4: /* find the start of the value range */
2858  if (buf[i] == '(') {
2859  state++;
2860  }
2861  break;
2862  case 5: /* mark the start of the value range */
2863  state++;
2864  break;
2865  case 6: /* find the end of the value range */
2866  if (buf[i] == ')') {
2867  buf[i] = '\0';
2868  state++;
2869  }
2870  break;
2871  case 7: /* process the values we found */
2872  if (group < sizeof(hfp->cind_index)) {
2873  if (!strcmp(indicator, "service")) {
2874  hfp->cind_map.service = group;
2876  } else if (!strcmp(indicator, "call")) {
2877  hfp->cind_map.call = group;
2878  hfp->cind_index[group] = HFP_CIND_CALL;
2879  } else if (!strcmp(indicator, "callsetup")) {
2880  hfp->nocallsetup = 0;
2881  hfp->cind_map.callsetup = group;
2883  } else if (!strcmp(indicator, "call_setup")) { /* non standard call setup identifier */
2884  hfp->nocallsetup = 0;
2885  hfp->cind_map.callsetup = group;
2887  } else if (!strcmp(indicator, "callheld")) {
2888  hfp->cind_map.callheld = group;
2890  } else if (!strcmp(indicator, "signal")) {
2891  hfp->cind_map.signal = group;
2893  } else if (!strcmp(indicator, "roam")) {
2894  hfp->cind_map.roam = group;
2895  hfp->cind_index[group] = HFP_CIND_ROAM;
2896  } else if (!strcmp(indicator, "battchg")) {
2897  hfp->cind_map.battchg = group;
2899  } else {
2901  ast_debug(2, "ignoring unknown CIND indicator '%s'\n", indicator);
2902  }
2903  } else {
2904  ast_debug(1, "can't store indicator %d (%s), we only support up to %d indicators", group, indicator, (int) sizeof(hfp->cind_index));
2905  }
2906 
2907  state = 0;
2908  break;
2909  }
2910  }
2911 
2912  hfp->owner->no_callsetup = hfp->nocallsetup;
2913 
2914  return 0;
2915 }
#define HFP_CIND_ROAM
Definition: chan_mobile.c:282
#define HFP_CIND_SIGNAL
Definition: chan_mobile.c:281
#define HFP_CIND_UNKNOWN
Definition: chan_mobile.c:275
#define HFP_CIND_BATTCHG
Definition: chan_mobile.c:283
#define HFP_CIND_SERVICE
Definition: chan_mobile.c:277
#define HFP_CIND_CALLHELD
Definition: chan_mobile.c:280
int callheld
Definition: chan_mobile.c:334
int battchg
Definition: chan_mobile.c:337
int signal
Definition: chan_mobile.c:335
int nocallsetup
Definition: chan_mobile.c:347
unsigned int no_callsetup
Definition: chan_mobile.c:140

References ast_debug, hfp_cind::battchg, buf, hfp_cind::call, hfp_cind::callheld, hfp_cind::callsetup, hfp_pvt::cind_index, hfp_pvt::cind_map, HFP_CIND_BATTCHG, HFP_CIND_CALL, HFP_CIND_CALLHELD, HFP_CIND_CALLSETUP, HFP_CIND_ROAM, HFP_CIND_SERVICE, HFP_CIND_SIGNAL, HFP_CIND_UNKNOWN, indicator, mbl_pvt::no_callsetup, hfp_pvt::nocallsetup, NULL, hfp_pvt::owner, hfp_cind::roam, hfp_cind::service, hfp_cind::signal, and state.

Referenced by handle_response_cind().

◆ hfp_parse_clip()

static struct cidinfo hfp_parse_clip ( struct hfp_pvt hfp,
char *  buf 
)
static

Parse a CLIP event.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)
Note
buf will be modified when the CID string is parsed
Returns
a cidinfo structure pointing to the cnam and cnum data in buf. On parse errors, either or both pointers will point to null strings

Definition at line 2197 of file chan_mobile.c.

2227 {
2228  int i;
2229  int tokens[6];
2230  char *cnamtmp;
2231  char delim = ' '; /* First token terminates with space */
2232  int invalid = 0; /* Number of invalid chars in cnam */
2233  struct cidinfo cidinfo = { NULL, NULL };
2234 
2235  /* parse clip info in the following format:
2236  * +CLIP: "123456789",128,...
2237  */
2238  ast_debug(3, "[%s] hfp_parse_clip is processing \"%s\"\n", hfp->owner->id, buf);
2239  tokens[0] = 0; /* First token starts in position 0 */
2240  for (i = 1; i < ARRAY_LEN(tokens); i++) {
2241  tokens[i] = parse_next_token(buf, tokens[i - 1], delim);
2242  delim = ','; /* Subsequent tokens terminate with comma */
2243  }
2244  ast_debug(3, "[%s] hfp_parse_clip found tokens: 0=%s, 1=%s, 2=%s, 3=%s, 4=%s, 5=%s\n",
2245  hfp->owner->id, &buf[tokens[0]], &buf[tokens[1]], &buf[tokens[2]],
2246  &buf[tokens[3]], &buf[tokens[4]], &buf[tokens[5]]);
2247 
2248  /* Clean up cnum, and make sure it is legitimate since it is untrusted. */
2249  cidinfo.cnum = ast_strip_quoted(&buf[tokens[1]], "\"", "\"");
2250  if (!ast_isphonenumber(cidinfo.cnum)) {
2251  ast_debug(1, "[%s] hfp_parse_clip invalid cidinfo.cnum data \"%s\" - deleting\n",
2252  hfp->owner->id, cidinfo.cnum);
2253  cidinfo.cnum = "";
2254  }
2255 
2256  /*
2257  * Some docs say tokens 2 and 3 including the commas are optional.
2258  * If absent, that would move CNAM back to token 3.
2259  */
2260  cidinfo.cnam = &buf[tokens[5]]; /* Assume it's in token 5 */
2261  if (buf[tokens[5]] == '\0' && buf[tokens[4]] == '\0') {
2262  /* Tokens 4 and 5 are empty. See if token 3 looks like CNAM (starts with ") */
2263  i = tokens[3];
2264  while (buf[i] == ' ') { /* Find the first non-blank */
2265  i++;
2266  }
2267  if (buf[i] == '"') {
2268  /* Starts with quote. Use this for CNAM. */
2269  cidinfo.cnam = &buf[i];
2270  }
2271  }
2272 
2273  /* Clean up CNAM. */
2274  cidinfo.cnam = ast_strip_quoted(cidinfo.cnam, "\"", "\"");
2275  for (cnamtmp = cidinfo.cnam; *cnamtmp != '\0'; cnamtmp++) {
2276  if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-,abcdefghijklmnopqrstuvwxyz_", *cnamtmp)) {
2277  *cnamtmp = '_'; /* Invalid. Replace with underscore. */
2278  invalid++;
2279  }
2280  }
2281  if (invalid) {
2282  ast_debug(2, "[%s] hfp_parse_clip replaced %d invalid byte(s) in cnam data\n",
2283  hfp->owner->id, invalid);
2284  }
2285  ast_debug(2, "[%s] hfp_parse_clip returns cnum=%s and cnam=%s\n",
2286  hfp->owner->id, cidinfo.cnum, cidinfo.cnam);
2287 
2288  return cidinfo;
2289 }
int ast_isphonenumber(const char *n)
Check if a string consists only of digits and + #.
Definition: callerid.c:998
static int parse_next_token(char string[], const int start, const char delim)
Terminate current token and return an index to start of the next token.
Definition: chan_mobile.c:2299
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: main/utils.c:1785
char * cnam
Definition: chan_mobile.c:169
char * cnum
Definition: chan_mobile.c:168

Referenced by handle_response_clip().

◆ hfp_parse_cmgr()

static int hfp_parse_cmgr ( struct hfp_pvt hfp,
char *  buf,
char **  from_number,
char **  text 
)
static

Parse a CMGR message.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)
from_numbera pointer to a char pointer which will store the from number
texta pointer to a char pointer which will store the message text
Note
buf will be modified when the CMGR message is parsed
Return values
-1parse error
0success

Definition at line 2354 of file chan_mobile.c.

2355 {
2356  int i, state;
2357  size_t s;
2358 
2359  /* parse cmgr info in the following format:
2360  * +CMGR: <msg status>,"+123456789",...\r\n
2361  * <message text>
2362  */
2363  state = 0;
2364  s = strlen(buf);
2365  for (i = 0; i < s && state != 6; i++) {
2366  switch (state) {
2367  case 0: /* search for start of the number section (,) */
2368  if (buf[i] == ',') {
2369  state++;
2370  }
2371  break;
2372  case 1: /* find the opening quote (") */
2373  if (buf[i] == '"') {
2374  state++;
2375  }
2376  break;
2377  case 2: /* mark the start of the number */
2378  if (from_number) {
2379  *from_number = &buf[i];
2380  state++;
2381  }
2382  /* fall through */
2383  case 3: /* search for the end of the number (") */
2384  if (buf[i] == '"') {
2385  buf[i] = '\0';
2386  state++;
2387  }
2388  break;
2389  case 4: /* search for the start of the message text (\n) */
2390  if (buf[i] == '\n') {
2391  state++;
2392  }
2393  break;
2394  case 5: /* mark the start of the message text */
2395  if (text) {
2396  *text = &buf[i];
2397  state++;
2398  }
2399  break;
2400  }
2401  }
2402 
2403  if (state != 6) {
2404  return -1;
2405  }
2406 
2407  return 0;
2408 }

References buf, state, and text.

Referenced by handle_response_cmgr().

◆ hfp_parse_cmti()

static int hfp_parse_cmti ( struct hfp_pvt hfp,
char *  buf 
)
static

Parse a CMTI notification.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)
Note
buf will be modified when the CMTI message is parsed
Returns
-1 on error (parse error) or the index of the new sms message

Definition at line 2328 of file chan_mobile.c.

2329 {
2330  int index = -1;
2331 
2332  /* parse cmti info in the following format:
2333  * +CMTI: <mem>,<index>
2334  */
2335  if (!sscanf(buf, "+CMTI: %*[^,],%d", &index)) {
2336  ast_debug(2, "[%s] error parsing CMTI event '%s'\n", hfp->owner->id, buf);
2337  return -1;
2338  }
2339 
2340  return index;
2341 }

References ast_debug, buf, mbl_pvt::id, and hfp_pvt::owner.

Referenced by handle_response_cmti().

◆ hfp_parse_cusd()

static char * hfp_parse_cusd ( struct hfp_pvt hfp,
char *  buf 
)
static

Parse a CUSD answer.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)
Note
buf will be modified when the CUSD string is parsed
Returns
NULL on error (parse error) or a pointer to the cusd message information in buf

Definition at line 2418 of file chan_mobile.c.

2419 {
2420  int i, message_start, message_end;
2421  char *cusd;
2422  size_t s;
2423 
2424  /* parse cusd message in the following format:
2425  * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#."
2426  */
2427  message_start = 0;
2428  message_end = 0;
2429  s = strlen(buf);
2430 
2431  /* Find the start of the message (") */
2432  for (i = 0; i < s; i++) {
2433  if (buf[i] == '"') {
2434  message_start = i + 1;
2435  break;
2436  }
2437  }
2438 
2439  if (message_start == 0 || message_start >= s) {
2440  return NULL;
2441  }
2442 
2443  /* Find the end of the message (") */
2444  for (i = s; i > 0; i--) {
2445  if (buf[i] == '"') {
2446  message_end = i;
2447  break;
2448  }
2449  }
2450 
2451  if (message_end == 0) {
2452  return NULL;
2453  }
2454 
2455  if (message_start >= message_end) {
2456  return NULL;
2457  }
2458 
2459  cusd = &buf[message_start];
2460  buf[message_end] = '\0';
2461 
2462  return cusd;
2463 }

References buf, and NULL.

Referenced by handle_response_cusd().

◆ hfp_parse_ecav()

static int hfp_parse_ecav ( struct hfp_pvt hfp,
char *  buf 
)
static

Parse a ECAV event.

Parameters
hfpan hfp_pvt struct
bufthe buffer to parse (null terminated)
Returns
-1 on error (parse error) or a ECAM value on success

Example:

*ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>]
                 [,exitcause][,<number>,<type>] 

Example indicating busy:

*ECAV: 1,7,1 

Definition at line 2166 of file chan_mobile.c.

2167 {
2168  int ccid = 0;
2169  int ccstatus = 0;
2170  int calltype = 0;
2171 
2172  if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
2173  ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
2174  return -1;
2175  }
2176 
2177  return ccstatus;
2178 }

References ast_debug, buf, mbl_pvt::id, and hfp_pvt::owner.

Referenced by do_monitor_phone().

◆ hfp_send_ata()

static int hfp_send_ata ( struct hfp_pvt hfp)
static

Send ATA.

Parameters
hfpan hfp_pvt struct

Definition at line 2704 of file chan_mobile.c.

2705 {
2706  return rfcomm_write(hfp->rsock, "ATA\r");
2707 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_answer().

◆ hfp_send_atd()

static int hfp_send_atd ( struct hfp_pvt hfp,
const char *  number 
)
static

Send ATD.

Parameters
hfpan hfp_pvt struct
numberthe number to send

Definition at line 2693 of file chan_mobile.c.

2694 {
2695  char cmd[64];
2696  snprintf(cmd, sizeof(cmd), "ATD%s;\r", number);
2697  return rfcomm_write(hfp->rsock, cmd);
2698 }
Number structure.
Definition: app_followme.c:154

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_call().

◆ hfp_send_brsf()

static int hfp_send_brsf ( struct hfp_pvt hfp,
struct hfp_hf brsf 
)
static

Send a BRSF request.

Parameters
hfpan hfp_pvt struct
brsfan hfp_hf brsf struct
Return values
0on success
-1on error

Definition at line 2516 of file chan_mobile.c.

2517 {
2518  char cmd[32];
2519  snprintf(cmd, sizeof(cmd), "AT+BRSF=%d\r", hfp_brsf2int(brsf));
2520  return rfcomm_write(hfp->rsock, cmd);
2521 }
static int hfp_brsf2int(struct hfp_hf *hf)
Convert a hfp_hf struct to a BRSF int.
Definition: chan_mobile.c:2470

References hfp_brsf2int(), rfcomm_write(), and hfp_pvt::rsock.

Referenced by do_monitor_phone().

◆ hfp_send_chup()

static int hfp_send_chup ( struct hfp_pvt hfp)
static

Send AT+CHUP.

Parameters
hfpan hfp_pvt struct

Definition at line 2683 of file chan_mobile.c.

2684 {
2685  return rfcomm_write(hfp->rsock, "AT+CHUP\r");
2686 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_clip(), and mbl_hangup().

◆ hfp_send_cind()

static int hfp_send_cind ( struct hfp_pvt hfp)
static

Send the CIND read command.

Parameters
hfpan hfp_pvt struct

Definition at line 2527 of file chan_mobile.c.

2528 {
2529  return rfcomm_write(hfp->rsock, "AT+CIND?\r");
2530 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

◆ hfp_send_cind_test()

static int hfp_send_cind_test ( struct hfp_pvt hfp)
static

Send the CIND test command.

Parameters
hfpan hfp_pvt struct

Definition at line 2536 of file chan_mobile.c.

2537 {
2538  return rfcomm_write(hfp->rsock, "AT+CIND=?\r");
2539 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

◆ hfp_send_clip()

static int hfp_send_clip ( struct hfp_pvt hfp,
int  status 
)
static

Enable or disable calling line identification.

Parameters
hfpan hfp_pvt struct
statusenable or disable calling line identification (should be 1 or 0)

Definition at line 2585 of file chan_mobile.c.

2586 {
2587  char cmd[32];
2588  snprintf(cmd, sizeof(cmd), "AT+CLIP=%d\r", status ? 1 : 0);
2589  return rfcomm_write(hfp->rsock, cmd);
2590 }
jack_status_t status
Definition: app_jack.c:146

References rfcomm_write(), hfp_pvt::rsock, and status.

Referenced by handle_response_ok().

◆ hfp_send_cmer()

static int hfp_send_cmer ( struct hfp_pvt hfp,
int  status 
)
static

Enable or disable indicator events reporting.

Parameters
hfpan hfp_pvt struct
statusenable or disable events reporting (should be 1 or 0)

Definition at line 2546 of file chan_mobile.c.

2547 {
2548  char cmd[32];
2549  snprintf(cmd, sizeof(cmd), "AT+CMER=3,0,0,%d\r", status ? 1 : 0);
2550  return rfcomm_write(hfp->rsock, cmd);
2551 }

References rfcomm_write(), hfp_pvt::rsock, and status.

Referenced by handle_response_ok().

◆ hfp_send_cmgf()

static int hfp_send_cmgf ( struct hfp_pvt hfp,
int  mode 
)
static

Set the SMS mode.

Parameters
hfpan hfp_pvt struct
modethe sms mode (0 = PDU, 1 = Text)

Definition at line 2627 of file chan_mobile.c.

2628 {
2629  char cmd[32];
2630  snprintf(cmd, sizeof(cmd), "AT+CMGF=%d\r", mode);
2631  return rfcomm_write(hfp->rsock, cmd);
2632 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_error(), and handle_response_ok().

◆ hfp_send_cmgr()

static int hfp_send_cmgr ( struct hfp_pvt hfp,
int  index 
)
static

Read an SMS message.

Parameters
hfpan hfp_pvt struct
indexthe location of the requested message

Definition at line 2648 of file chan_mobile.c.

2649 {
2650  char cmd[32];
2651  snprintf(cmd, sizeof(cmd), "AT+CMGR=%d\r", index);
2652  return rfcomm_write(hfp->rsock, cmd);
2653 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_cmti().

◆ hfp_send_cmgs()

static int hfp_send_cmgs ( struct hfp_pvt hfp,
const char *  number 
)
static

Start sending an SMS message.

Parameters
hfpan hfp_pvt struct
numberthe destination of the message

Definition at line 2660 of file chan_mobile.c.

2661 {
2662  char cmd[64];
2663  snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"\r", number);
2664  return rfcomm_write(hfp->rsock, cmd);
2665 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_sendsms_exec().

◆ hfp_send_cnmi()

static int hfp_send_cnmi ( struct hfp_pvt hfp)
static

Setup SMS new message indication.

Parameters
hfpan hfp_pvt struct

Definition at line 2638 of file chan_mobile.c.

2639 {
2640  return rfcomm_write(hfp->rsock, "AT+CNMI=2,1,0,0,0\r");
2641 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

◆ hfp_send_cusd()

static int hfp_send_cusd ( struct hfp_pvt hfp,
const char *  code 
)
static

Send CUSD.

Parameters
hfpan hfp_pvt struct
codethe CUSD code to send

Definition at line 2714 of file chan_mobile.c.

2715 {
2716  char cmd[128];
2717  snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code);
2718  return rfcomm_write(hfp->rsock, cmd);
2719 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_cli_mobile_cusd().

◆ hfp_send_dtmf()

static int hfp_send_dtmf ( struct hfp_pvt hfp,
char  digit 
)
static

Send a DTMF command.

Parameters
hfpan hfp_pvt struct
digitthe dtmf digit to send
Returns
the result of rfcomm_write() or -1 on an invalid digit being sent

Definition at line 2598 of file chan_mobile.c.

2599 {
2600  char cmd[10];
2601 
2602  switch(digit) {
2603  case '0':
2604  case '1':
2605  case '2':
2606  case '3':
2607  case '4':
2608  case '5':
2609  case '6':
2610  case '7':
2611  case '8':
2612  case '9':
2613  case '*':
2614  case '#':
2615  snprintf(cmd, sizeof(cmd), "AT+VTS=%c\r", digit);
2616  return rfcomm_write(hfp->rsock, cmd);
2617  default:
2618  return -1;
2619  }
2620 }
char digit

References digit, rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_digit_end().

◆ hfp_send_ecam()

static int hfp_send_ecam ( struct hfp_pvt hfp)
static

Enable Sony Ericsson extensions / indications.

Parameters
hfpan hfp_pvt struct

Definition at line 2184 of file chan_mobile.c.

2185 {
2186  return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
2187 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

◆ hfp_send_sms_text()

static int hfp_send_sms_text ( struct hfp_pvt hfp,
const char *  message 
)
static

Send the text of an SMS message.

Parameters
hfpan hfp_pvt struct
messagethe text of the message

Definition at line 2672 of file chan_mobile.c.

2673 {
2674  char cmd[162];
2675  snprintf(cmd, sizeof(cmd), "%.160s\x1a", message);
2676  return rfcomm_write(hfp->rsock, cmd);
2677 }

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_sms_prompt().

◆ hfp_send_vgs()

static int hfp_send_vgs ( struct hfp_pvt hfp,
int  value 
)
static

Send the current speaker gain level.

Parameters
hfpan hfp_pvt struct
valuethe value to send (must be between 0 and 15)

Definition at line 2558 of file chan_mobile.c.

2559 {
2560  char cmd[32];
2561  snprintf(cmd, sizeof(cmd), "AT+VGS=%d\r", value);
2562  return rfcomm_write(hfp->rsock, cmd);
2563 }

References rfcomm_write(), hfp_pvt::rsock, and value.

Referenced by handle_response_error(), and handle_response_ok().

◆ hsp_send_error()

static int hsp_send_error ( int  rsock)
static

Send an ERROR AT response.

Parameters
rsockthe rfcomm socket to use

Definition at line 2935 of file chan_mobile.c.

2936 {
2937  return rfcomm_write(rsock, "\r\nERROR\r\n");
2938 }

References rfcomm_write().

Referenced by do_monitor_headset().

◆ hsp_send_ok()

static int hsp_send_ok ( int  rsock)
static

Send an OK AT response.

Parameters
rsockthe rfcomm socket to use

Definition at line 2926 of file chan_mobile.c.

2927 {
2928  return rfcomm_write(rsock, "\r\nOK\r\n");
2929 }

References rfcomm_write().

Referenced by do_monitor_headset().

◆ hsp_send_ring()

static int hsp_send_ring ( int  rsock)
static

Send a RING unsolicited AT response.

Parameters
rsockthe rfcomm socket to use

Definition at line 2968 of file chan_mobile.c.

2969 {
2970  return rfcomm_write(rsock, "\r\nRING\r\n");
2971 }

References rfcomm_write().

Referenced by headset_send_ring(), and mbl_call().

◆ hsp_send_vgm()

static int hsp_send_vgm ( int  rsock,
int  gain 
)
static

Send a microphone gain unsolicited AT response.

Parameters
rsockthe rfcomm socket to use
gainthe microphone gain value

Definition at line 2957 of file chan_mobile.c.

2958 {
2959  char cmd[32];
2960  snprintf(cmd, sizeof(cmd), "\r\n+VGM=%d\r\n", gain);
2961  return rfcomm_write(rsock, cmd);
2962 }

References rfcomm_write().

Referenced by do_monitor_headset().

◆ hsp_send_vgs()

static int hsp_send_vgs ( int  rsock,
int  gain 
)
static

Send a speaker gain unsolicited AT response.

Parameters
rsockthe rfcomm socket to use
gainthe speaker gain value

Definition at line 2945 of file chan_mobile.c.

2946 {
2947  char cmd[32];
2948  snprintf(cmd, sizeof(cmd), "\r\n+VGS=%d\r\n", gain);
2949  return rfcomm_write(rsock, cmd);
2950 }

References rfcomm_write().

Referenced by do_monitor_headset().

◆ load_module()

static int load_module ( void  )
static

Definition at line 4778 of file chan_mobile.c.

4779 {
4780 
4781  int dev_id, s;
4782 
4784  return AST_MODULE_LOAD_DECLINE;
4785  }
4786 
4788  /* Check if we have Bluetooth, no point loading otherwise... */
4789  dev_id = hci_get_route(NULL);
4790 
4791  s = hci_open_dev(dev_id);
4792  if (dev_id < 0 || s < 0) {
4793  ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n");
4796  hci_close_dev(s);
4797  return AST_MODULE_LOAD_DECLINE;
4798  }
4799 
4800  hci_close_dev(s);
4801 
4802  if (mbl_load_config()) {
4803  ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG);
4806  return AST_MODULE_LOAD_DECLINE;
4807  }
4808 
4810 
4811  /* Spin the discovery thread */
4813  ast_log(LOG_ERROR, "Unable to create discovery thread.\n");
4814  goto e_cleanup;
4815  }
4816 
4817  /* register our channel type */
4819  ast_log(LOG_ERROR, "Unable to register channel class %s\n", "Mobile");
4820  goto e_cleanup;
4821  }
4822 
4823  ast_cli_register_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
4826 
4827  return AST_MODULE_LOAD_SUCCESS;
4828 
4829 e_cleanup:
4830  unload_module();
4831 
4832  return AST_MODULE_LOAD_DECLINE;
4833 }
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static char * mblsendsms_desc
Definition: chan_mobile.c:211
#define DEVICE_FRAME_FORMAT
Definition: chan_mobile.c:82
static char * app_mblsendsms
Definition: chan_mobile.c:209
#define MBL_CONFIG
Definition: chan_mobile.c:78
static int mbl_status_exec(struct ast_channel *ast, const char *data)
Definition: chan_mobile.c:715
static void * do_discovery(void *data)
Definition: chan_mobile.c:4284
static sdp_session_t * sdp_session
Definition: chan_mobile.c:87
static char * mblstatus_desc
Definition: chan_mobile.c:203
static int mbl_load_config(void)
Definition: chan_mobile.c:4626
static int mbl_sendsms_exec(struct ast_channel *ast, const char *data)
Definition: chan_mobile.c:763
static struct ast_cli_entry mbl_cli[]
Definition: chan_mobile.c:193
static char * app_mblstatus
Definition: chan_mobile.c:201
static char * mblstatus_synopsis
Definition: chan_mobile.c:202
static sdp_session_t * sdp_register(void)
Definition: chan_mobile.c:3121
static int unload_module(void)
Definition: chan_mobile.c:4704
static pthread_t discovery_thread
Definition: chan_mobile.c:86
static struct ast_channel_tech mbl_tech
Definition: chan_mobile.c:479
static char * mblsendsms_synopsis
Definition: chan_mobile.c:210
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:539
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
#define ast_register_application(app, execute, synopsis, description)
Register an application.
Definition: module.h:610
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
struct ast_format_cap * capabilities
Definition: channel.h:632
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:587

◆ mbl_answer()

static int mbl_answer ( struct ast_channel ast)
static

Definition at line 1066 of file chan_mobile.c.

1067 {
1068 
1069  struct mbl_pvt *pvt;
1070 
1071  pvt = ast_channel_tech_pvt(ast);
1072 
1073  if (pvt->type == MBL_TYPE_HEADSET)
1074  return 0;
1075 
1076  ast_mutex_lock(&pvt->lock);
1077  if (pvt->incoming) {
1078  hfp_send_ata(pvt->hfp);
1079  msg_queue_push(pvt, AT_OK, AT_A);
1080  pvt->answered = 1;
1081  }
1082  ast_mutex_unlock(&pvt->lock);
1083 
1084  return 0;
1085 
1086 }
static int hfp_send_ata(struct hfp_pvt *hfp)
Send ATA.
Definition: chan_mobile.c:2704
void * ast_channel_tech_pvt(const struct ast_channel *chan)
enum mbl_type type
Definition: chan_mobile.c:124

References mbl_pvt::answered, ast_channel_tech_pvt(), ast_mutex_lock, ast_mutex_unlock, AT_A, AT_OK, mbl_pvt::hfp, hfp_send_ata(), mbl_pvt::incoming, mbl_pvt::lock, MBL_TYPE_HEADSET, msg_queue_push(), and mbl_pvt::type.

◆ mbl_ast_hangup()

static int mbl_ast_hangup ( struct mbl_pvt pvt)
static

Definition at line 1354 of file chan_mobile.c.

1355 {
1356  ast_hangup(pvt->owner);
1357  return 0;
1358 }

References ast_hangup(), and mbl_pvt::owner.

Referenced by handle_response_clip(), and handle_response_cmgr().

◆ mbl_call()

static int mbl_call ( struct ast_channel ast,
const char *  dest,
int  timeout 
)
static

Definition at line 970 of file chan_mobile.c.

971 {
972  struct mbl_pvt *pvt;
973  char *dest_dev;
974  char *dest_num = NULL;
975 
976  dest_dev = ast_strdupa(dest);
977 
978  pvt = ast_channel_tech_pvt(ast);
979 
980  if (pvt->type == MBL_TYPE_PHONE) {
981  dest_num = strchr(dest_dev, '/');
982  if (!dest_num) {
983  ast_log(LOG_WARNING, "Cant determine destination number.\n");
984  return -1;
985  }
986  *dest_num++ = 0x00;
987  }
988 
990  ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
991  return -1;
992  }
993 
994  ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
995 
996  ast_mutex_lock(&pvt->lock);
997  if (pvt->type == MBL_TYPE_PHONE) {
998  if (hfp_send_atd(pvt->hfp, dest_num)) {
999  ast_mutex_unlock(&pvt->lock);
1000  ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
1001  return -1;
1002  }
1003  pvt->hangupcause = 0;
1004  pvt->needchup = 1;
1005  msg_queue_push(pvt, AT_OK, AT_D);
1006  } else {
1007  if (hsp_send_ring(pvt->rfcomm_socket)) {
1008  ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
1009  ast_mutex_unlock(&pvt->lock);
1010  return -1;
1011  }
1012 
1013  if ((pvt->ring_sched_id = ast_sched_add(pvt->sched, 6000, headset_send_ring, pvt)) == -1) {
1014  ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
1015  ast_mutex_unlock(&pvt->lock);
1016  return -1;
1017  }
1018 
1019  pvt->outgoing = 1;
1020  pvt->needring = 1;
1021  }
1022  ast_mutex_unlock(&pvt->lock);
1023 
1024  return 0;
1025 
1026 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
static int hfp_send_atd(struct hfp_pvt *hfp, const char *number)
Send ATD.
Definition: chan_mobile.c:2693
static int headset_send_ring(const void *data)
Definition: chan_mobile.c:4104
const char * ast_channel_name(const struct ast_channel *chan)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_RESERVED
Definition: channelstate.h:37
#define LOG_WARNING
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:567
int ring_sched_id
Definition: chan_mobile.c:147

References ast_channel_name(), ast_channel_tech_pvt(), ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_sched_add(), AST_STATE_DOWN, AST_STATE_RESERVED, ast_strdupa, AT_D, AT_OK, mbl_pvt::hangupcause, headset_send_ring(), mbl_pvt::hfp, hfp_send_atd(), hsp_send_ring(), mbl_pvt::id, mbl_pvt::lock, LOG_ERROR, LOG_WARNING, MBL_TYPE_PHONE, msg_queue_push(), mbl_pvt::needchup, mbl_pvt::needring, NULL, mbl_pvt::outgoing, mbl_pvt::rfcomm_socket, mbl_pvt::ring_sched_id, mbl_pvt::sched, and mbl_pvt::type.

◆ mbl_devicestate()

static int mbl_devicestate ( const char *  data)
static

Definition at line 1214 of file chan_mobile.c.

1215 {
1216 
1217  char *device;
1218  int res = AST_DEVICE_INVALID;
1219  struct mbl_pvt *pvt;
1220 
1221  device = ast_strdupa(S_OR(data, ""));
1222 
1223  ast_debug(1, "Checking device state for device %s\n", device);
1224 
1227  if (!strcmp(pvt->id, device))
1228  break;
1229  }
1231 
1232  if (!pvt)
1233  return res;
1234 
1235  ast_mutex_lock(&pvt->lock);
1236  if (pvt->connected) {
1237  if (pvt->owner)
1238  res = AST_DEVICE_INUSE;
1239  else
1240  res = AST_DEVICE_NOT_INUSE;
1241 
1242  if (!mbl_has_service(pvt))
1243  res = AST_DEVICE_UNAVAILABLE;
1244  }
1245  ast_mutex_unlock(&pvt->lock);
1246 
1247  return res;
1248 
1249 }
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80

References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, mbl_pvt::connected, mbl_pvt::id, mbl_pvt::lock, mbl_has_service(), mbl_pvt::owner, and S_OR.

◆ mbl_digit_end()

static int mbl_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
)
static

Definition at line 1088 of file chan_mobile.c.

1089 {
1090  struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
1091 
1092  if (pvt->type == MBL_TYPE_HEADSET)
1093  return 0;
1094 
1095  ast_mutex_lock(&pvt->lock);
1096  if (hfp_send_dtmf(pvt->hfp, digit)) {
1097  ast_mutex_unlock(&pvt->lock);
1098  ast_debug(1, "[%s] error sending digit %c\n", pvt->id, digit);
1099  return -1;
1100  }
1101  msg_queue_push(pvt, AT_OK, AT_VTS);
1102  ast_mutex_unlock(&pvt->lock);
1103 
1104  ast_debug(1, "[%s] dialed %c\n", pvt->id, digit);
1105 
1106  return 0;
1107 }
static int hfp_send_dtmf(struct hfp_pvt *hfp, char digit)
Send a DTMF command.
Definition: chan_mobile.c:2598

References ast_channel_tech_pvt(), ast_debug, ast_mutex_lock, ast_mutex_unlock, AT_OK, AT_VTS, digit, mbl_pvt::hfp, hfp_send_dtmf(), mbl_pvt::id, mbl_pvt::lock, MBL_TYPE_HEADSET, msg_queue_push(), and mbl_pvt::type.

◆ mbl_fixup()

static int mbl_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
)
static

Definition at line 1195 of file chan_mobile.c.

1196 {
1197 
1198  struct mbl_pvt *pvt = ast_channel_tech_pvt(newchan);
1199 
1200  if (!pvt) {
1201  ast_debug(1, "fixup failed, no pvt on newchan\n");
1202  return -1;
1203  }
1204 
1205  ast_mutex_lock(&pvt->lock);
1206  if (pvt->owner == oldchan)
1207  pvt->owner = newchan;
1208  ast_mutex_unlock(&pvt->lock);
1209 
1210  return 0;
1211 
1212 }

References ast_channel_tech_pvt(), ast_debug, ast_mutex_lock, ast_mutex_unlock, mbl_pvt::lock, and mbl_pvt::owner.

◆ mbl_hangup()

static int mbl_hangup ( struct ast_channel ast)
static

Definition at line 1028 of file chan_mobile.c.

1029 {
1030 
1031  struct mbl_pvt *pvt;
1032 
1033  if (!ast_channel_tech_pvt(ast)) {
1034  ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
1035  return 0;
1036  }
1037  pvt = ast_channel_tech_pvt(ast);
1038 
1039  ast_debug(1, "[%s] hanging up device\n", pvt->id);
1040 
1041  ast_mutex_lock(&pvt->lock);
1042  ast_channel_set_fd(ast, 0, -1);
1043  close(pvt->sco_socket);
1044  pvt->sco_socket = -1;
1045 
1046  if (pvt->needchup) {
1047  hfp_send_chup(pvt->hfp);
1048  msg_queue_push(pvt, AT_OK, AT_CHUP);
1049  pvt->needchup = 0;
1050  }
1051 
1052  pvt->outgoing = 0;
1053  pvt->incoming = 0;
1054  pvt->needring = 0;
1055  pvt->owner = NULL;
1057 
1058  ast_mutex_unlock(&pvt->lock);
1059 
1061 
1062  return 0;
1063 
1064 }
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)

References ast_channel_set_fd(), ast_channel_tech_pvt(), ast_channel_tech_pvt_set(), ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_setstate(), AST_STATE_DOWN, AT_CHUP, AT_OK, mbl_pvt::hfp, hfp_send_chup(), mbl_pvt::id, mbl_pvt::incoming, mbl_pvt::lock, LOG_WARNING, msg_queue_push(), mbl_pvt::needchup, mbl_pvt::needring, NULL, mbl_pvt::outgoing, mbl_pvt::owner, and mbl_pvt::sco_socket.

◆ mbl_has_service()

static int mbl_has_service ( struct mbl_pvt pvt)
static

Check if a mobile device has service.

Parameters
pvta mbl_pvt struct
Return values
1this device has service
0no service
Note
This function will always indicate that service is available if the given device does not support service indication.

Definition at line 1369 of file chan_mobile.c.

1370 {
1371 
1372  if (pvt->type != MBL_TYPE_PHONE)
1373  return 1;
1374 
1375  if (!pvt->hfp->cind_map.service)
1376  return 1;
1377 
1379  return 1;
1380 
1381  return 0;
1382 }
#define HFP_CIND_SERVICE_AVAILABLE
Definition: chan_mobile.c:297

References hfp_pvt::cind_map, hfp_pvt::cind_state, mbl_pvt::hfp, HFP_CIND_SERVICE_AVAILABLE, MBL_TYPE_PHONE, hfp_cind::service, and mbl_pvt::type.

Referenced by handle_cli_mobile_show_devices(), mbl_devicestate(), and mbl_request().

◆ mbl_load_adapter()

static struct adapter_pvt* mbl_load_adapter ( struct ast_config cfg,
const char *  cat 
)
static

Load an adapter from the configuration file.

Parameters
cfgthe config to load the adapter from
catthe adapter to load

This function loads the given adapter and starts the sco listener thread for that adapter.

Returns
NULL on error, a pointer to the adapter that was loaded on success

Definition at line 4366 of file chan_mobile.c.

4367 {
4368  const char *id, *address;
4369  struct adapter_pvt *adapter;
4370  struct ast_variable *v;
4371  struct hci_dev_req dr;
4372  uint16_t vs;
4373 
4374  id = ast_variable_retrieve(cfg, cat, "id");
4375  address = ast_variable_retrieve(cfg, cat, "address");
4376 
4377  if (ast_strlen_zero(id) || ast_strlen_zero(address)) {
4378  ast_log(LOG_ERROR, "Skipping adapter. Missing id or address settings.\n");
4379  goto e_return;
4380  }
4381 
4382  ast_debug(1, "Reading configuration for adapter %s %s.\n", id, address);
4383 
4384  if (!(adapter = ast_calloc(1, sizeof(*adapter)))) {
4385  ast_log(LOG_ERROR, "Skipping adapter %s. Error allocating memory.\n", id);
4386  goto e_return;
4387  }
4388 
4389  ast_copy_string(adapter->id, id, sizeof(adapter->id));
4390  str2ba(address, &adapter->addr);
4391 
4392  /* attempt to connect to the adapter */
4393  adapter->dev_id = hci_devid(address);
4394  adapter->hci_socket = hci_open_dev(adapter->dev_id);
4395  if (adapter->dev_id < 0 || adapter->hci_socket < 0) {
4396  ast_log(LOG_ERROR, "Skipping adapter %s. Unable to communicate with adapter.\n", adapter->id);
4397  goto e_free_adapter;
4398  }
4399 
4400  /* check voice setting */
4401  hci_read_voice_setting(adapter->hci_socket, &vs, 1000);
4402  vs = htobs(vs);
4403  if (vs != 0x0060) {
4404  ast_log(LOG_ERROR, "Skipping adapter %s. Voice setting must be 0x0060 - see 'man hciconfig' for details.\n", adapter->id);
4405  goto e_hci_close_dev;
4406  }
4407 
4408  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4409  if (!strcasecmp(v->name, "forcemaster")) {
4410  if (ast_true(v->value)) {
4411  dr.dev_id = adapter->dev_id;
4412  if (hci_strtolm("master", &dr.dev_opt)) {
4413  if (ioctl(adapter->hci_socket, HCISETLINKMODE, (unsigned long) &dr) < 0) {
4414  ast_log(LOG_WARNING, "Unable to set adapter %s link mode to MASTER. Ignoring 'forcemaster' option.\n", adapter->id);
4415  }
4416  }
4417  }
4418  } else if (!strcasecmp(v->name, "alignmentdetection")) {
4419  adapter->alignment_detection = ast_true(v->value);
4420  }
4421  }
4422 
4423  /* create io contexts */
4424  if (!(adapter->accept_io = io_context_create())) {
4425  ast_log(LOG_ERROR, "Unable to create I/O context for audio connection listener\n");
4426  goto e_hci_close_dev;
4427  }
4428 
4429  if (!(adapter->io = io_context_create())) {
4430  ast_log(LOG_ERROR, "Unable to create I/O context for audio connections\n");
4431  goto e_destroy_accept_io;
4432  }
4433 
4434  /* bind the sco listener socket */
4435  if (sco_bind(adapter) < 0) {
4436  ast_log(LOG_ERROR, "Skipping adapter %s. Error binding audio connection listener socket.\n", adapter->id);
4437  goto e_destroy_io;
4438  }
4439 
4440  /* add the socket to the io context */
4441  if (!(adapter->sco_id = ast_io_add(adapter->accept_io, adapter->sco_socket, sco_accept, AST_IO_IN, adapter))) {
4442  ast_log(LOG_ERROR, "Skipping adapter %s. Error adding listener socket to I/O context.\n", adapter->id);
4443  goto e_close_sco;
4444  }
4445 
4446  /* start the sco listener for this adapter */
4448  ast_log(LOG_ERROR, "Skipping adapter %s. Error creating audio connection listener thread.\n", adapter->id);
4449  goto e_remove_sco;
4450  }
4451 
4452  /* add the adapter to our global list */
4456  ast_debug(1, "Loaded adapter %s %s.\n", adapter->id, address);
4457 
4458  return adapter;
4459 
4460 e_remove_sco:
4461  ast_io_remove(adapter->accept_io, adapter->sco_id);
4462 e_close_sco:
4463  close(adapter->sco_socket);
4464 e_destroy_io:
4465  io_context_destroy(adapter->io);
4466 e_destroy_accept_io:
4467  io_context_destroy(adapter->accept_io);
4468 e_hci_close_dev:
4469  hci_close_dev(adapter->hci_socket);
4470 e_free_adapter:
4471  ast_free(adapter);
4472 e_return:
4473  return NULL;
4474 }
enum queue_result id
Definition: app_queue.c:1640
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static int sco_accept(int *id, int fd, short events, void *data)
Accept SCO connections. This function is an ast_io callback function used to accept incoming sco audi...
Definition: chan_mobile.c:1898
static int sco_bind(struct adapter_pvt *adapter)
Bind an SCO listener socket for the given adapter.
Definition: chan_mobile.c:1958
static void * do_sco_listen(void *data)
Service new and existing SCO connections. This thread accepts new sco connections and handles audio d...
Definition: chan_mobile.c:4328
char * address
Definition: f2c.h:59
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:768
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#define AST_IO_IN
Definition: io.h:34
void io_context_destroy(struct io_context *ioc)
Destroys a context.
Definition: io.c:107
struct io_context * io_context_create(void)
Creates a context Create a context for I/O operations Basically mallocs an IO structure and sets up s...
Definition: io.c:81
int * ast_io_add(struct io_context *ioc, int fd, ast_io_cb callback, short events, void *data)
Adds an IO context.
Definition: io.c:162
int ast_io_remove(struct io_context *ioc, int *id)
Removes an IO context.
Definition: io.c:245
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: main/utils.c:2097
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
pthread_t sco_listener_thread
Definition: chan_mobile.c:110
unsigned int alignment_detection
Definition: chan_mobile.c:105
int * sco_id
Definition: chan_mobile.c:108
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
static float dr[4]
Definition: tdd.c:58

References adapter_pvt::accept_io, adapter_pvt::addr, adapter_pvt::alignment_detection, ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_io_add(), AST_IO_IN, ast_io_remove(), ast_log, ast_pthread_create_background, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), adapter_pvt::dev_id, do_sco_listen(), dr, adapter_pvt::hci_socket, adapter_pvt::id, id, adapter_pvt::io, io_context_create(), io_context_destroy(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, NULL, sco_accept(), sco_bind(), adapter_pvt::sco_id, adapter_pvt::sco_listener_thread, adapter_pvt::sco_socket, and ast_variable::value.

Referenced by mbl_load_config().

◆ mbl_load_config()

static int mbl_load_config ( void  )
static

Definition at line 4626 of file chan_mobile.c.

4627 {
4628  struct ast_config *cfg;
4629  const char *cat;
4630  struct ast_variable *v;
4631  struct ast_flags config_flags = { 0 };
4632 
4633  cfg = ast_config_load(MBL_CONFIG, config_flags);
4634  if (!cfg) {
4635  cfg = ast_config_load(MBL_CONFIG_OLD, config_flags);
4636  }
4637  if (!cfg)
4638  return -1;
4639 
4640  /* parse [general] section */
4641  for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
4642  if (!strcasecmp(v->name, "interval")) {
4643  if (!sscanf(v->value, "%d", &discovery_interval)) {
4644  ast_log(LOG_NOTICE, "error parsing 'interval' in general section, using default value\n");
4645  }
4646  }
4647  }
4648 
4649  /* load adapters */
4650  for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
4651  if (!strcasecmp(cat, "adapter")) {
4652  mbl_load_adapter(cfg, cat);
4653  }
4654  }
4655 
4656  if (AST_RWLIST_EMPTY(&adapters)) {
4658  "***********************************************************************\n"
4659  "No adapters could be loaded from the configuration file.\n"
4660  "Please review mobile.conf. See sample for details.\n"
4661  "***********************************************************************\n"
4662  );
4663  ast_config_destroy(cfg);
4664  return -1;
4665  }
4666 
4667  /* now load devices */
4668  for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
4669  if (strcasecmp(cat, "general") && strcasecmp(cat, "adapter")) {
4670  mbl_load_device(cfg, cat);
4671  }
4672  }
4673 
4674  ast_config_destroy(cfg);
4675 
4676  return 0;
4677 }
static struct mbl_pvt * mbl_load_device(struct ast_config *cfg, const char *cat)
Load a device from the configuration file.
Definition: chan_mobile.c:4482
#define MBL_CONFIG_OLD
Definition: chan_mobile.c:79
static struct adapter_pvt * mbl_load_adapter(struct ast_config *cfg, const char *cat)
Load an adapter from the configuration file.
Definition: chan_mobile.c:4366
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3327
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
#define LOG_NOTICE
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:452
Structure used to handle boolean flags.
Definition: utils.h:199

References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_log, AST_RWLIST_EMPTY, ast_variable_browse(), discovery_interval, LOG_ERROR, LOG_NOTICE, MBL_CONFIG, MBL_CONFIG_OLD, mbl_load_adapter(), mbl_load_device(), ast_variable::name, ast_variable::next,