Asterisk - The Open Source Telephony Project  18.5.0
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 clasify 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 Erricson 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 itmes 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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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.

Referenced by mbl_load_device(), and mbl_new().

◆ DEVICE_FRAME_FORMAT

#define DEVICE_FRAME_FORMAT   ast_format_slin

Definition at line 82 of file chan_mobile.c.

Referenced by load_module(), mbl_new(), mbl_read(), and mbl_request().

◆ DEVICE_FRAME_SIZE

#define DEVICE_FRAME_SIZE   48

Definition at line 81 of file chan_mobile.c.

Referenced by mbl_load_device(), mbl_new(), and mbl_read().

◆ 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.

Referenced by hfp_int2brsf().

◆ HFP_AG_CW

#define HFP_AG_CW   (1 << 0)

Definition at line 265 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_AG_ECNR

#define HFP_AG_ECNR   (1 << 1)

Definition at line 266 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_AG_ERRORS

#define HFP_AG_ERRORS   (1 << 8)

Definition at line 273 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_AG_REJECT

#define HFP_AG_REJECT   (1 << 5)

Definition at line 270 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_AG_RING

#define HFP_AG_RING   (1 << 3)

Definition at line 268 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_AG_STATUS

#define HFP_AG_STATUS   (1 << 6)

Definition at line 271 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_AG_TAG

#define HFP_AG_TAG   (1 << 4)

Definition at line 269 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_AG_VOICE

#define HFP_AG_VOICE   (1 << 2)

Definition at line 267 of file chan_mobile.c.

Referenced by hfp_int2brsf().

◆ HFP_CIND_BATTCHG

#define HFP_CIND_BATTCHG   7

Definition at line 283 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

◆ HFP_CIND_CALL

#define HFP_CIND_CALL   2

Definition at line 278 of file chan_mobile.c.

Referenced by handle_response_ciev(), and hfp_parse_cind_test().

◆ HFP_CIND_CALL_ACTIVE

#define HFP_CIND_CALL_ACTIVE   1

Definition at line 287 of file chan_mobile.c.

Referenced by handle_response_ciev().

◆ HFP_CIND_CALL_NONE

#define HFP_CIND_CALL_NONE   0

Definition at line 286 of file chan_mobile.c.

Referenced by handle_response_ciev().

◆ HFP_CIND_CALLHELD

#define HFP_CIND_CALLHELD   4

Definition at line 280 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

◆ HFP_CIND_CALLSETUP

#define HFP_CIND_CALLSETUP   3

Definition at line 279 of file chan_mobile.c.

Referenced by handle_response_ciev(), and hfp_parse_cind_test().

◆ HFP_CIND_CALLSETUP_ALERTING

#define HFP_CIND_CALLSETUP_ALERTING   3

Definition at line 293 of file chan_mobile.c.

Referenced by handle_response_ciev().

◆ HFP_CIND_CALLSETUP_INCOMING

#define HFP_CIND_CALLSETUP_INCOMING   1

Definition at line 291 of file chan_mobile.c.

Referenced by handle_response_ciev().

◆ HFP_CIND_CALLSETUP_NONE

#define HFP_CIND_CALLSETUP_NONE   0

Definition at line 290 of file chan_mobile.c.

Referenced by handle_response_ciev().

◆ HFP_CIND_CALLSETUP_OUTGOING

#define HFP_CIND_CALLSETUP_OUTGOING   2

Definition at line 292 of file chan_mobile.c.

Referenced by handle_response_ciev().

◆ HFP_CIND_NONE

#define HFP_CIND_NONE   0

Definition at line 276 of file chan_mobile.c.

Referenced by handle_response_ciev(), and hfp_parse_ciev().

◆ HFP_CIND_ROAM

#define HFP_CIND_ROAM   6

Definition at line 282 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

◆ HFP_CIND_SERVICE

#define HFP_CIND_SERVICE   1

Definition at line 277 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

◆ HFP_CIND_SERVICE_AVAILABLE

#define HFP_CIND_SERVICE_AVAILABLE   1

Definition at line 297 of file chan_mobile.c.

Referenced by mbl_has_service().

◆ 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.

Referenced by hfp_parse_cind_test().

◆ HFP_CIND_UNKNOWN

#define HFP_CIND_UNKNOWN   -1

Definition at line 275 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

◆ HFP_HF_CID

#define HFP_HF_CID   (1 << 2)

Definition at line 259 of file chan_mobile.c.

Referenced by hfp_brsf2int().

◆ HFP_HF_CONTROL

#define HFP_HF_CONTROL   (1 << 6)

Definition at line 263 of file chan_mobile.c.

Referenced by hfp_brsf2int().

◆ HFP_HF_CW

#define HFP_HF_CW   (1 << 1)

Definition at line 258 of file chan_mobile.c.

Referenced by hfp_brsf2int().

◆ HFP_HF_ECNR

#define HFP_HF_ECNR   (1 << 0)

Definition at line 257 of file chan_mobile.c.

Referenced by hfp_brsf2int().

◆ HFP_HF_STATUS

#define HFP_HF_STATUS   (1 << 5)

Definition at line 262 of file chan_mobile.c.

Referenced by hfp_brsf2int().

◆ HFP_HF_VOICE

#define HFP_HF_VOICE   (1 << 3)

Definition at line 260 of file chan_mobile.c.

Referenced by hfp_brsf2int().

◆ HFP_HF_VOLUME

#define HFP_HF_VOLUME   (1 << 4)

Definition at line 261 of file chan_mobile.c.

Referenced by hfp_brsf2int().

◆ MBL_CONFIG

#define MBL_CONFIG   "chan_mobile.conf"

Definition at line 78 of file chan_mobile.c.

Referenced by load_module(), and mbl_load_config().

◆ MBL_CONFIG_OLD

#define MBL_CONFIG_OLD   "mobile.conf"

Definition at line 79 of file chan_mobile.c.

Referenced by mbl_load_config().

◆ rfcomm_read_debug

#define rfcomm_read_debug (   c)

Enumeration Type Documentation

◆ at_message_t

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

Definition at line 419 of file chan_mobile.c.

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

◆ mbl_type

enum mbl_type
Enumerator
MBL_TYPE_PHONE 
MBL_TYPE_HEADSET 

Definition at line 94 of file chan_mobile.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4838 of file chan_mobile.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 4838 of file chan_mobile.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 4838 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.

Referenced by at_read_full().

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:141

◆ 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.

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

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 }

◆ at_read_full()

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

Read an AT message and clasify 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.

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, and rfcomm_read().

Referenced by do_monitor_headset(), and do_monitor_phone().

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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int at_match_prefix(char *buf, char *prefix)
Match the given buffer with the given prefix.
Definition: chan_mobile.c:2003
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

◆ check_unloading()

static int check_unloading ( )
inlinestatic

Check if the module is unloading.

Return values
0not unloading
1unloading

Definition at line 4682 of file chan_mobile.c.

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

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

◆ 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.

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

Referenced by mbl_read().

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

◆ do_discovery()

static void* do_discovery ( void *  data)
static

Definition at line 4282 of file chan_mobile.c.

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

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

◆ do_monitor_headset()

static void* do_monitor_headset ( void *  data)
static

Definition at line 4119 of file chan_mobile.c.

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

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

◆ do_monitor_phone()

static void* do_monitor_phone ( void *  data)
static

Definition at line 3870 of file chan_mobile.c.

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, adapter_pvt::entry, errno, EVENT_FLAG_SYSTEM, msg_queue_entry::expected, 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_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, msg_queue_entry::response_to, mbl_pvt::rfcomm_socket, rfcomm_wait(), hfp_pvt::rsock, mbl_pvt::sco_socket, and mbl_pvt::timeout.

Referenced by start_monitor().

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

◆ 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 4326 of file chan_mobile.c.

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

4327 {
4328  struct adapter_pvt *adapter = (struct adapter_pvt *) data;
4329 
4330  while (!check_unloading()) {
4331  /* check for new sco connections */
4332  if (ast_io_wait(adapter->accept_io, 0) == -1) {
4333  /* handle errors */
4334  ast_log(LOG_ERROR, "ast_io_wait() failed for adapter %s\n", adapter->id);
4335  break;
4336  }
4337 
4338  /* handle audio data */
4339  if (ast_io_wait(adapter->io, 1) == -1) {
4340  ast_log(LOG_ERROR, "ast_io_wait() failed for audio on adapter %s\n", adapter->id);
4341  break;
4342  }
4343  }
4344 
4345  return NULL;
4346 }
int ast_io_wait(struct io_context *ioc, int howlong)
Waits for IO.
Definition: io.c:278
char id[31]
Definition: chan_mobile.c:102
struct io_context * accept_io
Definition: chan_mobile.c:107
static int check_unloading(void)
Check if the module is unloading.
Definition: chan_mobile.c:4682
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
struct io_context * io
Definition: chan_mobile.c:106
#define LOG_ERROR
Definition: logger.h:285

◆ 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.

References ast_cli_args::argc, ast_cli_args::argv, 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, ast_cli_args::fd, mbl_pvt::hfp, hfp_send_cusd(), mbl_pvt::id, mbl_pvt::lock, msg_queue_push(), NULL, and ast_cli_entry::usage.

660 {
661  char buf[128];
662  struct mbl_pvt *pvt = NULL;
663 
664  switch (cmd) {
665  case CLI_INIT:
666  e->command = "mobile cusd";
667  e->usage =
668  "Usage: mobile cusd <device ID> <command>\n"
669  " Send cusd <command> to the rfcomm port on the device\n"
670  " with the specified <device ID>.\n";
671  return NULL;
672  case CLI_GENERATE:
673  return NULL;
674  }
675 
676  if (a->argc != 4)
677  return CLI_SHOWUSAGE;
678 
681  if (!strcmp(pvt->id, a->argv[2]))
682  break;
683  }
685 
686  if (!pvt) {
687  ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
688  goto e_return;
689  }
690 
691  ast_mutex_lock(&pvt->lock);
692  if (!pvt->connected) {
693  ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
694  goto e_unlock_pvt;
695  }
696 
697  snprintf(buf, sizeof(buf), "%s", a->argv[3]);
698  if (hfp_send_cusd(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CUSD)) {
699  ast_cli(a->fd, "[%s] error sending CUSD\n", pvt->id);
700  goto e_unlock_pvt;
701  }
702 
703 e_unlock_pvt:
704  ast_mutex_unlock(&pvt->lock);
705 e_return:
706  return CLI_SUCCESS;
707 }
unsigned int connected
Definition: chan_mobile.c:161
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const int argc
Definition: cli.h:160
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Definition: cli.h:152
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
const int fd
Definition: cli.h:159
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
char id[31]
Definition: chan_mobile.c:125
ast_mutex_t lock
Definition: chan_mobile.c:121
static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code)
Send CUSD.
Definition: chan_mobile.c:2712
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
Definition: search.h:40
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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.

References ast_cli_args::argc, ast_cli_args::argv, 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, ast_cli_args::fd, mbl_pvt::id, mbl_pvt::lock, msg_queue_push(), NULL, mbl_pvt::rfcomm_socket, rfcomm_write(), and ast_cli_entry::usage.

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]);
650  rfcomm_write(pvt->rfcomm_socket, buf);
652 
653 e_unlock_pvt:
654  ast_mutex_unlock(&pvt->lock);
655 e_return:
656  return CLI_SUCCESS;
657 }
unsigned int connected
Definition: chan_mobile.c:161
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const int argc
Definition: cli.h:160
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Definition: cli.h:152
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
int rfcomm_socket
Definition: chan_mobile.c:132
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
const int fd
Definition: cli.h:159
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
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:2982
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
char id[31]
Definition: chan_mobile.c:125
ast_mutex_t lock
Definition: chan_mobile.c:121
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
Definition: search.h:40
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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.

References adapter_pvt::addr, ast_cli_args::argc, 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, ast_cli_args::fd, FORMAT1, FORMAT2, adapter_pvt::hci_socket, adapter_pvt::inuse, len(), name, NULL, sdp_search(), and ast_cli_entry::usage.

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

◆ 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.

References mbl_pvt::adapter, mbl_pvt::addr, ast_cli_args::argc, 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, ast_cli_args::fd, 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.

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 }
char id[31]
Definition: chan_mobile.c:102
unsigned int connected
Definition: chan_mobile.c:161
const int argc
Definition: cli.h:160
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Definition: cli.h:152
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define FORMAT1
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
bdaddr_t addr
Definition: chan_mobile.c:127
const int fd
Definition: cli.h:159
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
unsigned int has_sms
Definition: chan_mobile.c:141
#define CLI_SHOWUSAGE
Definition: cli.h:45
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
ast_mutex_t lock
Definition: chan_mobile.c:121
char * command
Definition: cli.h:186
unsigned int outgoing_sms
Definition: chan_mobile.c:155
const char * usage
Definition: cli.h:177
unsigned int incoming_sms
Definition: chan_mobile.c:156
#define CLI_SUCCESS
Definition: cli.h:44
struct adapter_pvt * adapter
Definition: chan_mobile.c:128
Definition: search.h:40
int group
Definition: chan_mobile.c:126
#define ast_mutex_unlock(a)
Definition: lock.h:188
static int mbl_has_service(struct mbl_pvt *pvt)
Check if a mobile device has service.
Definition: chan_mobile.c:1369

◆ 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 3196 of file chan_mobile.c.

References ast_debug, AT_BRSF, at_msg2str(), AT_OK, adapter_pvt::entry, msg_queue_entry::expected, 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().

3197 {
3198  struct msg_queue_entry *entry;
3199  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_BRSF) {
3200  if (hfp_parse_brsf(pvt->hfp, buf)) {
3201  ast_debug(1, "[%s] error parsing BRSF\n", pvt->id);
3202  goto e_return;
3203  }
3204 
3205  if (msg_queue_push(pvt, AT_OK, AT_BRSF)) {
3206  ast_debug(1, "[%s] error handling BRSF\n", pvt->id);
3207  goto e_return;
3208  }
3209 
3211  } else if (entry) {
3212  ast_debug(1, "[%s] received unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3213  } else {
3214  ast_debug(1, "[%s] received unexpected AT message 'BRSF'\n", pvt->id);
3215  }
3216 
3217  return 0;
3218 
3219 e_return:
3221  return -1;
3222 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf)
Parse BRSF data.
Definition: chan_mobile.c:2724
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
static const char * at_msg2str(at_message_t msg)
Get the string representation of the given AT message.
Definition: chan_mobile.c:2076
at_message_t expected
Definition: chan_mobile.c:461
char id[31]
Definition: chan_mobile.c:125
Definition: chan_mobile.c:460
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3058
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:3032
struct msg_queue_entry::@6 entry

◆ 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 3831 of file chan_mobile.c.

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

3832 {
3834  pvt->needchup = 1;
3836  return 0;
3837 }
int hangupcause
Definition: chan_mobile.c:150
static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
Definition: chan_mobile.c:1317
unsigned int needchup
Definition: chan_mobile.c:158
#define AST_CAUSE_USER_BUSY
Definition: causes.h:106

◆ 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 3559 of file chan_mobile.c.

References mbl_pvt::answered, AST_CONTROL_ANSWER, AST_CONTROL_RINGING, ast_debug, ast_log, ast_setstate(), AST_STATE_UP, ast_verb, 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().

3560 {
3561  int i;
3562  switch (hfp_parse_ciev(pvt->hfp, buf, &i)) {
3563  case HFP_CIND_CALL:
3564  switch (i) {
3565  case HFP_CIND_CALL_NONE:
3566  ast_debug(1, "[%s] line disconnected\n", pvt->id);
3567  if (pvt->owner) {
3568  ast_debug(1, "[%s] hanging up owner\n", pvt->id);
3569  if (mbl_queue_hangup(pvt)) {
3570  ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
3571  return -1;
3572  }
3573  }
3574  pvt->needchup = 0;
3575  pvt->needcallerid = 0;
3576  pvt->incoming = 0;
3577  pvt->outgoing = 0;
3578  break;
3579  case HFP_CIND_CALL_ACTIVE:
3580  if (pvt->outgoing) {
3581  ast_debug(1, "[%s] remote end answered\n", pvt->id);
3583  } else if (pvt->incoming && pvt->answered) {
3585  } else if (pvt->incoming) {
3586  /* user answered from handset, disconnecting */
3587  ast_verb(3, "[%s] user answered bluetooth device from handset, disconnecting\n", pvt->id);
3588  mbl_queue_hangup(pvt);
3589  return -1;
3590  }
3591  break;
3592  }
3593  break;
3594 
3595  case HFP_CIND_CALLSETUP:
3596  switch (i) {
3598  if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
3599  if (pvt->owner) {
3600  if (pvt->hfp->sent_alerting == 1) {
3601  handle_response_busy(pvt);
3602  }
3603  if (mbl_queue_hangup(pvt)) {
3604  ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
3605  return -1;
3606  }
3607  }
3608  pvt->needchup = 0;
3609  pvt->needcallerid = 0;
3610  pvt->incoming = 0;
3611  pvt->outgoing = 0;
3612  }
3613  break;
3615  ast_debug(1, "[%s] incoming call, waiting for caller id\n", pvt->id);
3616  pvt->needcallerid = 1;
3617  pvt->incoming = 1;
3618  break;
3620  if (pvt->outgoing) {
3621  pvt->hfp->sent_alerting = 0;
3622  ast_debug(1, "[%s] outgoing call\n", pvt->id);
3623  } else {
3624  ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
3625  return -1;
3626  }
3627  break;
3629  if (pvt->outgoing) {
3630  ast_debug(1, "[%s] remote alerting\n", pvt->id);
3632  pvt->hfp->sent_alerting = 1;
3633  }
3634  break;
3635  }
3636  break;
3637  case HFP_CIND_NONE:
3638  ast_debug(1, "[%s] error parsing CIND: %s\n", pvt->id, buf);
3639  break;
3640  }
3641  return 0;
3642 }
static int mbl_queue_hangup(struct mbl_pvt *pvt)
Definition: chan_mobile.c:1334
static int handle_response_busy(struct mbl_pvt *pvt)
Handle BUSY messages.
Definition: chan_mobile.c:3831
#define HFP_CIND_CALL
Definition: chan_mobile.c:278
#define HFP_CIND_CALL_ACTIVE
Definition: chan_mobile.c:287
#define HFP_CIND_NONE
Definition: chan_mobile.c:276
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define HFP_CIND_CALLSETUP
Definition: chan_mobile.c:279
unsigned int answered
Definition: chan_mobile.c:160
#define HFP_CIND_CALL_NONE
Definition: chan_mobile.c:286
unsigned int incoming
Definition: chan_mobile.c:154
#define HFP_CIND_CALLSETUP_ALERTING
Definition: chan_mobile.c:293
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
int sent_alerting
Definition: chan_mobile.c:354
static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
Definition: chan_mobile.c:1317
#define LOG_ERROR
Definition: logger.h:285
int cind_state[16]
Definition: chan_mobile.c:350
struct hfp_cind cind_map
Definition: chan_mobile.c:351
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
unsigned int needchup
Definition: chan_mobile.c:158
static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
Parse a CIEV event.
Definition: chan_mobile.c:2195
#define HFP_CIND_CALLSETUP_INCOMING
Definition: chan_mobile.c:291
unsigned int outgoing
Definition: chan_mobile.c:153
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7486
unsigned int needcallerid
Definition: chan_mobile.c:157
#define HFP_CIND_CALLSETUP_NONE
Definition: chan_mobile.c:290
#define HFP_CIND_CALLSETUP_OUTGOING
Definition: chan_mobile.c:292

◆ 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 3231 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

3232 {
3233  struct msg_queue_entry *entry;
3234  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_CIND) {
3235  switch (entry->response_to) {
3236  case AT_CIND_TEST:
3238  ast_debug(1, "[%s] error performing CIND test\n", pvt->id);
3239  goto e_return;
3240  }
3241  break;
3242  case AT_CIND:
3243  if (hfp_parse_cind(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND)) {
3244  ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3245  goto e_return;
3246  }
3247  break;
3248  default:
3249  ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3250  goto e_return;
3251  }
3253  } else if (entry) {
3254  ast_debug(1, "[%s] received unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3255  } else {
3256  ast_debug(1, "[%s] received unexpected AT message 'CIND'\n", pvt->id);
3257  }
3258 
3259  return 0;
3260 
3261 e_return:
3263  return -1;
3264 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
Parse the result of the AT+CIND=? command.
Definition: chan_mobile.c:2818
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
static const char * at_msg2str(at_message_t msg)
Get the string representation of the given AT message.
Definition: chan_mobile.c:2076
at_message_t expected
Definition: chan_mobile.c:461
char id[31]
Definition: chan_mobile.c:125
at_message_t response_to
Definition: chan_mobile.c:462
Definition: chan_mobile.c:460
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3058
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:3032
static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf)
Read the result of the AT+CIND? command.
Definition: chan_mobile.c:2768
struct msg_queue_entry::@6 entry

◆ 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 3651 of file chan_mobile.c.

References ast_log, ast_pbx_start(), AST_STATE_RING, AT_CHUP, AT_CLIP, AT_OK, 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().

3652 {
3653  struct msg_queue_entry *msg;
3654  struct ast_channel *chan;
3655  struct cidinfo cidinfo;
3656 
3657  if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CLIP) {
3659 
3660  pvt->needcallerid = 0;
3661  cidinfo = hfp_parse_clip(pvt->hfp, buf);
3662 
3663  if (!(chan = mbl_new(AST_STATE_RING, pvt, &cidinfo, NULL, NULL))) {
3664  ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
3665  hfp_send_chup(pvt->hfp);
3666  msg_queue_push(pvt, AT_OK, AT_CHUP);
3667  return -1;
3668  }
3669 
3670  /* from this point on, we need to send a chup in the event of a
3671  * hangup */
3672  pvt->needchup = 1;
3673 
3674  if (ast_pbx_start(chan)) {
3675  ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
3676  mbl_ast_hangup(pvt);
3677  return -1;
3678  }
3679  }
3680 
3681  return 0;
3682 }
Main Channel structure associated with a channel.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4712
#define NULL
Definition: resample.c:96
static int mbl_ast_hangup(struct mbl_pvt *pvt)
Definition: chan_mobile.c:1354
#define ast_log
Definition: astobj2.c:42
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
#define LOG_ERROR
Definition: logger.h:285
at_message_t expected
Definition: chan_mobile.c:461
char id[31]
Definition: chan_mobile.c:125
unsigned int needchup
Definition: chan_mobile.c:158
static int hfp_send_chup(struct hfp_pvt *hfp)
Send AT+CHUP.
Definition: chan_mobile.c:2681
Definition: chan_mobile.c:460
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3058
unsigned int needcallerid
Definition: chan_mobile.c:157
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:3032
static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
Parse a CLIP event.
Definition: chan_mobile.c:2224
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

◆ 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 3735 of file chan_mobile.c.

References ast_channel_exten_set(), ast_debug, ast_log, ast_pbx_start(), AST_STATE_DOWN, AT_CMGR, 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().

3736 {
3737  char *from_number = NULL, *text = NULL;
3738  struct ast_channel *chan;
3739  struct msg_queue_entry *msg;
3740 
3741  if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CMGR) {
3743 
3744  if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)) {
3745  ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
3746  return -1;
3747  }
3748 
3749  ast_debug(1, "[%s] successfully read sms message\n", pvt->id);
3750  pvt->incoming_sms = 0;
3751 
3752  /* XXX this channel probably does not need to be associated with this pvt */
3753  if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
3754  ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
3755  return -1;
3756  }
3757 
3758  ast_channel_exten_set(chan, "sms");
3759  pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
3760  pbx_builtin_setvar_helper(chan, "SMSTXT", text);
3761 
3762  if (ast_pbx_start(chan)) {
3763  ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming sms\n", pvt->id);
3764  mbl_ast_hangup(pvt);
3765  }
3766  } else {
3767  ast_debug(1, "[%s] got unexpected +CMGR message, ignoring\n", pvt->id);
3768  }
3769 
3770  return 0;
3771 }
Main Channel structure associated with a channel.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4712
char * text
Definition: app_queue.c:1508
#define NULL
Definition: resample.c:96
static int mbl_ast_hangup(struct mbl_pvt *pvt)
Definition: chan_mobile.c:1354
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
#define LOG_ERROR
Definition: logger.h:285
at_message_t expected
Definition: chan_mobile.c:461
char id[31]
Definition: chan_mobile.c:125
Definition: chan_mobile.c:460
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
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...
unsigned int incoming_sms
Definition: chan_mobile.c:156
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3058
static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text)
Parse a CMGR message.
Definition: chan_mobile.c:2352
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:3032
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

◆ 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 3708 of file chan_mobile.c.

References ast_debug, AT_CMGR, 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().

3709 {
3710  int index = hfp_parse_cmti(pvt->hfp, buf);
3711  if (index > 0) {
3712  ast_debug(1, "[%s] incoming sms message\n", pvt->id);
3713 
3714  if (hfp_send_cmgr(pvt->hfp, index)
3715  || msg_queue_push(pvt, AT_CMGR, AT_CMGR)) {
3716  ast_debug(1, "[%s] error sending CMGR to retrieve SMS message\n", pvt->id);
3717  return -1;
3718  }
3719 
3720  pvt->incoming_sms = 1;
3721  return 0;
3722  } else {
3723  ast_debug(1, "[%s] error parsing incoming sms message alert, disconnecting\n", pvt->id);
3724  return -1;
3725  }
3726 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
Parse a CMTI notification.
Definition: chan_mobile.c:2326
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
char id[31]
Definition: chan_mobile.c:125
static int hfp_send_cmgr(struct hfp_pvt *hfp, int index)
Read an SMS message.
Definition: chan_mobile.c:2646
unsigned int incoming_sms
Definition: chan_mobile.c:156

◆ 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 3811 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

3812 {
3813  char *cusd;
3814 
3815  if (!(cusd = hfp_parse_cusd(pvt->hfp, buf))) {
3816  ast_verb(0, "[%s] error parsing CUSD: %s\n", pvt->id, buf);
3817  return 0;
3818  }
3819 
3820  ast_verb(0, "[%s] CUSD response: %s\n", pvt->id, cusd);
3821 
3822  return 0;
3823 }
static char * hfp_parse_cusd(struct hfp_pvt *hfp, char *buf)
Parse a CUSD answer.
Definition: chan_mobile.c:2416
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_verb(level,...)
Definition: logger.h:463
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
char id[31]
Definition: chan_mobile.c:125

◆ 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 3442 of file chan_mobile.c.

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, adapter_pvt::entry, msg_queue_entry::expected, 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, msg_queue_entry::response_to, and mbl_pvt::timeout.

Referenced by do_monitor_phone().

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

◆ 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 3861 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

3862 {
3863  ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
3864  pvt->needchup = 1;
3866  return 0;
3867 }
#define ast_verb(level,...)
Definition: logger.h:463
static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
Definition: chan_mobile.c:1317
char id[31]
Definition: chan_mobile.c:125
unsigned int needchup
Definition: chan_mobile.c:158

◆ 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 3846 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

3847 {
3848  ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
3849  pvt->needchup = 1;
3851  return 0;
3852 }
#define ast_verb(level,...)
Definition: logger.h:463
static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
Definition: chan_mobile.c:1317
char id[31]
Definition: chan_mobile.c:125
unsigned int needchup
Definition: chan_mobile.c:158

◆ 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 3273 of file chan_mobile.c.

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, adapter_pvt::entry, msg_queue_entry::expected, 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, msg_queue_entry::response_to, hfp_cind::service, and mbl_pvt::timeout.

Referenced by do_monitor_phone().

3274 {
3275  struct msg_queue_entry *entry;
3276  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_OK) {
3277  switch (entry->response_to) {
3278 
3279  /* initialization stuff */
3280  case AT_BRSF:
3281  ast_debug(1, "[%s] BSRF sent successfully\n", pvt->id);
3282 
3283  /* If this is a blackberry do CMER now, otherwise
3284  * continue with CIND as normal. */
3285  if (pvt->blackberry) {
3286  if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
3287  ast_debug(1, "[%s] error sending CMER\n", pvt->id);
3288  goto e_return;
3289  }
3290  } else {
3292  ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
3293  goto e_return;
3294  }
3295  }
3296  break;
3297  case AT_CIND_TEST:
3298  ast_debug(1, "[%s] CIND test sent successfully\n", pvt->id);
3299 
3300  ast_debug(2, "[%s] call: %d\n", pvt->id, pvt->hfp->cind_map.call);
3301  ast_debug(2, "[%s] callsetup: %d\n", pvt->id, pvt->hfp->cind_map.callsetup);
3302  ast_debug(2, "[%s] service: %d\n", pvt->id, pvt->hfp->cind_map.service);
3303 
3304  if (hfp_send_cind(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND)) {
3305  ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
3306  goto e_return;
3307  }
3308  break;
3309  case AT_CIND:
3310  ast_debug(1, "[%s] CIND sent successfully\n", pvt->id);
3311 
3312  /* check if a call is active */
3313  if (pvt->hfp->cind_state[pvt->hfp->cind_map.call]) {
3314  ast_verb(3, "Bluetooth Device %s has a call in progress - delaying connection.\n", pvt->id);
3315  goto e_return;
3316  }
3317 
3318  /* If this is NOT a blackberry proceed with CMER,
3319  * otherwise send CLIP. */
3320  if (!pvt->blackberry) {
3321  if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
3322  ast_debug(1, "[%s] error sending CMER\n", pvt->id);
3323  goto e_return;
3324  }
3325  } else {
3326  if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
3327  ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
3328  goto e_return;
3329  }
3330  }
3331  break;
3332  case AT_CMER:
3333  ast_debug(1, "[%s] CMER sent successfully\n", pvt->id);
3334 
3335  /* If this is a blackberry proceed with the CIND test,
3336  * otherwise send CLIP. */
3337  if (pvt->blackberry) {
3339  ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
3340  goto e_return;
3341  }
3342  } else {
3343  if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
3344  ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
3345  goto e_return;
3346  }
3347  }
3348  break;
3349  case AT_CLIP:
3350  ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
3351  if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
3352  ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
3353  goto e_return;
3354  }
3355 
3356  break;
3357  case AT_ECAM:
3358  ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
3359  if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
3360  ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
3361  goto e_return;
3362  }
3363 
3364  pvt->timeout = -1;
3365  pvt->hfp->initialized = 1;
3366  ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
3367 
3368  break;
3369  case AT_VGS:
3370  ast_debug(1, "[%s] volume level synchronization successful\n", pvt->id);
3371 
3372  /* set the SMS operating mode to text mode */
3373  if (pvt->has_sms) {
3374  if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
3375  ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
3376  goto e_return;
3377  }
3378  }
3379  break;
3380  case AT_CMGF:
3381  ast_debug(1, "[%s] sms text mode enabled\n", pvt->id);
3382  /* turn on SMS new message indication */
3383  if (hfp_send_cnmi(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_CNMI)) {
3384  ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
3385  goto e_return;
3386  }
3387  break;
3388  case AT_CNMI:
3389  ast_debug(1, "[%s] sms new message indication enabled\n", pvt->id);
3390  pvt->has_sms = 1;
3391  break;
3392  /* end initialization stuff */
3393 
3394  case AT_A:
3395  ast_debug(1, "[%s] answer sent successfully\n", pvt->id);
3396  pvt->needchup = 1;
3397  break;
3398  case AT_D:
3399  ast_debug(1, "[%s] dial sent successfully\n", pvt->id);
3400  pvt->needchup = 1;
3401  pvt->outgoing = 1;
3403  break;
3404  case AT_CHUP:
3405  ast_debug(1, "[%s] successful hangup\n", pvt->id);
3406  break;
3407  case AT_CMGS:
3408  ast_debug(1, "[%s] successfully sent sms message\n", pvt->id);
3409  pvt->outgoing_sms = 0;
3410  break;
3411  case AT_VTS:
3412  ast_debug(1, "[%s] digit sent successfully\n", pvt->id);
3413  break;
3414  case AT_CUSD:
3415  ast_debug(1, "[%s] CUSD code sent successfully\n", pvt->id);
3416  break;
3417  case AT_UNKNOWN:
3418  default:
3419  ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
3420  break;
3421  }
3423  } else if (entry) {
3424  ast_debug(1, "[%s] received AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3425  } else {
3426  ast_debug(1, "[%s] received unexpected AT message 'OK'\n", pvt->id);
3427  }
3428  return 0;
3429 
3430 e_return:
3432  return -1;
3433 }
unsigned int blackberry
Definition: chan_mobile.c:144
static int hfp_send_cind(struct hfp_pvt *hfp)
Send the CIND read command.
Definition: chan_mobile.c:2525
int timeout
Definition: chan_mobile.c:139
static int hfp_send_cmer(struct hfp_pvt *hfp, int status)
Enable or disable indicator events reporting.
Definition: chan_mobile.c:2544
#define ast_verb(level,...)
Definition: logger.h:463
static int hfp_send_clip(struct hfp_pvt *hfp, int status)
Enable or disable calling line identification.
Definition: chan_mobile.c:2583
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static int hfp_send_vgs(struct hfp_pvt *hfp, int value)
Send the current speaker gain level.
Definition: chan_mobile.c:2556
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
unsigned int has_sms
Definition: chan_mobile.c:141
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:2982
int initialized
Definition: chan_mobile.c:346
static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
Definition: chan_mobile.c:1317
static const char * at_msg2str(at_message_t msg)
Get the string representation of the given AT message.
Definition: chan_mobile.c:2076
int callsetup
Definition: chan_mobile.c:333
static int hfp_send_cind_test(struct hfp_pvt *hfp)
Send the CIND test command.
Definition: chan_mobile.c:2534
int cind_state[16]
Definition: chan_mobile.c:350
at_message_t expected
Definition: chan_mobile.c:461
struct hfp_cind cind_map
Definition: chan_mobile.c:351
char id[31]
Definition: chan_mobile.c:125
at_message_t response_to
Definition: chan_mobile.c:462
unsigned int needchup
Definition: chan_mobile.c:158
static int hfp_send_cnmi(struct hfp_pvt *hfp)
Setup SMS new message indication.
Definition: chan_mobile.c:2636
static int hfp_send_ecam(struct hfp_pvt *hfp)
Enable Sony Erricson extensions / indications.
Definition: chan_mobile.c:2182
static int hfp_send_cmgf(struct hfp_pvt *hfp, int mode)
Set the SMS mode.
Definition: chan_mobile.c:2625
unsigned int outgoing_sms
Definition: chan_mobile.c:155
Definition: chan_mobile.c:460
int service
Definition: chan_mobile.c:331
unsigned int outgoing
Definition: chan_mobile.c:153
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3058
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:3032
struct msg_queue_entry::@6 entry

◆ 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 3691 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

3692 {
3693  if (pvt->needcallerid) {
3694  ast_debug(1, "[%s] got ring while waiting for caller id\n", pvt->id);
3695  return msg_queue_push(pvt, AT_CLIP, AT_UNKNOWN);
3696  } else {
3697  return 0;
3698  }
3699 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
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:2982
char id[31]
Definition: chan_mobile.c:125
unsigned int needcallerid
Definition: chan_mobile.c:157

◆ 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 3780 of file chan_mobile.c.

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

3781 {
3782  struct msg_queue_entry *msg;
3783  if (!(msg = msg_queue_head(pvt))) {
3784  ast_debug(1, "[%s] error, got sms prompt with no pending sms messages\n", pvt->id);
3785  return 0;
3786  }
3787 
3788  if (msg->expected != AT_SMS_PROMPT) {
3789  ast_debug(1, "[%s] error, got sms prompt but no pending sms messages\n", pvt->id);
3790  return 0;
3791  }
3792 
3793  if (hfp_send_sms_text(pvt->hfp, msg->data)
3794  || msg_queue_push(pvt, AT_OK, AT_CMGS)) {
3796  ast_debug(1, "[%s] error sending sms message\n", pvt->id);
3797  return 0;
3798  }
3799 
3801  return 0;
3802 }
static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message)
Send the text of an SMS message.
Definition: chan_mobile.c:2670
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
at_message_t expected
Definition: chan_mobile.c:461
char id[31]
Definition: chan_mobile.c:125
Definition: chan_mobile.c:460
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3058
void * data
Definition: chan_mobile.c:463
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:3032

◆ headset_send_ring()

static int headset_send_ring ( const void *  data)
static

Definition at line 4102 of file chan_mobile.c.

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

4103 {
4104  struct mbl_pvt *pvt = (struct mbl_pvt *) data;
4105  ast_mutex_lock(&pvt->lock);
4106  if (!pvt->needring) {
4107  ast_mutex_unlock(&pvt->lock);
4108  return 0;
4109  }
4110  ast_mutex_unlock(&pvt->lock);
4111 
4112  if (hsp_send_ring(pvt->rfcomm_socket)) {
4113  ast_debug(1, "[%s] error sending RING\n", pvt->id);
4114  return 0;
4115  }
4116  return 1;
4117 }
#define ast_mutex_lock(a)
Definition: lock.h:187
int rfcomm_socket
Definition: chan_mobile.c:132
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
char id[31]
Definition: chan_mobile.c:125
static int hsp_send_ring(int rsock)
Send a RING unsolicited AT response.
Definition: chan_mobile.c:2966
ast_mutex_t lock
Definition: chan_mobile.c:121
unsigned int needring
Definition: chan_mobile.c:159
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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 2468 of file chan_mobile.c.

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

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

◆ 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 2490 of file chan_mobile.c.

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

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

◆ 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 2724 of file chan_mobile.c.

References hfp_pvt::brsf, and hfp_int2brsf().

Referenced by handle_response_brsf().

2725 {
2726  int brsf;
2727 
2728  if (!sscanf(buf, "+BRSF:%d", &brsf))
2729  return -1;
2730 
2731  hfp_int2brsf(brsf, &hfp->brsf);
2732 
2733  return 0;
2734 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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:2490
struct hfp_ag brsf
Definition: chan_mobile.c:348

◆ 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 2195 of file chan_mobile.c.

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

Referenced by handle_response_ciev().

2196 {
2197  int i, v;
2198  if (!value)
2199  value = &v;
2200 
2201  if (!sscanf(buf, "+CIEV: %d,%d", &i, value)) {
2202  ast_debug(2, "[%s] error parsing CIEV event '%s'\n", hfp->owner->id, buf);
2203  return HFP_CIND_NONE;
2204  }
2205 
2206  if (i >= ARRAY_LEN(hfp->cind_state)) {
2207  ast_debug(2, "[%s] CIEV event index too high (%s)\n", hfp->owner->id, buf);
2208  return HFP_CIND_NONE;
2209  }
2210 
2211  hfp->cind_state[i] = *value;
2212  return hfp->cind_index[i];
2213 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define HFP_CIND_NONE
Definition: chan_mobile.c:276
int cind_index[16]
Definition: chan_mobile.c:349
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int value
Definition: syslog.c:37
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct mbl_pvt * owner
Definition: chan_mobile.c:345
int cind_state[16]
Definition: chan_mobile.c:350
char id[31]
Definition: chan_mobile.c:125

◆ 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 2768 of file chan_mobile.c.

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

Referenced by handle_response_cind().

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

◆ 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 2742 of file chan_mobile.c.

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

Referenced by hfp_parse_cind().

2743 {
2744  int value;
2745 
2746  /* store the current indicator */
2747  if (group >= ARRAY_LEN(hfp->cind_state)) {
2748  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));
2749  return -1;
2750  }
2751 
2752  if (!sscanf(indicator, "%d", &value)) {
2753  ast_debug(1, "error parsing CIND state '%s' for group %d\n", indicator, group);
2754  return -1;
2755  }
2756 
2757  hfp->cind_state[group] = value;
2758  return 0;
2759 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int indicator
int value
Definition: syslog.c:37
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int cind_state[16]
Definition: chan_mobile.c:350
int group
Definition: chan_mobile.c:126

◆ 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 2818 of file chan_mobile.c.

References ast_debug, hfp_cind::battchg, 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().

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

◆ 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 2224 of file chan_mobile.c.

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

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

◆ 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 2352 of file chan_mobile.c.

References state.

Referenced by handle_response_cmgr().

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

◆ 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 2326 of file chan_mobile.c.

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

Referenced by handle_response_cmti().

2327 {
2328  int index = -1;
2329 
2330  /* parse cmti info in the following format:
2331  * +CMTI: <mem>,<index>
2332  */
2333  if (!sscanf(buf, "+CMTI: %*[^,],%d", &index)) {
2334  ast_debug(2, "[%s] error parsing CMTI event '%s'\n", hfp->owner->id, buf);
2335  return -1;
2336  }
2337 
2338  return index;
2339 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct mbl_pvt * owner
Definition: chan_mobile.c:345
char id[31]
Definition: chan_mobile.c:125

◆ 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 2416 of file chan_mobile.c.

References NULL.

Referenced by handle_response_cusd().

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

◆ 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 string: *ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>] [,exitcause][,<number>,<type>]

Example indicating busy: *ECAV: 1,7,1

Definition at line 2164 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

2165 {
2166  int ccid = 0;
2167  int ccstatus = 0;
2168  int calltype = 0;
2169 
2170  if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
2171  ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
2172  return -1;
2173  }
2174 
2175  return ccstatus;
2176 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct mbl_pvt * owner
Definition: chan_mobile.c:345
char id[31]
Definition: chan_mobile.c:125

◆ hfp_send_ata()

static int hfp_send_ata ( struct hfp_pvt hfp)
static

Send ATA.

Parameters
hfpan hfp_pvt struct

Definition at line 2702 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_answer().

2703 {
2704  return rfcomm_write(hfp->rsock, "ATA\r");
2705 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2691 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_call().

2692 {
2693  char cmd[64];
2694  snprintf(cmd, sizeof(cmd), "ATD%s;\r", number);
2695  return rfcomm_write(hfp->rsock, cmd);
2696 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
Number structure.
Definition: app_followme.c:154

◆ 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 2514 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

2515 {
2516  char cmd[32];
2517  snprintf(cmd, sizeof(cmd), "AT+BRSF=%d\r", hfp_brsf2int(brsf));
2518  return rfcomm_write(hfp->rsock, cmd);
2519 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
static int hfp_brsf2int(struct hfp_hf *hf)
Convert a hfp_hf struct to a BRSF int.
Definition: chan_mobile.c:2468

◆ hfp_send_chup()

static int hfp_send_chup ( struct hfp_pvt hfp)
static

Send AT+CHUP.

Parameters
hfpan hfp_pvt struct

Definition at line 2681 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_clip(), and mbl_hangup().

2682 {
2683  return rfcomm_write(hfp->rsock, "AT+CHUP\r");
2684 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2525 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2526 {
2527  return rfcomm_write(hfp->rsock, "AT+CIND?\r");
2528 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2534 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2535 {
2536  return rfcomm_write(hfp->rsock, "AT+CIND=?\r");
2537 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2583 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2584 {
2585  char cmd[32];
2586  snprintf(cmd, sizeof(cmd), "AT+CLIP=%d\r", status ? 1 : 0);
2587  return rfcomm_write(hfp->rsock, cmd);
2588 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
jack_status_t status
Definition: app_jack.c:146

◆ 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 2544 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2545 {
2546  char cmd[32];
2547  snprintf(cmd, sizeof(cmd), "AT+CMER=3,0,0,%d\r", status ? 1 : 0);
2548  return rfcomm_write(hfp->rsock, cmd);
2549 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
jack_status_t status
Definition: app_jack.c:146

◆ 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 2625 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_error(), and handle_response_ok().

2626 {
2627  char cmd[32];
2628  snprintf(cmd, sizeof(cmd), "AT+CMGF=%d\r", mode);
2629  return rfcomm_write(hfp->rsock, cmd);
2630 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2646 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_cmti().

2647 {
2648  char cmd[32];
2649  snprintf(cmd, sizeof(cmd), "AT+CMGR=%d\r", index);
2650  return rfcomm_write(hfp->rsock, cmd);
2651 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2658 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_sendsms_exec().

2659 {
2660  char cmd[64];
2661  snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"\r", number);
2662  return rfcomm_write(hfp->rsock, cmd);
2663 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
Number structure.
Definition: app_followme.c:154

◆ 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 2636 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2637 {
2638  return rfcomm_write(hfp->rsock, "AT+CNMI=2,1,0,0,0\r");
2639 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2712 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_cli_mobile_cusd().

2713 {
2714  char cmd[128];
2715  snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code);
2716  return rfcomm_write(hfp->rsock, cmd);
2717 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2596 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_digit_end().

2597 {
2598  char cmd[10];
2599 
2600  switch(digit) {
2601  case '0':
2602  case '1':
2603  case '2':
2604  case '3':
2605  case '4':
2606  case '5':
2607  case '6':
2608  case '7':
2609  case '8':
2610  case '9':
2611  case '*':
2612  case '#':
2613  snprintf(cmd, sizeof(cmd), "AT+VTS=%c\r", digit);
2614  return rfcomm_write(hfp->rsock, cmd);
2615  default:
2616  return -1;
2617  }
2618 }
char digit
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ hfp_send_ecam()

static int hfp_send_ecam ( struct hfp_pvt hfp)
static

Enable Sony Erricson extensions / indications.

Parameters
hfpan hfp_pvt struct

Definition at line 2182 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2183 {
2184  return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
2185 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2670 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_sms_prompt().

2671 {
2672  char cmd[162];
2673  snprintf(cmd, sizeof(cmd), "%.160s\x1a", message);
2674  return rfcomm_write(hfp->rsock, cmd);
2675 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2556 of file chan_mobile.c.

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

Referenced by handle_response_error(), and handle_response_ok().

2557 {
2558  char cmd[32];
2559  snprintf(cmd, sizeof(cmd), "AT+VGS=%d\r", value);
2560  return rfcomm_write(hfp->rsock, cmd);
2561 }
int rsock
Definition: chan_mobile.c:352
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
int value
Definition: syslog.c:37

◆ 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 2933 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

2934 {
2935  return rfcomm_write(rsock, "\r\nERROR\r\n");
2936 }
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2924 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

2925 {
2926  return rfcomm_write(rsock, "\r\nOK\r\n");
2927 }
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2966 of file chan_mobile.c.

References rfcomm_write().

Referenced by headset_send_ring(), and mbl_call().

2967 {
2968  return rfcomm_write(rsock, "\r\nRING\r\n");
2969 }
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2955 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

2956 {
2957  char cmd[32];
2958  snprintf(cmd, sizeof(cmd), "\r\n+VGM=%d\r\n", gain);
2959  return rfcomm_write(rsock, cmd);
2960 }
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ 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 2943 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

2944 {
2945  char cmd[32];
2946  snprintf(cmd, sizeof(cmd), "\r\n+VGS=%d\r\n", gain);
2947  return rfcomm_write(rsock, cmd);
2948 }
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436

◆ load_module()

static int load_module ( void  )
static

Definition at line 4776 of file chan_mobile.c.

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_MODFLAG_LOAD_ORDER, AST_MODPRI_CHANNEL_DRIVER, AST_MODULE_INFO(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_MODULE_SUPPORT_EXTENDED, ast_pthread_create_background, ast_register_application, ASTERISK_GPL_KEY, ast_channel_tech::capabilities, adapter_pvt::dev_id, DEVICE_FRAME_FORMAT, discovery_thread, do_discovery(), LOG_ERROR, MBL_CONFIG, mbl_load_config(), mbl_sendsms_exec(), mbl_status_exec(), mblsendsms_desc, mblsendsms_synopsis, mblstatus_desc, mblstatus_synopsis, NULL, sdp_register(), sdp_session, and unload_module().

4777 {
4778 
4779  int dev_id, s;
4780 
4782  return AST_MODULE_LOAD_DECLINE;
4783  }
4784 
4786  /* Check if we have Bluetooth, no point loading otherwise... */
4787  dev_id = hci_get_route(NULL);
4788 
4789  s = hci_open_dev(dev_id);
4790  if (dev_id < 0 || s < 0) {
4791  ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n");
4794  hci_close_dev(s);
4795  return AST_MODULE_LOAD_DECLINE;
4796  }
4797 
4798  hci_close_dev(s);
4799 
4800  if (mbl_load_config()) {
4801  ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG);
4804  return AST_MODULE_LOAD_DECLINE;
4805  }
4806 
4808 
4809  /* Spin the discovery thread */
4811  ast_log(LOG_ERROR, "Unable to create discovery thread.\n");
4812  goto e_cleanup;
4813  }
4814 
4815  /* register our channel type */
4817  ast_log(LOG_ERROR, "Unable to register channel class %s\n", "Mobile");
4818  goto e_cleanup;
4819  }
4820 
4821  ast_cli_register_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
4824 
4825  return AST_MODULE_LOAD_SUCCESS;
4826 
4827 e_cleanup:
4828  unload_module();
4829 
4830  return AST_MODULE_LOAD_DECLINE;
4831 }
static struct ast_cli_entry mbl_cli[]
Definition: chan_mobile.c:193
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
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 NULL
Definition: resample.c:96
static sdp_session_t * sdp_session
Definition: chan_mobile.c:87
static pthread_t discovery_thread
Definition: chan_mobile.c:86
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
static int mbl_status_exec(struct ast_channel *ast, const char *data)
Definition: chan_mobile.c:715
#define ast_log
Definition: astobj2.c:42
#define ast_register_application(app, execute, synopsis, description)
Register an application.
Definition: module.h:610
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define DEVICE_FRAME_FORMAT
Definition: chan_mobile.c:82
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
static char * mblsendsms_synopsis
Definition: chan_mobile.c:210
static char * app_mblstatus
Definition: chan_mobile.c:201
#define LOG_ERROR
Definition: logger.h:285
#define MBL_CONFIG
Definition: chan_mobile.c:78
static int mbl_load_config(void)
Definition: chan_mobile.c:4624
static sdp_session_t * sdp_register(void)
Definition: chan_mobile.c:3119
struct ast_format_cap * capabilities
Definition: channel.h:633
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int mbl_sendsms_exec(struct ast_channel *ast, const char *data)
Definition: chan_mobile.c:763
static char * mblsendsms_desc
Definition: chan_mobile.c:211
static void * do_discovery(void *data)
Definition: chan_mobile.c:4282
static char * app_mblsendsms
Definition: chan_mobile.c:209
static char * mblstatus_desc
Definition: chan_mobile.c:203
static struct ast_channel_tech mbl_tech
Definition: chan_mobile.c:479
static char * mblstatus_synopsis
Definition: chan_mobile.c:202
static int unload_module(void)
Definition: chan_mobile.c:4702

◆ mbl_answer()

static int mbl_answer ( struct ast_channel ast)
static

Definition at line 1066 of file chan_mobile.c.

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.

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 }
void * ast_channel_tech_pvt(const struct ast_channel *chan)
unsigned int answered
Definition: chan_mobile.c:160
#define ast_mutex_lock(a)
Definition: lock.h:187
static int hfp_send_ata(struct hfp_pvt *hfp)
Send ATA.
Definition: chan_mobile.c:2702
unsigned int incoming
Definition: chan_mobile.c:154
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
enum mbl_type type
Definition: chan_mobile.c:124
ast_mutex_t lock
Definition: chan_mobile.c:121
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ mbl_ast_hangup()

static int mbl_ast_hangup ( struct mbl_pvt pvt)
static

Definition at line 1354 of file chan_mobile.c.

References ast_hangup(), and mbl_pvt::owner.

Referenced by handle_response_clip(), and handle_response_cmgr().

1355 {
1356  ast_hangup(pvt->owner);
1357  return 0;
1358 }
struct ast_channel * owner
Definition: chan_mobile.c:119
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548

◆ 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.

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.

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 }
static int hfp_send_atd(struct hfp_pvt *hfp, const char *number)
Send ATD.
Definition: chan_mobile.c:2691
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int hangupcause
Definition: chan_mobile.c:150
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
int rfcomm_socket
Definition: chan_mobile.c:132
static int headset_send_ring(const void *data)
Definition: chan_mobile.c:4102
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:2982
#define LOG_ERROR
Definition: logger.h:285
char id[31]
Definition: chan_mobile.c:125
unsigned int needchup
Definition: chan_mobile.c:158
static int hsp_send_ring(int rsock)
Send a RING unsolicited AT response.
Definition: chan_mobile.c:2966
enum mbl_type type
Definition: chan_mobile.c:124
ast_mutex_t lock
Definition: chan_mobile.c:121
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:565
unsigned int outgoing
Definition: chan_mobile.c:153
const char * ast_channel_name(const struct ast_channel *chan)
unsigned int needring
Definition: chan_mobile.c:159
int ring_sched_id
Definition: chan_mobile.c:147
struct ast_sched_context * sched
Definition: chan_mobile.c:149
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ mbl_devicestate()

static int mbl_devicestate ( const char *  data)
static

Definition at line 1214 of file chan_mobile.c.

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.

1215 {
1216 
1217  char *device;
1218  int res = AST_DEVICE_INVALID;
1219  struct mbl_pvt *pvt;
1220 
1221  device = ast_strdupa(S_OR(data, ""));
1222 
1223  ast_debug(1, "Checking device state for device %s\n", device);
1224 
1227  if (!strcmp(pvt->id, device))
1228  break;
1229  }
1231 
1232  if (!pvt)
1233  return res;
1234 
1235  ast_mutex_lock(&pvt->lock);
1236  if (pvt->connected) {
1237  if (pvt->owner)
1238  res = AST_DEVICE_INUSE;
1239  else
1240  res = AST_DEVICE_NOT_INUSE;
1241 
1242  if (!mbl_has_service(pvt))
1243  res = AST_DEVICE_UNAVAILABLE;
1244  }
1245  ast_mutex_unlock(&pvt->lock);
1246 
1247  return res;
1248 
1249 }
unsigned int connected
Definition: chan_mobile.c:161
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
ast_mutex_t lock
Definition: chan_mobile.c:121
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
Definition: search.h:40
#define ast_mutex_unlock(a)
Definition: lock.h:188
static int mbl_has_service(struct mbl_pvt *pvt)
Check if a mobile device has service.
Definition: chan_mobile.c:1369

◆ 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.

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

1089 {
1090  struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
1091 
1092  if (pvt->type == MBL_TYPE_HEADSET)
1093  return 0;
1094 
1095  ast_mutex_lock(&pvt->lock);
1096  if (hfp_send_dtmf(pvt->hfp, digit)) {
1097  ast_mutex_unlock(&pvt->lock);
1098  ast_debug(1, "[%s] error sending digit %c\n", pvt->id, digit);
1099  return -1;
1100  }
1101  msg_queue_push(pvt, AT_OK, AT_VTS);
1102  ast_mutex_unlock(&pvt->lock);
1103 
1104  ast_debug(1, "[%s] dialed %c\n", pvt->id, digit);
1105 
1106  return 0;
1107 }
char digit
static int hfp_send_dtmf(struct hfp_pvt *hfp, char digit)
Send a DTMF command.
Definition: chan_mobile.c:2596
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_mutex_lock(a)
Definition: lock.h:187
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
char id[31]
Definition: chan_mobile.c:125
enum mbl_type type
Definition: chan_mobile.c:124
ast_mutex_t lock
Definition: chan_mobile.c:121
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ mbl_fixup()

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

Definition at line 1195 of file chan_mobile.c.

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

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 }
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_mutex_lock(a)
Definition: lock.h:187
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ast_channel * owner
Definition: chan_mobile.c:119
ast_mutex_t lock
Definition: chan_mobile.c:121
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ mbl_hangup()

static int mbl_hangup ( struct ast_channel ast)
static

Definition at line 1028 of file chan_mobile.c.

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.

1029 {
1030 
1031  struct mbl_pvt *pvt;
1032 
1033  if (!ast_channel_tech_pvt(ast)) {
1034  ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
1035  return 0;
1036  }
1037  pvt = ast_channel_tech_pvt(ast);
1038 
1039  ast_debug(1, "[%s] hanging up device\n", pvt->id);
1040 
1041  ast_mutex_lock(&pvt->lock);
1042  ast_channel_set_fd(ast, 0, -1);
1043  close(pvt->sco_socket);
1044  pvt->sco_socket = -1;
1045 
1046  if (pvt->needchup) {
1047  hfp_send_chup(pvt->hfp);
1048  msg_queue_push(pvt, AT_OK, AT_CHUP);
1049  pvt->needchup = 0;
1050  }
1051 
1052  pvt->outgoing = 0;
1053  pvt->incoming = 0;
1054  pvt->needring = 0;
1055  pvt->owner = NULL;
1057 
1058  ast_mutex_unlock(&pvt->lock);
1059 
1061 
1062  return 0;
1063 
1064 }
int sco_socket
Definition: chan_mobile.c:137
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
unsigned int incoming
Definition: chan_mobile.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
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:2982
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
unsigned int needchup
Definition: chan_mobile.c:158
ast_mutex_t lock
Definition: chan_mobile.c:121
static int hfp_send_chup(struct hfp_pvt *hfp)
Send AT+CHUP.
Definition: chan_mobile.c:2681
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2431
unsigned int outgoing
Definition: chan_mobile.c:153
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7486
unsigned int needring
Definition: chan_mobile.c:159
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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.

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

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 }
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
int cind_state[16]
Definition: chan_mobile.c:350
struct hfp_cind cind_map
Definition: chan_mobile.c:351
enum mbl_type type
Definition: chan_mobile.c:124
int service
Definition: chan_mobile.c:331
#define HFP_CIND_SERVICE_AVAILABLE
Definition: chan_mobile.c:297

◆ 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 4364 of file chan_mobile.c.

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(), adapter_pvt::hci_socket, adapter_pvt::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().

4365 {
4366  const char *id, *address;
4367  struct adapter_pvt *adapter;
4368  struct ast_variable *v;
4369  struct hci_dev_req dr;
4370  uint16_t vs;
4371 
4372  id = ast_variable_retrieve(cfg, cat, "id");
4373  address = ast_variable_retrieve(cfg, cat, "address");
4374 
4375  if (ast_strlen_zero(id) || ast_strlen_zero(address)) {
4376  ast_log(LOG_ERROR, "Skipping adapter. Missing id or address settings.\n");
4377  goto e_return;
4378  }
4379 
4380  ast_debug(1, "Reading configuration for adapter %s %s.\n", id, address);
4381 
4382  if (!(adapter = ast_calloc(1, sizeof(*adapter)))) {
4383  ast_log(LOG_ERROR, "Skipping adapter %s. Error allocating memory.\n", id);
4384  goto e_return;
4385  }
4386 
4387  ast_copy_string(adapter->id, id, sizeof(adapter->id));
4388  str2ba(address, &adapter->addr);
4389 
4390  /* attempt to connect to the adapter */
4391  adapter->dev_id = hci_devid(address);
4392  adapter->hci_socket = hci_open_dev(adapter->dev_id);
4393  if (adapter->dev_id < 0 || adapter->hci_socket < 0) {
4394  ast_log(LOG_ERROR, "Skipping adapter %s. Unable to communicate with adapter.\n", adapter->id);
4395  goto e_free_adapter;
4396  }
4397 
4398  /* check voice setting */
4399  hci_read_voice_setting(adapter->hci_socket, &vs, 1000);
4400  vs = htobs(vs);
4401  if (vs != 0x0060) {
4402  ast_log(LOG_ERROR, "Skipping adapter %s. Voice setting must be 0x0060 - see 'man hciconfig' for details.\n", adapter->id);
4403  goto e_hci_close_dev;
4404  }
4405 
4406  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4407  if (!strcasecmp(v->name, "forcemaster")) {
4408  if (ast_true(v->value)) {
4409  dr.dev_id = adapter->dev_id;
4410  if (hci_strtolm("master", &dr.dev_opt)) {
4411  if (ioctl(adapter->hci_socket, HCISETLINKMODE, (unsigned long) &dr) < 0) {
4412  ast_log(LOG_WARNING, "Unable to set adapter %s link mode to MASTER. Ignoring 'forcemaster' option.\n", adapter->id);
4413  }
4414  }
4415  }
4416  } else if (!strcasecmp(v->name, "alignmentdetection")) {
4417  adapter->alignment_detection = ast_true(v->value);
4418  }
4419  }
4420 
4421  /* create io contexts */
4422  if (!(adapter->accept_io = io_context_create())) {
4423  ast_log(LOG_ERROR, "Unable to create I/O context for audio connection listener\n");
4424  goto e_hci_close_dev;
4425  }
4426 
4427  if (!(adapter->io = io_context_create())) {
4428  ast_log(LOG_ERROR, "Unable to create I/O context for audio connections\n");
4429  goto e_destroy_accept_io;
4430  }
4431 
4432  /* bind the sco listener socket */
4433  if (sco_bind(adapter) < 0) {
4434  ast_log(LOG_ERROR, "Skipping adapter %s. Error binding audio connection listerner socket.\n", adapter->id);
4435  goto e_destroy_io;
4436  }
4437 
4438  /* add the socket to the io context */
4439  if (!(adapter->sco_id = ast_io_add(adapter->accept_io, adapter->sco_socket, sco_accept, AST_IO_IN, adapter))) {
4440  ast_log(LOG_ERROR, "Skipping adapter %s. Error adding listener socket to I/O context.\n", adapter->id);
4441  goto e_close_sco;
4442  }
4443 
4444  /* start the sco listener for this adapter */
4446  ast_log(LOG_ERROR, "Skipping adapter %s. Error creating audio connection listerner thread.\n", adapter->id);
4447  goto e_remove_sco;
4448  }
4449 
4450  /* add the adapter to our global list */
4454  ast_debug(1, "Loaded adapter %s %s.\n", adapter->id, address);
4455 
4456  return adapter;
4457 
4458 e_remove_sco:
4459  ast_io_remove(adapter->accept_io, adapter->sco_id);
4460 e_close_sco:
4461  close(adapter->sco_socket);
4462 e_destroy_io:
4463  io_context_destroy(adapter->io);
4464 e_destroy_accept_io:
4465  io_context_destroy(adapter->accept_io);
4466 e_hci_close_dev:
4467  hci_close_dev(adapter->hci_socket);
4468 e_free_adapter:
4469  ast_free(adapter);
4470 e_return:
4471  return NULL;
4472 }
struct ast_variable * next
static float dr[4]
Definition: tdd.c:58
char id[31]
Definition: chan_mobile.c:102
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
char * address
Definition: f2c.h:59
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
struct io_context * accept_io
Definition: chan_mobile.c:107
#define LOG_WARNING
Definition: logger.h:274
pthread_t sco_listener_thread
Definition: chan_mobile.c:110
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Structure for variables, used for configurations and for channel variables.
#define AST_IO_IN
Definition: io.h:34
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
#define NULL
Definition: resample.c:96
static int sco_bind(struct adapter_pvt *adapter)
Bind an SCO listener socket for the given adapter.
Definition: chan_mobile.c:1958
int * sco_id
Definition: chan_mobile.c:108
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
void io_context_destroy(struct io_context *ioc)
Destroys a context.
Definition: io.c:107
struct io_context * io
Definition: chan_mobile.c:106
unsigned int alignment_detection
Definition: chan_mobile.c:105
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
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
bdaddr_t addr
Definition: chan_mobile.c:103
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:4326
int ast_io_remove(struct io_context *ioc, int *id)
Removes an IO context.
Definition: io.c:245
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
Definition: search.h:40
enum queue_result id
Definition: app_queue.c:1507
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

◆ mbl_load_config()

static int mbl_load_config ( void  )
static

Definition at line 4624 of file chan_mobile.c.

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

4625 {
4626  struct ast_config *cfg;
4627  const char *cat;
4628  struct ast_variable *v;
4629  struct ast_flags config_flags = { 0 };
4630 
4631  cfg = ast_config_load(MBL_CONFIG, config_flags);
4632  if (!cfg) {
4633  cfg = ast_config_load(MBL_CONFIG_OLD, config_flags);
4634  }
4635  if (!cfg)
4636  return -1;
4637 
4638  /* parse [general] section */
4639  for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
4640  if (!strcasecmp(v->name, "interval")) {
4641  if (!sscanf(v->value, "%d", &discovery_interval)) {
4642  ast_log(LOG_NOTICE, "error parsing 'interval' in general section, using default value\n");
4643  }
4644  }
4645  }
4646 
4647  /* load adapters */
4648  for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
4649  if (!strcasecmp(cat, "adapter")) {
4650  mbl_load_adapter(cfg, cat);
4651  }
4652  }
4653 
4654  if (AST_RWLIST_EMPTY(&adapters)) {
4656  "***********************************************************************\n"
4657  "No adapters could be loaded from the configuration file.\n"
4658  "Please review mobile.conf. See sample for details.\n"
4659  "***********************************************************************\n"
4660  );
4661  ast_config_destroy(cfg);
4662  return -1;
4663  }
4664 
4665  /* now load devices */
4666  for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
4667  if (strcasecmp(cat, "general") && strcasecmp(cat, "adapter")) {
4668  mbl_load_device(cfg, cat);
4669  }
4670  }
4671 
4672  ast_config_destroy(cfg);
4673 
4674  return 0;
4675 }
struct ast_variable * next
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
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:4480
Structure for variables, used for configurations and for channel variables.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
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:4364
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define MBL_CONFIG_OLD
Definition: chan_mobile.c:79
static int discovery_interval
Definition: chan_mobile.c:85
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define LOG_ERROR
Definition: logger.h:285
#define MBL_CONFIG
Definition: chan_mobile.c:78
#define LOG_NOTICE
Definition: logger.h:263
Structure used to handle boolean flags.
Definition: utils.h:199

◆ 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 4480 of file chan_mobile.c.

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

4481 {
4482  struct mbl_pvt *pvt;
4483  struct adapter_pvt *adapter;
4484  struct ast_variable *v;
4485  const char *address, *adapter_str, *port;
4486  ast_debug(1, "Reading configuration for device %s.\n", cat);
4487 
4488  adapter_str = ast_variable_retrieve(cfg, cat, "adapter");
4489  if(ast_strlen_zero(adapter_str)) {
4490  ast_log(LOG_ERROR, "Skipping device %s. No adapter specified.\n", cat);
4491  goto e_return;
4492  }
4493 
4494  /* find the adapter */
4496  AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
4497  if (!strcmp(adapter->id, adapter_str))
4498  break;
4499  }
4501  if (!adapter) {
4502  ast_log(LOG_ERROR, "Skiping device %s. Unknown adapter '%s' specified.\n", cat, adapter_str);
4503  goto e_return;
4504  }
4505 
4506  address = ast_variable_retrieve(cfg, cat, "address");
4507  port = ast_variable_retrieve(cfg, cat, "port");
4508  if (ast_strlen_zero(port) || ast_strlen_zero(address)) {
4509  ast_log(LOG_ERROR, "Skipping device %s. Missing required port or address setting.\n", cat);
4510  goto e_return;
4511  }
4512 
4513  /* create and initialize our pvt structure */
4514  if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
4515  ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", cat);
4516  goto e_return;
4517  }
4518 
4519  ast_mutex_init(&pvt->lock);
4521 
4522  /* set some defaults */
4523 
4524  pvt->type = MBL_TYPE_PHONE;
4525  ast_copy_string(pvt->context, "default", sizeof(pvt->context));
4526 
4527  /* populate the pvt structure */
4528  pvt->adapter = adapter;
4529  ast_copy_string(pvt->id, cat, sizeof(pvt->id));
4530  str2ba(address, &pvt->addr);
4531  pvt->timeout = -1;
4532  pvt->rfcomm_socket = -1;
4533  pvt->rfcomm_port = atoi(port);
4534  pvt->sco_socket = -1;
4536  pvt->ring_sched_id = -1;
4537  pvt->has_sms = 1;
4538 
4539  /* setup the bt_out_smoother */
4541  ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_out_smoother.\n", cat);
4542  goto e_free_pvt;
4543  }
4544 
4545  /* setup the bt_in_smoother */
4547  ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_in_smoother.\n", cat);
4548  goto e_free_bt_out_smoother;
4549  }
4550 
4551  /* setup the dsp */
4552  if (!(pvt->dsp = ast_dsp_new())) {
4553  ast_log(LOG_ERROR, "Skipping device %s. Error setting up dsp for dtmf detection.\n", cat);
4554  goto e_free_bt_in_smoother;
4555  }
4556 
4557  /* setup the scheduler */
4558  if (!(pvt->sched = ast_sched_context_create())) {
4559  ast_log(LOG_ERROR, "Unable to create scheduler context for headset device\n");
4560  goto e_free_dsp;
4561  }
4562 
4565 
4566  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4567  if (!strcasecmp(v->name, "type")) {
4568  if (!strcasecmp(v->value, "headset"))
4569  pvt->type = MBL_TYPE_HEADSET;
4570  else
4571  pvt->type = MBL_TYPE_PHONE;
4572  } else if (!strcasecmp(v->name, "context")) {
4573  ast_copy_string(pvt->context, v->value, sizeof(pvt->context));
4574  } else if (!strcasecmp(v->name, "group")) {
4575  /* group is set to 0 if invalid */
4576  pvt->group = atoi(v->value);
4577  } else if (!strcasecmp(v->name, "sms")) {
4578  pvt->has_sms = ast_true(v->value);
4579  } else if (!strcasecmp(v->name, "nocallsetup")) {
4580  pvt->no_callsetup = ast_true(v->value);
4581 
4582  if (pvt->no_callsetup)
4583  ast_debug(1, "Setting nocallsetup mode for device %s.\n", pvt->id);
4584  } else if (!strcasecmp(v->name, "blackberry")) {
4585  pvt->blackberry = ast_true(v->value);
4586  pvt->has_sms = 0;
4587  }
4588  }
4589 
4590  if (pvt->type == MBL_TYPE_PHONE) {
4591  if (!(pvt->hfp = ast_calloc(1, sizeof(*pvt->hfp)))) {
4592  ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", pvt->id);
4593  goto e_free_sched;
4594  }
4595 
4596  pvt->hfp->owner = pvt;
4597  pvt->hfp->rport = pvt->rfcomm_port;
4598  pvt->hfp->nocallsetup = pvt->no_callsetup;
4599  } else {
4600  pvt->has_sms = 0;
4601  }
4602 
4606  ast_debug(1, "Loaded device %s.\n", pvt->id);
4607 
4608  return pvt;
4609 
4610 e_free_sched:
4612 e_free_dsp:
4613  ast_dsp_free(pvt->dsp);
4614 e_free_bt_in_smoother:
4616 e_free_bt_out_smoother:
4618 e_free_pvt:
4619  ast_free(pvt);
4620 e_return:
4621  return NULL;
4622 }
int rfcomm_port
Definition: chan_mobile.c:131
struct ast_variable * next
char context[AST_MAX_CONTEXT]
Definition: chan_mobile.c:129
int sco_socket
Definition: chan_mobile.c:137
#define CHANNEL_FRAME_SIZE
Definition: chan_mobile.c:83
char id[31]
Definition: chan_mobile.c:102
struct ast_smoother * ast_smoother_new(int bytes)
Definition: smoother.c:108
struct ast_smoother * bt_in_smoother
Definition: chan_mobile.c:136
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define DSP_DIGITMODE_DTMF
Definition: dsp.h:31
char * address
Definition: f2c.h:59
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1770
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1745
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Structure for variables, used for configurations and for channel variables.
unsigned int blackberry
Definition: chan_mobile.c:144
struct ast_dsp * dsp
Definition: chan_mobile.c:148
int timeout
Definition: chan_mobile.c:139
int nocallsetup
Definition: chan_mobile.c:347
#define NULL
Definition: resample.c:96
int rfcomm_socket
Definition: chan_mobile.c:132
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
void ast_smoother_free(struct ast_smoother *s)
Definition: smoother.c:220
#define DSP_DIGITMODE_RELAXDTMF
Definition: dsp.h:37
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
bdaddr_t addr
Definition: chan_mobile.c:127
struct mbl_pvt * owner
Definition: chan_mobile.c:345
unsigned int no_callsetup
Definition: chan_mobile.c:140
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
unsigned int has_sms
Definition: chan_mobile.c:141
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:236
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
char id[31]
Definition: chan_mobile.c:125
#define DEVICE_FRAME_SIZE
Definition: chan_mobile.c:81
enum mbl_type type
Definition: chan_mobile.c:124
pthread_t monitor_thread
Definition: chan_mobile.c:138
ast_mutex_t lock
Definition: chan_mobile.c:121
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1755
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
struct mbl_pvt::msg_queue msg_queue
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct adapter_pvt * adapter
Definition: chan_mobile.c:128
struct ast_smoother * bt_out_smoother
Definition: chan_mobile.c:135
Definition: search.h:40
int group
Definition: chan_mobile.c:126
#define ast_mutex_init(pmutex)
Definition: lock.h:184
int rport
Definition: chan_mobile.c:353
int ring_sched_id
Definition: chan_mobile.c:147
struct ast_sched_context * sched
Definition: chan_mobile.c:149
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition: dsp.c:1844

◆ 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.

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, NULL, mbl_pvt::owner, and mbl_pvt::sco_socket.

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

849 {
850  struct ast_channel *chn;
851 
852  pvt->answered = 0;
853  pvt->alignment_count = 0;
855  if (pvt->adapter->alignment_detection)
856  pvt->do_alignment_detection = 1;
857  else
858  pvt->do_alignment_detection = 0;
859 
862  ast_dsp_digitreset(pvt->dsp);
863 
864  chn = ast_channel_alloc(1, state,
865  cidinfo ? cidinfo->cnum : NULL,
866  cidinfo ? cidinfo->cnam : NULL,
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  }
890  ast_channel_unlock(chn);
891 
892  return chn;
893 
894 e_return:
895  return NULL;
896 }
int alignment_count
Definition: chan_mobile.c:146
char context[AST_MAX_CONTEXT]
Definition: chan_mobile.c:129
Main Channel structure associated with a channel.
int sco_socket
Definition: chan_mobile.c:137
#define CHANNEL_FRAME_SIZE
Definition: chan_mobile.c:83
struct ast_smoother * bt_in_smoother
Definition: chan_mobile.c:136
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
unsigned int answered
Definition: chan_mobile.c:160
struct ast_dsp * dsp
Definition: chan_mobile.c:148
void ast_dsp_digitreset(struct ast_dsp *dsp)
Reset DTMF detector.
Definition: dsp.c:1797
unsigned int do_alignment_detection
Definition: chan_mobile.c:142
#define NULL
Definition: resample.c:96
char * cnam
Definition: chan_mobile.c:169
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_rings_set(struct ast_channel *chan, int value)
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
long int ast_random(void)
Definition: main/utils.c:2064
#define DEVICE_FRAME_FORMAT
Definition: chan_mobile.c:82
unsigned int alignment_detection
Definition: chan_mobile.c:105
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
#define DEVICE_FRAME_SIZE
Definition: chan_mobile.c:81
void ast_smoother_reset(struct ast_smoother *s, int bytes)
Definition: smoother.c:79
struct ast_format_cap * capabilities
Definition: channel.h:633
#define ast_channel_unlock(chan)
Definition: channel.h:2946
unsigned int alignment_detection_triggered
Definition: chan_mobile.c:143
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2431
struct adapter_pvt * adapter
Definition: chan_mobile.c:128
char * cnum
Definition: chan_mobile.c:168
struct ast_smoother * bt_out_smoother
Definition: chan_mobile.c:135
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1259
static struct ast_channel_tech mbl_tech
Definition: chan_mobile.c:479
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)

◆ 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.

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

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);
1325  ast_channel_unlock(pvt->owner);
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 DEADLOCK_AVOIDANCE(lock)
Definition: lock.h:374
struct ast_channel * owner
Definition: chan_mobile.c:119
ast_mutex_t lock
Definition: chan_mobile.c:121
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_channel_trylock(chan)
Definition: channel.h:2947

◆ mbl_queue_hangup()

static int mbl_queue_hangup ( struct mbl_pvt pvt)
static

Definition at line 1334 of file chan_mobile.c.

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

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);
1345  ast_channel_unlock(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)
#define DEADLOCK_AVOIDANCE(lock)
Definition: lock.h:374
int hangupcause
Definition: chan_mobile.c:150
struct ast_channel * owner
Definition: chan_mobile.c:119
ast_mutex_t lock
Definition: chan_mobile.c:121
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_channel_trylock(chan)
Definition: channel.h:2947

◆ mbl_read()

static struct ast_frame * mbl_read ( struct ast_channel ast)
static

Definition at line 1109 of file chan_mobile.c.

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.

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));
1127  pvt->fr.frametype = AST_FRAME_VOICE;
1129  pvt->fr.src = "Mobile";
1130  pvt->fr.offset = AST_FRIENDLY_OFFSET;
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);
1154  fr = ast_smoother_read(pvt->bt_in_smoother);
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 
1162 e_return:
1163  ast_mutex_unlock(&pvt->lock);
1164  return fr;
1165 }
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:1494
int sco_socket
Definition: chan_mobile.c:137
#define ast_smoother_feed(s, f)
Definition: smoother.h:76
struct ast_smoother * bt_in_smoother
Definition: chan_mobile.c:136
void * ast_channel_tech_pvt(const struct ast_channel *chan)
static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen)
Definition: chan_mobile.c:1281
struct ast_dsp * dsp
Definition: chan_mobile.c:148
unsigned int do_alignment_detection
Definition: chan_mobile.c:142
#define NULL
Definition: resample.c:96
struct ast_frame_subclass subclass
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
const char * src
#define ast_mutex_trylock(a)
Definition: lock.h:189
#define DEVICE_FRAME_FORMAT
Definition: chan_mobile.c:82
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
#define DEVICE_FRAME_SIZE
Definition: chan_mobile.c:81
int errno
char io_buf[CHANNEL_FRAME_SIZE+AST_FRIENDLY_OFFSET]
Definition: chan_mobile.c:134
ast_mutex_t lock
Definition: chan_mobile.c:121
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition: lock.h:352
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2431
struct timeval delivery
struct ast_frame ast_null_frame
Definition: main/frame.c:79
struct ast_frame * ast_smoother_read(struct ast_smoother *s)
Definition: smoother.c:169
Data structure associated with a single frame of data.
union ast_frame::@263 data
enum ast_frame_type frametype
struct ast_format * format
struct ast_frame fr
Definition: chan_mobile.c:120
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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.

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.

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 
915  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
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 }
Main Channel structure associated with a channel.
#define AST_CAUSE_INCOMPATIBLE_DESTINATION
Definition: causes.h:134
unsigned int connected
Definition: chan_mobile.c:161
#define LOG_WARNING
Definition: logger.h:274
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define NULL
Definition: resample.c:96
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:583
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_log
Definition: astobj2.c:42
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define DEVICE_FRAME_FORMAT
Definition: chan_mobile.c:82
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define AST_CAUSE_FACILITY_NOT_IMPLEMENTED
Definition: causes.h:132
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
enum mbl_type type
Definition: chan_mobile.c:124
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:736
ast_mutex_t lock
Definition: chan_mobile.c:121
#define AST_CAUSE_REQUESTED_CHAN_UNAVAIL
Definition: causes.h:124
Definition: search.h:40
int group
Definition: chan_mobile.c:126
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
#define ast_mutex_unlock(a)
Definition: lock.h:188
static int mbl_has_service(struct mbl_pvt *pvt)
Check if a mobile device has service.
Definition: chan_mobile.c:1369

◆ 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.

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, msg_queue_push_data(), and parse().

Referenced by load_module().

764 {
765 
766  struct mbl_pvt *pvt;
767  char *parse, *message;
768 
770  AST_APP_ARG(device);
771  AST_APP_ARG(dest);
772  AST_APP_ARG(message);
773  );
774 
775  if (ast_strlen_zero(data))
776  return -1;
777 
778  parse = ast_strdupa(data);
779 
780  AST_STANDARD_APP_ARGS(args, parse);
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)
823  || msg_queue_push_data(pvt, AT_SMS_PROMPT, AT_CMGS, message)) {
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 
833 e_free_message:
834  ast_free(message);
835 e_unlock_pvt:
836  ast_mutex_unlock(&pvt->lock);
837 e_return:
838  return -1;
839 }
unsigned int connected
Definition: chan_mobile.c:161
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * args
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_log
Definition: astobj2.c:42
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
unsigned int has_sms
Definition: chan_mobile.c:141
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define LOG_ERROR
Definition: logger.h:285
char id[31]
Definition: chan_mobile.c:125
ast_mutex_t lock
Definition: chan_mobile.c:121
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define ast_free(a)
Definition: astmm.h:182
static int hfp_send_cmgs(struct hfp_pvt *hfp, const char *number)
Start sending an SMS message.
Definition: chan_mobile.c:2658
Definition: search.h:40
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
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:3004
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define AST_APP_ARG(name)
Define an application argument.

◆ 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.

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, parse(), pbx_builtin_setvar_helper(), and status.

Referenced by load_module().

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 
733  AST_STANDARD_APP_ARGS(args, parse);
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 }
unsigned int connected
Definition: chan_mobile.c:161
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
const char * args
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct ast_channel * owner
Definition: chan_mobile.c:119
char id[31]
Definition: chan_mobile.c:125
ast_mutex_t lock
Definition: chan_mobile.c:121
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
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...
Definition: search.h:40
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
jack_status_t status
Definition: app_jack.c:146
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define AST_APP_ARG(name)
Define an application argument.

◆ mbl_write()

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

Definition at line 1167 of file chan_mobile.c.

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

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 
1183  ast_smoother_feed(pvt->bt_out_smoother, frame);
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 }
int sco_socket
Definition: chan_mobile.c:137
#define ast_smoother_feed(s, f)
Definition: smoother.h:76
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_mutex_trylock(a)
Definition: lock.h:189
static int sco_write(int s, char *buf, int len)
Definition: chan_mobile.c:1871
ast_mutex_t lock
Definition: chan_mobile.c:121
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition: lock.h:352
struct ast_frame * ast_smoother_read(struct ast_smoother *s)
Definition: smoother.c:169
struct ast_smoother * bt_out_smoother
Definition: chan_mobile.c:135
Data structure associated with a single frame of data.
union ast_frame::@263 data
enum ast_frame_type frametype
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ msg_queue_flush()

static void msg_queue_flush ( struct mbl_pvt pvt)
static

Remove all itmes from the queue and free them.

Parameters
pvta mbl_pvt structure

Definition at line 3046 of file chan_mobile.c.

References msg_queue_free_and_pop(), and msg_queue_head().

Referenced by do_monitor_phone(), and unload_module().

3047 {
3048  struct msg_queue_entry *msg;
3049  while ((msg = msg_queue_head(pvt)))
3051 }
Definition: chan_mobile.c:460
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3058
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:3032

◆ 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 3032 of file chan_mobile.c.

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

3033 {
3034  struct msg_queue_entry *msg;
3035  if ((msg = msg_queue_pop(pvt))) {
3036  if (msg->data)
3037  ast_free(msg->data);
3038  ast_free(msg);
3039  }
3040 }
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:3023
#define ast_free(a)
Definition: astmm.h:182
Definition: chan_mobile.c:460
void * data
Definition: chan_mobile.c:463

◆ 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 3058 of file chan_mobile.c.

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

3059 {
3060  return AST_LIST_FIRST(&pvt->msg_queue);
3061 }
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
struct mbl_pvt::msg_queue msg_queue

◆ 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 3023 of file chan_mobile.c.

References AST_LIST_REMOVE_HEAD, and mbl_pvt::msg_queue.

Referenced by msg_queue_free_and_pop().

3024 {
3025  return AST_LIST_REMOVE_HEAD(&pvt->msg_queue, entry);
3026 }
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
struct mbl_pvt::msg_queue msg_queue
Definition: search.h:40

◆ 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 2982 of file chan_mobile.c.

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

2983 {
2984  struct msg_queue_entry *msg;
2985  if (!(msg = ast_calloc(1, sizeof(*msg)))) {
2986  return -1;
2987  }
2988  msg->expected = expect;
2989  msg->response_to = response_to;
2990 
2991  AST_LIST_INSERT_TAIL(&pvt->msg_queue, msg, entry);
2992  return 0;
2993 }
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
at_message_t expected
Definition: chan_mobile.c:461
at_message_t response_to
Definition: chan_mobile.c:462
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
Definition: chan_mobile.c:460
struct mbl_pvt::msg_queue msg_queue
Definition: search.h:40

◆ 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 3004 of file chan_mobile.c.

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

3005 {
3006  struct msg_queue_entry *msg;
3007  if (!(msg = ast_calloc(1, sizeof(*msg)))) {
3008  return -1;
3009  }
3010  msg->expected = expect;
3011  msg->response_to = response_to;
3012  msg->data = data;
3013 
3014  AST_LIST_INSERT_TAIL(&pvt->msg_queue, msg, entry);
3015  return 0;
3016 }
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
at_message_t expected
Definition: chan_mobile.c:461
at_message_t response_to
Definition: chan_mobile.c:462
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
Definition: chan_mobile.c:460
struct mbl_pvt::msg_queue msg_queue
Definition: search.h:40
void * data
Definition: chan_mobile.c:463

◆ 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 2297 of file chan_mobile.c.

Referenced by hfp_parse_clip().

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

◆ 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.

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

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

◆ 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.

References ast_debug, and errno.

Referenced by do_discovery().

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 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int errno

◆ 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.

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

Referenced by at_read_full().

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 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
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct test_val c
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
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 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

◆ 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.

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

Referenced by rfcomm_read_result(), and rfcomm_read_sms_prompt().

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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct test_val c
static PGresult * result
Definition: cel_pgsql.c:88
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 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

◆ 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.

References c, 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().

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 }
static struct test_val c
#define rfcomm_read_debug(c)
Definition: chan_mobile.c:1501
static PGresult * result
Definition: cel_pgsql.c:88

◆ 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.

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

Referenced by rfcomm_read_result().

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
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
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

◆ 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.

References c, rfcomm_append_buf(), and rfcomm_read_debug.

Referenced by rfcomm_read().

1764 {
1765  int res;
1766  char c;
1767 
1768  while ((res = read(rsock, &c, 1)) == 1) {
1769  rfcomm_read_debug(c);
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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct test_val c
#define rfcomm_read_debug(c)
Definition: chan_mobile.c:1501
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

◆ 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.

References ast_log, 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().

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 
1754 e_return:
1755  ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket\n");
1756  return res;
1757 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct test_val c
#define ast_log
Definition: astobj2.c:42
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_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_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
Read the remainder of a +CMGR message.
Definition: chan_mobile.c:1706
#define LOG_ERROR
Definition: logger.h:285
static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
Read until.
Definition: chan_mobile.c:1564
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 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

◆ 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.

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

Referenced by rfcomm_read_result().

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 
1601 e_return:
1602  ast_log(LOG_ERROR, "error parsing SMS prompt on rfcomm socket\n");
1603  return res;
1604 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
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
#define LOG_ERROR
Definition: logger.h:285

◆ 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.

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

Referenced by rfcomm_read_result(), and rfcomm_read_until_ok().

1565 {
1566  int res;
1567  char c;
1568 
1569  while ((res = read(rsock, &c, 1)) == 1) {
1570  rfcomm_read_debug(c);
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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct test_val c
#define rfcomm_read_debug(c)
Definition: chan_mobile.c:1501
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 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

◆ 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.

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

Referenced by rfcomm_read_cmgr().

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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct test_val c
static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
Read until.
Definition: chan_mobile.c:1564
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 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

◆ 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.

References ast_debug, ast_waitfor_n_fd(), and c.

Referenced by do_monitor_headset(), and do_monitor_phone().

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:2989

◆ 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.

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

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

◆ 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.

References ast_debug, buf, and errno.

Referenced by rfcomm_write().

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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int errno

◆ 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.

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

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 }
int sco_socket
Definition: chan_mobile.c:137
char id[31]
Definition: chan_mobile.c:102
#define LOG_WARNING
Definition: logger.h:274
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
bdaddr_t addr
Definition: chan_mobile.c:127
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define LOG_ERROR
Definition: logger.h:285
struct ast_channel * owner
Definition: chan_mobile.c:119
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
ast_mutex_t lock
Definition: chan_mobile.c:121
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2431
Definition: search.h:40
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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.

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

Referenced by mbl_load_adapter().

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 
1986 e_close_socket:
1987  close(adapter->sco_socket);
1988  adapter->sco_socket = -1;
1989 e_return:
1990  return -1;
1991 }
char id[31]
Definition: chan_mobile.c:102
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
int errno
bdaddr_t addr
Definition: chan_mobile.c:103

◆ sco_connect()

static int sco_connect ( bdaddr_t  src,
bdaddr_t  dst 
)
static

Definition at line 1833 of file chan_mobile.c.

References ast_debug, and errno.

Referenced by do_monitor_headset().

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 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int errno

◆ sco_write()

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

Definition at line 1871 of file chan_mobile.c.

References ast_debug, and errno.

Referenced by mbl_write().

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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno

◆ sdp_register()

static sdp_session_t* sdp_register ( void  )
static

Definition at line 3119 of file chan_mobile.c.

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

Referenced by load_module().

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

◆ sdp_search()

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

Definition at line 3071 of file chan_mobile.c.

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

Referenced by handle_cli_mobile_search().

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

◆ set_unloading()

static void set_unloading ( void  )
inlinestatic

Set the unloading flag.

Definition at line 4695 of file chan_mobile.c.

References ast_mutex_lock, ast_mutex_unlock, unload_mutex, and unloading_flag.

Referenced by unload_module().

4696 {
4698  unloading_flag = 1;
4700 }
static int unloading_flag
Definition: chan_mobile.c:90
#define ast_mutex_lock(a)
Definition: lock.h:187
static ast_mutex_t unload_mutex
Definition: chan_mobile.c:89
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ start_monitor()

static int start_monitor ( struct mbl_pvt pvt)
static

Definition at line 4261 of file chan_mobile.c.

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

4262 {
4263 
4264  if (pvt->type == MBL_TYPE_PHONE) {
4265  pvt->hfp->rsock = pvt->rfcomm_socket;
4266 
4269  return 0;
4270  }
4271  } else {
4274  return 0;
4275  }
4276  }
4277 
4278  return 1;
4279 
4280 }
int rsock
Definition: chan_mobile.c:352
#define NULL
Definition: resample.c:96
int rfcomm_socket
Definition: chan_mobile.c:132
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
static void * do_monitor_phone(void *data)
Definition: chan_mobile.c:3870
#define AST_PTHREADT_NULL
Definition: lock.h:66
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
enum mbl_type type
Definition: chan_mobile.c:124
pthread_t monitor_thread
Definition: chan_mobile.c:138
static void * do_monitor_headset(void *data)
Definition: chan_mobile.c:4119

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 4702 of file chan_mobile.c.

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

4703 {
4704  struct mbl_pvt *pvt;
4705  struct adapter_pvt *adapter;
4706 
4707  /* First, take us out of the channel loop */
4709 
4710  /* Unregister the CLI & APP */
4711  ast_cli_unregister_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
4714 
4715  /* signal everyone we are unloading */
4716  set_unloading();
4717 
4718  /* Kill the discovery thread */
4720  pthread_kill(discovery_thread, SIGURG);
4721  pthread_join(discovery_thread, NULL);
4722  }
4723 
4724  /* stop the sco listener threads */
4726  AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
4727  pthread_kill(adapter->sco_listener_thread, SIGURG);
4728  pthread_join(adapter->sco_listener_thread, NULL);
4729  }
4731 
4732  /* Destroy the device list */
4734  while ((pvt = AST_RWLIST_REMOVE_HEAD(&devices, entry))) {
4735  if (pvt->monitor_thread != AST_PTHREADT_NULL) {
4736  pthread_kill(pvt->monitor_thread, SIGURG);
4737  pthread_join(pvt->monitor_thread, NULL);
4738  }
4739 
4740  close(pvt->sco_socket);
4741  close(pvt->rfcomm_socket);
4742 
4743  msg_queue_flush(pvt);
4744 
4745  if (pvt->hfp) {
4746  ast_free(pvt->hfp);
4747  }
4748 
4751  ast_dsp_free(pvt->dsp);
4753  ast_free(pvt);
4754  }
4756 
4757  /* Destroy the adapter list */
4759  while ((adapter = AST_RWLIST_REMOVE_HEAD(&adapters, entry))) {
4760  close(adapter->sco_socket);
4761  io_context_destroy(adapter->io);
4762  io_context_destroy(adapter->accept_io);
4763  hci_close_dev(adapter->hci_socket);
4764  ast_free(adapter);
4765  }
4767 
4768  if (sdp_session)
4769  sdp_close(sdp_session);
4770 
4773  return 0;
4774 }
int sco_socket
Definition: chan_mobile.c:137
static struct ast_cli_entry mbl_cli[]
Definition: chan_mobile.c:193
struct ast_smoother * bt_in_smoother
Definition: chan_mobile.c:136
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1770
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
struct io_context * accept_io
Definition: chan_mobile.c:107
pthread_t sco_listener_thread
Definition: chan_mobile.c:110
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
struct ast_dsp * dsp
Definition: chan_mobile.c:148
#define NULL
Definition: resample.c:96
static sdp_session_t * sdp_session
Definition: chan_mobile.c:87
int rfcomm_socket
Definition: chan_mobile.c:132
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static pthread_t discovery_thread
Definition: chan_mobile.c:86
void ast_smoother_free(struct ast_smoother *s)
Definition: smoother.c:220
void io_context_destroy(struct io_context *ioc)
Destroys a context.
Definition: io.c:107
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
struct io_context * io
Definition: chan_mobile.c:106
static char * app_mblstatus
Definition: chan_mobile.c:201
pthread_t monitor_thread
Definition: chan_mobile.c:138
struct ast_format_cap * capabilities
Definition: channel.h:633
#define ast_free(a)
Definition: astmm.h:182
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
static void msg_queue_flush(struct mbl_pvt *pvt)
Remove all itmes from the queue and free them.
Definition: chan_mobile.c:3046
struct ast_smoother * bt_out_smoother
Definition: chan_mobile.c:135
static void set_unloading(void)
Set the unloading flag.
Definition: chan_mobile.c:4695
static char * app_mblsendsms
Definition: chan_mobile.c:209
Definition: search.h:40
struct ast_sched_context * sched
Definition: chan_mobile.c:149
static struct ast_channel_tech mbl_tech
Definition: chan_mobile.c:479
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
static

Definition at line 4838 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 4838 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.

◆ mbl_cli

struct ast_cli_entry mbl_cli[]
static

Definition at line 193 of file chan_mobile.c.

◆ mbl_tech

struct ast_channel_tech mbl_tech
static

Definition at line 479 of file chan_mobile.c.

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