Asterisk - The Open Source Telephony Project GIT-master-a358458
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,
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,
449 AT_CUSD,
450 AT_BUSY,
453 AT_ECAM,
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:190
#define ast_mutex_lock(a)
Definition: lock.h:189

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
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().

Referenced by load_module().

◆ 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;
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 */
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
4235e_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:2541
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2426
@ 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:4708
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;
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
4074e_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
703e_unlock_pvt:
704 ast_mutex_unlock(&pvt->lock);
705e_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
653e_unlock_pvt:
654 ast_mutex_unlock(&pvt->lock);
655e_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 */
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
3221e_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;
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) {
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:7386
@ 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
3263e_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);
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:1639
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
3549e_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
3432e_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:666

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}
enum cc_state state
Definition: ccss.c:393
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
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;
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;
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 2226 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]], "\"", "\"");
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:1053
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: utils.c:1818
char * cnam
Definition: chan_mobile.c:169
char * cnum
Definition: chan_mobile.c:168

References ARRAY_LEN, ast_debug, ast_isphonenumber(), ast_strip_quoted(), buf, cidinfo::cnam, cidinfo::cnum, NULL, and parse_next_token().

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
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);
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);
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
4828
4829e_cleanup:
4830 unload_module();
4831
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 int unload_module(void)
Definition: chan_mobile.c:4704
static pthread_t discovery_thread
Definition: chan_mobile.c:86
static sdp_session_t * sdp_register(void)
Definition: chan_mobile.c:3121
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:592

References ao2_ref, app_mblsendsms, app_mblstatus, ast_channel_register(), ast_cli_register_multiple, ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_pthread_create_background, ast_register_application, ast_channel_tech::capabilities, adapter_pvt::dev_id, DEVICE_FRAME_FORMAT, discovery_thread, do_discovery(), LOG_ERROR, mbl_cli, MBL_CONFIG, mbl_load_config(), mbl_sendsms_exec(), mbl_status_exec(), mbl_tech, mblsendsms_desc, mblsendsms_synopsis, mblstatus_desc, mblstatus_synopsis, NULL, sdp_register(), sdp_session, and unload_module().

◆ 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
1241
1242 if (!mbl_has_service(pvt))
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 }
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);
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
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
4460e_remove_sco:
4461 ast_io_remove(adapter->accept_io, adapter->sco_id);
4462e_close_sco:
4463 close(adapter->sco_socket);
4464e_destroy_io:
4465 io_context_destroy(adapter->io);
4466e_destroy_accept_io:
4467 io_context_destroy(adapter->accept_io);
4468e_hci_close_dev:
4469 hci_close_dev(adapter->hci_socket);
4470e_free_adapter:
4471 ast_free(adapter);
4472e_return:
4473 return NULL;
4474}
enum queue_result id
Definition: app_queue.c:1638
#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:783
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
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
void io_context_destroy(struct io_context *ioc)
Destroys a context.
Definition: io.c:107
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: utils.c:2199
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:425
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 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 MBL_CONFIG_OLD
Definition: chan_mobile.c:79
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 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:3326
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, NULL, and ast_variable::value.

Referenced by load_module().

◆ mbl_load_device()

static struct mbl_pvt * mbl_load_device ( struct ast_config cfg,
const char *  cat 
)
static

Load a device from the configuration file.

Parameters
cfgthe config to load the device from
catthe device to load
Returns
NULL on error, a pointer to the device that was loaded on success

Definition at line 4482 of file chan_mobile.c.

4483{
4484 struct mbl_pvt *pvt;
4485 struct adapter_pvt *adapter;
4486 struct ast_variable *v;
4487 const char *address, *adapter_str, *port;
4488 ast_debug(1, "Reading configuration for device %s.\n", cat);
4489
4490 adapter_str = ast_variable_retrieve(cfg, cat, "adapter");
4491 if(ast_strlen_zero(adapter_str)) {
4492 ast_log(LOG_ERROR, "Skipping device %s. No adapter specified.\n", cat);
4493 goto e_return;
4494 }
4495
4496 /* find the adapter */
4498 AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
4499 if (!strcmp(adapter->id, adapter_str))
4500 break;
4501 }
4503 if (!adapter) {
4504 ast_log(LOG_ERROR, "Skipping device %s. Unknown adapter '%s' specified.\n", cat, adapter_str);
4505 goto e_return;
4506 }
4507
4508 address = ast_variable_retrieve(cfg, cat, "address");
4509 port = ast_variable_retrieve(cfg, cat, "port");
4510 if (ast_strlen_zero(port) || ast_strlen_zero(address)) {
4511 ast_log(LOG_ERROR, "Skipping device %s. Missing required port or address setting.\n", cat);
4512 goto e_return;
4513 }
4514
4515 /* create and initialize our pvt structure */
4516 if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
4517 ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", cat);
4518 goto e_return;
4519 }
4520
4521 ast_mutex_init(&pvt->lock);
4523
4524 /* set some defaults */
4525
4526 pvt->type = MBL_TYPE_PHONE;
4527 ast_copy_string(pvt->context, "default", sizeof(pvt->context));
4528
4529 /* populate the pvt structure */
4530 pvt->adapter = adapter;
4531 ast_copy_string(pvt->id, cat, sizeof(pvt->id));
4532 str2ba(address, &pvt->addr);
4533 pvt->timeout = -1;
4534 pvt->rfcomm_socket = -1;
4535 pvt->rfcomm_port = atoi(port);
4536 pvt->sco_socket = -1;
4538 pvt->ring_sched_id = -1;
4539 pvt->has_sms = 1;
4540
4541 /* setup the bt_out_smoother */
4543 ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_out_smoother.\n", cat);
4544 goto e_free_pvt;
4545 }
4546
4547 /* setup the bt_in_smoother */
4549 ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_in_smoother.\n", cat);
4550 goto e_free_bt_out_smoother;
4551 }
4552
4553 /* setup the dsp */
4554 if (!(pvt->dsp = ast_dsp_new())) {
4555 ast_log(LOG_ERROR, "Skipping device %s. Error setting up dsp for dtmf detection.\n", cat);
4556 goto e_free_bt_in_smoother;
4557 }
4558
4559 /* setup the scheduler */
4560 if (!(pvt->sched = ast_sched_context_create())) {
4561 ast_log(LOG_ERROR, "Unable to create scheduler context for headset device\n");
4562 goto e_free_dsp;
4563 }
4564
4567
4568 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4569 if (!strcasecmp(v->name, "type")) {
4570 if (!strcasecmp(v->value, "headset"))
4571 pvt->type = MBL_TYPE_HEADSET;
4572 else
4573 pvt->type = MBL_TYPE_PHONE;
4574 } else if (!strcasecmp(v->name, "context")) {
4575 ast_copy_string(pvt->context, v->value, sizeof(pvt->context));
4576 } else if (!strcasecmp(v->name, "group")) {
4577 /* group is set to 0 if invalid */
4578 pvt->group = atoi(v->value);
4579 } else if (!strcasecmp(v->name, "sms")) {
4580 pvt->has_sms = ast_true(v->value);
4581 } else if (!strcasecmp(v->name, "nocallsetup")) {
4582 pvt->no_callsetup = ast_true(v->value);
4583
4584 if (pvt->no_callsetup)
4585 ast_debug(1, "Setting nocallsetup mode for device %s.\n", pvt->id);
4586 } else if (!strcasecmp(v->name, "blackberry")) {
4587 pvt->blackberry = ast_true(v->value);
4588 pvt->has_sms = 0;
4589 }
4590 }
4591
4592 if (pvt->type == MBL_TYPE_PHONE) {
4593 if (!(pvt->hfp = ast_calloc(1, sizeof(*pvt->hfp)))) {
4594 ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", pvt->id);
4595 goto e_free_sched;
4596 }
4597
4598 pvt->hfp->owner = pvt;
4599 pvt->hfp->rport = pvt->rfcomm_port;
4600 pvt->hfp->nocallsetup = pvt->no_callsetup;
4601 } else {
4602 pvt->has_sms = 0;
4603 }
4604
4608 ast_debug(1, "Loaded device %s.\n", pvt->id);
4609
4610 return pvt;
4611
4612e_free_sched:
4614e_free_dsp:
4615 ast_dsp_free(pvt->dsp);
4616e_free_bt_in_smoother:
4618e_free_bt_out_smoother:
4620e_free_pvt:
4621 ast_free(pvt);
4622e_return:
4623 return NULL;
4624}
#define DEVICE_FRAME_SIZE
Definition: chan_mobile.c:81
#define CHANNEL_FRAME_SIZE
Definition: chan_mobile.c:83
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition: dsp.c:1857
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
#define DSP_DIGITMODE_DTMF
Definition: dsp.h:31
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
#define DSP_DIGITMODE_RELAXDTMF
Definition: dsp.h:37
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_mutex_init(pmutex)
Definition: lock.h:186
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
void ast_smoother_free(struct ast_smoother *s)
Definition: smoother.c:220
struct ast_smoother * ast_smoother_new(int bytes)
Definition: smoother.c:108
int rport
Definition: chan_mobile.c:353
struct mbl_pvt::msg_queue msg_queue
struct ast_smoother * bt_in_smoother
Definition: chan_mobile.c:136
struct ast_smoother * bt_out_smoother
Definition: chan_mobile.c:135
struct ast_dsp * dsp
Definition: chan_mobile.c:148
char context[AST_MAX_CONTEXT]
Definition: chan_mobile.c:129
pthread_t monitor_thread
Definition: chan_mobile.c:138

References mbl_pvt::adapter, mbl_pvt::addr, ast_calloc, ast_copy_string(), ast_debug, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_digitmode(), ast_dsp_set_features(), ast_free, AST_LIST_HEAD_INIT_NOLOCK, ast_log, ast_mutex_init, AST_PTHREADT_NULL, AST_RWLIST_INSERT_HEAD, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sched_context_create(), ast_sched_context_destroy(), ast_smoother_free(), ast_smoother_new(), ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), mbl_pvt::blackberry, mbl_pvt::bt_in_smoother, mbl_pvt::bt_out_smoother, CHANNEL_FRAME_SIZE, mbl_pvt::context, DEVICE_FRAME_SIZE, mbl_pvt::dsp, DSP_DIGITMODE_DTMF, DSP_DIGITMODE_RELAXDTMF, DSP_FEATURE_DIGIT_DETECT, mbl_pvt::group, mbl_pvt::has_sms, mbl_pvt::hfp, adapter_pvt::id, mbl_pvt::id, mbl_pvt::lock, LOG_ERROR, MBL_TYPE_HEADSET, MBL_TYPE_PHONE, mbl_pvt::monitor_thread, mbl_pvt::msg_queue, ast_variable::name, ast_variable::next, mbl_pvt::no_callsetup, hfp_pvt::nocallsetup, NULL, hfp_pvt::owner, mbl_pvt::rfcomm_port, mbl_pvt::rfcomm_socket, mbl_pvt::ring_sched_id, hfp_pvt::rport, mbl_pvt::sched, mbl_pvt::sco_socket, mbl_pvt::timeout, mbl_pvt::type, and ast_variable::value.

Referenced by mbl_load_config().

◆ mbl_new()

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 
)
static

Definition at line 847 of file chan_mobile.c.

849{
850 struct ast_channel *chn;
851
852 pvt->answered = 0;
853 pvt->alignment_count = 0;
856 pvt->do_alignment_detection = 1;
857 else
858 pvt->do_alignment_detection = 0;
859
863
864 chn = ast_channel_alloc(1, state,
867 0, 0, pvt->context, assignedids, requestor, 0,
868 "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
869 if (!chn) {
870 goto e_return;
871 }
872
879 ast_channel_tech_pvt_set(chn, pvt);
880
881 if (state == AST_STATE_RING)
882 ast_channel_rings_set(chn, 1);
883
884 ast_channel_language_set(chn, "en");
885 pvt->owner = chn;
886
887 if (pvt->sco_socket != -1) {
888 ast_channel_set_fd(chn, 0, pvt->sco_socket);
889 }
891
892 return chn;
893
894e_return:
895 return NULL;
896}
void ast_channel_rings_set(struct ast_channel *chan, int value)
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1258
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
void ast_dsp_digitreset(struct ast_dsp *dsp)
Reset DTMF detector.
Definition: dsp.c:1810
void ast_smoother_reset(struct ast_smoother *s, int bytes)
Definition: smoother.c:79
long int ast_random(void)
Definition: utils.c:2312

References mbl_pvt::adapter, mbl_pvt::alignment_count, adapter_pvt::alignment_detection, mbl_pvt::alignment_detection_triggered, mbl_pvt::answered, ast_channel_alloc, ast_channel_nativeformats_set(), ast_channel_rings_set(), ast_channel_set_fd(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_set_readformat(), ast_channel_set_writeformat(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_unlock, ast_dsp_digitreset(), ast_random(), ast_smoother_reset(), AST_STATE_RING, mbl_pvt::bt_in_smoother, mbl_pvt::bt_out_smoother, ast_channel_tech::capabilities, CHANNEL_FRAME_SIZE, cidinfo::cnam, cidinfo::cnum, mbl_pvt::context, DEVICE_FRAME_FORMAT, DEVICE_FRAME_SIZE, mbl_pvt::do_alignment_detection, mbl_pvt::dsp, mbl_pvt::id, mbl_tech, NULL, mbl_pvt::owner, and mbl_pvt::sco_socket.

Referenced by do_monitor_headset(), handle_response_clip(), handle_response_cmgr(), and mbl_request().

◆ mbl_queue_control()

static int mbl_queue_control ( struct mbl_pvt pvt,
enum ast_control_frame_type  control 
)
static

Definition at line 1317 of file chan_mobile.c.

1318{
1319 for (;;) {
1320 if (pvt->owner) {
1321 if (ast_channel_trylock(pvt->owner)) {
1322 DEADLOCK_AVOIDANCE(&pvt->lock);
1323 } else {
1324 ast_queue_control(pvt->owner, control);
1326 break;
1327 }
1328 } else
1329 break;
1330 }
1331 return 0;
1332}
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1231
#define ast_channel_trylock(chan)
Definition: channel.h:2924
#define DEADLOCK_AVOIDANCE(lock)
Definition: lock.h:479

References ast_channel_trylock, ast_channel_unlock, ast_queue_control(), DEADLOCK_AVOIDANCE, mbl_pvt::lock, and mbl_pvt::owner.

Referenced by do_monitor_headset(), handle_response_busy(), handle_response_ciev(), handle_response_error(), handle_response_no_carrier(), handle_response_no_dialtone(), and handle_response_ok().

◆ mbl_queue_hangup()

static int mbl_queue_hangup ( struct mbl_pvt pvt)
static

Definition at line 1334 of file chan_mobile.c.

1335{
1336 for (;;) {
1337 if (pvt->owner) {
1338 if (ast_channel_trylock(pvt->owner)) {
1339 DEADLOCK_AVOIDANCE(&pvt->lock);
1340 } else {
1341 if (pvt->hangupcause != 0) {
1343 }
1344 ast_queue_hangup(pvt->owner);
1346 break;
1347 }
1348 } else
1349 break;
1350 }
1351 return 0;
1352}
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1150
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)

References ast_channel_hangupcause_set(), ast_channel_trylock, ast_channel_unlock, ast_queue_hangup(), DEADLOCK_AVOIDANCE, mbl_pvt::hangupcause, mbl_pvt::lock, and mbl_pvt::owner.

Referenced by do_monitor_headset(), do_monitor_phone(), handle_response_ciev(), and handle_response_error().

◆ mbl_read()

static struct ast_frame * mbl_read ( struct ast_channel ast)
static

Definition at line 1109 of file chan_mobile.c.

1110{
1111
1112 struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
1113 struct ast_frame *fr = &ast_null_frame;
1114 int r;
1115
1116 ast_debug(3, "*** mbl_read()\n");
1117
1118 while (ast_mutex_trylock(&pvt->lock)) {
1120 }
1121
1122 if (!pvt->owner || pvt->sco_socket == -1) {
1123 goto e_return;
1124 }
1125
1126 memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
1129 pvt->fr.src = "Mobile";
1131 pvt->fr.mallocd = 0;
1132 pvt->fr.delivery.tv_sec = 0;
1133 pvt->fr.delivery.tv_usec = 0;
1134 pvt->fr.data.ptr = pvt->io_buf + AST_FRIENDLY_OFFSET;
1135
1136 do {
1137 if ((r = read(pvt->sco_socket, pvt->fr.data.ptr, DEVICE_FRAME_SIZE)) == -1) {
1138 if (errno != EAGAIN && errno != EINTR) {
1139 ast_debug(1, "[%s] read error %d, going to wait for new connection\n", pvt->id, errno);
1140 close(pvt->sco_socket);
1141 pvt->sco_socket = -1;
1142 ast_channel_set_fd(ast, 0, -1);
1143 }
1144 goto e_return;
1145 }
1146
1147 pvt->fr.datalen = r;
1148 pvt->fr.samples = r / 2;
1149
1150 if (pvt->do_alignment_detection)
1151 do_alignment_detection(pvt, pvt->fr.data.ptr, r);
1152
1153 ast_smoother_feed(pvt->bt_in_smoother, &pvt->fr);
1155 } while (fr == NULL);
1156 fr = ast_dsp_process(ast, pvt->dsp, fr);
1157
1158 ast_mutex_unlock(&pvt->lock);
1159
1160 return fr;
1161
1162e_return:
1163 ast_mutex_unlock(&pvt->lock);
1164 return fr;
1165}
static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen)
Definition: chan_mobile.c:1281
struct ast_frame * ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *inf)
Return AST_FRAME_NULL frames when there is silence, AST_FRAME_BUSY on busies, and call progress,...
Definition: dsp.c:1499
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_VOICE
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition: lock.h:474
#define ast_mutex_trylock(a)
Definition: lock.h:191
struct ast_frame * ast_smoother_read(struct ast_smoother *s)
Definition: smoother.c:169
#define ast_smoother_feed(s, f)
Definition: smoother.h:75
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
struct timeval delivery
enum ast_frame_type frametype
const char * src
struct ast_frame fr
Definition: chan_mobile.c:120
char io_buf[CHANNEL_FRAME_SIZE+AST_FRIENDLY_OFFSET]
Definition: chan_mobile.c:134

References ast_channel_set_fd(), ast_channel_tech_pvt(), ast_debug, ast_dsp_process(), AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_mutex_trylock, ast_mutex_unlock, ast_null_frame, ast_smoother_feed, ast_smoother_read(), mbl_pvt::bt_in_smoother, CHANNEL_DEADLOCK_AVOIDANCE, ast_frame::data, ast_frame::datalen, ast_frame::delivery, DEVICE_FRAME_FORMAT, DEVICE_FRAME_SIZE, mbl_pvt::do_alignment_detection, do_alignment_detection(), mbl_pvt::dsp, errno, ast_frame_subclass::format, mbl_pvt::fr, ast_frame::frametype, mbl_pvt::id, mbl_pvt::io_buf, mbl_pvt::lock, ast_frame::mallocd, NULL, ast_frame::offset, mbl_pvt::owner, ast_frame::ptr, ast_frame::samples, mbl_pvt::sco_socket, ast_frame::src, and ast_frame::subclass.

◆ mbl_request()

static struct ast_channel * mbl_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

Definition at line 898 of file chan_mobile.c.

900{
901
902 struct ast_channel *chn = NULL;
903 struct mbl_pvt *pvt;
904 char *dest_dev = NULL;
905 char *dest_num = NULL;
906 int group = -1;
907
908 if (!data) {
909 ast_log(LOG_WARNING, "Channel requested with no data\n");
911 return NULL;
912 }
913
916 ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
918 return NULL;
919 }
920
921 dest_dev = ast_strdupa(data);
922
923 dest_num = strchr(dest_dev, '/');
924 if (dest_num)
925 *dest_num++ = 0x00;
926
927 if (((dest_dev[0] == 'g') || (dest_dev[0] == 'G')) && ((dest_dev[1] >= '0') && (dest_dev[1] <= '9'))) {
928 group = atoi(&dest_dev[1]);
929 }
930
931 /* Find requested device and make sure it's connected. */
934 if (group > -1 && pvt->group == group && pvt->connected && !pvt->owner) {
935 if (!mbl_has_service(pvt)) {
936 continue;
937 }
938
939 break;
940 } else if (!strcmp(pvt->id, dest_dev)) {
941 break;
942 }
943 }
945 if (!pvt || !pvt->connected || pvt->owner) {
946 ast_log(LOG_WARNING, "Request to call on device %s which is not connected / already in use.\n", dest_dev);
948 return NULL;
949 }
950
951 if ((pvt->type == MBL_TYPE_PHONE) && !dest_num) {
952 ast_log(LOG_WARNING, "Can't determine destination number.\n");
954 return NULL;
955 }
956
957 ast_mutex_lock(&pvt->lock);
958 chn = mbl_new(AST_STATE_DOWN, pvt, NULL, assignedids, requestor);
959 ast_mutex_unlock(&pvt->lock);
960 if (!chn) {
961 ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
963 return NULL;
964 }
965
966 return chn;
967
968}
#define AST_CAUSE_INCOMPATIBLE_DESTINATION
Definition: causes.h:135
#define AST_CAUSE_REQUESTED_CHAN_UNAVAIL
Definition: causes.h:125
#define AST_CAUSE_FACILITY_NOT_IMPLEMENTED
Definition: causes.h:133
@ AST_FORMAT_CMP_NOT_EQUAL
Definition: format.h:38
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:324
enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
Find if ast_format is within the capabilities of the ast_format_cap object.
Definition: format_cap.c:581
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:734
#define ast_str_alloca(init_len)
Definition: strings.h:848
Support for dynamic strings.
Definition: strings.h:623

References AST_CAUSE_FACILITY_NOT_IMPLEMENTED, AST_CAUSE_INCOMPATIBLE_DESTINATION, AST_CAUSE_REQUESTED_CHAN_UNAVAIL, ast_format_cap_get_names(), ast_format_cap_iscompatible_format(), AST_FORMAT_CAP_NAMES_LEN, AST_FORMAT_CMP_NOT_EQUAL, ast_log, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STATE_DOWN, ast_str_alloca, ast_strdupa, mbl_pvt::connected, DEVICE_FRAME_FORMAT, mbl_pvt::group, mbl_pvt::id, mbl_pvt::lock, LOG_WARNING, mbl_has_service(), mbl_new(), MBL_TYPE_PHONE, NULL, mbl_pvt::owner, and mbl_pvt::type.

◆ mbl_sendsms_exec()

static int mbl_sendsms_exec ( struct ast_channel ast,
const char *  data 
)
static

Definition at line 763 of file chan_mobile.c.

764{
765
766 struct mbl_pvt *pvt;
767 char *parse, *message;
768
770 AST_APP_ARG(device);
771 AST_APP_ARG(dest);
773 );
774
775 if (ast_strlen_zero(data))
776 return -1;
777
778 parse = ast_strdupa(data);
779
781
782 if (ast_strlen_zero(args.device)) {
783 ast_log(LOG_ERROR,"NULL device for message -- SMS will not be sent.\n");
784 return -1;
785 }
786
787 if (ast_strlen_zero(args.dest)) {
788 ast_log(LOG_ERROR,"NULL destination for message -- SMS will not be sent.\n");
789 return -1;
790 }
791
792 if (ast_strlen_zero(args.message)) {
793 ast_log(LOG_ERROR,"NULL Message to be sent -- SMS will not be sent.\n");
794 return -1;
795 }
796
799 if (!strcmp(pvt->id, args.device))
800 break;
801 }
803
804 if (!pvt) {
805 ast_log(LOG_ERROR,"Bluetooth device %s wasn't found in the list -- SMS will not be sent.\n", args.device);
806 goto e_return;
807 }
808
809 ast_mutex_lock(&pvt->lock);
810 if (!pvt->connected) {
811 ast_log(LOG_ERROR,"Bluetooth device %s wasn't connected -- SMS will not be sent.\n", args.device);
812 goto e_unlock_pvt;
813 }
814
815 if (!pvt->has_sms) {
816 ast_log(LOG_ERROR,"Bluetooth device %s doesn't handle SMS -- SMS will not be sent.\n", args.device);
817 goto e_unlock_pvt;
818 }
819
820 message = ast_strdup(args.message);
821
822 if (hfp_send_cmgs(pvt->hfp, args.dest)
824
825 ast_log(LOG_ERROR, "[%s] problem sending SMS message\n", pvt->id);
826 goto e_free_message;
827 }
828
829 ast_mutex_unlock(&pvt->lock);
830
831 return 0;
832
833e_free_message:
835e_unlock_pvt:
836 ast_mutex_unlock(&pvt->lock);
837e_return:
838 return -1;
839}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
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.
Definition: chan_mobile.c:3006
static int hfp_send_cmgs(struct hfp_pvt *hfp, const char *number)
Start sending an SMS message.
Definition: chan_mobile.c:2660
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
const char * args

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_strdup, ast_strdupa, ast_strlen_zero(), AT_CMGS, AT_SMS_PROMPT, mbl_pvt::connected, mbl_pvt::has_sms, mbl_pvt::hfp, hfp_send_cmgs(), mbl_pvt::id, mbl_pvt::lock, LOG_ERROR, and msg_queue_push_data().

Referenced by load_module().

◆ mbl_status_exec()

static int mbl_status_exec ( struct ast_channel ast,
const char *  data 
)
static

Definition at line 715 of file chan_mobile.c.

716{
717
718 struct mbl_pvt *pvt;
719 char *parse;
720 int stat;
721 char status[2];
722
724 AST_APP_ARG(device);
725 AST_APP_ARG(variable);
726 );
727
728 if (ast_strlen_zero(data))
729 return -1;
730
731 parse = ast_strdupa(data);
732
734
735 if (ast_strlen_zero(args.device) || ast_strlen_zero(args.variable))
736 return -1;
737
738 stat = 1;
739
742 if (!strcmp(pvt->id, args.device))
743 break;
744 }
746
747 if (pvt) {
748 ast_mutex_lock(&pvt->lock);
749 if (pvt->connected)
750 stat = 2;
751 if (pvt->owner)
752 stat = 3;
753 ast_mutex_unlock(&pvt->lock);
754 }
755
756 snprintf(status, sizeof(status), "%d", stat);
757 pbx_builtin_setvar_helper(ast, args.variable, status);
758
759 return 0;
760
761}

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), mbl_pvt::connected, mbl_pvt::id, mbl_pvt::lock, mbl_pvt::owner, pbx_builtin_setvar_helper(), and status.

Referenced by load_module().

◆ mbl_write()

static int mbl_write ( struct ast_channel ast,
struct ast_frame frame 
)
static

Definition at line 1167 of file chan_mobile.c.

1168{
1169
1170 struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
1171 struct ast_frame *f;
1172
1173 ast_debug(3, "*** mbl_write\n");
1174
1175 if (frame->frametype != AST_FRAME_VOICE) {
1176 return 0;
1177 }
1178
1179 while (ast_mutex_trylock(&pvt->lock)) {
1181 }
1182
1184
1185 while ((f = ast_smoother_read(pvt->bt_out_smoother))) {
1186 sco_write(pvt->sco_socket, f->data.ptr, f->datalen);
1187 }
1188
1189 ast_mutex_unlock(&pvt->lock);
1190
1191 return 0;
1192
1193}
static int sco_write(int s, char *buf, int len)
Definition: chan_mobile.c:1871

References ast_channel_tech_pvt(), ast_debug, AST_FRAME_VOICE, ast_mutex_trylock, ast_mutex_unlock, ast_smoother_feed, ast_smoother_read(), mbl_pvt::bt_out_smoother, CHANNEL_DEADLOCK_AVOIDANCE, ast_frame::data, ast_frame::datalen, ast_frame::frametype, mbl_pvt::lock, ast_frame::ptr, mbl_pvt::sco_socket, and sco_write().

◆ msg_queue_flush()

static void msg_queue_flush ( struct mbl_pvt pvt)
static

Remove all items from the queue and free them.

Parameters
pvta mbl_pvt structure

Definition at line 3048 of file chan_mobile.c.

3049{
3050 struct msg_queue_entry *msg;
3051 while ((msg = msg_queue_head(pvt)))
3053}

References msg_queue_free_and_pop(), and msg_queue_head().

Referenced by do_monitor_phone(), and unload_module().

◆ msg_queue_free_and_pop()

static void msg_queue_free_and_pop ( struct mbl_pvt pvt)
static

Remove an item from the front of the queue, and free it.

Parameters
pvta mbl_pvt structure

Definition at line 3034 of file chan_mobile.c.

3035{
3036 struct msg_queue_entry *msg;
3037 if ((msg = msg_queue_pop(pvt))) {
3038 if (msg->data)
3039 ast_free(msg->data);
3040 ast_free(msg);
3041 }
3042}
static struct msg_queue_entry * msg_queue_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue.
Definition: chan_mobile.c:3025

References ast_free, msg_queue_entry::data, and msg_queue_pop().

Referenced by handle_response_brsf(), handle_response_cind(), handle_response_clip(), handle_response_cmgr(), handle_response_error(), handle_response_ok(), handle_sms_prompt(), and msg_queue_flush().

◆ msg_queue_head()

static struct msg_queue_entry * msg_queue_head ( struct mbl_pvt pvt)
static

Get the head of a queue.

Parameters
pvta mbl_pvt structure
Returns
a pointer to the head of the given msg queue

Definition at line 3060 of file chan_mobile.c.

3061{
3062 return AST_LIST_FIRST(&pvt->msg_queue);
3063}
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421

References AST_LIST_FIRST, and mbl_pvt::msg_queue.

Referenced by do_monitor_phone(), handle_response_brsf(), handle_response_cind(), handle_response_clip(), handle_response_cmgr(), handle_response_error(), handle_response_ok(), handle_sms_prompt(), and msg_queue_flush().

◆ msg_queue_pop()

static struct msg_queue_entry * msg_queue_pop ( struct mbl_pvt pvt)
static

Remove an item from the front of the queue.

Parameters
pvta mbl_pvt structure
Returns
a pointer to the removed item

Definition at line 3025 of file chan_mobile.c.

3026{
3027 return AST_LIST_REMOVE_HEAD(&pvt->msg_queue, entry);
3028}
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833

References AST_LIST_REMOVE_HEAD, and mbl_pvt::msg_queue.

Referenced by msg_queue_free_and_pop().

◆ msg_queue_push()

static int msg_queue_push ( struct mbl_pvt pvt,
at_message_t  expect,
at_message_t  response_to 
)
static

Add an item to the back of the queue.

Parameters
pvta mbl_pvt structure
expectthe msg we expect to receive
response_tothe message that was sent to generate the expected response

Definition at line 2984 of file chan_mobile.c.

2985{
2986 struct msg_queue_entry *msg;
2987 if (!(msg = ast_calloc(1, sizeof(*msg)))) {
2988 return -1;
2989 }
2990 msg->expected = expect;
2991 msg->response_to = response_to;
2992
2994 return 0;
2995}
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
at_message_t response_to
Definition: chan_mobile.c:462

References ast_calloc, AST_LIST_INSERT_TAIL, msg_queue_entry::expected, mbl_pvt::msg_queue, and msg_queue_entry::response_to.

Referenced by do_monitor_phone(), handle_cli_mobile_cusd(), handle_cli_mobile_rfcomm(), handle_response_brsf(), handle_response_cind(), handle_response_clip(), handle_response_cmti(), handle_response_error(), handle_response_ok(), handle_response_ring(), handle_sms_prompt(), mbl_answer(), mbl_call(), mbl_digit_end(), and mbl_hangup().

◆ msg_queue_push_data()

static int msg_queue_push_data ( struct mbl_pvt pvt,
at_message_t  expect,
at_message_t  response_to,
void *  data 
)
static

Add an item to the back of the queue with data.

Parameters
pvta mbl_pvt structure
expectthe msg we expect to receive
response_tothe message that was sent to generate the expected response
datadata associated with this message, it will be freed when the message is freed

Definition at line 3006 of file chan_mobile.c.

3007{
3008 struct msg_queue_entry *msg;
3009 if (!(msg = ast_calloc(1, sizeof(*msg)))) {
3010 return -1;
3011 }
3012 msg->expected = expect;
3013 msg->response_to = response_to;
3014 msg->data = data;
3015
3017 return 0;
3018}

References ast_calloc, AST_LIST_INSERT_TAIL, msg_queue_entry::data, msg_queue_entry::expected, mbl_pvt::msg_queue, and msg_queue_entry::response_to.

Referenced by mbl_sendsms_exec().

◆ parse_next_token()

static int parse_next_token ( char  string[],
const int  start,
const char  delim 
)
static

Terminate current token and return an index to start of the next token.

Parameters
stringthe null-terminated string being parsed (will be altered!)
startwhere the current token starts
delimthe token termination delimiter. \0 is also considered a terminator.
Returns
index of the next token. May be the same as this token if the string is exhausted.

Definition at line 2299 of file chan_mobile.c.

2300{
2301 int index;
2302 int quoting = 0;
2303
2304 for (index = start; string[index] != 0; index++) {
2305 if ((string[index] == delim) && !quoting ) {
2306 /* Found the delimiter, outside of quotes. This is the end of the token. */
2307 string[index] = '\0'; /* Terminate this token. */
2308 index++; /* Point the index to the start of the next token. */
2309 break; /* We're done. */
2310 } else if (string[index] == '"' && !quoting) {
2311 /* Found a beginning quote mark. Remember it. */
2312 quoting = 1;
2313 } else if (string[index] == '"' ) {
2314 /* Found the end quote mark. */
2315 quoting = 0;
2316 }
2317 }
2318 return index;
2319}

Referenced by hfp_parse_clip().

◆ rfcomm_append_buf()

static void rfcomm_append_buf ( char **  buf,
size_t  count,
size_t *  in_count,
char  c 
)
inlinestatic

Append the given character to the given buffer and increase the in_count.

Definition at line 1508 of file chan_mobile.c.

1509{
1510 if (*in_count < count) {
1511 (*in_count)++;
1512 *(*buf)++ = c;
1513 }
1514}
static struct test_val c

References c.

Referenced by rfcomm_read(), rfcomm_read_and_append_char(), rfcomm_read_cmgr(), rfcomm_read_command(), rfcomm_read_result(), rfcomm_read_until_crlf(), and rfcomm_read_until_ok().

◆ rfcomm_connect()

static int rfcomm_connect ( bdaddr_t  src,
bdaddr_t  dst,
int  remote_channel 
)
static

Definition at line 1390 of file chan_mobile.c.

1391{
1392
1393 struct sockaddr_rc addr;
1394 int s;
1395
1396 if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
1397 ast_debug(1, "socket() failed (%d).\n", errno);
1398 return -1;
1399 }
1400
1401 memset(&addr, 0, sizeof(addr));
1402 addr.rc_family = AF_BLUETOOTH;
1403 bacpy(&addr.rc_bdaddr, &src);
1404 addr.rc_channel = (uint8_t) 0;
1405 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1406 ast_debug(1, "bind() failed (%d).\n", errno);
1407 close(s);
1408 return -1;
1409 }
1410
1411 memset(&addr, 0, sizeof(addr));
1412 addr.rc_family = AF_BLUETOOTH;
1413 bacpy(&addr.rc_bdaddr, &dst);
1414 addr.rc_channel = remote_channel;
1415 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1416 ast_debug(1, "connect() failed (%d).\n", errno);
1417 close(s);
1418 return -1;
1419 }
1420
1421 return s;
1422
1423}

References ast_debug, and errno.

Referenced by do_discovery().

◆ rfcomm_read()

static ssize_t rfcomm_read ( int  rsock,
char *  buf,
size_t  count 
)
static

Read one Hayes AT message from an rfcomm socket.

Parameters
rsockthe rfcomm socket to read from
bufthe buffer to store the result in
countthe size of the buffer or the maximum number of characters to read

Here we need to read complete Hayes AT messages. The AT message formats we support are listed below.

* \r\n<result code>\r\n
* <at command>\r
* \r\n>
* 

These formats correspond to AT result codes, AT commands, and the AT SMS prompt respectively. When messages are read the leading and trailing

'\r' 

and

'\n' 

characters are discarded. If the given buffer is not large enough to hold the response, what does not fit in the buffer will be dropped.

Note
The rfcomm connection to the device is asynchronous, so there is no guarantee that responses will be returned in a single read() call. We handle this by blocking until we can read an entire response.
Return values
0end of file
-1read error
-2parse error
otherthe number of characters added to buf

Definition at line 1808 of file chan_mobile.c.

1809{
1810 ssize_t res;
1811 size_t in_count = 0;
1812 char c;
1813
1814 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) == 1) {
1815 res = rfcomm_read_result(rsock, &buf, count, &in_count);
1816 } else if (res == -2) {
1817 rfcomm_append_buf(&buf, count, &in_count, c);
1818 res = rfcomm_read_command(rsock, &buf, count, &in_count);
1819 }
1820
1821 if (res < 1)
1822 return res;
1823 else
1824 return in_count;
1825}
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.
Definition: chan_mobile.c:1508
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.
Definition: chan_mobile.c:1520
static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_count)
Read and AT result code.
Definition: chan_mobile.c:1725
static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_count)
Read the remainder of an AT command.
Definition: chan_mobile.c:1763

References buf, c, rfcomm_append_buf(), rfcomm_read_and_expect_char(), rfcomm_read_command(), and rfcomm_read_result().

Referenced by at_read_full().

◆ rfcomm_read_and_append_char()

static int rfcomm_read_and_append_char ( int  rsock,
char **  buf,
size_t  count,
size_t *  in_count,
char *  result,
char  expected 
)
static

Read a character from the given stream and append it to the given buffer if it matches the expected character.

Definition at line 1544 of file chan_mobile.c.

1545{
1546 int res;
1547 char c;
1548
1549 if (!result)
1550 result = &c;
1551
1552 if ((res = rfcomm_read_and_expect_char(rsock, result, expected)) < 1) {
1553 return res;
1554 }
1555
1556 rfcomm_append_buf(buf, count, in_count, *result);
1557 return 1;
1558}
static PGresult * result
Definition: cel_pgsql.c:84

References buf, c, result, rfcomm_append_buf(), and rfcomm_read_and_expect_char().

Referenced by rfcomm_read_result(), and rfcomm_read_sms_prompt().

◆ rfcomm_read_and_expect_char()

static int rfcomm_read_and_expect_char ( int  rsock,
char *  result,
char  expected 
)
static

Read a character from the given stream and check if it matches what we expected.

Definition at line 1520 of file chan_mobile.c.

1521{
1522 int res;
1523 char c;
1524
1525 if (!result)
1526 result = &c;
1527
1528 if ((res = read(rsock, result, 1)) < 1) {
1529 return res;
1530 }
1532
1533 if (*result != expected) {
1534 return -2;
1535 }
1536
1537 return 1;
1538}
#define rfcomm_read_debug(c)
Definition: chan_mobile.c:1501

References c, result, and rfcomm_read_debug.

Referenced by rfcomm_read(), rfcomm_read_and_append_char(), rfcomm_read_result(), rfcomm_read_until_crlf(), and rfcomm_read_until_ok().

◆ rfcomm_read_cmgr()

static int rfcomm_read_cmgr ( int  rsock,
char **  buf,
size_t  count,
size_t *  in_count 
)
static

Read the remainder of a +CMGR message.

Note
the entire parsed string is
'+CMGR: ...\r\n...\r\n...\r\n...\r\nOK\r\n' 

Definition at line 1706 of file chan_mobile.c.

1707{
1708 int res;
1709
1710 /* append the \r\n that was stripped by the calling function */
1711 rfcomm_append_buf(buf, count, in_count, '\r');
1712 rfcomm_append_buf(buf, count, in_count, '\n');
1713
1714 if ((res = rfcomm_read_until_ok(rsock, buf, count, in_count)) != 1) {
1715 ast_log(LOG_ERROR, "error reading +CMGR message on rfcomm socket\n");
1716 }
1717
1718 return res;
1719}
static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_count)
Read until a.
Definition: chan_mobile.c:1609

References ast_log, buf, LOG_ERROR, rfcomm_append_buf(), and rfcomm_read_until_ok().

Referenced by rfcomm_read_result().

◆ rfcomm_read_command()

static int rfcomm_read_command ( int  rsock,
char **  buf,
size_t  count,
size_t *  in_count 
)
static

Read the remainder of an AT command.

Note
the entire parsed string is
'<at command>\r' 

Definition at line 1763 of file chan_mobile.c.

1764{
1765 int res;
1766 char c;
1767
1768 while ((res = read(rsock, &c, 1)) == 1) {
1770 /* stop when we get to '\r' */
1771 if (c == '\r')
1772 break;
1773
1774 rfcomm_append_buf(buf, count, in_count, c);
1775 }
1776 return res;
1777}

References buf, c, rfcomm_append_buf(), and rfcomm_read_debug.

Referenced by rfcomm_read().

◆ rfcomm_read_result()

static int rfcomm_read_result ( int  rsock,
char **  buf,
size_t  count,
size_t *  in_count 
)
static

Read and AT result code.

Note
the entire parsed string is
'\r\n<result code>\r\n' 

Definition at line 1725 of file chan_mobile.c.

1726{
1727 int res;
1728 char c;
1729
1730 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) < 1) {
1731 goto e_return;
1732 }
1733
1734 if ((res = rfcomm_read_and_append_char(rsock, buf, count, in_count, &c, '>')) == 1) {
1735 return rfcomm_read_sms_prompt(rsock, buf, count, in_count);
1736 } else if (res != -2) {
1737 goto e_return;
1738 }
1739
1740 rfcomm_append_buf(buf, count, in_count, c);
1741 res = rfcomm_read_until_crlf(rsock, buf, count, in_count);
1742
1743 if (res != 1)
1744 return res;
1745
1746 /* check for CMGR, which contains an embedded \r\n pairs terminated by
1747 * an \r\nOK\r\n message */
1748 if (*in_count >= 5 && !strncmp(*buf - *in_count, "+CMGR", 5)) {
1749 return rfcomm_read_cmgr(rsock, buf, count, in_count);
1750 }
1751
1752 return 1;
1753
1754e_return:
1755 ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket\n");
1756 return res;
1757}
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 c...
Definition: chan_mobile.c:1544
static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
Read the remainder of a +CMGR message.
Definition: chan_mobile.c:1706
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.
Definition: chan_mobile.c:1593
static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
Read until.
Definition: chan_mobile.c:1564

References ast_log, buf, c, LOG_ERROR, rfcomm_append_buf(), rfcomm_read_and_append_char(), rfcomm_read_and_expect_char(), rfcomm_read_cmgr(), rfcomm_read_sms_prompt(), and rfcomm_read_until_crlf().

Referenced by rfcomm_read().

◆ rfcomm_read_sms_prompt()

static int rfcomm_read_sms_prompt ( int  rsock,
char **  buf,
size_t  count,
size_t *  in_count 
)
static

Read the remainder of an AT SMS prompt.

Note
the entire parsed string is
'\r\n> ' 

By the time this function is executed, only a ' ' is left to read.

Definition at line 1593 of file chan_mobile.c.

1594{
1595 int res;
1596 if ((res = rfcomm_read_and_append_char(rsock, buf, count, in_count, NULL, ' ')) < 1)
1597 goto e_return;
1598
1599 return 1;
1600
1601e_return:
1602 ast_log(LOG_ERROR, "error parsing SMS prompt on rfcomm socket\n");
1603 return res;
1604}

References ast_log, buf, LOG_ERROR, NULL, and rfcomm_read_and_append_char().

Referenced by rfcomm_read_result().

◆ rfcomm_read_until_crlf()

static int rfcomm_read_until_crlf ( int  rsock,
char **  buf,
size_t  count,
size_t *  in_count 
)
static

Read until.

'\r\n'. 

This function consumes the

'\r\n'

but does not add it to buf.

Definition at line 1564 of file chan_mobile.c.

1565{
1566 int res;
1567 char c;
1568
1569 while ((res = read(rsock, &c, 1)) == 1) {
1571 if (c == '\r') {
1572 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) == 1) {
1573 break;
1574 } else if (res == -2) {
1575 rfcomm_append_buf(buf, count, in_count, '\r');
1576 } else {
1577 rfcomm_append_buf(buf, count, in_count, '\r');
1578 break;
1579 }
1580 }
1581
1582 rfcomm_append_buf(buf, count, in_count, c);
1583 }
1584 return res;
1585}

References buf, c, rfcomm_append_buf(), rfcomm_read_and_expect_char(), and rfcomm_read_debug.

Referenced by rfcomm_read_result(), and rfcomm_read_until_ok().

◆ rfcomm_read_until_ok()

static int rfcomm_read_until_ok ( int  rsock,
char **  buf,
size_t  count,
size_t *  in_count 
)
static

Read until a.

\r\nOK\r\n 

message.

Definition at line 1609 of file chan_mobile.c.

1610{
1611 int res;
1612 char c;
1613
1614 /* here, we read until finding a \r\n, then we read one character at a
1615 * time looking for the string '\r\nOK\r\n'. If we only find a partial
1616 * match, we place that in the buffer and try again. */
1617
1618 for (;;) {
1619 if ((res = rfcomm_read_until_crlf(rsock, buf, count, in_count)) != 1) {
1620 break;
1621 }
1622
1623 rfcomm_append_buf(buf, count, in_count, '\r');
1624 rfcomm_append_buf(buf, count, in_count, '\n');
1625
1626 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
1627 if (res != -2) {
1628 break;
1629 }
1630
1631 rfcomm_append_buf(buf, count, in_count, c);
1632 continue;
1633 }
1634
1635 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
1636 if (res != -2) {
1637 break;
1638 }
1639
1640 rfcomm_append_buf(buf, count, in_count, '\r');
1641 rfcomm_append_buf(buf, count, in_count, c);
1642 continue;
1643 }
1644 if ((res = rfcomm_read_and_expect_char(rsock, &c, 'O')) != 1) {
1645 if (res != -2) {
1646 break;
1647 }
1648
1649 rfcomm_append_buf(buf, count, in_count, '\r');
1650 rfcomm_append_buf(buf, count, in_count, '\n');
1651 rfcomm_append_buf(buf, count, in_count, c);
1652 continue;
1653 }
1654
1655 if ((res = rfcomm_read_and_expect_char(rsock, &c, 'K')) != 1) {
1656 if (res != -2) {
1657 break;
1658 }
1659
1660 rfcomm_append_buf(buf, count, in_count, '\r');
1661 rfcomm_append_buf(buf, count, in_count, '\n');
1662 rfcomm_append_buf(buf, count, in_count, 'O');
1663 rfcomm_append_buf(buf, count, in_count, c);
1664 continue;
1665 }
1666
1667 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
1668 if (res != -2) {
1669 break;
1670 }
1671
1672 rfcomm_append_buf(buf, count, in_count, '\r');
1673 rfcomm_append_buf(buf, count, in_count, '\n');
1674 rfcomm_append_buf(buf, count, in_count, 'O');
1675 rfcomm_append_buf(buf, count, in_count, 'K');
1676 rfcomm_append_buf(buf, count, in_count, c);
1677 continue;
1678 }
1679
1680 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
1681 if (res != -2) {
1682 break;
1683 }
1684
1685 rfcomm_append_buf(buf, count, in_count, '\r');
1686 rfcomm_append_buf(buf, count, in_count, '\n');
1687 rfcomm_append_buf(buf, count, in_count, 'O');
1688 rfcomm_append_buf(buf, count, in_count, 'K');
1689 rfcomm_append_buf(buf, count, in_count, '\r');
1690 rfcomm_append_buf(buf, count, in_count, c);
1691 continue;
1692 }
1693
1694 /* we have successfully parsed a '\r\nOK\r\n' string */
1695 return 1;
1696 }
1697
1698 return res;
1699}

References buf, c, rfcomm_append_buf(), rfcomm_read_and_expect_char(), and rfcomm_read_until_crlf().

Referenced by rfcomm_read_cmgr().

◆ rfcomm_wait()

static int rfcomm_wait ( int  rsock,
int *  ms 
)
static

Wait for activity on an rfcomm socket.

Parameters
rsockthe socket to watch
msa pointer to an int containing a timeout in ms
Returns
zero on timeout and the socket fd (non-zero) otherwise
Return values
0timeout

Definition at line 1479 of file chan_mobile.c.

1480{
1481 int exception, outfd;
1482 outfd = ast_waitfor_n_fd(&rsock, 1, ms, &exception);
1483 if (outfd < 0)
1484 outfd = 0;
1485
1486 return outfd;
1487}
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
Waits for input on an fd.
Definition: channel.c:2980

References ast_waitfor_n_fd().

Referenced by do_monitor_headset(), and do_monitor_phone().

◆ rfcomm_write()

static int rfcomm_write ( int  rsock,
char *  buf 
)
static

Write to an rfcomm socket.

Parameters
rsockthe socket to write to
bufthe null terminated buffer to write

This function will write characters from buf. The buffer must be null terminated.

Return values
-1error
0success

Definition at line 1436 of file chan_mobile.c.

1437{
1438 return rfcomm_write_full(rsock, buf, strlen(buf));
1439}
static int rfcomm_write_full(int rsock, char *buf, size_t count)
Write to an rfcomm socket.
Definition: chan_mobile.c:1454

References buf, and rfcomm_write_full().

Referenced by handle_cli_mobile_rfcomm(), hfp_send_ata(), hfp_send_atd(), hfp_send_brsf(), hfp_send_chup(), hfp_send_cind(), hfp_send_cind_test(), hfp_send_clip(), hfp_send_cmer(), hfp_send_cmgf(), hfp_send_cmgr(), hfp_send_cmgs(), hfp_send_cnmi(), hfp_send_cusd(), hfp_send_dtmf(), hfp_send_ecam(), hfp_send_sms_text(), hfp_send_vgs(), hsp_send_error(), hsp_send_ok(), hsp_send_ring(), hsp_send_vgm(), and hsp_send_vgs().

◆ rfcomm_write_full()

static int rfcomm_write_full ( int  rsock,
char *  buf,
size_t  count 
)
static

Write to an rfcomm socket.

Parameters
rsockthe socket to write to
bufthe buffer to write
countthe number of characters from the buffer to write

This function will write count characters from buf. It will always write count chars unless it encounters an error.

Return values
-1error
0success

Definition at line 1454 of file chan_mobile.c.

1455{
1456 char *p = buf;
1457 ssize_t out_count;
1458
1459 ast_debug(1, "rfcomm_write() (%d) [%.*s]\n", rsock, (int) count, buf);
1460 while (count > 0) {
1461 if ((out_count = write(rsock, p, count)) == -1) {
1462 ast_debug(1, "rfcomm_write() error [%d]\n", errno);
1463 return -1;
1464 }
1465 count -= out_count;
1466 p += out_count;
1467 }
1468
1469 return 0;
1470}

References ast_debug, buf, and errno.

Referenced by rfcomm_write().

◆ sco_accept()

static int sco_accept ( int *  id,
int  fd,
short  events,
void *  data 
)
static

Accept SCO connections. This function is an ast_io callback function used to accept incoming sco audio connections.

Definition at line 1898 of file chan_mobile.c.

1899{
1900 struct adapter_pvt *adapter = (struct adapter_pvt *) data;
1901 struct sockaddr_sco addr;
1902 socklen_t addrlen;
1903 struct mbl_pvt *pvt;
1904 socklen_t len;
1905 char saddr[18];
1906 struct sco_options so;
1907 int sock;
1908
1909 addrlen = sizeof(struct sockaddr_sco);
1910 if ((sock = accept(fd, (struct sockaddr *)&addr, &addrlen)) == -1) {
1911 ast_log(LOG_ERROR, "error accepting audio connection on adapter %s\n", adapter->id);
1912 return 0;
1913 }
1914
1915 len = sizeof(so);
1916 getsockopt(sock, SOL_SCO, SCO_OPTIONS, &so, &len);
1917
1918 ba2str(&addr.sco_bdaddr, saddr);
1919 ast_debug(1, "Incoming Audio Connection from device %s MTU is %d\n", saddr, so.mtu);
1920
1921 /* figure out which device this sco connection belongs to */
1922 pvt = NULL;
1925 if (!bacmp(&pvt->addr, &addr.sco_bdaddr))
1926 break;
1927 }
1929 if (!pvt) {
1930 ast_log(LOG_WARNING, "could not find device for incoming audio connection\n");
1931 close(sock);
1932 return 1;
1933 }
1934
1935 ast_mutex_lock(&pvt->lock);
1936 if (pvt->sco_socket != -1) {
1937 close(pvt->sco_socket);
1938 pvt->sco_socket = -1;
1939 }
1940
1941 pvt->sco_socket = sock;
1942 if (pvt->owner) {
1943 ast_channel_set_fd(pvt->owner, 0, sock);
1944 } else {
1945 ast_debug(1, "incoming audio connection for pvt without owner\n");
1946 }
1947
1948 ast_mutex_unlock(&pvt->lock);
1949
1950 return 1;
1951}

References mbl_pvt::addr, ast_channel_set_fd(), ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, adapter_pvt::id, len(), mbl_pvt::lock, LOG_ERROR, LOG_WARNING, NULL, mbl_pvt::owner, and mbl_pvt::sco_socket.

Referenced by mbl_load_adapter().

◆ sco_bind()

static int sco_bind ( struct adapter_pvt adapter)
static

Bind an SCO listener socket for the given adapter.

Parameters
adapteran adapter_pvt
Returns
-1 on error, non zero on success

Definition at line 1958 of file chan_mobile.c.

1959{
1960 struct sockaddr_sco addr;
1961 int opt = 1;
1962
1963 if ((adapter->sco_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1964 ast_log(LOG_ERROR, "Unable to create sco listener socket for adapter %s.\n", adapter->id);
1965 goto e_return;
1966 }
1967
1968 memset(&addr, 0, sizeof(addr));
1969 addr.sco_family = AF_BLUETOOTH;
1970 bacpy(&addr.sco_bdaddr, &adapter->addr);
1971 if (bind(adapter->sco_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1972 ast_log(LOG_ERROR, "Unable to bind sco listener socket. (%d)\n", errno);
1973 goto e_close_socket;
1974 }
1975 if (setsockopt(adapter->sco_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
1976 ast_log(LOG_ERROR, "Unable to setsockopt sco listener socket.\n");
1977 goto e_close_socket;
1978 }
1979 if (listen(adapter->sco_socket, 5) < 0) {
1980 ast_log(LOG_ERROR, "Unable to listen sco listener socket.\n");
1981 goto e_close_socket;
1982 }
1983
1984 return adapter->sco_socket;
1985
1986e_close_socket:
1987 close(adapter->sco_socket);
1988 adapter->sco_socket = -1;
1989e_return:
1990 return -1;
1991}

References adapter_pvt::addr, ast_log, errno, adapter_pvt::id, LOG_ERROR, and adapter_pvt::sco_socket.

Referenced by mbl_load_adapter().

◆ sco_connect()

static int sco_connect ( bdaddr_t  src,
bdaddr_t  dst 
)
static

Definition at line 1833 of file chan_mobile.c.

1834{
1835
1836 struct sockaddr_sco addr;
1837 int s;
1838
1839 if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1840 ast_debug(1, "socket() failed (%d).\n", errno);
1841 return -1;
1842 }
1843
1844/* XXX this does not work with the do_sco_listen() thread (which also bind()s
1845 * to this address). Also I am not sure if it is necessary. */
1846#if 0
1847 memset(&addr, 0, sizeof(addr));
1848 addr.sco_family = AF_BLUETOOTH;
1849 bacpy(&addr.sco_bdaddr, &src);
1850 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1851 ast_debug(1, "bind() failed (%d).\n", errno);
1852 close(s);
1853 return -1;
1854 }
1855#endif
1856
1857 memset(&addr, 0, sizeof(addr));
1858 addr.sco_family = AF_BLUETOOTH;
1859 bacpy(&addr.sco_bdaddr, &dst);
1860
1861 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1862 ast_debug(1, "sco connect() failed (%d).\n", errno);
1863 close(s);
1864 return -1;
1865 }
1866
1867 return s;
1868
1869}

References ast_debug, and errno.

Referenced by do_monitor_headset().

◆ sco_write()

static int sco_write ( int  s,
char *  buf,
int  len 
)
static

Definition at line 1871 of file chan_mobile.c.

1872{
1873
1874 int r;
1875
1876 if (s == -1) {
1877 ast_debug(3, "sco_write() not ready\n");
1878 return 0;
1879 }
1880
1881 ast_debug(3, "sco_write()\n");
1882
1883 r = write(s, buf, len);
1884 if (r == -1) {
1885 ast_debug(3, "sco write error %d\n", errno);
1886 return 0;
1887 }
1888
1889 return 1;
1890
1891}

References ast_debug, buf, errno, and len().

Referenced by mbl_write().

◆ sdp_register()

static sdp_session_t * sdp_register ( void  )
static

Definition at line 3121 of file chan_mobile.c.

3122{
3123 uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
3124 uint8_t rfcomm_channel = 1;
3125 const char *service_name = "Asterisk PABX";
3126 const char *service_dsc = "Asterisk PABX";
3127 const char *service_prov = "Asterisk";
3128
3129 uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class1_uuid, svc_class2_uuid;
3130 sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
3131 sdp_data_t *channel = 0;
3132
3133 sdp_session_t *session = 0;
3134
3135 sdp_record_t *record = sdp_record_alloc();
3136
3137 sdp_uuid128_create(&svc_uuid, &service_uuid_int);
3138 sdp_set_service_id(record, svc_uuid);
3139
3140 sdp_uuid32_create(&svc_class1_uuid, GENERIC_AUDIO_SVCLASS_ID);
3141 sdp_uuid32_create(&svc_class2_uuid, HEADSET_PROFILE_ID);
3142
3143 svc_uuid_list = sdp_list_append(0, &svc_class1_uuid);
3144 svc_uuid_list = sdp_list_append(svc_uuid_list, &svc_class2_uuid);
3145 sdp_set_service_classes(record, svc_uuid_list);
3146
3147 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3148 root_list = sdp_list_append(0, &root_uuid);
3149 sdp_set_browse_groups( record, root_list );
3150
3151 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3152 l2cap_list = sdp_list_append(0, &l2cap_uuid);
3153 proto_list = sdp_list_append(0, l2cap_list);
3154
3155 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3156 channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
3157 rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
3158 sdp_list_append(rfcomm_list, channel);
3159 sdp_list_append(proto_list, rfcomm_list);
3160
3161 access_proto_list = sdp_list_append(0, proto_list);
3162 sdp_set_access_protos(record, access_proto_list);
3163
3164 sdp_set_info_attr(record, service_name, service_prov, service_dsc);
3165
3166 if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
3167 ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
3168 else {
3169 if (sdp_record_register(session, record, 0) < 0) {
3170 ast_log(LOG_WARNING, "Failed to sdp_record_register error: %d\n", errno);
3171 return NULL;
3172 }
3173 }
3174
3175 sdp_data_free(channel);
3176 sdp_list_free(rfcomm_list, 0);
3177 sdp_list_free(root_list, 0);
3178 sdp_list_free(access_proto_list, 0);
3179 sdp_list_free(svc_uuid_list, 0);
3180
3181 return session;
3182
3183}
static struct ast_mansession session

References ast_log, errno, LOG_WARNING, NULL, and session.

Referenced by load_module().

◆ sdp_search()

static int sdp_search ( char *  addr,
int  profile 
)
static

Definition at line 3073 of file chan_mobile.c.

3074{
3075
3076 sdp_session_t *session = 0;
3077 bdaddr_t bdaddr;
3078 uuid_t svc_uuid;
3079 uint32_t range = 0x0000ffff;
3080 sdp_list_t *response_list, *search_list, *attrid_list;
3081 int status, port;
3082 sdp_list_t *proto_list;
3083 sdp_record_t *sdprec;
3084
3085 str2ba(addr, &bdaddr);
3086 port = 0;
3087 session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
3088 if (!session) {
3089 ast_debug(1, "sdp_connect() failed on device %s.\n", addr);
3090 return 0;
3091 }
3092
3093 sdp_uuid32_create(&svc_uuid, profile);
3094 search_list = sdp_list_append(0, &svc_uuid);
3095 attrid_list = sdp_list_append(0, &range);
3096 response_list = 0x00;
3097 status = sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
3098 if (status == 0) {
3099 if (response_list) {
3100 sdprec = (sdp_record_t *) response_list->data;
3101 proto_list = 0x00;
3102 if (sdp_get_access_protos(sdprec, &proto_list) == 0) {
3103 port = sdp_get_proto_port(proto_list, RFCOMM_UUID);
3104 sdp_list_free(proto_list, 0);
3105 }
3106 sdp_record_free(sdprec);
3107 sdp_list_free(response_list, 0);
3108 } else
3109 ast_debug(1, "No responses returned for device %s.\n", addr);
3110 } else
3111 ast_debug(1, "sdp_service_search_attr_req() failed on device %s.\n", addr);
3112
3113 sdp_list_free(search_list, 0);
3114 sdp_list_free(attrid_list, 0);
3115 sdp_close(session);
3116
3117 return port;
3118
3119}
if(!yyg->yy_init)
Definition: ast_expr2f.c:854

References ast_debug, if(), session, and status.

Referenced by handle_cli_mobile_search().

◆ set_unloading()

static void set_unloading ( void  )
inlinestatic

Set the unloading flag.

Definition at line 4697 of file chan_mobile.c.

References ast_mutex_lock, ast_mutex_unlock, unload_mutex, and unloading_flag.

Referenced by unload_module().

◆ start_monitor()

static int start_monitor ( struct mbl_pvt pvt)
static

Definition at line 4263 of file chan_mobile.c.

4264{
4265
4266 if (pvt->type == MBL_TYPE_PHONE) {
4267 pvt->hfp->rsock = pvt->rfcomm_socket;
4268
4271 return 0;
4272 }
4273 } else {
4276 return 0;
4277 }
4278 }
4279
4280 return 1;
4281
4282}
static void * do_monitor_headset(void *data)
Definition: chan_mobile.c:4121
static void * do_monitor_phone(void *data)
Definition: chan_mobile.c:3872

References ast_pthread_create_background, AST_PTHREADT_NULL, do_monitor_headset(), do_monitor_phone(), mbl_pvt::hfp, MBL_TYPE_PHONE, mbl_pvt::monitor_thread, NULL, mbl_pvt::rfcomm_socket, hfp_pvt::rsock, and mbl_pvt::type.

Referenced by do_discovery().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 4704 of file chan_mobile.c.

4705{
4706 struct mbl_pvt *pvt;
4707 struct adapter_pvt *adapter;
4708
4709 /* First, take us out of the channel loop */
4711
4712 /* Unregister the CLI & APP */
4713 ast_cli_unregister_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
4716
4717 /* signal everyone we are unloading */
4718 set_unloading();
4719
4720 /* Kill the discovery thread */
4722 pthread_kill(discovery_thread, SIGURG);
4723 pthread_join(discovery_thread, NULL);
4724 }
4725
4726 /* stop the sco listener threads */
4728 AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
4729 pthread_kill(adapter->sco_listener_thread, SIGURG);
4730 pthread_join(adapter->sco_listener_thread, NULL);
4731 }
4733
4734 /* Destroy the device list */
4736 while ((pvt = AST_RWLIST_REMOVE_HEAD(&devices, entry))) {
4737 if (pvt->monitor_thread != AST_PTHREADT_NULL) {
4738 pthread_kill(pvt->monitor_thread, SIGURG);
4739 pthread_join(pvt->monitor_thread, NULL);
4740 }
4741
4742 close(pvt->sco_socket);
4743 close(pvt->rfcomm_socket);
4744
4745 msg_queue_flush(pvt);
4746
4747 if (pvt->hfp) {
4748 ast_free(pvt->hfp);
4749 }
4750
4753 ast_dsp_free(pvt->dsp);
4755 ast_free(pvt);
4756 }
4758
4759 /* Destroy the adapter list */
4761 while ((adapter = AST_RWLIST_REMOVE_HEAD(&adapters, entry))) {
4762 close(adapter->sco_socket);
4763 io_context_destroy(adapter->io);
4764 io_context_destroy(adapter->accept_io);
4765 hci_close_dev(adapter->hci_socket);
4766 ast_free(adapter);
4767 }
4769
4770 if (sdp_session)
4771 sdp_close(sdp_session);
4772
4775 return 0;
4776}
static void set_unloading(void)
Set the unloading flag.
Definition: chan_mobile.c:4697
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References adapter_pvt::accept_io, ao2_ref, app_mblsendsms, app_mblstatus, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_dsp_free(), ast_free, AST_PTHREADT_NULL, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sched_context_destroy(), ast_smoother_free(), ast_unregister_application(), mbl_pvt::bt_in_smoother, mbl_pvt::bt_out_smoother, ast_channel_tech::capabilities, discovery_thread, mbl_pvt::dsp, adapter_pvt::hci_socket, mbl_pvt::hfp, adapter_pvt::io, io_context_destroy(), mbl_cli, mbl_tech, mbl_pvt::monitor_thread, msg_queue_flush(), NULL, mbl_pvt::rfcomm_socket, mbl_pvt::sched, adapter_pvt::sco_listener_thread, adapter_pvt::sco_socket, mbl_pvt::sco_socket, sdp_session, and set_unloading().

Referenced by load_module().

Variable Documentation

◆ __mod_info

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

Definition at line 4840 of file chan_mobile.c.

◆ adapters

struct adapters adapters = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static

◆ app_mblsendsms

char* app_mblsendsms = "MobileSendSMS"
static

Definition at line 209 of file chan_mobile.c.

Referenced by load_module(), and unload_module().

◆ app_mblstatus

char* app_mblstatus = "MobileStatus"
static

Definition at line 201 of file chan_mobile.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 4840 of file chan_mobile.c.

◆ devices

struct devices devices = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static

◆ discovery_interval

int discovery_interval = 60
static

Definition at line 85 of file chan_mobile.c.

Referenced by do_discovery(), and mbl_load_config().

◆ discovery_thread

pthread_t discovery_thread = AST_PTHREADT_NULL
static

Definition at line 86 of file chan_mobile.c.

Referenced by load_module(), and unload_module().

◆ hfp_our_brsf

struct hfp_hf hfp_our_brsf
static

Definition at line 361 of file chan_mobile.c.

Referenced by do_monitor_phone().

◆ mbl_cli

struct ast_cli_entry mbl_cli[]
static

Definition at line 193 of file chan_mobile.c.

Referenced by load_module(), and unload_module().

◆ mbl_tech

struct ast_channel_tech mbl_tech
static

Definition at line 479 of file chan_mobile.c.

Referenced by load_module(), mbl_new(), and unload_module().

◆ mblsendsms_desc

char* mblsendsms_desc
static
Initial value:
=
"MobileSendSms(Device,Dest,Message)\n"
" Device - Id of device from mobile.conf\n"
" Dest - destination\n"
" Message - text of the message\n"

Definition at line 211 of file chan_mobile.c.

Referenced by load_module().

◆ mblsendsms_synopsis

char* mblsendsms_synopsis = "MobileSendSMS(Device,Dest,Message)"
static

Definition at line 210 of file chan_mobile.c.

Referenced by load_module().

◆ mblstatus_desc

char* mblstatus_desc
static
Initial value:
=
"MobileStatus(Device,Variable)\n"
" Device - Id of mobile device from mobile.conf\n"
" Variable - Variable to store status in will be 1-3.\n"
" In order, Disconnected, Connected & Free, Connected & Busy.\n"

Definition at line 203 of file chan_mobile.c.

Referenced by load_module().

◆ mblstatus_synopsis

char* mblstatus_synopsis = "MobileStatus(Device,Variable)"
static

Definition at line 202 of file chan_mobile.c.

Referenced by load_module().

◆ sdp_session

sdp_session_t* sdp_session
static

Definition at line 87 of file chan_mobile.c.

Referenced by load_module(), and unload_module().

◆ unload_mutex

ast_mutex_t unload_mutex = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Definition at line 89 of file chan_mobile.c.

Referenced by check_unloading(), and set_unloading().

◆ unloading_flag

int unloading_flag = 0
static

Definition at line 90 of file chan_mobile.c.

Referenced by check_unloading(), and set_unloading().