Asterisk - The Open Source Telephony Project  21.4.1
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"

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Function Documentation

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

Referenced by 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 }
static at_message_t at_read_full ( int  rsock,
char *  buf,
size_t  count 
)
static

Read an AT message and classify it.

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

Definition at line 2017 of file chan_mobile.c.

References at_match_prefix(), and rfcomm_read().

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

Check if the module is unloading.

Return values
0not unloading
1unloading

Definition at line 4684 of file chan_mobile.c.

Referenced by do_sco_listen().

4685 {
4686  int res;
4687  ast_mutex_lock(&unload_mutex);
4688  res = unloading_flag;
4689  ast_mutex_unlock(&unload_mutex);
4690 
4691  return res;
4692 }
static int handle_response_brsf ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle the BRSF response.

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

Definition at line 3198 of file chan_mobile.c.

References ast_debug, at_msg2str(), mbl_pvt::hfp, hfp_parse_brsf(), msg_queue_free_and_pop(), msg_queue_head(), and msg_queue_push().

3199 {
3200  struct msg_queue_entry *entry;
3201  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_BRSF) {
3202  if (hfp_parse_brsf(pvt->hfp, buf)) {
3203  ast_debug(1, "[%s] error parsing BRSF\n", pvt->id);
3204  goto e_return;
3205  }
3206 
3207  if (msg_queue_push(pvt, AT_OK, AT_BRSF)) {
3208  ast_debug(1, "[%s] error handling BRSF\n", pvt->id);
3209  goto e_return;
3210  }
3211 
3213  } else if (entry) {
3214  ast_debug(1, "[%s] received unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3215  } else {
3216  ast_debug(1, "[%s] received unexpected AT message 'BRSF'\n", pvt->id);
3217  }
3218 
3219  return 0;
3220 
3221 e_return:
3223  return -1;
3224 }
static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf)
Parse BRSF data.
Definition: chan_mobile.c:2726
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
#define ast_debug(level,...)
Log a DEBUG message.
static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
Add an item to the back of the queue.
Definition: chan_mobile.c:2984
static const char * at_msg2str(at_message_t msg)
Get the string representation of the given AT message.
Definition: chan_mobile.c:2076
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:3060
Definition: search.h:40
static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue, and free it.
Definition: chan_mobile.c:3034
static int handle_response_busy ( struct mbl_pvt pvt)
static

Handle BUSY messages.

Parameters
pvta mbl_pvt structure
Return values
0success
-1error

Definition at line 3833 of file chan_mobile.c.

References AST_CONTROL_BUSY, and mbl_pvt::needchup.

Referenced by handle_response_ciev().

3834 {
3835  pvt->hangupcause = AST_CAUSE_USER_BUSY;
3836  pvt->needchup = 1;
3837  mbl_queue_control(pvt, AST_CONTROL_BUSY);
3838  return 0;
3839 }
unsigned int needchup
Definition: chan_mobile.c:158
static int handle_response_ciev ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CIEV messages.

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

Definition at line 3561 of file chan_mobile.c.

References mbl_pvt::answered, AST_CONTROL_ANSWER, AST_CONTROL_RINGING, ast_debug, ast_setstate(), AST_STATE_UP, hfp_cind::call, hfp_pvt::cind_map, hfp_pvt::cind_state, handle_response_busy(), mbl_pvt::hfp, hfp_parse_ciev(), mbl_pvt::incoming, mbl_pvt::needcallerid, mbl_pvt::needchup, mbl_pvt::outgoing, and hfp_pvt::sent_alerting.

3562 {
3563  int i;
3564  switch (hfp_parse_ciev(pvt->hfp, buf, &i)) {
3565  case HFP_CIND_CALL:
3566  switch (i) {
3567  case HFP_CIND_CALL_NONE:
3568  ast_debug(1, "[%s] line disconnected\n", pvt->id);
3569  if (pvt->owner) {
3570  ast_debug(1, "[%s] hanging up owner\n", pvt->id);
3571  if (mbl_queue_hangup(pvt)) {
3572  ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnecting...\n", pvt->id);
3573  return -1;
3574  }
3575  }
3576  pvt->needchup = 0;
3577  pvt->needcallerid = 0;
3578  pvt->incoming = 0;
3579  pvt->outgoing = 0;
3580  break;
3581  case HFP_CIND_CALL_ACTIVE:
3582  if (pvt->outgoing) {
3583  ast_debug(1, "[%s] remote end answered\n", pvt->id);
3584  mbl_queue_control(pvt, AST_CONTROL_ANSWER);
3585  } else if (pvt->incoming && pvt->answered) {
3586  ast_setstate(pvt->owner, AST_STATE_UP);
3587  } else if (pvt->incoming) {
3588  /* user answered from handset, disconnecting */
3589  ast_verb(3, "[%s] user answered bluetooth device from handset, disconnecting\n", pvt->id);
3590  mbl_queue_hangup(pvt);
3591  return -1;
3592  }
3593  break;
3594  }
3595  break;
3596 
3597  case HFP_CIND_CALLSETUP:
3598  switch (i) {
3599  case HFP_CIND_CALLSETUP_NONE:
3600  if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
3601  if (pvt->owner) {
3602  if (pvt->hfp->sent_alerting == 1) {
3603  handle_response_busy(pvt);
3604  }
3605  if (mbl_queue_hangup(pvt)) {
3606  ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnecting...\n", pvt->id);
3607  return -1;
3608  }
3609  }
3610  pvt->needchup = 0;
3611  pvt->needcallerid = 0;
3612  pvt->incoming = 0;
3613  pvt->outgoing = 0;
3614  }
3615  break;
3616  case HFP_CIND_CALLSETUP_INCOMING:
3617  ast_debug(1, "[%s] incoming call, waiting for caller id\n", pvt->id);
3618  pvt->needcallerid = 1;
3619  pvt->incoming = 1;
3620  break;
3621  case HFP_CIND_CALLSETUP_OUTGOING:
3622  if (pvt->outgoing) {
3623  pvt->hfp->sent_alerting = 0;
3624  ast_debug(1, "[%s] outgoing call\n", pvt->id);
3625  } else {
3626  ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
3627  return -1;
3628  }
3629  break;
3630  case HFP_CIND_CALLSETUP_ALERTING:
3631  if (pvt->outgoing) {
3632  ast_debug(1, "[%s] remote alerting\n", pvt->id);
3633  mbl_queue_control(pvt, AST_CONTROL_RINGING);
3634  pvt->hfp->sent_alerting = 1;
3635  }
3636  break;
3637  }
3638  break;
3639  case HFP_CIND_NONE:
3640  ast_debug(1, "[%s] error parsing CIND: %s\n", pvt->id, buf);
3641  break;
3642  }
3643  return 0;
3644 }
static int handle_response_busy(struct mbl_pvt *pvt)
Handle BUSY messages.
Definition: chan_mobile.c:3833
unsigned int answered
Definition: chan_mobile.c:160
unsigned int incoming
Definition: chan_mobile.c:154
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
int sent_alerting
Definition: chan_mobile.c:354
#define ast_debug(level,...)
Log a DEBUG message.
int cind_state[16]
Definition: chan_mobile.c:350
struct hfp_cind cind_map
Definition: chan_mobile.c:351
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:2197
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:7386
unsigned int needcallerid
Definition: chan_mobile.c:157
static int handle_response_cind ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle the CIND response.

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

Definition at line 3233 of file chan_mobile.c.

References ast_debug, at_msg2str(), mbl_pvt::hfp, hfp_parse_cind(), hfp_parse_cind_test(), msg_queue_free_and_pop(), msg_queue_head(), and msg_queue_push().

3234 {
3235  struct msg_queue_entry *entry;
3236  if ((entry = msg_queue_head(pvt)) && entry->expected == AT_CIND) {
3237  switch (entry->response_to) {
3238  case AT_CIND_TEST:
3239  if (hfp_parse_cind_test(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND_TEST)) {
3240  ast_debug(1, "[%s] error performing CIND test\n", pvt->id);
3241  goto e_return;
3242  }
3243  break;
3244  case AT_CIND:
3245  if (hfp_parse_cind(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND)) {
3246  ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3247  goto e_return;
3248  }
3249  break;
3250  default:
3251  ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3252  goto e_return;
3253  }
3255  } else if (entry) {
3256  ast_debug(1, "[%s] received unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3257  } else {
3258  ast_debug(1, "[%s] received unexpected AT message 'CIND'\n", pvt->id);
3259  }
3260 
3261  return 0;
3262 
3263 e_return:
3265  return -1;
3266 }
static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
Parse the result of the AT+CIND=? command.
Definition: chan_mobile.c:2820
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
#define ast_debug(level,...)
Log a DEBUG message.
static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
Add an item to the back of the queue.
Definition: chan_mobile.c:2984
static const char * at_msg2str(at_message_t msg)
Get the string representation of the given AT message.
Definition: chan_mobile.c:2076
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:3060
Definition: search.h:40
static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue, and free it.
Definition: chan_mobile.c:3034
static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf)
Read the result of the AT+CIND? command.
Definition: chan_mobile.c:2770
static int handle_response_clip ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CLIP messages.

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

Definition at line 3653 of file chan_mobile.c.

References ast_pbx_start(), AST_STATE_RING, mbl_pvt::hfp, hfp_parse_clip(), hfp_send_chup(), msg_queue_free_and_pop(), msg_queue_head(), msg_queue_push(), mbl_pvt::needcallerid, and mbl_pvt::needchup.

3654 {
3655  struct msg_queue_entry *msg;
3656  struct ast_channel *chan;
3657  struct cidinfo cidinfo;
3658 
3659  if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CLIP) {
3661 
3662  pvt->needcallerid = 0;
3663  cidinfo = hfp_parse_clip(pvt->hfp, buf);
3664 
3665  if (!(chan = mbl_new(AST_STATE_RING, pvt, &cidinfo, NULL, NULL))) {
3666  ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
3667  hfp_send_chup(pvt->hfp);
3668  msg_queue_push(pvt, AT_OK, AT_CHUP);
3669  return -1;
3670  }
3671 
3672  /* from this point on, we need to send a chup in the event of a
3673  * hangup */
3674  pvt->needchup = 1;
3675 
3676  if (ast_pbx_start(chan)) {
3677  ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
3678  mbl_ast_hangup(pvt);
3679  return -1;
3680  }
3681  }
3682 
3683  return 0;
3684 }
Main Channel structure associated with a channel.
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4708
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:2984
unsigned int needchup
Definition: chan_mobile.c:158
static int hfp_send_chup(struct hfp_pvt *hfp)
Send AT+CHUP.
Definition: chan_mobile.c:2683
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:3060
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:3034
static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
Parse a CLIP event.
Definition: chan_mobile.c:2226
static int handle_response_cmgr ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CMGR messages.

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

Definition at line 3737 of file chan_mobile.c.

References ast_debug, ast_pbx_start(), AST_STATE_DOWN, mbl_pvt::hfp, hfp_parse_cmgr(), mbl_pvt::incoming_sms, msg_queue_free_and_pop(), msg_queue_head(), and pbx_builtin_setvar_helper().

3738 {
3739  char *from_number = NULL, *text = NULL;
3740  struct ast_channel *chan;
3741  struct msg_queue_entry *msg;
3742 
3743  if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CMGR) {
3745 
3746  if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)) {
3747  ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
3748  return -1;
3749  }
3750 
3751  ast_debug(1, "[%s] successfully read sms message\n", pvt->id);
3752  pvt->incoming_sms = 0;
3753 
3754  /* XXX this channel probably does not need to be associated with this pvt */
3755  if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
3756  ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
3757  return -1;
3758  }
3759 
3760  ast_channel_exten_set(chan, "sms");
3761  pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
3762  pbx_builtin_setvar_helper(chan, "SMSTXT", text);
3763 
3764  if (ast_pbx_start(chan)) {
3765  ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming sms\n", pvt->id);
3766  mbl_ast_hangup(pvt);
3767  }
3768  } else {
3769  ast_debug(1, "[%s] got unexpected +CMGR message, ignoring\n", pvt->id);
3770  }
3771 
3772  return 0;
3773 }
Main Channel structure associated with a channel.
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4708
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
#define ast_debug(level,...)
Log a DEBUG message.
Definition: chan_mobile.c:460
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:3060
static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text)
Parse a CMGR message.
Definition: chan_mobile.c:2354
static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue, and free it.
Definition: chan_mobile.c:3034
static int handle_response_cmti ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle AT+CMTI messages.

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

Definition at line 3710 of file chan_mobile.c.

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

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

Handle CUSD messages.

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

Definition at line 3813 of file chan_mobile.c.

References mbl_pvt::hfp, and hfp_parse_cusd().

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

Handle ERROR AT messages.

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

Definition at line 3444 of file chan_mobile.c.

References AST_CONTROL_CONGESTION, ast_debug, at_msg2str(), mbl_pvt::hfp, hfp_send_cmgf(), hfp_send_vgs(), mbl_pvt::incoming_sms, hfp_pvt::initialized, msg_queue_free_and_pop(), msg_queue_head(), msg_queue_push(), mbl_pvt::needchup, mbl_pvt::outgoing_sms, and mbl_pvt::timeout.

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

Handle NO CARRIER messages.

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

Definition at line 3863 of file chan_mobile.c.

References AST_CONTROL_CONGESTION, and mbl_pvt::needchup.

3864 {
3865  ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
3866  pvt->needchup = 1;
3867  mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
3868  return 0;
3869 }
unsigned int needchup
Definition: chan_mobile.c:158
static int handle_response_no_dialtone ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle NO DIALTONE messages.

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

Definition at line 3848 of file chan_mobile.c.

References AST_CONTROL_CONGESTION, and mbl_pvt::needchup.

3849 {
3850  ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
3851  pvt->needchup = 1;
3852  mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
3853  return 0;
3854 }
unsigned int needchup
Definition: chan_mobile.c:158
static int handle_response_ok ( struct mbl_pvt pvt,
char *  buf 
)
static

Handle OK AT messages.

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

Definition at line 3275 of file chan_mobile.c.

References AST_CONTROL_PROGRESS, ast_debug, at_msg2str(), hfp_cind::call, hfp_cind::callsetup, hfp_pvt::cind_map, hfp_pvt::cind_state, 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(), hfp_pvt::initialized, msg_queue_free_and_pop(), msg_queue_head(), msg_queue_push(), mbl_pvt::needchup, mbl_pvt::outgoing, mbl_pvt::outgoing_sms, hfp_cind::service, and mbl_pvt::timeout.

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

Handle RING messages.

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

Definition at line 3693 of file chan_mobile.c.

References ast_debug, msg_queue_push(), and mbl_pvt::needcallerid.

3694 {
3695  if (pvt->needcallerid) {
3696  ast_debug(1, "[%s] got ring while waiting for caller id\n", pvt->id);
3697  return msg_queue_push(pvt, AT_CLIP, AT_UNKNOWN);
3698  } else {
3699  return 0;
3700  }
3701 }
#define ast_debug(level,...)
Log a DEBUG message.
static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
Add an item to the back of the queue.
Definition: chan_mobile.c:2984
unsigned int needcallerid
Definition: chan_mobile.c:157
static int handle_sms_prompt ( struct mbl_pvt pvt,
char *  buf 
)
static

Send an SMS message from the queue.

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

Definition at line 3782 of file chan_mobile.c.

References ast_debug, mbl_pvt::hfp, hfp_send_sms_text(), msg_queue_free_and_pop(), msg_queue_head(), and msg_queue_push().

3783 {
3784  struct msg_queue_entry *msg;
3785  if (!(msg = msg_queue_head(pvt))) {
3786  ast_debug(1, "[%s] error, got sms prompt with no pending sms messages\n", pvt->id);
3787  return 0;
3788  }
3789 
3790  if (msg->expected != AT_SMS_PROMPT) {
3791  ast_debug(1, "[%s] error, got sms prompt but no pending sms messages\n", pvt->id);
3792  return 0;
3793  }
3794 
3795  if (hfp_send_sms_text(pvt->hfp, msg->data)
3796  || msg_queue_push(pvt, AT_OK, AT_CMGS)) {
3798  ast_debug(1, "[%s] error sending sms message\n", pvt->id);
3799  return 0;
3800  }
3801 
3803  return 0;
3804 }
static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message)
Send the text of an SMS message.
Definition: chan_mobile.c:2672
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
#define ast_debug(level,...)
Log a DEBUG message.
static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
Add an item to the back of the queue.
Definition: chan_mobile.c:2984
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:3060
static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue, and free it.
Definition: chan_mobile.c:3034
static int hfp_brsf2int ( struct hfp_hf hf)
static

Convert a hfp_hf struct to a BRSF int.

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

Definition at line 2470 of file chan_mobile.c.

References hfp_hf::cid, hfp_hf::control, hfp_hf::cw, hfp_hf::ecnr, hfp_hf::status, hfp_hf::voice, and hfp_hf::volume.

Referenced by hfp_send_brsf().

2471 {
2472  int brsf = 0;
2473 
2474  brsf |= hf->ecnr ? HFP_HF_ECNR : 0;
2475  brsf |= hf->cw ? HFP_HF_CW : 0;
2476  brsf |= hf->cid ? HFP_HF_CID : 0;
2477  brsf |= hf->voice ? HFP_HF_VOICE : 0;
2478  brsf |= hf->volume ? HFP_HF_VOLUME : 0;
2479  brsf |= hf->status ? HFP_HF_STATUS : 0;
2480  brsf |= hf->control ? HFP_HF_CONTROL : 0;
2481 
2482  return brsf;
2483 }
int control
Definition: chan_mobile.c:309
int status
Definition: chan_mobile.c:308
int volume
Definition: chan_mobile.c:307
int ecnr
Definition: chan_mobile.c:303
int cid
Definition: chan_mobile.c:305
int cw
Definition: chan_mobile.c:304
int voice
Definition: chan_mobile.c:306
static struct hfp_ag * hfp_int2brsf ( int  brsf,
struct hfp_ag ag 
)
static

Convert a BRSF int to an hfp_ag struct.

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

Definition at line 2492 of file chan_mobile.c.

References hfp_ag::control, hfp_ag::cw, hfp_ag::ecnr, hfp_ag::errors, hfp_ag::reject, hfp_ag::ring, hfp_ag::status, hfp_ag::tag, and hfp_ag::voice.

Referenced by hfp_parse_brsf().

2493 {
2494  ag->cw = brsf & HFP_AG_CW ? 1 : 0;
2495  ag->ecnr = brsf & HFP_AG_ECNR ? 1 : 0;
2496  ag->voice = brsf & HFP_AG_VOICE ? 1 : 0;
2497  ag->ring = brsf & HFP_AG_RING ? 1 : 0;
2498  ag->tag = brsf & HFP_AG_TAG ? 1 : 0;
2499  ag->reject = brsf & HFP_AG_REJECT ? 1 : 0;
2500  ag->status = brsf & HFP_AG_STATUS ? 1 : 0;
2501  ag->control = brsf & HFP_AG_CONTROL ? 1 : 0;
2502  ag->errors = brsf & HFP_AG_ERRORS ? 1 : 0;
2503 
2504  return ag;
2505 }
int ecnr
Definition: chan_mobile.c:317
int reject
Definition: chan_mobile.c:321
int control
Definition: chan_mobile.c:323
int ring
Definition: chan_mobile.c:319
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
int status
Definition: chan_mobile.c:322
static int hfp_parse_brsf ( struct hfp_pvt hfp,
const char *  buf 
)
static

Parse BRSF data.

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

Definition at line 2726 of file chan_mobile.c.

References hfp_pvt::brsf, and hfp_int2brsf().

Referenced by handle_response_brsf().

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

Parse a CIEV event.

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

Definition at line 2197 of file chan_mobile.c.

References ast_debug, hfp_pvt::cind_index, hfp_pvt::cind_state, and hfp_pvt::owner.

Referenced by handle_response_ciev().

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

Read the result of the AT+CIND? command.

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

Definition at line 2770 of file chan_mobile.c.

References hfp_parse_cind_indicator().

Referenced by handle_response_cind().

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

Parse and store the given indicator.

Parameters
hfpan hfp_pvt struct
groupthe indicator group
indicatorthe indicator to parse

Definition at line 2744 of file chan_mobile.c.

References ast_debug, and hfp_pvt::cind_state.

Referenced by hfp_parse_cind().

2745 {
2746  int value;
2747 
2748  /* store the current indicator */
2749  if (group >= ARRAY_LEN(hfp->cind_state)) {
2750  ast_debug(1, "ignoring CIND state '%s' for group %d, we only support up to %d indicators\n", indicator, group, (int) sizeof(hfp->cind_state));
2751  return -1;
2752  }
2753 
2754  if (!sscanf(indicator, "%d", &value)) {
2755  ast_debug(1, "error parsing CIND state '%s' for group %d\n", indicator, group);
2756  return -1;
2757  }
2758 
2759  hfp->cind_state[group] = value;
2760  return 0;
2761 }
#define ast_debug(level,...)
Log a DEBUG message.
int cind_state[16]
Definition: chan_mobile.c:350
static int hfp_parse_cind_test ( struct hfp_pvt hfp,
char *  buf 
)
static

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

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

Definition at line 2820 of file chan_mobile.c.

References ast_debug, hfp_cind::battchg, hfp_cind::call, hfp_cind::callheld, hfp_cind::callsetup, hfp_pvt::cind_index, hfp_pvt::cind_map, hfp_pvt::nocallsetup, hfp_pvt::owner, hfp_cind::roam, hfp_cind::service, and hfp_cind::signal.

Referenced by handle_response_cind().

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

Parse a CLIP event.

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

Definition at line 2226 of file chan_mobile.c.

References ast_debug, ast_isphonenumber(), ast_strip_quoted(), and parse_next_token().

Referenced by handle_response_clip().

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

Parse a CMGR message.

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

Definition at line 2354 of file chan_mobile.c.

Referenced by handle_response_cmgr().

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

Parse a CMTI notification.

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

Definition at line 2328 of file chan_mobile.c.

References ast_debug, and hfp_pvt::owner.

Referenced by handle_response_cmti().

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

Parse a CUSD answer.

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

Definition at line 2418 of file chan_mobile.c.

Referenced by handle_response_cusd().

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

Parse a ECAV event.

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

Example:

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

Example indicating busy:

*ECAV: 1,7,1 

Definition at line 2166 of file chan_mobile.c.

References ast_debug, and hfp_pvt::owner.

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

Send ATA.

Parameters
hfpan hfp_pvt struct

Definition at line 2704 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

2705 {
2706  return rfcomm_write(hfp->rsock, "ATA\r");
2707 }
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_send_atd ( struct hfp_pvt hfp,
const char *  number 
)
static

Send ATD.

Parameters
hfpan hfp_pvt struct
numberthe number to send

Definition at line 2693 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

2694 {
2695  char cmd[64];
2696  snprintf(cmd, sizeof(cmd), "ATD%s;\r", number);
2697  return rfcomm_write(hfp->rsock, cmd);
2698 }
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
static int hfp_send_brsf ( struct hfp_pvt hfp,
struct hfp_hf brsf 
)
static

Send a BRSF request.

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

Definition at line 2516 of file chan_mobile.c.

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

2517 {
2518  char cmd[32];
2519  snprintf(cmd, sizeof(cmd), "AT+BRSF=%d\r", hfp_brsf2int(brsf));
2520  return rfcomm_write(hfp->rsock, cmd);
2521 }
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:2470
static int hfp_send_chup ( struct hfp_pvt hfp)
static

Send AT+CHUP.

Parameters
hfpan hfp_pvt struct

Definition at line 2683 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_clip().

2684 {
2685  return rfcomm_write(hfp->rsock, "AT+CHUP\r");
2686 }
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_send_cind ( struct hfp_pvt hfp)
static

Send the CIND read command.

Parameters
hfpan hfp_pvt struct

Definition at line 2527 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2528 {
2529  return rfcomm_write(hfp->rsock, "AT+CIND?\r");
2530 }
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_send_cind_test ( struct hfp_pvt hfp)
static

Send the CIND test command.

Parameters
hfpan hfp_pvt struct

Definition at line 2536 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2537 {
2538  return rfcomm_write(hfp->rsock, "AT+CIND=?\r");
2539 }
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_send_clip ( struct hfp_pvt hfp,
int  status 
)
static

Enable or disable calling line identification.

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

Definition at line 2585 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2586 {
2587  char cmd[32];
2588  snprintf(cmd, sizeof(cmd), "AT+CLIP=%d\r", status ? 1 : 0);
2589  return rfcomm_write(hfp->rsock, cmd);
2590 }
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_send_cmer ( struct hfp_pvt hfp,
int  status 
)
static

Enable or disable indicator events reporting.

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

Definition at line 2546 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2547 {
2548  char cmd[32];
2549  snprintf(cmd, sizeof(cmd), "AT+CMER=3,0,0,%d\r", status ? 1 : 0);
2550  return rfcomm_write(hfp->rsock, cmd);
2551 }
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_send_cmgf ( struct hfp_pvt hfp,
int  mode 
)
static

Set the SMS mode.

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

Definition at line 2627 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_error(), and handle_response_ok().

2628 {
2629  char cmd[32];
2630  snprintf(cmd, sizeof(cmd), "AT+CMGF=%d\r", mode);
2631  return rfcomm_write(hfp->rsock, cmd);
2632 }
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_send_cmgr ( struct hfp_pvt hfp,
int  index 
)
static

Read an SMS message.

Parameters
hfpan hfp_pvt struct
indexthe location of the requested message

Definition at line 2648 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_cmti().

2649 {
2650  char cmd[32];
2651  snprintf(cmd, sizeof(cmd), "AT+CMGR=%d\r", index);
2652  return rfcomm_write(hfp->rsock, cmd);
2653 }
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_send_cmgs ( struct hfp_pvt hfp,
const char *  number 
)
static

Start sending an SMS message.

Parameters
hfpan hfp_pvt struct
numberthe destination of the message

Definition at line 2660 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

2661 {
2662  char cmd[64];
2663  snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"\r", number);
2664  return rfcomm_write(hfp->rsock, cmd);
2665 }
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
static int hfp_send_cnmi ( struct hfp_pvt hfp)
static

Setup SMS new message indication.

Parameters
hfpan hfp_pvt struct

Definition at line 2638 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2639 {
2640  return rfcomm_write(hfp->rsock, "AT+CNMI=2,1,0,0,0\r");
2641 }
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_send_cusd ( struct hfp_pvt hfp,
const char *  code 
)
static

Send CUSD.

Parameters
hfpan hfp_pvt struct
codethe CUSD code to send

Definition at line 2714 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

2715 {
2716  char cmd[128];
2717  snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code);
2718  return rfcomm_write(hfp->rsock, cmd);
2719 }
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_send_dtmf ( struct hfp_pvt hfp,
char  digit 
)
static

Send a DTMF command.

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

Definition at line 2598 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

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

Enable Sony Ericsson extensions / indications.

Parameters
hfpan hfp_pvt struct

Definition at line 2184 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

2185 {
2186  return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
2187 }
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_send_sms_text ( struct hfp_pvt hfp,
const char *  message 
)
static

Send the text of an SMS message.

Parameters
hfpan hfp_pvt struct
messagethe text of the message

Definition at line 2672 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_sms_prompt().

2673 {
2674  char cmd[162];
2675  snprintf(cmd, sizeof(cmd), "%.160s\x1a", message);
2676  return rfcomm_write(hfp->rsock, cmd);
2677 }
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_send_vgs ( struct hfp_pvt hfp,
int  value 
)
static

Send the current speaker gain level.

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

Definition at line 2558 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_error(), and handle_response_ok().

2559 {
2560  char cmd[32];
2561  snprintf(cmd, sizeof(cmd), "AT+VGS=%d\r", value);
2562  return rfcomm_write(hfp->rsock, cmd);
2563 }
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 hsp_send_error ( int  rsock)
static

Send an ERROR AT response.

Parameters
rsockthe rfcomm socket to use

Definition at line 2935 of file chan_mobile.c.

References rfcomm_write().

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

Send an OK AT response.

Parameters
rsockthe rfcomm socket to use

Definition at line 2926 of file chan_mobile.c.

References rfcomm_write().

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

Send a RING unsolicited AT response.

Parameters
rsockthe rfcomm socket to use

Definition at line 2968 of file chan_mobile.c.

References rfcomm_write().

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

Send a microphone gain unsolicited AT response.

Parameters
rsockthe rfcomm socket to use
gainthe microphone gain value

Definition at line 2957 of file chan_mobile.c.

References rfcomm_write().

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

Send a speaker gain unsolicited AT response.

Parameters
rsockthe rfcomm socket to use
gainthe speaker gain value

Definition at line 2945 of file chan_mobile.c.

References rfcomm_write().

2946 {
2947  char cmd[32];
2948  snprintf(cmd, sizeof(cmd), "\r\n+VGS=%d\r\n", gain);
2949  return rfcomm_write(rsock, cmd);
2950 }
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
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, and hfp_cind::service.

1370 {
1371 
1372  if (pvt->type != MBL_TYPE_PHONE)
1373  return 1;
1374 
1375  if (!pvt->hfp->cind_map.service)
1376  return 1;
1377 
1378  if (pvt->hfp->cind_state[pvt->hfp->cind_map.service] == HFP_CIND_SERVICE_AVAILABLE)
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
int service
Definition: chan_mobile.c:331
static struct adapter_pvt* mbl_load_adapter ( struct ast_config cfg,
const char *  cat 
)
static

Load an adapter from the configuration file.

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

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

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

Definition at line 4366 of file chan_mobile.c.

References adapter_pvt::accept_io, address, ast_calloc, ast_copy_string(), ast_debug, ast_io_add(), AST_IO_IN, ast_io_remove(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_true(), do_sco_listen(), adapter_pvt::io, io_context_create(), io_context_destroy(), ast_variable::name, ast_variable::next, sco_accept(), sco_bind(), adapter_pvt::sco_id, adapter_pvt::sco_listener_thread, adapter_pvt::sco_socket, and ast_variable::value.

4367 {
4368  const char *id, *address;
4369  struct adapter_pvt *adapter;
4370  struct ast_variable *v;
4371  struct hci_dev_req dr;
4372  uint16_t vs;
4373 
4374  id = ast_variable_retrieve(cfg, cat, "id");
4375  address = ast_variable_retrieve(cfg, cat, "address");
4376 
4377  if (ast_strlen_zero(id) || ast_strlen_zero(address)) {
4378  ast_log(LOG_ERROR, "Skipping adapter. Missing id or address settings.\n");
4379  goto e_return;
4380  }
4381 
4382  ast_debug(1, "Reading configuration for adapter %s %s.\n", id, address);
4383 
4384  if (!(adapter = ast_calloc(1, sizeof(*adapter)))) {
4385  ast_log(LOG_ERROR, "Skipping adapter %s. Error allocating memory.\n", id);
4386  goto e_return;
4387  }
4388 
4389  ast_copy_string(adapter->id, id, sizeof(adapter->id));
4390  str2ba(address, &adapter->addr);
4391 
4392  /* attempt to connect to the adapter */
4393  adapter->dev_id = hci_devid(address);
4394  adapter->hci_socket = hci_open_dev(adapter->dev_id);
4395  if (adapter->dev_id < 0 || adapter->hci_socket < 0) {
4396  ast_log(LOG_ERROR, "Skipping adapter %s. Unable to communicate with adapter.\n", adapter->id);
4397  goto e_free_adapter;
4398  }
4399 
4400  /* check voice setting */
4401  hci_read_voice_setting(adapter->hci_socket, &vs, 1000);
4402  vs = htobs(vs);
4403  if (vs != 0x0060) {
4404  ast_log(LOG_ERROR, "Skipping adapter %s. Voice setting must be 0x0060 - see 'man hciconfig' for details.\n", adapter->id);
4405  goto e_hci_close_dev;
4406  }
4407 
4408  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4409  if (!strcasecmp(v->name, "forcemaster")) {
4410  if (ast_true(v->value)) {
4411  dr.dev_id = adapter->dev_id;
4412  if (hci_strtolm("master", &dr.dev_opt)) {
4413  if (ioctl(adapter->hci_socket, HCISETLINKMODE, (unsigned long) &dr) < 0) {
4414  ast_log(LOG_WARNING, "Unable to set adapter %s link mode to MASTER. Ignoring 'forcemaster' option.\n", adapter->id);
4415  }
4416  }
4417  }
4418  } else if (!strcasecmp(v->name, "alignmentdetection")) {
4419  adapter->alignment_detection = ast_true(v->value);
4420  }
4421  }
4422 
4423  /* create io contexts */
4424  if (!(adapter->accept_io = io_context_create())) {
4425  ast_log(LOG_ERROR, "Unable to create I/O context for audio connection listener\n");
4426  goto e_hci_close_dev;
4427  }
4428 
4429  if (!(adapter->io = io_context_create())) {
4430  ast_log(LOG_ERROR, "Unable to create I/O context for audio connections\n");
4431  goto e_destroy_accept_io;
4432  }
4433 
4434  /* bind the sco listener socket */
4435  if (sco_bind(adapter) < 0) {
4436  ast_log(LOG_ERROR, "Skipping adapter %s. Error binding audio connection listener socket.\n", adapter->id);
4437  goto e_destroy_io;
4438  }
4439 
4440  /* add the socket to the io context */
4441  if (!(adapter->sco_id = ast_io_add(adapter->accept_io, adapter->sco_socket, sco_accept, AST_IO_IN, adapter))) {
4442  ast_log(LOG_ERROR, "Skipping adapter %s. Error adding listener socket to I/O context.\n", adapter->id);
4443  goto e_close_sco;
4444  }
4445 
4446  /* start the sco listener for this adapter */
4447  if (ast_pthread_create_background(&adapter->sco_listener_thread, NULL, do_sco_listen, adapter)) {
4448  ast_log(LOG_ERROR, "Skipping adapter %s. Error creating audio connection listener thread.\n", adapter->id);
4449  goto e_remove_sco;
4450  }
4451 
4452  /* add the adapter to our global list */
4454  AST_RWLIST_INSERT_HEAD(&adapters, adapter, entry);
4456  ast_debug(1, "Loaded adapter %s %s.\n", adapter->id, address);
4457 
4458  return adapter;
4459 
4460 e_remove_sco:
4461  ast_io_remove(adapter->accept_io, adapter->sco_id);
4462 e_close_sco:
4463  close(adapter->sco_socket);
4464 e_destroy_io:
4465  io_context_destroy(adapter->io);
4466 e_destroy_accept_io:
4467  io_context_destroy(adapter->accept_io);
4468 e_hci_close_dev:
4469  hci_close_dev(adapter->hci_socket);
4470 e_free_adapter:
4471  ast_free(adapter);
4472 e_return:
4473  return NULL;
4474 }
struct ast_variable * next
struct io_context * accept_io
Definition: chan_mobile.c:107
pthread_t sco_listener_thread
Definition: chan_mobile.c:110
Structure for variables, used for configurations and for channel variables.
static struct ast_sockaddr address
Address for UDPTL.
Definition: res_pjsip_t38.c:56
#define AST_IO_IN
Definition: io.h:34
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
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
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
void io_context_destroy(struct io_context *ioc)
Destroys a context.
Definition: io.c:107
struct io_context * io
Definition: chan_mobile.c:106
#define ast_debug(level,...)
Log a DEBUG message.
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
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: utils.c:2199
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static void * do_sco_listen(void *data)
Service new and existing SCO connections. This thread accepts new sco connections and handles audio d...
Definition: chan_mobile.c:4328
int ast_io_remove(struct io_context *ioc, int *id)
Removes an IO context.
Definition: io.c:245
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Definition: search.h:40
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
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
static struct mbl_pvt* mbl_load_device ( struct ast_config cfg,
const char *  cat 
)
static

Load a device from the configuration file.

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

Definition at line 4482 of file chan_mobile.c.

References address, ast_calloc, ast_copy_string(), ast_debug, ast_dsp_new(), ast_dsp_set_digitmode(), ast_dsp_set_features(), AST_LIST_HEAD_INIT_NOLOCK, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sched_context_create(), ast_sched_context_destroy(), ast_true(), DSP_DIGITMODE_DTMF, DSP_DIGITMODE_RELAXDTMF, mbl_pvt::hfp, mbl_pvt::lock, ast_variable::name, ast_variable::next, hfp_pvt::nocallsetup, hfp_pvt::owner, hfp_pvt::rport, mbl_pvt::timeout, and ast_variable::value.

4483 {
4484  struct mbl_pvt *pvt;
4485  struct adapter_pvt *adapter;
4486  struct ast_variable *v;
4487  const char *address, *adapter_str, *port;
4488  ast_debug(1, "Reading configuration for device %s.\n", cat);
4489 
4490  adapter_str = ast_variable_retrieve(cfg, cat, "adapter");
4491  if(ast_strlen_zero(adapter_str)) {
4492  ast_log(LOG_ERROR, "Skipping device %s. No adapter specified.\n", cat);
4493  goto e_return;
4494  }
4495 
4496  /* find the adapter */
4498  AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
4499  if (!strcmp(adapter->id, adapter_str))
4500  break;
4501  }
4503  if (!adapter) {
4504  ast_log(LOG_ERROR, "Skipping device %s. Unknown adapter '%s' specified.\n", cat, adapter_str);
4505  goto e_return;
4506  }
4507 
4508  address = ast_variable_retrieve(cfg, cat, "address");
4509  port = ast_variable_retrieve(cfg, cat, "port");
4510  if (ast_strlen_zero(port) || ast_strlen_zero(address)) {
4511  ast_log(LOG_ERROR, "Skipping device %s. Missing required port or address setting.\n", cat);
4512  goto e_return;
4513  }
4514 
4515  /* create and initialize our pvt structure */
4516  if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
4517  ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", cat);
4518  goto e_return;
4519  }
4520 
4521  ast_mutex_init(&pvt->lock);
4522  AST_LIST_HEAD_INIT_NOLOCK(&pvt->msg_queue);
4523 
4524  /* set some defaults */
4525 
4526  pvt->type = MBL_TYPE_PHONE;
4527  ast_copy_string(pvt->context, "default", sizeof(pvt->context));
4528 
4529  /* populate the pvt structure */
4530  pvt->adapter = adapter;
4531  ast_copy_string(pvt->id, cat, sizeof(pvt->id));
4532  str2ba(address, &pvt->addr);
4533  pvt->timeout = -1;
4534  pvt->rfcomm_socket = -1;
4535  pvt->rfcomm_port = atoi(port);
4536  pvt->sco_socket = -1;
4537  pvt->monitor_thread = AST_PTHREADT_NULL;
4538  pvt->ring_sched_id = -1;
4539  pvt->has_sms = 1;
4540 
4541  /* setup the bt_out_smoother */
4542  if (!(pvt->bt_out_smoother = ast_smoother_new(DEVICE_FRAME_SIZE))) {
4543  ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_out_smoother.\n", cat);
4544  goto e_free_pvt;
4545  }
4546 
4547  /* setup the bt_in_smoother */
4548  if (!(pvt->bt_in_smoother = ast_smoother_new(CHANNEL_FRAME_SIZE))) {
4549  ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_in_smoother.\n", cat);
4550  goto e_free_bt_out_smoother;
4551  }
4552 
4553  /* setup the dsp */
4554  if (!(pvt->dsp = ast_dsp_new())) {
4555  ast_log(LOG_ERROR, "Skipping device %s. Error setting up dsp for dtmf detection.\n", cat);
4556  goto e_free_bt_in_smoother;
4557  }
4558 
4559  /* setup the scheduler */
4560  if (!(pvt->sched = ast_sched_context_create())) {
4561  ast_log(LOG_ERROR, "Unable to create scheduler context for headset device\n");
4562  goto e_free_dsp;
4563  }
4564 
4565  ast_dsp_set_features(pvt->dsp, DSP_FEATURE_DIGIT_DETECT);
4567 
4568  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4569  if (!strcasecmp(v->name, "type")) {
4570  if (!strcasecmp(v->value, "headset"))
4571  pvt->type = MBL_TYPE_HEADSET;
4572  else
4573  pvt->type = MBL_TYPE_PHONE;
4574  } else if (!strcasecmp(v->name, "context")) {
4575  ast_copy_string(pvt->context, v->value, sizeof(pvt->context));
4576  } else if (!strcasecmp(v->name, "group")) {
4577  /* group is set to 0 if invalid */
4578  pvt->group = atoi(v->value);
4579  } else if (!strcasecmp(v->name, "sms")) {
4580  pvt->has_sms = ast_true(v->value);
4581  } else if (!strcasecmp(v->name, "nocallsetup")) {
4582  pvt->no_callsetup = ast_true(v->value);
4583 
4584  if (pvt->no_callsetup)
4585  ast_debug(1, "Setting nocallsetup mode for device %s.\n", pvt->id);
4586  } else if (!strcasecmp(v->name, "blackberry")) {
4587  pvt->blackberry = ast_true(v->value);
4588  pvt->has_sms = 0;
4589  }
4590  }
4591 
4592  if (pvt->type == MBL_TYPE_PHONE) {
4593  if (!(pvt->hfp = ast_calloc(1, sizeof(*pvt->hfp)))) {
4594  ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", pvt->id);
4595  goto e_free_sched;
4596  }
4597 
4598  pvt->hfp->owner = pvt;
4599  pvt->hfp->rport = pvt->rfcomm_port;
4600  pvt->hfp->nocallsetup = pvt->no_callsetup;
4601  } else {
4602  pvt->has_sms = 0;
4603  }
4604 
4606  AST_RWLIST_INSERT_HEAD(&devices, pvt, entry);
4608  ast_debug(1, "Loaded device %s.\n", pvt->id);
4609 
4610  return pvt;
4611 
4612 e_free_sched:
4613  ast_sched_context_destroy(pvt->sched);
4614 e_free_dsp:
4615  ast_dsp_free(pvt->dsp);
4616 e_free_bt_in_smoother:
4617  ast_smoother_free(pvt->bt_in_smoother);
4618 e_free_bt_out_smoother:
4619  ast_smoother_free(pvt->bt_out_smoother);
4620 e_free_pvt:
4621  ast_free(pvt);
4622 e_return:
4623  return NULL;
4624 }
struct ast_variable * next
#define DSP_DIGITMODE_DTMF
Definition: dsp.h:31
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
Structure for variables, used for configurations and for channel variables.
static struct ast_sockaddr address
Address for UDPTL.
Definition: res_pjsip_t38.c:56
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
int timeout
Definition: chan_mobile.c:139
int nocallsetup
Definition: chan_mobile.c:347
#define DSP_DIGITMODE_RELAXDTMF
Definition: dsp.h:37
struct mbl_pvt * owner
Definition: chan_mobile.c:345
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
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: utils.c:2199
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:1768
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Definition: search.h:40
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
int rport
Definition: chan_mobile.c:353
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition: dsp.c:1857
static void msg_queue_flush ( struct mbl_pvt pvt)
static

Remove all items from the queue and free them.

Parameters
pvta mbl_pvt structure

Definition at line 3048 of file chan_mobile.c.

References msg_queue_free_and_pop(), and msg_queue_head().

3049 {
3050  struct msg_queue_entry *msg;
3051  while ((msg = msg_queue_head(pvt)))
3053 }
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:3060
static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue, and free it.
Definition: chan_mobile.c:3034
static void msg_queue_free_and_pop ( struct mbl_pvt pvt)
static

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

Parameters
pvta mbl_pvt structure

Definition at line 3034 of file chan_mobile.c.

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

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

Get the head of a queue.

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

Definition at line 3060 of file chan_mobile.c.

References AST_LIST_FIRST.

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

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

Remove an item from the front of the queue.

Parameters
pvta mbl_pvt structure
Returns
a pointer to the removed item

Definition at line 3025 of file chan_mobile.c.

References AST_LIST_REMOVE_HEAD.

Referenced by msg_queue_free_and_pop().

3026 {
3027  return AST_LIST_REMOVE_HEAD(&pvt->msg_queue, entry);
3028 }
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
Definition: search.h:40
static int msg_queue_push ( struct mbl_pvt pvt,
at_message_t  expect,
at_message_t  response_to 
)
static

Add an item to the back of the queue.

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

Definition at line 2984 of file chan_mobile.c.

References ast_calloc, and AST_LIST_INSERT_TAIL.

Referenced by handle_response_brsf(), handle_response_cind(), handle_response_clip(), handle_response_cmti(), handle_response_error(), handle_response_ok(), handle_response_ring(), and handle_sms_prompt().

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

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

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

Definition at line 3006 of file chan_mobile.c.

References ast_calloc, and AST_LIST_INSERT_TAIL.

3007 {
3008  struct msg_queue_entry *msg;
3009  if (!(msg = ast_calloc(1, sizeof(*msg)))) {
3010  return -1;
3011  }
3012  msg->expected = expect;
3013  msg->response_to = response_to;
3014  msg->data = data;
3015 
3016  AST_LIST_INSERT_TAIL(&pvt->msg_queue, msg, entry);
3017  return 0;
3018 }
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
Definition: chan_mobile.c:460
Definition: search.h:40
static int parse_next_token ( char  string[],
const int  start,
const char  delim 
)
static

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

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

Definition at line 2299 of file chan_mobile.c.

Referenced by hfp_parse_clip().

2300 {
2301  int index;
2302  int quoting = 0;
2303 
2304  for (index = start; string[index] != 0; index++) {
2305  if ((string[index] == delim) && !quoting ) {
2306  /* Found the delimiter, outside of quotes. This is the end of the token. */
2307  string[index] = '\0'; /* Terminate this token. */
2308  index++; /* Point the index to the start of the next token. */
2309  break; /* We're done. */
2310  } else if (string[index] == '"' && !quoting) {
2311  /* Found a beginning quote mark. Remember it. */
2312  quoting = 1;
2313  } else if (string[index] == '"' ) {
2314  /* Found the end quote mark. */
2315  quoting = 0;
2316  }
2317  }
2318  return index;
2319 }
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 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
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
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 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
static void rfcomm_append_buf(char **buf, size_t count, size_t *in_count, char c)
Append the given character to the given buffer and increase the in_count.
Definition: chan_mobile.c:1508
static int rfcomm_read_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 rfcomm_append_buf().

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 }
static void rfcomm_append_buf(char **buf, size_t count, size_t *in_count, char c)
Append the given character to the given buffer and increase the in_count.
Definition: chan_mobile.c:1508
static int rfcomm_read_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 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 }
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
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
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 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 }
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_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 rfcomm_append_buf(), and rfcomm_read_and_expect_char().

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

1480 {
1481  int exception, outfd;
1482  outfd = ast_waitfor_n_fd(&rsock, 1, ms, &exception);
1483  if (outfd < 0)
1484  outfd = 0;
1485 
1486  return outfd;
1487 }
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
Waits for input on an fd.
Definition: channel.c:2980
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 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 }
static int rfcomm_write_full(int rsock, char *buf, size_t count)
Write to an rfcomm socket.
Definition: chan_mobile.c:1454
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.

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 }
#define ast_debug(level,...)
Log a DEBUG message.
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::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 }

Variable Documentation

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.

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.