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/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
#include "asterisk/cli.h"
#include "asterisk/devicestate.h"
#include "asterisk/causes.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/io.h"
#include "asterisk/smoother.h"
#include "asterisk/format_cache.h"

Include dependency graph for chan_mobile.c:

Go to the source code of this file.

Data Structures

struct  adapter_pvt
struct  adapters
struct  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

Defines

#define CHANNEL_FRAME_SIZE   320
#define DEVICE_FRAME_FORMAT   ast_format_slin
#define DEVICE_FRAME_SIZE   48
#define FORMAT1   "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n"
#define FORMAT1   "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-10.10s %-3.3s\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 __fini_adapters (void)
static void __fini_devices (void)
static void __init_adapters (void)
static void __init_devices (void)
static void __reg_module (void)
static void __unreg_module (void)
static int at_match_prefix (char *buf, char *prefix)
 Match the given buffer with the given prefix.
static const char * at_msg2str (at_message_t msg)
 Get the string representation of the given AT message.
static at_message_t at_read_full (int rsock, char *buf, size_t count)
 Read an AT message and clasify it.
static int check_unloading ()
 Check if the module is unloading.
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.
static int handle_response_busy (struct mbl_pvt *pvt)
 Handle BUSY messages.
static int handle_response_ciev (struct mbl_pvt *pvt, char *buf)
 Handle AT+CIEV messages.
static int handle_response_cind (struct mbl_pvt *pvt, char *buf)
 Handle the CIND response.
static int handle_response_clip (struct mbl_pvt *pvt, char *buf)
 Handle AT+CLIP messages.
static int handle_response_cmgr (struct mbl_pvt *pvt, char *buf)
 Handle AT+CMGR messages.
static int handle_response_cmti (struct mbl_pvt *pvt, char *buf)
 Handle AT+CMTI messages.
static int handle_response_cusd (struct mbl_pvt *pvt, char *buf)
 Handle CUSD messages.
static int handle_response_error (struct mbl_pvt *pvt, char *buf)
 Handle ERROR AT messages.
static int handle_response_no_carrier (struct mbl_pvt *pvt, char *buf)
 Handle NO CARRIER messages.
static int handle_response_no_dialtone (struct mbl_pvt *pvt, char *buf)
 Handle NO DIALTONE messages.
static int handle_response_ok (struct mbl_pvt *pvt, char *buf)
 Handle OK AT messages.
static int handle_response_ring (struct mbl_pvt *pvt, char *buf)
 Handle RING messages.
static int handle_sms_prompt (struct mbl_pvt *pvt, char *buf)
 Send an SMS message from the queue.
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.
static struct hfp_aghfp_int2brsf (int brsf, struct hfp_ag *ag)
 Convert a BRSF int to an hfp_ag struct.
static int hfp_parse_brsf (struct hfp_pvt *hfp, const char *buf)
 Parse BRSF data.
static int hfp_parse_ciev (struct hfp_pvt *hfp, char *buf, int *value)
 Parse a CIEV event.
static int hfp_parse_cind (struct hfp_pvt *hfp, char *buf)
 Read the result of the AT+CIND? command.
static int hfp_parse_cind_indicator (struct hfp_pvt *hfp, int group, char *indicator)
 Parse and store the given indicator.
static int hfp_parse_cind_test (struct hfp_pvt *hfp, char *buf)
 Parse the result of the AT+CIND=? command.
static char * hfp_parse_clip (struct hfp_pvt *hfp, char *buf)
 Parse a CLIP event.
static int hfp_parse_cmgr (struct hfp_pvt *hfp, char *buf, char **from_number, char **text)
 Parse a CMGR message.
static int hfp_parse_cmti (struct hfp_pvt *hfp, char *buf)
 Parse a CMTI notification.
static char * hfp_parse_cusd (struct hfp_pvt *hfp, char *buf)
 Parse a CUSD answer.
static int hfp_parse_ecav (struct hfp_pvt *hfp, char *buf)
 Parse a ECAV event.
static int hfp_send_ata (struct hfp_pvt *hfp)
 Send ATA.
static int hfp_send_atd (struct hfp_pvt *hfp, const char *number)
 Send ATD.
static int hfp_send_brsf (struct hfp_pvt *hfp, struct hfp_hf *brsf)
 Send a BRSF request.
static int hfp_send_chup (struct hfp_pvt *hfp)
 Send AT+CHUP.
static int hfp_send_cind (struct hfp_pvt *hfp)
 Send the CIND read command.
static int hfp_send_cind_test (struct hfp_pvt *hfp)
 Send the CIND test command.
static int hfp_send_clip (struct hfp_pvt *hfp, int status)
 Enable or disable calling line identification.
static int hfp_send_cmer (struct hfp_pvt *hfp, int status)
 Enable or disable indicator events reporting.
static int hfp_send_cmgf (struct hfp_pvt *hfp, int mode)
 Set the SMS mode.
static int hfp_send_cmgr (struct hfp_pvt *hfp, int index)
 Read an SMS message.
static int hfp_send_cmgs (struct hfp_pvt *hfp, const char *number)
 Start sending an SMS message.
static int hfp_send_cnmi (struct hfp_pvt *hfp)
 Setup SMS new message indication.
static int hfp_send_cusd (struct hfp_pvt *hfp, const char *code)
 Send CUSD.
static int hfp_send_dtmf (struct hfp_pvt *hfp, char digit)
 Send a DTMF command.
static int hfp_send_ecam (struct hfp_pvt *hfp)
 Enable Sony Erricson extensions / indications.
static int hfp_send_sms_text (struct hfp_pvt *hfp, const char *message)
 Send the text of an SMS message.
static int hfp_send_vgs (struct hfp_pvt *hfp, int value)
 Send the current speaker gain level.
static int hsp_send_error (int rsock)
 Send an ERROR AT response.
static int hsp_send_ok (int rsock)
 Send an OK AT response.
static int hsp_send_ring (int rsock)
 Send a RING unsolicited AT response.
static int hsp_send_vgm (int rsock, int gain)
 Send a microphone gain unsolicited AT response.
static int hsp_send_vgs (int rsock, int gain)
 Send a speaker gain unsolicited AT response.
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.
static struct adapter_pvtmbl_load_adapter (struct ast_config *cfg, const char *cat)
 Load an adapter from the configuration file.
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.
static struct ast_channelmbl_new (int state, struct mbl_pvt *pvt, char *cid_num, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
static int mbl_queue_control (struct mbl_pvt *pvt, enum ast_control_frame_type control)
static int mbl_queue_hangup (struct mbl_pvt *pvt)
static struct ast_framembl_read (struct ast_channel *ast)
static struct ast_channelmbl_request (const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
static int mbl_sendsms_exec (struct ast_channel *ast, const char *data)
static int mbl_status_exec (struct ast_channel *ast, const char *data)
static int mbl_write (struct ast_channel *ast, struct ast_frame *frame)
static void msg_queue_flush (struct mbl_pvt *pvt)
 Remove all itmes from the queue and free them.
static void msg_queue_free_and_pop (struct mbl_pvt *pvt)
 Remove an item from the front of the queue, and free it.
static struct msg_queue_entrymsg_queue_head (struct mbl_pvt *pvt)
 Get the head of a queue.
static struct msg_queue_entrymsg_queue_pop (struct mbl_pvt *pvt)
 Remove an item from the front of the queue.
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.
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.
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.
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.
static int rfcomm_read_command (int rsock, char **buf, size_t count, size_t *in_count)
 Read the remainder of an AT command.
static int rfcomm_read_result (int rsock, char **buf, size_t count, size_t *in_count)
 Read and AT result code.
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.
static int rfcomm_read_until_crlf (int rsock, char **buf, size_t count, size_t *in_count)
 Read until.
static int rfcomm_read_until_ok (int rsock, char **buf, size_t count, size_t *in_count)
 Read until a.
static int rfcomm_wait (int rsock, int *ms)
 Wait for activity on an rfcomm socket.
static int rfcomm_write (int rsock, char *buf)
 Write to an rfcomm socket.
static int rfcomm_write_full (int rsock, char *buf, size_t count)
 Write to an rfcomm socket.
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.
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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
static char * app_mblsendsms = "MobileSendSMS"
static char * app_mblstatus = "MobileStatus"
static struct ast_module_infoast_module_info = &__mod_info
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_MUTEX_INITIALIZER , NULL, 1 }
static int unloading_flag = 0


Detailed Description

Bluetooth Mobile Device channel driver.

Author:
Dave Bowerman <david.bowerman@gmail.com>

Definition in file chan_mobile.c.


Define Documentation

#define CHANNEL_FRAME_SIZE   320

Definition at line 84 of file chan_mobile.c.

#define DEVICE_FRAME_FORMAT   ast_format_slin

Definition at line 83 of file chan_mobile.c.

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

#define DEVICE_FRAME_SIZE   48

Definition at line 82 of file chan_mobile.c.

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

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

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

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

#define HFP_AG_CONTROL   (1 << 7)

Definition at line 266 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_CW   (1 << 0)

Definition at line 259 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_ECNR   (1 << 1)

Definition at line 260 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_ERRORS   (1 << 8)

Definition at line 267 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_REJECT   (1 << 5)

Definition at line 264 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_RING   (1 << 3)

Definition at line 262 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_STATUS   (1 << 6)

Definition at line 265 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_TAG   (1 << 4)

Definition at line 263 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_AG_VOICE   (1 << 2)

Definition at line 261 of file chan_mobile.c.

Referenced by hfp_int2brsf().

#define HFP_CIND_BATTCHG   7

Definition at line 277 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

#define HFP_CIND_CALL   2

Definition at line 272 of file chan_mobile.c.

Referenced by handle_response_ciev(), and hfp_parse_cind_test().

#define HFP_CIND_CALL_ACTIVE   1

Definition at line 281 of file chan_mobile.c.

Referenced by handle_response_ciev().

#define HFP_CIND_CALL_NONE   0

Definition at line 280 of file chan_mobile.c.

Referenced by handle_response_ciev().

#define HFP_CIND_CALLHELD   4

Definition at line 274 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

#define HFP_CIND_CALLSETUP   3

Definition at line 273 of file chan_mobile.c.

Referenced by handle_response_ciev(), and hfp_parse_cind_test().

#define HFP_CIND_CALLSETUP_ALERTING   3

Definition at line 287 of file chan_mobile.c.

Referenced by handle_response_ciev().

#define HFP_CIND_CALLSETUP_INCOMING   1

Definition at line 285 of file chan_mobile.c.

Referenced by handle_response_ciev().

#define HFP_CIND_CALLSETUP_NONE   0

Definition at line 284 of file chan_mobile.c.

Referenced by handle_response_ciev().

#define HFP_CIND_CALLSETUP_OUTGOING   2

Definition at line 286 of file chan_mobile.c.

Referenced by handle_response_ciev().

#define HFP_CIND_NONE   0

Definition at line 270 of file chan_mobile.c.

Referenced by handle_response_ciev(), and hfp_parse_ciev().

#define HFP_CIND_ROAM   6

Definition at line 276 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

#define HFP_CIND_SERVICE   1

Definition at line 271 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

#define HFP_CIND_SERVICE_AVAILABLE   1

Definition at line 291 of file chan_mobile.c.

Referenced by mbl_has_service().

#define HFP_CIND_SERVICE_NONE   0

Definition at line 290 of file chan_mobile.c.

#define HFP_CIND_SIGNAL   5

Definition at line 275 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

#define HFP_CIND_UNKNOWN   -1

Definition at line 269 of file chan_mobile.c.

Referenced by hfp_parse_cind_test().

#define HFP_HF_CID   (1 << 2)

Definition at line 253 of file chan_mobile.c.

Referenced by hfp_brsf2int().

#define HFP_HF_CONTROL   (1 << 6)

Definition at line 257 of file chan_mobile.c.

Referenced by hfp_brsf2int().

#define HFP_HF_CW   (1 << 1)

Definition at line 252 of file chan_mobile.c.

Referenced by hfp_brsf2int().

#define HFP_HF_ECNR   (1 << 0)

Definition at line 251 of file chan_mobile.c.

Referenced by hfp_brsf2int().

#define HFP_HF_STATUS   (1 << 5)

Definition at line 256 of file chan_mobile.c.

Referenced by hfp_brsf2int().

#define HFP_HF_VOICE   (1 << 3)

Definition at line 254 of file chan_mobile.c.

Referenced by hfp_brsf2int().

#define HFP_HF_VOLUME   (1 << 4)

Definition at line 255 of file chan_mobile.c.

Referenced by hfp_brsf2int().

#define MBL_CONFIG   "chan_mobile.conf"

Definition at line 79 of file chan_mobile.c.

Referenced by load_module(), and mbl_load_config().

#define MBL_CONFIG_OLD   "mobile.conf"

Definition at line 80 of file chan_mobile.c.

Referenced by mbl_load_config().

#define rfcomm_read_debug ( c   ) 


Enumeration Type Documentation

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

Definition at line 412 of file chan_mobile.c.

00412              {
00413    /* errors */
00414    AT_PARSE_ERROR = -2,
00415    AT_READ_ERROR = -1,
00416    AT_UNKNOWN = 0,
00417    /* at responses */
00418    AT_OK,
00419    AT_ERROR,
00420    AT_RING,
00421    AT_BRSF,
00422    AT_CIND,
00423    AT_CIEV,
00424    AT_CLIP,
00425    AT_CMTI,
00426    AT_CMGR,
00427    AT_SMS_PROMPT,
00428    AT_CMS_ERROR,
00429    /* at commands */
00430    AT_A,
00431    AT_D,
00432    AT_CHUP,
00433    AT_CKPD,
00434    AT_CMGS,
00435    AT_VGM,
00436    AT_VGS,
00437    AT_VTS,
00438    AT_CMGF,
00439    AT_CNMI,
00440    AT_CMER,
00441    AT_CIND_TEST,
00442    AT_CUSD,
00443    AT_BUSY,
00444    AT_NO_DIALTONE,
00445    AT_NO_CARRIER,
00446    AT_ECAM,
00447 } at_message_t;

enum mbl_type

Enumerator:
MBL_TYPE_PHONE 
MBL_TYPE_HEADSET 

Definition at line 95 of file chan_mobile.c.

00095               {
00096    MBL_TYPE_PHONE,
00097    MBL_TYPE_HEADSET
00098 };


Function Documentation

static void __fini_adapters ( void   )  [static]

Definition at line 115 of file chan_mobile.c.

00119 {

static void __fini_devices ( void   )  [static]

Definition at line 166 of file chan_mobile.c.

00187 {

static void __init_adapters ( void   )  [static]

Definition at line 115 of file chan_mobile.c.

00119 {

static void __init_devices ( void   )  [static]

Definition at line 166 of file chan_mobile.c.

00187 {

static void __reg_module ( void   )  [static]

Definition at line 4761 of file chan_mobile.c.

static void __unreg_module ( void   )  [static]

Definition at line 4761 of file chan_mobile.c.

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

Match the given buffer with the given prefix.

Parameters:
buf the buffer to match
prefix the prefix to match

Definition at line 1989 of file chan_mobile.c.

Referenced by at_read_full().

01990 {
01991    return !strncmp(buf, prefix, strlen(prefix));
01992 }

static const char * at_msg2str ( at_message_t  msg  )  [inline, static]

Get the string representation of the given AT message.

Parameters:
msg the message to process
Returns:
a string describing the given message

Definition at line 2062 of file chan_mobile.c.

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

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

02063 {
02064    switch (msg) {
02065    /* errors */
02066    case AT_PARSE_ERROR:
02067       return "PARSE ERROR";
02068    case AT_READ_ERROR:
02069       return "READ ERROR";
02070    default:
02071    case AT_UNKNOWN:
02072       return "UNKNOWN";
02073    /* at responses */
02074    case AT_OK:
02075       return "OK";
02076    case AT_ERROR:
02077       return "ERROR";
02078    case AT_RING:
02079       return "RING";
02080    case AT_BRSF:
02081       return "AT+BRSF";
02082    case AT_CIND:
02083       return "AT+CIND";
02084    case AT_CIEV:
02085       return "AT+CIEV";
02086    case AT_CLIP:
02087       return "AT+CLIP";
02088    case AT_CMTI:
02089       return "AT+CMTI";
02090    case AT_CMGR:
02091       return "AT+CMGR";
02092    case AT_SMS_PROMPT:
02093       return "SMS PROMPT";
02094    case AT_CMS_ERROR:
02095       return "+CMS ERROR";
02096    case AT_BUSY:
02097       return "BUSY";
02098    case AT_NO_DIALTONE:
02099       return "NO DIALTONE";
02100    case AT_NO_CARRIER:
02101       return "NO CARRIER";
02102    /* at commands */
02103    case AT_A:
02104       return "ATA";
02105    case AT_D:
02106       return "ATD";
02107    case AT_CHUP:
02108       return "AT+CHUP";
02109    case AT_CKPD:
02110       return "AT+CKPD";
02111    case AT_CMGS:
02112       return "AT+CMGS";
02113    case AT_VGM:
02114       return "AT+VGM";
02115    case AT_VGS:
02116       return "AT+VGS";
02117    case AT_VTS:
02118       return "AT+VTS";
02119    case AT_CMGF:
02120       return "AT+CMGF";
02121    case AT_CNMI:
02122       return "AT+CNMI";
02123    case AT_CMER:
02124       return "AT+CMER";
02125    case AT_CIND_TEST:
02126       return "AT+CIND=?";
02127    case AT_CUSD:
02128       return "AT+CUSD";
02129    case AT_ECAM:
02130       return "AT*ECAM";
02131    }
02132 }

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

Read an AT message and clasify it.

Parameters:
rsock an rfcomm socket
buf the buffer to store the result in
count the 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 2003 of file chan_mobile.c.

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

Referenced by do_monitor_headset(), and do_monitor_phone().

02004 {
02005    ssize_t s;
02006    if ((s = rfcomm_read(rsock, buf, count - 1)) < 1)
02007       return s;
02008    buf[s] = '\0';
02009 
02010    if (!strcmp("OK", buf)) {
02011       return AT_OK;
02012    } else if (!strcmp("ERROR", buf)) {
02013       return AT_ERROR;
02014    } else if (!strcmp("RING", buf)) {
02015       return AT_RING;
02016    } else if (!strcmp("AT+CKPD=200", buf)) {
02017       return AT_CKPD;
02018    } else if (!strcmp("> ", buf)) {
02019       return AT_SMS_PROMPT;
02020    } else if (at_match_prefix(buf, "+CMTI:")) {
02021       return AT_CMTI;
02022    } else if (at_match_prefix(buf, "+CIEV:")) {
02023       return AT_CIEV;
02024    } else if (at_match_prefix(buf, "+BRSF:")) {
02025       return AT_BRSF;
02026    } else if (at_match_prefix(buf, "+CIND:")) {
02027       return AT_CIND;
02028    } else if (at_match_prefix(buf, "+CLIP:")) {
02029       return AT_CLIP;
02030    } else if (at_match_prefix(buf, "+CMGR:")) {
02031       return AT_CMGR;
02032    } else if (at_match_prefix(buf, "+VGM:")) {
02033       return AT_VGM;
02034    } else if (at_match_prefix(buf, "+VGS:")) {
02035       return AT_VGS;
02036    } else if (at_match_prefix(buf, "+CMS ERROR:")) {
02037       return AT_CMS_ERROR;
02038    } else if (at_match_prefix(buf, "AT+VGM=")) {
02039       return AT_VGM;
02040    } else if (at_match_prefix(buf, "AT+VGS=")) {
02041       return AT_VGS;
02042    } else if (at_match_prefix(buf, "+CUSD:")) {
02043       return AT_CUSD;
02044    } else if (at_match_prefix(buf, "BUSY")) {
02045       return AT_BUSY;
02046    } else if (at_match_prefix(buf, "NO DIALTONE")) {
02047       return AT_NO_DIALTONE;
02048    } else if (at_match_prefix(buf, "NO CARRIER")) {
02049       return AT_NO_CARRIER;
02050    } else if (at_match_prefix(buf, "*ECAV:")) {
02051       return AT_ECAM;
02052    } else {
02053       return AT_UNKNOWN;
02054    }
02055 }

static int check_unloading (  )  [inline, static]

Check if the module is unloading.

Return values:
0 not unloading
1 unloading

Definition at line 4611 of file chan_mobile.c.

References ast_mutex_lock, ast_mutex_unlock, and unload_mutex.

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

04612 {
04613    int res;
04614    ast_mutex_lock(&unload_mutex);
04615    res = unloading_flag;
04616    ast_mutex_unlock(&unload_mutex);
04617 
04618    return res;
04619 }

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

Definition at line 1267 of file chan_mobile.c.

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

Referenced by mbl_read().

01268 {
01269 
01270    int i;
01271    short a, *s;
01272    char *p;
01273 
01274    if (pvt->alignment_detection_triggered) {
01275       for (i=buflen, p=buf+buflen-1; i>0; i--, p--)
01276          *p = *(p-1);
01277       *(p+1) = 0;
01278       return;
01279    }
01280 
01281    if (pvt->alignment_count < 4) {
01282       s = (short *)buf;
01283       for (i=0, a=0; i<buflen/2; i++) {
01284          a += *s++;
01285          a /= i+1;
01286       }
01287       pvt->alignment_samples[pvt->alignment_count++] = a;
01288       return;
01289    }
01290 
01291    ast_debug(1, "Alignment Detection result is [%-d %-d %-d %-d]\n", pvt->alignment_samples[0], pvt->alignment_samples[1], pvt->alignment_samples[2], pvt->alignment_samples[3]);
01292 
01293    a = abs(pvt->alignment_samples[1]) + abs(pvt->alignment_samples[2]) + abs(pvt->alignment_samples[3]);
01294    a /= 3;
01295    if (a > 100) {
01296       pvt->alignment_detection_triggered = 1;
01297       ast_debug(1, "Alignment Detection Triggered.\n");
01298    } else
01299       pvt->do_alignment_detection = 0;
01300 
01301 }

static void* do_discovery ( void *  data  )  [static]

Definition at line 4219 of file chan_mobile.c.

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

Referenced by load_module().

04220 {
04221 
04222    struct adapter_pvt *adapter;
04223    struct mbl_pvt *pvt;
04224 
04225    while (!check_unloading()) {
04226       AST_RWLIST_RDLOCK(&adapters);
04227       AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
04228          if (!adapter->inuse) {
04229             AST_RWLIST_RDLOCK(&devices);
04230             AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
04231                ast_mutex_lock(&pvt->lock);
04232                if (!adapter->inuse && !pvt->connected && !strcmp(adapter->id, pvt->adapter->id)) {
04233                   if ((pvt->rfcomm_socket = rfcomm_connect(adapter->addr, pvt->addr, pvt->rfcomm_port)) > -1) {
04234                      if (start_monitor(pvt)) {
04235                         pvt->connected = 1;
04236                         adapter->inuse = 1;
04237                         manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Connect\r\nDevice: %s\r\n", pvt->id);
04238                         ast_verb(3, "Bluetooth Device %s has connected, initializing...\n", pvt->id);
04239                      }
04240                   }
04241                }
04242                ast_mutex_unlock(&pvt->lock);
04243             }
04244             AST_RWLIST_UNLOCK(&devices);
04245          }
04246       }
04247       AST_RWLIST_UNLOCK(&adapters);
04248 
04249 
04250       /* Go to sleep (only if we are not unloading) */
04251       if (!check_unloading())
04252          sleep(discovery_interval);
04253    }
04254 
04255    return NULL;
04256 }

static void* do_monitor_headset ( void *  data  )  [static]

Definition at line 4052 of file chan_mobile.c.

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

Referenced by start_monitor().

04053 {
04054 
04055    struct mbl_pvt *pvt = (struct mbl_pvt *)data;
04056    char buf[256];
04057    int t;
04058    at_message_t at_msg;
04059    struct ast_channel *chan = NULL;
04060 
04061    ast_verb(3, "Bluetooth Device %s initialised and ready.\n", pvt->id);
04062 
04063    while (!check_unloading()) {
04064 
04065       t = ast_sched_wait(pvt->sched);
04066       if (t == -1) {
04067          t = 6000;
04068       }
04069 
04070       ast_sched_runq(pvt->sched);
04071 
04072       if (rfcomm_wait(pvt->rfcomm_socket, &t) == 0)
04073          continue;
04074 
04075       if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
04076          if (strerror_r(errno, buf, sizeof(buf)))
04077             ast_debug(1, "[%s] error reading from device\n", pvt->id);
04078          else
04079             ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, buf, errno);
04080 
04081          goto e_cleanup;
04082       }
04083       ast_debug(1, "[%s] %s\n", pvt->id, buf);
04084 
04085       switch (at_msg) {
04086       case AT_VGS:
04087       case AT_VGM:
04088          /* XXX volume change requested, we will just
04089           * pretend to do something with it */
04090          if (hsp_send_ok(pvt->rfcomm_socket)) {
04091             ast_debug(1, "[%s] error sending AT message 'OK'\n", pvt->id);
04092             goto e_cleanup;
04093          }
04094          break;
04095       case AT_CKPD:
04096          ast_mutex_lock(&pvt->lock);
04097          if (pvt->outgoing) {
04098             pvt->needring = 0;
04099             hsp_send_ok(pvt->rfcomm_socket);
04100             if (pvt->answered) {
04101                /* we have an answered call up to the
04102                 * HS, he wants to hangup */
04103                mbl_queue_hangup(pvt);
04104             } else {
04105                /* we have an outgoing call to the HS,
04106                 * he wants to answer */
04107                if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
04108                   ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
04109                   mbl_queue_hangup(pvt);
04110                   ast_mutex_unlock(&pvt->lock);
04111                   goto e_cleanup;
04112                }
04113 
04114                ast_channel_set_fd(pvt->owner, 0, pvt->sco_socket);
04115 
04116                mbl_queue_control(pvt, AST_CONTROL_ANSWER);
04117                pvt->answered = 1;
04118 
04119                if (hsp_send_vgs(pvt->rfcomm_socket, 13) || hsp_send_vgm(pvt->rfcomm_socket, 13)) {
04120                   ast_debug(1, "[%s] error sending VGS/VGM\n", pvt->id);
04121                   mbl_queue_hangup(pvt);
04122                   ast_mutex_unlock(&pvt->lock);
04123                   goto e_cleanup;
04124                }
04125             }
04126          } else if (pvt->incoming) {
04127             /* we have an incoming call from the
04128              * HS, he wants to hang up */
04129             mbl_queue_hangup(pvt);
04130          } else {
04131             /* no call is up, HS wants to dial */
04132             hsp_send_ok(pvt->rfcomm_socket);
04133 
04134             if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
04135                ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
04136                ast_mutex_unlock(&pvt->lock);
04137                goto e_cleanup;
04138             }
04139 
04140             pvt->incoming = 1;
04141 
04142             if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL, NULL))) {
04143                ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
04144                ast_mutex_unlock(&pvt->lock);
04145                goto e_cleanup;
04146             }
04147 
04148             ast_channel_set_fd(chan, 0, pvt->sco_socket);
04149 
04150             ast_channel_exten_set(chan, "s");
04151             if (ast_pbx_start(chan)) {
04152                ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
04153                ast_hangup(chan);
04154                ast_mutex_unlock(&pvt->lock);
04155                goto e_cleanup;
04156             }
04157          }
04158          ast_mutex_unlock(&pvt->lock);
04159          break;
04160       default:
04161          ast_debug(1, "[%s] received unknown AT command: %s (%s)\n", pvt->id, buf, at_msg2str(at_msg));
04162          if (hsp_send_error(pvt->rfcomm_socket)) {
04163             ast_debug(1, "[%s] error sending AT message 'ERROR'\n", pvt->id);
04164             goto e_cleanup;
04165          }
04166          break;
04167       }
04168    }
04169 
04170 e_cleanup:
04171    ast_mutex_lock(&pvt->lock);
04172    if (pvt->owner) {
04173       ast_debug(1, "[%s] device disconnected, hanging up owner\n", pvt->id);
04174       mbl_queue_hangup(pvt);
04175    }
04176 
04177 
04178    close(pvt->rfcomm_socket);
04179    close(pvt->sco_socket);
04180    pvt->sco_socket = -1;
04181 
04182    pvt->connected = 0;
04183 
04184    pvt->needring = 0;
04185    pvt->outgoing = 0;
04186    pvt->incoming = 0;
04187 
04188    pvt->adapter->inuse = 0;
04189    ast_mutex_unlock(&pvt->lock);
04190 
04191    manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
04192    ast_verb(3, "Bluetooth Device %s has disconnected\n", pvt->id);
04193 
04194    return NULL;
04195 
04196 }

static void* do_monitor_phone ( void *  data  )  [static]

Definition at line 3800 of file chan_mobile.c.

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

Referenced by start_monitor().

03801 {
03802    struct mbl_pvt *pvt = (struct mbl_pvt *)data;
03803    struct hfp_pvt *hfp = pvt->hfp;
03804    char buf[350];
03805    int t;
03806    at_message_t at_msg;
03807    struct msg_queue_entry *entry;
03808 
03809    /* Note: At one point the initialization procedure was neatly contained
03810     * in the hfp_init() function, but that initialization method did not
03811     * work with non standard devices.  As a result, the initialization
03812     * procedure is not spread throughout the event handling loop.
03813     */
03814 
03815    /* start initialization with the BRSF request */
03816    ast_mutex_lock(&pvt->lock);
03817    pvt->timeout = 10000;
03818    if (hfp_send_brsf(hfp, &hfp_our_brsf)  || msg_queue_push(pvt, AT_BRSF, AT_BRSF)) {
03819       ast_debug(1, "[%s] error sending BRSF\n", hfp->owner->id);
03820       goto e_cleanup;
03821    }
03822    ast_mutex_unlock(&pvt->lock);
03823 
03824    while (!check_unloading()) {
03825       ast_mutex_lock(&pvt->lock);
03826       t = pvt->timeout;
03827       ast_mutex_unlock(&pvt->lock);
03828 
03829       if (!rfcomm_wait(pvt->rfcomm_socket, &t)) {
03830          ast_debug(1, "[%s] timeout waiting for rfcomm data, disconnecting\n", pvt->id);
03831          ast_mutex_lock(&pvt->lock);
03832          if (!hfp->initialized) {
03833             if ((entry = msg_queue_head(pvt))) {
03834                switch (entry->response_to) {
03835                case AT_CIND_TEST:
03836                   if (pvt->blackberry)
03837                      ast_debug(1, "[%s] timeout during CIND test\n", hfp->owner->id);
03838                   else
03839                      ast_debug(1, "[%s] timeout during CIND test, try setting 'blackberry=yes'\n", hfp->owner->id);
03840                   break;
03841                case AT_CMER:
03842                   if (pvt->blackberry)
03843                      ast_debug(1, "[%s] timeout after sending CMER, try setting 'blackberry=no'\n", hfp->owner->id);
03844                   else
03845                      ast_debug(1, "[%s] timeout after sending CMER\n", hfp->owner->id);
03846                   break;
03847                default:
03848                   ast_debug(1, "[%s] timeout while waiting for %s in response to %s\n", pvt->id, at_msg2str(entry->expected), at_msg2str(entry->response_to));
03849                   break;
03850                }
03851             }
03852          }
03853          ast_mutex_unlock(&pvt->lock);
03854          goto e_cleanup;
03855       }
03856 
03857       if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) {
03858          /* XXX gnu specific strerror_r is assummed here, this
03859           * is not really safe.  See the strerror(3) man page
03860           * for more info. */
03861          ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
03862          break;
03863       }
03864 
03865       ast_debug(1, "[%s] %s\n", pvt->id, buf);
03866 
03867       switch (at_msg) {
03868       case AT_BRSF:
03869          ast_mutex_lock(&pvt->lock);
03870          if (handle_response_brsf(pvt, buf)) {
03871             ast_mutex_unlock(&pvt->lock);
03872             goto e_cleanup;
03873          }
03874          ast_mutex_unlock(&pvt->lock);
03875          break;
03876       case AT_CIND:
03877          ast_mutex_lock(&pvt->lock);
03878          if (handle_response_cind(pvt, buf)) {
03879             ast_mutex_unlock(&pvt->lock);
03880             goto e_cleanup;
03881          }
03882          ast_mutex_unlock(&pvt->lock);
03883          break;
03884       case AT_OK:
03885          ast_mutex_lock(&pvt->lock);
03886          if (handle_response_ok(pvt, buf)) {
03887             ast_mutex_unlock(&pvt->lock);
03888             goto e_cleanup;
03889          }
03890          ast_mutex_unlock(&pvt->lock);
03891          break;
03892       case AT_CMS_ERROR:
03893       case AT_ERROR:
03894          ast_mutex_lock(&pvt->lock);
03895          if (handle_response_error(pvt, buf)) {
03896             ast_mutex_unlock(&pvt->lock);
03897             goto e_cleanup;
03898          }
03899          ast_mutex_unlock(&pvt->lock);
03900          break;
03901       case AT_RING:
03902          ast_mutex_lock(&pvt->lock);
03903          if (handle_response_ring(pvt, buf)) {
03904             ast_mutex_unlock(&pvt->lock);
03905             goto e_cleanup;
03906          }
03907          ast_mutex_unlock(&pvt->lock);
03908          break;
03909       case AT_CIEV:
03910          ast_mutex_lock(&pvt->lock);
03911          if (handle_response_ciev(pvt, buf)) {
03912             ast_mutex_unlock(&pvt->lock);
03913             goto e_cleanup;
03914          }
03915          ast_mutex_unlock(&pvt->lock);
03916          break;
03917       case AT_CLIP:
03918          ast_mutex_lock(&pvt->lock);
03919          if (handle_response_clip(pvt, buf)) {
03920             ast_mutex_unlock(&pvt->lock);
03921             goto e_cleanup;
03922          }
03923          ast_mutex_unlock(&pvt->lock);
03924          break;
03925       case AT_CMTI:
03926          ast_mutex_lock(&pvt->lock);
03927          if (handle_response_cmti(pvt, buf)) {
03928             ast_mutex_unlock(&pvt->lock);
03929             goto e_cleanup;
03930          }
03931          ast_mutex_unlock(&pvt->lock);
03932          break;
03933       case AT_CMGR:
03934          ast_mutex_lock(&pvt->lock);
03935          if (handle_response_cmgr(pvt, buf)) {
03936             ast_mutex_unlock(&pvt->lock);
03937             goto e_cleanup;
03938          }
03939          ast_mutex_unlock(&pvt->lock);
03940          break;
03941       case AT_SMS_PROMPT:
03942          ast_mutex_lock(&pvt->lock);
03943          if (handle_sms_prompt(pvt, buf)) {
03944             ast_mutex_unlock(&pvt->lock);
03945             goto e_cleanup;
03946          }
03947          ast_mutex_unlock(&pvt->lock);
03948          break;
03949       case AT_CUSD:
03950          ast_mutex_lock(&pvt->lock);
03951          if (handle_response_cusd(pvt, buf)) {
03952             ast_mutex_unlock(&pvt->lock);
03953             goto e_cleanup;
03954          }
03955          ast_mutex_unlock(&pvt->lock);
03956          break;
03957       case AT_BUSY:
03958          ast_mutex_lock(&pvt->lock);
03959          if (handle_response_busy(pvt)) {
03960             ast_mutex_unlock(&pvt->lock);
03961             goto e_cleanup;
03962          }
03963          ast_mutex_unlock(&pvt->lock);
03964          break;
03965       case AT_NO_DIALTONE:
03966          ast_mutex_lock(&pvt->lock);
03967          if (handle_response_no_dialtone(pvt, buf)) {
03968             ast_mutex_unlock(&pvt->lock);
03969             goto e_cleanup;
03970          }
03971          ast_mutex_unlock(&pvt->lock);
03972          break;
03973       case AT_NO_CARRIER:
03974          ast_mutex_lock(&pvt->lock);
03975          if (handle_response_no_carrier(pvt, buf)) {
03976             ast_mutex_unlock(&pvt->lock);
03977             goto e_cleanup;
03978          }
03979          ast_mutex_unlock(&pvt->lock);
03980          break;
03981       case AT_ECAM:
03982          ast_mutex_lock(&pvt->lock);
03983          if (hfp_parse_ecav(hfp, buf) == 7) {
03984             if (handle_response_busy(pvt)) {
03985                ast_mutex_unlock(&pvt->lock);
03986                goto e_cleanup;
03987             }
03988          }
03989          ast_mutex_unlock(&pvt->lock);
03990          break;
03991       case AT_UNKNOWN:
03992          ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
03993          break;
03994       case AT_PARSE_ERROR:
03995          ast_debug(1, "[%s] error parsing message\n", pvt->id);
03996          goto e_cleanup;
03997       case AT_READ_ERROR:
03998          ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
03999          goto e_cleanup;
04000       default:
04001          break;
04002       }
04003    }
04004 
04005 e_cleanup:
04006 
04007    if (!hfp->initialized)
04008       ast_verb(3, "Error initializing Bluetooth device %s.\n", pvt->id);
04009 
04010    ast_mutex_lock(&pvt->lock);
04011    if (pvt->owner) {
04012       ast_debug(1, "[%s] device disconnected, hanging up owner\n", pvt->id);
04013       pvt->needchup = 0;
04014       mbl_queue_hangup(pvt);
04015    }
04016 
04017    close(pvt->rfcomm_socket);
04018    close(pvt->sco_socket);
04019    pvt->sco_socket = -1;
04020 
04021    msg_queue_flush(pvt);
04022 
04023    pvt->connected = 0;
04024    hfp->initialized = 0;
04025 
04026    pvt->adapter->inuse = 0;
04027    ast_mutex_unlock(&pvt->lock);
04028 
04029    ast_verb(3, "Bluetooth Device %s has disconnected.\n", pvt->id);
04030    manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
04031 
04032    return NULL;
04033 }

static void * do_sco_listen ( void *  data  )  [static]

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

Definition at line 4263 of file chan_mobile.c.

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

Referenced by mbl_load_adapter().

04264 {
04265    struct adapter_pvt *adapter = (struct adapter_pvt *) data;
04266 
04267    while (!check_unloading()) {
04268       /* check for new sco connections */
04269       if (ast_io_wait(adapter->accept_io, 0) == -1) {
04270          /* handle errors */
04271          ast_log(LOG_ERROR, "ast_io_wait() failed for adapter %s\n", adapter->id);
04272          break;
04273       }
04274 
04275       /* handle audio data */
04276       if (ast_io_wait(adapter->io, 1) == -1) {
04277          ast_log(LOG_ERROR, "ast_io_wait() failed for audio on adapter %s\n", adapter->id);
04278          break;
04279       }
04280    }
04281 
04282    return NULL;
04283 }

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

Definition at line 652 of file chan_mobile.c.

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

00653 {
00654    char buf[128];
00655    struct mbl_pvt *pvt = NULL;
00656 
00657    switch (cmd) {
00658    case CLI_INIT:
00659       e->command = "mobile cusd";
00660       e->usage =
00661          "Usage: mobile cusd <device ID> <command>\n"
00662          "       Send cusd <command> to the rfcomm port on the device\n"
00663          "       with the specified <device ID>.\n";
00664       return NULL;
00665    case CLI_GENERATE:
00666       return NULL;
00667    }
00668 
00669    if (a->argc != 4)
00670       return CLI_SHOWUSAGE;
00671 
00672    AST_RWLIST_RDLOCK(&devices);
00673    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
00674       if (!strcmp(pvt->id, a->argv[2]))
00675          break;
00676    }
00677    AST_RWLIST_UNLOCK(&devices);
00678 
00679    if (!pvt) {
00680       ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
00681       goto e_return;
00682    }
00683 
00684    ast_mutex_lock(&pvt->lock);
00685    if (!pvt->connected) {
00686       ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
00687       goto e_unlock_pvt;
00688    }
00689 
00690    snprintf(buf, sizeof(buf), "%s", a->argv[3]);
00691    if (hfp_send_cusd(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CUSD)) {
00692       ast_cli(a->fd, "[%s] error sending CUSD\n", pvt->id);
00693       goto e_unlock_pvt;
00694    }
00695 
00696 e_unlock_pvt:
00697    ast_mutex_unlock(&pvt->lock);
00698 e_return:
00699    return CLI_SUCCESS;
00700 }

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

Definition at line 604 of file chan_mobile.c.

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

00605 {
00606    char buf[128];
00607    struct mbl_pvt *pvt = NULL;
00608 
00609    switch (cmd) {
00610    case CLI_INIT:
00611       e->command = "mobile rfcomm";
00612       e->usage =
00613          "Usage: mobile rfcomm <device ID> <command>\n"
00614          "       Send <command> to the rfcomm port on the device\n"
00615          "       with the specified <device ID>.\n";
00616       return NULL;
00617    case CLI_GENERATE:
00618       return NULL;
00619    }
00620 
00621    if (a->argc != 4)
00622       return CLI_SHOWUSAGE;
00623 
00624    AST_RWLIST_RDLOCK(&devices);
00625    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
00626       if (!strcmp(pvt->id, a->argv[2]))
00627          break;
00628    }
00629    AST_RWLIST_UNLOCK(&devices);
00630 
00631    if (!pvt) {
00632       ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
00633       goto e_return;
00634    }
00635 
00636    ast_mutex_lock(&pvt->lock);
00637    if (!pvt->connected) {
00638       ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
00639       goto e_unlock_pvt;
00640    }
00641 
00642    snprintf(buf, sizeof(buf), "%s\r", a->argv[3]);
00643    rfcomm_write(pvt->rfcomm_socket, buf);
00644    msg_queue_push(pvt, AT_OK, AT_UNKNOWN);
00645 
00646 e_unlock_pvt:
00647    ast_mutex_unlock(&pvt->lock);
00648 e_return:
00649    return CLI_SUCCESS;
00650 }

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

Definition at line 534 of file chan_mobile.c.

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

00535 {
00536    struct adapter_pvt *adapter;
00537    inquiry_info *ii = NULL;
00538    int max_rsp, num_rsp;
00539    int len, flags;
00540    int i, phport, hsport;
00541    char addr[19] = {0};
00542    char name[31] = {0};
00543 
00544 #define FORMAT1 "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n"
00545 #define FORMAT2 "%-17.17s %-30.30s %-6.6s %-7.7s %d\n"
00546 
00547    switch (cmd) {
00548    case CLI_INIT:
00549       e->command = "mobile search";
00550       e->usage =
00551          "Usage: mobile search\n"
00552          "       Searches for Bluetooth Cell / Mobile devices in range.\n";
00553       return NULL;
00554    case CLI_GENERATE:
00555       return NULL;
00556    }
00557 
00558    if (a->argc != 2)
00559       return CLI_SHOWUSAGE;
00560 
00561    /* find a free adapter */
00562    AST_RWLIST_RDLOCK(&adapters);
00563    AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
00564       if (!adapter->inuse)
00565          break;
00566    }
00567    AST_RWLIST_UNLOCK(&adapters);
00568 
00569    if (!adapter) {
00570       ast_cli(a->fd, "All Bluetooth adapters are in use at this time.\n");
00571       return CLI_SUCCESS;
00572    }
00573 
00574    len  = 8;
00575    max_rsp = 255;
00576    flags = IREQ_CACHE_FLUSH;
00577 
00578    ii = ast_alloca(max_rsp * sizeof(inquiry_info));
00579    num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
00580    if (num_rsp > 0) {
00581       ast_cli(a->fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
00582       for (i = 0; i < num_rsp; i++) {
00583          ba2str(&(ii + i)->bdaddr, addr);
00584          name[0] = 0x00;
00585          if (hci_read_remote_name(adapter->hci_socket, &(ii + i)->bdaddr, sizeof(name) - 1, name, 0) < 0)
00586             strcpy(name, "[unknown]");
00587          phport = sdp_search(addr, HANDSFREE_AGW_PROFILE_ID);
00588          if (!phport)
00589             hsport = sdp_search(addr, HEADSET_PROFILE_ID);
00590          else
00591             hsport = 0;
00592          ast_cli(a->fd, FORMAT2, addr, name, (phport > 0 || hsport > 0) ? "Yes" : "No",
00593             (phport > 0) ? "Phone" : "Headset", (phport > 0) ? phport : hsport);
00594       }
00595    } else
00596       ast_cli(a->fd, "No Bluetooth Cell / Mobile devices found.\n");
00597 
00598 #undef FORMAT1
00599 #undef FORMAT2
00600 
00601    return CLI_SUCCESS;
00602 }

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

Definition at line 488 of file chan_mobile.c.

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

00489 {
00490    struct mbl_pvt *pvt;
00491    char bdaddr[18];
00492    char group[6];
00493 
00494 #define FORMAT1 "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-10.10s %-3.3s\n"
00495 
00496    switch (cmd) {
00497    case CLI_INIT:
00498       e->command = "mobile show devices";
00499       e->usage =
00500          "Usage: mobile show devices\n"
00501          "       Shows the state of Bluetooth Cell / Mobile devices.\n";
00502       return NULL;
00503    case CLI_GENERATE:
00504       return NULL;
00505    }
00506 
00507    if (a->argc != 3)
00508       return CLI_SHOWUSAGE;
00509 
00510    ast_cli(a->fd, FORMAT1, "ID", "Address", "Group", "Adapter", "Connected", "State", "SMS");
00511    AST_RWLIST_RDLOCK(&devices);
00512    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
00513       ast_mutex_lock(&pvt->lock);
00514       ba2str(&pvt->addr, bdaddr);
00515       snprintf(group, sizeof(group), "%d", pvt->group);
00516       ast_cli(a->fd, FORMAT1,
00517             pvt->id,
00518             bdaddr,
00519             group,
00520             pvt->adapter->id,
00521             pvt->connected ? "Yes" : "No",
00522             (!pvt->connected) ? "None" : (pvt->owner) ? "Busy" : (pvt->outgoing_sms || pvt->incoming_sms) ? "SMS" : (mbl_has_service(pvt)) ? "Free" : "No Service",
00523             (pvt->has_sms) ? "Yes" : "No"
00524              );
00525       ast_mutex_unlock(&pvt->lock);
00526    }
00527    AST_RWLIST_UNLOCK(&devices);
00528 
00529 #undef FORMAT1
00530 
00531    return CLI_SUCCESS;
00532 }

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

Handle the BRSF response.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3124 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03125 {
03126    struct msg_queue_entry *entry;
03127    if ((entry = msg_queue_head(pvt)) && entry->expected == AT_BRSF) {
03128       if (hfp_parse_brsf(pvt->hfp, buf)) {
03129          ast_debug(1, "[%s] error parsing BRSF\n", pvt->id);
03130          goto e_return;
03131       }
03132 
03133       if (msg_queue_push(pvt, AT_OK, AT_BRSF)) {
03134          ast_debug(1, "[%s] error handling BRSF\n", pvt->id);
03135          goto e_return;
03136       }
03137 
03138       msg_queue_free_and_pop(pvt);
03139    } else if (entry) {
03140       ast_debug(1, "[%s] received unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
03141    } else {
03142       ast_debug(1, "[%s] received unexpected AT message 'BRSF'\n", pvt->id);
03143    }
03144 
03145    return 0;
03146 
03147 e_return:
03148    msg_queue_free_and_pop(pvt);
03149    return -1;
03150 }

static int handle_response_busy ( struct mbl_pvt pvt  )  [static]

Handle BUSY messages.

Parameters:
pvt a mbl_pvt structure
Return values:
0 success
-1 error

Definition at line 3761 of file chan_mobile.c.

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

Referenced by do_monitor_phone(), and handle_response_ciev().

03762 {
03763    pvt->hangupcause = AST_CAUSE_USER_BUSY;
03764    pvt->needchup = 1;
03765    mbl_queue_control(pvt, AST_CONTROL_BUSY);
03766    return 0;
03767 }

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

Handle AT+CIEV messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3487 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03488 {
03489    int i;
03490    switch (hfp_parse_ciev(pvt->hfp, buf, &i)) {
03491    case HFP_CIND_CALL:
03492       switch (i) {
03493       case HFP_CIND_CALL_NONE:
03494          ast_debug(1, "[%s] line disconnected\n", pvt->id);
03495          if (pvt->owner) {
03496             ast_debug(1, "[%s] hanging up owner\n", pvt->id);
03497             if (mbl_queue_hangup(pvt)) {
03498                ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
03499                return -1;
03500             }
03501          }
03502          pvt->needchup = 0;
03503          pvt->needcallerid = 0;
03504          pvt->incoming = 0;
03505          pvt->outgoing = 0;
03506          break;
03507       case HFP_CIND_CALL_ACTIVE:
03508          if (pvt->outgoing) {
03509             ast_debug(1, "[%s] remote end answered\n", pvt->id);
03510             mbl_queue_control(pvt, AST_CONTROL_ANSWER);
03511          } else if (pvt->incoming && pvt->answered) {
03512             ast_setstate(pvt->owner, AST_STATE_UP);
03513          } else if (pvt->incoming) {
03514             /* user answered from handset, disconnecting */
03515             ast_verb(3, "[%s] user answered bluetooth device from handset, disconnecting\n", pvt->id);
03516             mbl_queue_hangup(pvt);
03517             return -1;
03518          }
03519          break;
03520       }
03521       break;
03522 
03523    case HFP_CIND_CALLSETUP:
03524       switch (i) {
03525       case HFP_CIND_CALLSETUP_NONE:
03526          if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
03527             if (pvt->owner) {
03528                if (pvt->hfp->sent_alerting == 1) {
03529                   handle_response_busy(pvt);
03530                }
03531                if (mbl_queue_hangup(pvt)) {
03532                   ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
03533                   return -1;
03534                }
03535             }
03536             pvt->needchup = 0;
03537             pvt->needcallerid = 0;
03538             pvt->incoming = 0;
03539             pvt->outgoing = 0;
03540          }
03541          break;
03542       case HFP_CIND_CALLSETUP_INCOMING:
03543          ast_debug(1, "[%s] incoming call, waiting for caller id\n", pvt->id);
03544          pvt->needcallerid = 1;
03545          pvt->incoming = 1;
03546          break;
03547       case HFP_CIND_CALLSETUP_OUTGOING:
03548          if (pvt->outgoing) {
03549             pvt->hfp->sent_alerting = 0;
03550             ast_debug(1, "[%s] outgoing call\n", pvt->id);
03551          } else {
03552             ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
03553             return -1;
03554          }
03555          break;
03556       case HFP_CIND_CALLSETUP_ALERTING:
03557          if (pvt->outgoing) {
03558             ast_debug(1, "[%s] remote alerting\n", pvt->id);
03559             mbl_queue_control(pvt, AST_CONTROL_RINGING);
03560             pvt->hfp->sent_alerting = 1;
03561          }
03562          break;
03563       }
03564       break;
03565    case HFP_CIND_NONE:
03566       ast_debug(1, "[%s] error parsing CIND: %s\n", pvt->id, buf);
03567       break;
03568    }
03569    return 0;
03570 }

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

Handle the CIND response.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3159 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03160 {
03161    struct msg_queue_entry *entry;
03162    if ((entry = msg_queue_head(pvt)) && entry->expected == AT_CIND) {
03163       switch (entry->response_to) {
03164       case AT_CIND_TEST:
03165          if (hfp_parse_cind_test(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND_TEST)) {
03166             ast_debug(1, "[%s] error performing CIND test\n", pvt->id);
03167             goto e_return;
03168          }
03169          break;
03170       case AT_CIND:
03171          if (hfp_parse_cind(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND)) {
03172             ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
03173             goto e_return;
03174          }
03175          break;
03176       default:
03177          ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
03178          goto e_return;
03179       }
03180       msg_queue_free_and_pop(pvt);
03181    } else if (entry) {
03182       ast_debug(1, "[%s] received unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
03183    } else {
03184       ast_debug(1, "[%s] received unexpected AT message 'CIND'\n", pvt->id);
03185    }
03186 
03187    return 0;
03188 
03189 e_return:
03190    msg_queue_free_and_pop(pvt);
03191    return -1;
03192 }

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

Handle AT+CLIP messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3579 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03580 {
03581    char *clip;
03582    struct msg_queue_entry *msg;
03583    struct ast_channel *chan;
03584 
03585    if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CLIP) {
03586       msg_queue_free_and_pop(pvt);
03587 
03588       pvt->needcallerid = 0;
03589       if (!(clip = hfp_parse_clip(pvt->hfp, buf))) {
03590          ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);
03591       }
03592 
03593       if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL, NULL))) {
03594          ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
03595          hfp_send_chup(pvt->hfp);
03596          msg_queue_push(pvt, AT_OK, AT_CHUP);
03597          return -1;
03598       }
03599 
03600       /* from this point on, we need to send a chup in the event of a
03601        * hangup */
03602       pvt->needchup = 1;
03603 
03604       if (ast_pbx_start(chan)) {
03605          ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
03606          mbl_ast_hangup(pvt);
03607          return -1;
03608       }
03609    }
03610 
03611    return 0;
03612 }

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

Handle AT+CMGR messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3665 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03666 {
03667    char *from_number = NULL, *text = NULL;
03668    struct ast_channel *chan;
03669    struct msg_queue_entry *msg;
03670 
03671    if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CMGR) {
03672       msg_queue_free_and_pop(pvt);
03673 
03674       if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)) {
03675          ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
03676          return -1;
03677       }
03678 
03679       ast_debug(1, "[%s] successfully read sms message\n", pvt->id);
03680       pvt->incoming_sms = 0;
03681 
03682       /* XXX this channel probably does not need to be associated with this pvt */
03683       if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
03684          ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
03685          return -1;
03686       }
03687 
03688       ast_channel_exten_set(chan, "sms");
03689       pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
03690       pbx_builtin_setvar_helper(chan, "SMSTXT", text);
03691 
03692       if (ast_pbx_start(chan)) {
03693          ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming sms\n", pvt->id);
03694          mbl_ast_hangup(pvt);
03695       }
03696    } else {
03697       ast_debug(1, "[%s] got unexpected +CMGR message, ignoring\n", pvt->id);
03698    }
03699 
03700    return 0;
03701 }

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

Handle AT+CMTI messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3638 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03639 {
03640    int index = hfp_parse_cmti(pvt->hfp, buf);
03641    if (index > 0) {
03642       ast_debug(1, "[%s] incoming sms message\n", pvt->id);
03643 
03644       if (hfp_send_cmgr(pvt->hfp, index)
03645             || msg_queue_push(pvt, AT_CMGR, AT_CMGR)) {
03646          ast_debug(1, "[%s] error sending CMGR to retrieve SMS message\n", pvt->id);
03647          return -1;
03648       }
03649 
03650       pvt->incoming_sms = 1;
03651       return 0;
03652    } else {
03653       ast_debug(1, "[%s] error parsing incoming sms message alert, disconnecting\n", pvt->id);
03654       return -1;
03655    }
03656 }

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

Handle CUSD messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3741 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03742 {
03743    char *cusd;
03744 
03745    if (!(cusd = hfp_parse_cusd(pvt->hfp, buf))) {
03746       ast_verb(0, "[%s] error parsing CUSD: %s\n", pvt->id, buf);
03747       return 0;
03748    }
03749 
03750    ast_verb(0, "[%s] CUSD response: %s\n", pvt->id, cusd);
03751 
03752    return 0;
03753 }

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

Handle ERROR AT messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3370 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03371 {
03372    struct msg_queue_entry *entry;
03373    if ((entry = msg_queue_head(pvt))
03374          && (entry->expected == AT_OK
03375          || entry->expected == AT_ERROR
03376          || entry->expected == AT_CMS_ERROR
03377          || entry->expected == AT_CMGR
03378          || entry->expected == AT_SMS_PROMPT)) {
03379       switch (entry->response_to) {
03380 
03381       /* initialization stuff */
03382       case AT_BRSF:
03383          ast_debug(1, "[%s] error reading BSRF\n", pvt->id);
03384          goto e_return;
03385       case AT_CIND_TEST:
03386          ast_debug(1, "[%s] error during CIND test\n", pvt->id);
03387          goto e_return;
03388       case AT_CIND:
03389          ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
03390          goto e_return;
03391       case AT_CMER:
03392          ast_debug(1, "[%s] error during CMER request\n", pvt->id);
03393          goto e_return;
03394       case AT_CLIP:
03395          ast_debug(1, "[%s] error enabling calling line indication\n", pvt->id);
03396          goto e_return;
03397       case AT_VGS:
03398          ast_debug(1, "[%s] volume level synchronization failed\n", pvt->id);
03399 
03400          /* this is not a fatal error, let's continue with initialization */
03401 
03402          /* set the SMS operating mode to text mode */
03403          if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
03404             ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
03405             goto e_return;
03406          }
03407          break;
03408       case AT_CMGF:
03409          pvt->has_sms = 0;
03410          ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
03411          ast_debug(1, "[%s] no SMS support\n", pvt->id);
03412          break;
03413       case AT_CNMI:
03414          pvt->has_sms = 0;
03415          ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
03416          ast_debug(1, "[%s] no SMS support\n", pvt->id);
03417          break;
03418       case AT_ECAM:
03419          ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id);
03420 
03421          /* this is not a fatal error, let's continue with the initialization */
03422 
03423          if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
03424             ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
03425             goto e_return;
03426          }
03427 
03428          pvt->timeout = -1;
03429          pvt->hfp->initialized = 1;
03430          ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
03431 
03432          break;
03433       /* end initialization stuff */
03434 
03435       case AT_A:
03436          ast_debug(1, "[%s] answer failed\n", pvt->id);
03437          mbl_queue_hangup(pvt);
03438          break;
03439       case AT_D:
03440          ast_debug(1, "[%s] dial failed\n", pvt->id);
03441          pvt->needchup = 0;
03442          mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
03443          break;
03444       case AT_CHUP:
03445          ast_debug(1, "[%s] error sending hangup, disconnecting\n", pvt->id);
03446          goto e_return;
03447       case AT_CMGR:
03448          ast_debug(1, "[%s] error reading sms message\n", pvt->id);
03449          pvt->incoming_sms = 0;
03450          break;
03451       case AT_CMGS:
03452          ast_debug(1, "[%s] error sending sms message\n", pvt->id);
03453          pvt->outgoing_sms = 0;
03454          break;
03455       case AT_VTS:
03456          ast_debug(1, "[%s] error sending digit\n", pvt->id);
03457          break;
03458       case AT_CUSD:
03459          ast_verb(0, "[%s] error sending CUSD command\n", pvt->id);
03460          break;
03461       case AT_UNKNOWN:
03462       default:
03463          ast_debug(1, "[%s] received ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
03464          break;
03465       }
03466       msg_queue_free_and_pop(pvt);
03467    } else if (entry) {
03468       ast_debug(1, "[%s] received AT message 'ERROR' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
03469    } else {
03470       ast_debug(1, "[%s] received unexpected AT message 'ERROR'\n", pvt->id);
03471    }
03472 
03473    return 0;
03474 
03475 e_return:
03476    msg_queue_free_and_pop(pvt);
03477    return -1;
03478 }

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

Handle NO CARRIER messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3791 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03792 {
03793    ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
03794    pvt->needchup = 1;
03795    mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
03796    return 0;
03797 }

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

Handle NO DIALTONE messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3776 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03777 {
03778    ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
03779    pvt->needchup = 1;
03780    mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
03781    return 0;
03782 }

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

Handle OK AT messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3201 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03202 {
03203    struct msg_queue_entry *entry;
03204    if ((entry = msg_queue_head(pvt)) && entry->expected == AT_OK) {
03205       switch (entry->response_to) {
03206 
03207       /* initialization stuff */
03208       case AT_BRSF:
03209          ast_debug(1, "[%s] BSRF sent successfully\n", pvt->id);
03210 
03211          /* If this is a blackberry do CMER now, otherwise
03212           * continue with CIND as normal. */
03213          if (pvt->blackberry) {
03214             if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
03215                ast_debug(1, "[%s] error sending CMER\n", pvt->id);
03216                goto e_return;
03217             }
03218          } else {
03219             if (hfp_send_cind_test(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND_TEST)) {
03220                ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
03221                goto e_return;
03222             }
03223          }
03224          break;
03225       case AT_CIND_TEST:
03226          ast_debug(1, "[%s] CIND test sent successfully\n", pvt->id);
03227 
03228          ast_debug(2, "[%s] call: %d\n", pvt->id, pvt->hfp->cind_map.call);
03229          ast_debug(2, "[%s] callsetup: %d\n", pvt->id, pvt->hfp->cind_map.callsetup);
03230          ast_debug(2, "[%s] service: %d\n", pvt->id, pvt->hfp->cind_map.service);
03231 
03232          if (hfp_send_cind(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND)) {
03233             ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
03234             goto e_return;
03235          }
03236          break;
03237       case AT_CIND:
03238          ast_debug(1, "[%s] CIND sent successfully\n", pvt->id);
03239 
03240          /* check if a call is active */
03241          if (pvt->hfp->cind_state[pvt->hfp->cind_map.call]) {
03242             ast_verb(3, "Bluetooth Device %s has a call in progress - delaying connection.\n", pvt->id);
03243             goto e_return;
03244          }
03245 
03246          /* If this is NOT a blackberry proceed with CMER,
03247           * otherwise send CLIP. */
03248          if (!pvt->blackberry) {
03249             if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
03250                ast_debug(1, "[%s] error sending CMER\n", pvt->id);
03251                goto e_return;
03252             }
03253          } else {
03254             if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
03255                ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
03256                goto e_return;
03257             }
03258          }
03259          break;
03260       case AT_CMER:
03261          ast_debug(1, "[%s] CMER sent successfully\n", pvt->id);
03262 
03263          /* If this is a blackberry proceed with the CIND test,
03264           * otherwise send CLIP. */
03265          if (pvt->blackberry) {
03266             if (hfp_send_cind_test(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND_TEST)) {
03267                ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
03268                goto e_return;
03269             }
03270          } else {
03271             if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
03272                ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
03273                goto e_return;
03274             }
03275          }
03276          break;
03277       case AT_CLIP:
03278          ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
03279          if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
03280             ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
03281             goto e_return;
03282          }
03283 
03284          break;
03285       case AT_ECAM:
03286          ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
03287          if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
03288             ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
03289             goto e_return;
03290          }
03291 
03292          pvt->timeout = -1;
03293          pvt->hfp->initialized = 1;
03294          ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
03295 
03296          break;
03297       case AT_VGS:
03298          ast_debug(1, "[%s] volume level synchronization successful\n", pvt->id);
03299 
03300          /* set the SMS operating mode to text mode */
03301          if (pvt->has_sms) {
03302             if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
03303                ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
03304                goto e_return;
03305             }
03306          }
03307          break;
03308       case AT_CMGF:
03309          ast_debug(1, "[%s] sms text mode enabled\n", pvt->id);
03310          /* turn on SMS new message indication */
03311          if (hfp_send_cnmi(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_CNMI)) {
03312             ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
03313             goto e_return;
03314          }
03315          break;
03316       case AT_CNMI:
03317          ast_debug(1, "[%s] sms new message indication enabled\n", pvt->id);
03318          pvt->has_sms = 1;
03319          break;
03320       /* end initialization stuff */
03321 
03322       case AT_A:
03323          ast_debug(1, "[%s] answer sent successfully\n", pvt->id);
03324          pvt->needchup = 1;
03325          break;
03326       case AT_D:
03327          ast_debug(1, "[%s] dial sent successfully\n", pvt->id);
03328          pvt->needchup = 1;
03329          pvt->outgoing = 1;
03330          mbl_queue_control(pvt, AST_CONTROL_PROGRESS);
03331          break;
03332       case AT_CHUP:
03333          ast_debug(1, "[%s] successful hangup\n", pvt->id);
03334          break;
03335       case AT_CMGS:
03336          ast_debug(1, "[%s] successfully sent sms message\n", pvt->id);
03337          pvt->outgoing_sms = 0;
03338          break;
03339       case AT_VTS:
03340          ast_debug(1, "[%s] digit sent successfully\n", pvt->id);
03341          break;
03342       case AT_CUSD:
03343          ast_debug(1, "[%s] CUSD code sent successfully\n", pvt->id);
03344          break;
03345       case AT_UNKNOWN:
03346       default:
03347          ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
03348          break;
03349       }
03350       msg_queue_free_and_pop(pvt);
03351    } else if (entry) {
03352       ast_debug(1, "[%s] received AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
03353    } else {
03354       ast_debug(1, "[%s] received unexpected AT message 'OK'\n", pvt->id);
03355    }
03356    return 0;
03357 
03358 e_return:
03359    msg_queue_free_and_pop(pvt);
03360    return -1;
03361 }

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

Handle RING messages.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3621 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03622 {
03623    if (pvt->needcallerid) {
03624       ast_debug(1, "[%s] got ring while waiting for caller id\n", pvt->id);
03625       return msg_queue_push(pvt, AT_CLIP, AT_UNKNOWN);
03626    } else {
03627       return 0;
03628    }
03629 }

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

Send an SMS message from the queue.

Parameters:
pvt a mbl_pvt structure
buf a null terminated buffer containing an AT message
Return values:
0 success
-1 error

Definition at line 3710 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

03711 {
03712    struct msg_queue_entry *msg;
03713    if (!(msg = msg_queue_head(pvt))) {
03714       ast_debug(1, "[%s] error, got sms prompt with no pending sms messages\n", pvt->id);
03715       return 0;
03716    }
03717 
03718    if (msg->expected != AT_SMS_PROMPT) {
03719       ast_debug(1, "[%s] error, got sms prompt but no pending sms messages\n", pvt->id);
03720       return 0;
03721    }
03722 
03723    if (hfp_send_sms_text(pvt->hfp, msg->data)
03724          || msg_queue_push(pvt, AT_OK, AT_CMGS)) {
03725       msg_queue_free_and_pop(pvt);
03726       ast_debug(1, "[%s] error sending sms message\n", pvt->id);
03727       return 0;
03728    }
03729 
03730    msg_queue_free_and_pop(pvt);
03731    return 0;
03732 }

static int headset_send_ring ( const void *  data  )  [static]

Definition at line 4035 of file chan_mobile.c.

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

Referenced by mbl_call().

04036 {
04037    struct mbl_pvt *pvt = (struct mbl_pvt *) data;
04038    ast_mutex_lock(&pvt->lock);
04039    if (!pvt->needring) {
04040       ast_mutex_unlock(&pvt->lock);
04041       return 0;
04042    }
04043    ast_mutex_unlock(&pvt->lock);
04044 
04045    if (hsp_send_ring(pvt->rfcomm_socket)) {
04046       ast_debug(1, "[%s] error sending RING\n", pvt->id);
04047       return 0;
04048    }
04049    return 1;
04050 }

static int hfp_brsf2int ( struct hfp_hf hf  )  [static]

Convert a hfp_hf struct to a BRSF int.

Parameters:
hf an hfp_hf brsf object
Returns:
an integer representing the given brsf struct

Definition at line 2396 of file chan_mobile.c.

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

Referenced by hfp_send_brsf().

02397 {
02398    int brsf = 0;
02399 
02400    brsf |= hf->ecnr ? HFP_HF_ECNR : 0;
02401    brsf |= hf->cw ? HFP_HF_CW : 0;
02402    brsf |= hf->cid ? HFP_HF_CID : 0;
02403    brsf |= hf->voice ? HFP_HF_VOICE : 0;
02404    brsf |= hf->volume ? HFP_HF_VOLUME : 0;
02405    brsf |= hf->status ? HFP_HF_STATUS : 0;
02406    brsf |= hf->control ? HFP_HF_CONTROL : 0;
02407 
02408    return brsf;
02409 }

static struct hfp_ag * hfp_int2brsf ( int  brsf,
struct hfp_ag ag 
) [static, read]

Convert a BRSF int to an hfp_ag struct.

Parameters:
brsf a brsf integer
ag a 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 2418 of file chan_mobile.c.

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

Referenced by hfp_parse_brsf().

02419 {
02420    ag->cw = brsf & HFP_AG_CW ? 1 : 0;
02421    ag->ecnr = brsf & HFP_AG_ECNR ? 1 : 0;
02422    ag->voice = brsf & HFP_AG_VOICE ? 1 : 0;
02423    ag->ring = brsf & HFP_AG_RING ? 1 : 0;
02424    ag->tag = brsf & HFP_AG_TAG ? 1 : 0;
02425    ag->reject = brsf & HFP_AG_REJECT ? 1 : 0;
02426    ag->status = brsf & HFP_AG_STATUS ? 1 : 0;
02427    ag->control = brsf & HFP_AG_CONTROL ? 1 : 0;
02428    ag->errors = brsf & HFP_AG_ERRORS ? 1 : 0;
02429 
02430    return ag;
02431 }

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

Parse BRSF data.

Parameters:
hfp an hfp_pvt struct
buf the buffer to parse (null terminated)

Definition at line 2652 of file chan_mobile.c.

References hfp_pvt::brsf, and hfp_int2brsf().

Referenced by handle_response_brsf().

02653 {
02654    int brsf;
02655 
02656    if (!sscanf(buf, "+BRSF:%d", &brsf))
02657       return -1;
02658 
02659    hfp_int2brsf(brsf, &hfp->brsf);
02660 
02661    return 0;
02662 }

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

Parse a CIEV event.

Parameters:
hfp an hfp_pvt struct
buf the buffer to parse (null terminated)
value a 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 2181 of file chan_mobile.c.

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

Referenced by handle_response_ciev().

02182 {
02183    int i, v;
02184    if (!value)
02185       value = &v;
02186 
02187    if (!sscanf(buf, "+CIEV: %d,%d", &i, value)) {
02188       ast_debug(2, "[%s] error parsing CIEV event '%s'\n", hfp->owner->id, buf);
02189       return HFP_CIND_NONE;
02190    }
02191 
02192    if (i >= ARRAY_LEN(hfp->cind_state)) {
02193       ast_debug(2, "[%s] CIEV event index too high (%s)\n", hfp->owner->id, buf);
02194       return HFP_CIND_NONE;
02195    }
02196 
02197    hfp->cind_state[i] = *value;
02198    return hfp->cind_index[i];
02199 }

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

Read the result of the AT+CIND? command.

Parameters:
hfp an hfp_pvt struct
buf the 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 2696 of file chan_mobile.c.

References hfp_parse_cind_indicator(), indicator, and NULL.

Referenced by handle_response_cind().

02697 {
02698    int i, state, group;
02699    size_t s;
02700    char *indicator = NULL;
02701 
02702    /* parse current state of all of our indicators.  The list is in the
02703     * following format:
02704     * +CIND: 1,0,2,0,0,0,0
02705     */
02706    group = 0;
02707    state = 0;
02708    s = strlen(buf);
02709    for (i = 0; i < s; i++) {
02710       switch (state) {
02711       case 0: /* search for start of the status indicators (a space) */
02712          if (buf[i] == ' ') {
02713             group++;
02714             state++;
02715          }
02716          break;
02717       case 1: /* mark this indicator */
02718          indicator = &buf[i];
02719          state++;
02720          break;
02721       case 2: /* search for the start of the next indicator (a comma) */
02722          if (buf[i] == ',') {
02723             buf[i] = '\0';
02724 
02725             hfp_parse_cind_indicator(hfp, group, indicator);
02726 
02727             group++;
02728             state = 1;
02729          }
02730          break;
02731       }
02732    }
02733 
02734    /* store the last indicator */
02735    if (state == 2)
02736       hfp_parse_cind_indicator(hfp, group, indicator);
02737 
02738    return 0;
02739 }

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

Parse and store the given indicator.

Parameters:
hfp an hfp_pvt struct
group the indicator group
indicator the indicator to parse

Definition at line 2670 of file chan_mobile.c.

References ARRAY_LEN, ast_debug, and hfp_pvt::cind_state.

Referenced by hfp_parse_cind().

02671 {
02672    int value;
02673 
02674    /* store the current indicator */
02675    if (group >= ARRAY_LEN(hfp->cind_state)) {
02676       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));
02677       return -1;
02678    }
02679 
02680    if (!sscanf(indicator, "%d", &value)) {
02681       ast_debug(1, "error parsing CIND state '%s' for group %d\n", indicator, group);
02682       return -1;
02683    }
02684 
02685    hfp->cind_state[group] = value;
02686    return 0;
02687 }

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

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

Parameters:
hfp an hfp_pvt struct
buf the buffer to parse (null terminated)

Definition at line 2746 of file chan_mobile.c.

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

Referenced by handle_response_cind().

02747 {
02748    int i, state, group;
02749    size_t s;
02750    char *indicator = NULL;
02751 
02752    hfp->nocallsetup = 1;
02753 
02754    /* parse the indications list.  It is in the follwing format:
02755     * +CIND: ("ind1",(0-1)),("ind2",(0-5))
02756     */
02757    group = 0;
02758    state = 0;
02759    s = strlen(buf);
02760    for (i = 0; i < s; i++) {
02761       switch (state) {
02762       case 0: /* search for start of indicator block */
02763          if (buf[i] == '(') {
02764             group++;
02765             state++;
02766          }
02767          break;
02768       case 1: /* search for '"' in indicator block */
02769          if (buf[i] == '"') {
02770             state++;
02771          }
02772          break;
02773       case 2: /* mark the start of the indicator name */
02774          indicator = &buf[i];
02775          state++;
02776          break;
02777       case 3: /* look for the end of the indicator name */
02778          if (buf[i] == '"') {
02779             buf[i] = '\0';
02780             state++;
02781          }
02782          break;
02783       case 4: /* find the start of the value range */
02784          if (buf[i] == '(') {
02785             state++;
02786          }
02787          break;
02788       case 5: /* mark the start of the value range */
02789          state++;
02790          break;
02791       case 6: /* find the end of the value range */
02792          if (buf[i] == ')') {
02793             buf[i] = '\0';
02794             state++;
02795          }
02796          break;
02797       case 7: /* process the values we found */
02798          if (group < sizeof(hfp->cind_index)) {
02799             if (!strcmp(indicator, "service")) {
02800                hfp->cind_map.service = group;
02801                hfp->cind_index[group] = HFP_CIND_SERVICE;
02802             } else if (!strcmp(indicator, "call")) {
02803                hfp->cind_map.call = group;
02804                hfp->cind_index[group] = HFP_CIND_CALL;
02805             } else if (!strcmp(indicator, "callsetup")) {
02806                hfp->nocallsetup = 0;
02807                hfp->cind_map.callsetup = group;
02808                hfp->cind_index[group] = HFP_CIND_CALLSETUP;
02809             } else if (!strcmp(indicator, "call_setup")) { /* non standard call setup identifier */
02810                hfp->nocallsetup = 0;
02811                hfp->cind_map.callsetup = group;
02812                hfp->cind_index[group] = HFP_CIND_CALLSETUP;
02813             } else if (!strcmp(indicator, "callheld")) {
02814                hfp->cind_map.callheld = group;
02815                hfp->cind_index[group] = HFP_CIND_CALLHELD;
02816             } else if (!strcmp(indicator, "signal")) {
02817                hfp->cind_map.signal = group;
02818                hfp->cind_index[group] = HFP_CIND_SIGNAL;
02819             } else if (!strcmp(indicator, "roam")) {
02820                hfp->cind_map.roam = group;
02821                hfp->cind_index[group] = HFP_CIND_ROAM;
02822             } else if (!strcmp(indicator, "battchg")) {
02823                hfp->cind_map.battchg = group;
02824                hfp->cind_index[group] = HFP_CIND_BATTCHG;
02825             } else {
02826                hfp->cind_index[group] = HFP_CIND_UNKNOWN;
02827                ast_debug(2, "ignoring unknown CIND indicator '%s'\n", indicator);
02828             }
02829          } else {
02830                ast_debug(1, "can't store indicator %d (%s), we only support up to %d indicators", group, indicator, (int) sizeof(hfp->cind_index));
02831          }
02832 
02833          state = 0;
02834          break;
02835       }
02836    }
02837 
02838    hfp->owner->no_callsetup = hfp->nocallsetup;
02839 
02840    return 0;
02841 }

static char * hfp_parse_clip ( struct hfp_pvt hfp,
char *  buf 
) [static]

Parse a CLIP event.

Parameters:
hfp an hfp_pvt struct
buf the buffer to parse (null terminated)
Note:
buf will be modified when the CID string is parsed
Returns:
NULL on error (parse error) or a pointer to the caller id information in buf

Definition at line 2209 of file chan_mobile.c.

References NULL.

Referenced by handle_response_clip().

02210 {
02211    int i, state;
02212    char *clip = NULL;
02213    size_t s;
02214 
02215    /* parse clip info in the following format:
02216     * +CLIP: "123456789",128,...
02217     */
02218    state = 0;
02219    s = strlen(buf);
02220    for (i = 0; i < s && state != 3; i++) {
02221       switch (state) {
02222       case 0: /* search for start of the number (") */
02223          if (buf[i] == '"') {
02224             state++;
02225          }
02226          break;
02227       case 1: /* mark the number */
02228          clip = &buf[i];
02229          state++;
02230          /* fall through */
02231       case 2: /* search for the end of the number (") */
02232          if (buf[i] == '"') {
02233             buf[i] = '\0';
02234             state++;
02235          }
02236          break;
02237       }
02238    }
02239 
02240    if (state != 3) {
02241       return NULL;
02242    }
02243 
02244    return clip;
02245 }

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

Parse a CMGR message.

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

Definition at line 2280 of file chan_mobile.c.

Referenced by handle_response_cmgr().

02281 {
02282    int i, state;
02283    size_t s;
02284 
02285    /* parse cmgr info in the following format:
02286     * +CMGR: <msg status>,"+123456789",...\r\n
02287     * <message text>
02288     */
02289    state = 0;
02290    s = strlen(buf);
02291    for (i = 0; i < s && state != 6; i++) {
02292       switch (state) {
02293       case 0: /* search for start of the number section (,) */
02294          if (buf[i] == ',') {
02295             state++;
02296          }
02297          break;
02298       case 1: /* find the opening quote (") */
02299          if (buf[i] == '"') {
02300             state++;
02301          }
02302          break;
02303       case 2: /* mark the start of the number */
02304          if (from_number) {
02305             *from_number = &buf[i];
02306             state++;
02307          }
02308          /* fall through */
02309       case 3: /* search for the end of the number (") */
02310          if (buf[i] == '"') {
02311             buf[i] = '\0';
02312             state++;
02313          }
02314          break;
02315       case 4: /* search for the start of the message text (\n) */
02316          if (buf[i] == '\n') {
02317             state++;
02318          }
02319          break;
02320       case 5: /* mark the start of the message text */
02321          if (text) {
02322             *text = &buf[i];
02323             state++;
02324          }
02325          break;
02326       }
02327    }
02328 
02329    if (state != 6) {
02330       return -1;
02331    }
02332 
02333    return 0;
02334 }

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

Parse a CMTI notification.

Parameters:
hfp an hfp_pvt struct
buf the 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 2254 of file chan_mobile.c.

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

Referenced by handle_response_cmti().

02255 {
02256    int index = -1;
02257 
02258    /* parse cmti info in the following format:
02259     * +CMTI: <mem>,<index> 
02260     */
02261    if (!sscanf(buf, "+CMTI: %*[^,],%d", &index)) {
02262       ast_debug(2, "[%s] error parsing CMTI event '%s'\n", hfp->owner->id, buf);
02263       return -1;
02264    }
02265 
02266    return index;
02267 }

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

Parse a CUSD answer.

Parameters:
hfp an hfp_pvt struct
buf the 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 2344 of file chan_mobile.c.

References NULL.

Referenced by handle_response_cusd().

02345 {
02346    int i, message_start, message_end;
02347    char *cusd;
02348    size_t s;
02349 
02350    /* parse cusd message in the following format:
02351     * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#."
02352     */
02353    message_start = 0;
02354    message_end = 0;
02355    s = strlen(buf);
02356 
02357    /* Find the start of the message (") */
02358    for (i = 0; i < s; i++) {
02359       if (buf[i] == '"') {
02360          message_start = i + 1;
02361          break;
02362       }
02363    }
02364 
02365    if (message_start == 0 || message_start >= s) {
02366       return NULL;
02367    }
02368 
02369    /* Find the end of the message (") */
02370    for (i = s; i > 0; i--) {
02371       if (buf[i] == '"') {
02372          message_end = i;
02373          break;
02374       }
02375    }
02376 
02377    if (message_end == 0) {
02378       return NULL;
02379    }
02380 
02381    if (message_start >= message_end) {
02382       return NULL;
02383    }
02384 
02385    cusd = &buf[message_start];
02386    buf[message_end] = '\0';
02387 
02388    return cusd;
02389 }

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

Parse a ECAV event.

Parameters:
hfp an hfp_pvt struct
buf the buffer to parse (null terminated)
Returns:
-1 on error (parse error) or a ECAM value on success
Example string: *ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>] [,exitcause][,<number>,<type>]

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

Definition at line 2150 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

02151 {
02152    int ccid = 0;
02153    int ccstatus = 0;
02154    int calltype = 0;
02155 
02156    if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
02157       ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
02158       return -1;
02159    }
02160 
02161    return ccstatus;
02162 }

static int hfp_send_ata ( struct hfp_pvt hfp  )  [static]

Send ATA.

Parameters:
hfp an hfp_pvt struct

Definition at line 2630 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_answer().

02631 {
02632    return rfcomm_write(hfp->rsock, "ATA\r");
02633 }

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

Send ATD.

Parameters:
hfp an hfp_pvt struct
number the number to send

Definition at line 2619 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_call().

02620 {
02621    char cmd[64];
02622    snprintf(cmd, sizeof(cmd), "ATD%s;\r", number);
02623    return rfcomm_write(hfp->rsock, cmd);
02624 }

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

Send a BRSF request.

Parameters:
hfp an hfp_pvt struct
brsf an hfp_hf brsf struct
Return values:
0 on success
-1 on error

Definition at line 2442 of file chan_mobile.c.

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

Referenced by do_monitor_phone().

02443 {
02444    char cmd[32];
02445    snprintf(cmd, sizeof(cmd), "AT+BRSF=%d\r", hfp_brsf2int(brsf));
02446    return rfcomm_write(hfp->rsock, cmd);
02447 }

static int hfp_send_chup ( struct hfp_pvt hfp  )  [static]

Send AT+CHUP.

Parameters:
hfp an hfp_pvt struct

Definition at line 2609 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_clip(), and mbl_hangup().

02610 {
02611    return rfcomm_write(hfp->rsock, "AT+CHUP\r");
02612 }

static int hfp_send_cind ( struct hfp_pvt hfp  )  [static]

Send the CIND read command.

Parameters:
hfp an hfp_pvt struct

Definition at line 2453 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

02454 {
02455    return rfcomm_write(hfp->rsock, "AT+CIND?\r");
02456 }

static int hfp_send_cind_test ( struct hfp_pvt hfp  )  [static]

Send the CIND test command.

Parameters:
hfp an hfp_pvt struct

Definition at line 2462 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

02463 {
02464    return rfcomm_write(hfp->rsock, "AT+CIND=?\r");
02465 }

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

Enable or disable calling line identification.

Parameters:
hfp an hfp_pvt struct
status enable or disable calling line identification (should be 1 or 0)

Definition at line 2511 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

02512 {
02513    char cmd[32];
02514    snprintf(cmd, sizeof(cmd), "AT+CLIP=%d\r", status ? 1 : 0);
02515    return rfcomm_write(hfp->rsock, cmd);
02516 }

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

Enable or disable indicator events reporting.

Parameters:
hfp an hfp_pvt struct
status enable or disable events reporting (should be 1 or 0)

Definition at line 2472 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

02473 {
02474    char cmd[32];
02475    snprintf(cmd, sizeof(cmd), "AT+CMER=3,0,0,%d\r", status ? 1 : 0);
02476    return rfcomm_write(hfp->rsock, cmd);
02477 }

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

Set the SMS mode.

Parameters:
hfp an hfp_pvt struct
mode the sms mode (0 = PDU, 1 = Text)

Definition at line 2553 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_error(), and handle_response_ok().

02554 {
02555    char cmd[32];
02556    snprintf(cmd, sizeof(cmd), "AT+CMGF=%d\r", mode);
02557    return rfcomm_write(hfp->rsock, cmd);
02558 }

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

Read an SMS message.

Parameters:
hfp an hfp_pvt struct
index the location of the requested message

Definition at line 2574 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_cmti().

02575 {
02576    char cmd[32];
02577    snprintf(cmd, sizeof(cmd), "AT+CMGR=%d\r", index);
02578    return rfcomm_write(hfp->rsock, cmd);
02579 }

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

Start sending an SMS message.

Parameters:
hfp an hfp_pvt struct
number the destination of the message

Definition at line 2586 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_sendsms_exec().

02587 {
02588    char cmd[64];
02589    snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"\r", number);
02590    return rfcomm_write(hfp->rsock, cmd);
02591 }

static int hfp_send_cnmi ( struct hfp_pvt hfp  )  [static]

Setup SMS new message indication.

Parameters:
hfp an hfp_pvt struct

Definition at line 2564 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

02565 {
02566    return rfcomm_write(hfp->rsock, "AT+CNMI=2,1,0,0,0\r");
02567 }

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

Send CUSD.

Parameters:
hfp an hfp_pvt struct
code the CUSD code to send

Definition at line 2640 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_cli_mobile_cusd().

02641 {
02642    char cmd[128];
02643    snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code);
02644    return rfcomm_write(hfp->rsock, cmd);
02645 }

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

Send a DTMF command.

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

Definition at line 2524 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by mbl_digit_end().

02525 {
02526    char cmd[10];
02527 
02528    switch(digit) {
02529    case '0':
02530    case '1':
02531    case '2':
02532    case '3':
02533    case '4':
02534    case '5':
02535    case '6':
02536    case '7':
02537    case '8':
02538    case '9':
02539    case '*':
02540    case '#':
02541       snprintf(cmd, sizeof(cmd), "AT+VTS=%c\r", digit);
02542       return rfcomm_write(hfp->rsock, cmd);
02543    default:
02544       return -1;
02545    }
02546 }

static int hfp_send_ecam ( struct hfp_pvt hfp  )  [static]

Enable Sony Erricson extensions / indications.

Parameters:
hfp an hfp_pvt struct

Definition at line 2168 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_ok().

02169 {
02170    return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
02171 }

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

Send the text of an SMS message.

Parameters:
hfp an hfp_pvt struct
message the text of the message

Definition at line 2598 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_sms_prompt().

02599 {
02600    char cmd[162];
02601    snprintf(cmd, sizeof(cmd), "%.160s\x1a", message);
02602    return rfcomm_write(hfp->rsock, cmd);
02603 }

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

Send the current speaker gain level.

Parameters:
hfp an hfp_pvt struct
value the value to send (must be between 0 and 15)

Definition at line 2484 of file chan_mobile.c.

References rfcomm_write(), and hfp_pvt::rsock.

Referenced by handle_response_error(), and handle_response_ok().

02485 {
02486    char cmd[32];
02487    snprintf(cmd, sizeof(cmd), "AT+VGS=%d\r", value);
02488    return rfcomm_write(hfp->rsock, cmd);
02489 }

static int hsp_send_error ( int  rsock  )  [static]

Send an ERROR AT response.

Parameters:
rsock the rfcomm socket to use

Definition at line 2861 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

02862 {
02863    return rfcomm_write(rsock, "\r\nERROR\r\n");
02864 }

static int hsp_send_ok ( int  rsock  )  [static]

Send an OK AT response.

Parameters:
rsock the rfcomm socket to use

Definition at line 2852 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

02853 {
02854    return rfcomm_write(rsock, "\r\nOK\r\n");
02855 }

static int hsp_send_ring ( int  rsock  )  [static]

Send a RING unsolicited AT response.

Parameters:
rsock the rfcomm socket to use

Definition at line 2894 of file chan_mobile.c.

References rfcomm_write().

Referenced by headset_send_ring(), and mbl_call().

02895 {
02896    return rfcomm_write(rsock, "\r\nRING\r\n");
02897 }

static int hsp_send_vgm ( int  rsock,
int  gain 
) [static]

Send a microphone gain unsolicited AT response.

Parameters:
rsock the rfcomm socket to use
gain the microphone gain value

Definition at line 2883 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

02884 {
02885    char cmd[32];
02886    snprintf(cmd, sizeof(cmd), "\r\n+VGM=%d\r\n", gain);
02887    return rfcomm_write(rsock, cmd);
02888 }

static int hsp_send_vgs ( int  rsock,
int  gain 
) [static]

Send a speaker gain unsolicited AT response.

Parameters:
rsock the rfcomm socket to use
gain the speaker gain value

Definition at line 2871 of file chan_mobile.c.

References rfcomm_write().

Referenced by do_monitor_headset().

02872 {
02873    char cmd[32];
02874    snprintf(cmd, sizeof(cmd), "\r\n+VGS=%d\r\n", gain);
02875    return rfcomm_write(rsock, cmd);
02876 }

static int load_module ( void   )  [static]

Definition at line 4704 of file chan_mobile.c.

References ast_channel_register(), ast_cli_register_multiple(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_pthread_create_background, ast_register_application, ast_channel_tech::capabilities, adapter_pvt::dev_id, DEVICE_FRAME_FORMAT, do_discovery(), LOG_ERROR, mbl_cli, MBL_CONFIG, mbl_load_config(), mbl_sendsms_exec(), mbl_status_exec(), mbl_tech, NULL, and sdp_register().

04705 {
04706 
04707    int dev_id, s;
04708 
04709    if (!(mbl_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
04710       return AST_MODULE_LOAD_DECLINE;
04711    }
04712 
04713    ast_format_cap_append(mbl_tech.capabilities, DEVICE_FRAME_FORMAT, 0);
04714    /* Check if we have Bluetooth, no point loading otherwise... */
04715    dev_id = hci_get_route(NULL);
04716    s = hci_open_dev(dev_id);
04717    if (dev_id < 0 || s < 0) {
04718       ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n");
04719       return AST_MODULE_LOAD_DECLINE;
04720    }
04721 
04722    hci_close_dev(s);
04723 
04724    if (mbl_load_config()) {
04725       ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG);
04726       return AST_MODULE_LOAD_DECLINE;
04727    }
04728 
04729    sdp_session = sdp_register();
04730 
04731    /* Spin the discovery thread */
04732    if (ast_pthread_create_background(&discovery_thread, NULL, do_discovery, NULL) < 0) {
04733       ast_log(LOG_ERROR, "Unable to create discovery thread.\n");
04734       goto e_cleanup;
04735    }
04736 
04737    /* register our channel type */
04738    if (ast_channel_register(&mbl_tech)) {
04739       ast_log(LOG_ERROR, "Unable to register channel class %s\n", "Mobile");
04740       goto e_cleanup;
04741    }
04742 
04743    ast_cli_register_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
04744    ast_register_application(app_mblstatus, mbl_status_exec, mblstatus_synopsis, mblstatus_desc);
04745    ast_register_application(app_mblsendsms, mbl_sendsms_exec, mblsendsms_synopsis, mblsendsms_desc);
04746 
04747    return AST_MODULE_LOAD_SUCCESS;
04748 
04749 e_cleanup:
04750    if (sdp_session)
04751       sdp_close(sdp_session);
04752 
04753    return AST_MODULE_LOAD_FAILURE;
04754 }

static int mbl_answer ( struct ast_channel ast  )  [static]

Definition at line 1056 of file chan_mobile.c.

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

01057 {
01058 
01059    struct mbl_pvt *pvt;
01060 
01061    pvt = ast_channel_tech_pvt(ast);
01062 
01063    if (pvt->type == MBL_TYPE_HEADSET)
01064       return 0;
01065 
01066    ast_mutex_lock(&pvt->lock);
01067    if (pvt->incoming) {
01068       hfp_send_ata(pvt->hfp);
01069       msg_queue_push(pvt, AT_OK, AT_A);
01070       pvt->answered = 1;
01071    }
01072    ast_mutex_unlock(&pvt->lock);
01073 
01074    return 0;
01075 
01076 }

static int mbl_ast_hangup ( struct mbl_pvt pvt  )  [static]

Definition at line 1340 of file chan_mobile.c.

References ast_hangup(), and mbl_pvt::owner.

Referenced by handle_response_clip(), and handle_response_cmgr().

01341 {
01342    ast_hangup(pvt->owner);
01343    return 0;
01344 }

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

Definition at line 960 of file chan_mobile.c.

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

00961 {
00962    struct mbl_pvt *pvt;
00963    char *dest_dev;
00964    char *dest_num = NULL;
00965 
00966    dest_dev = ast_strdupa(dest);
00967 
00968    pvt = ast_channel_tech_pvt(ast);
00969 
00970    if (pvt->type == MBL_TYPE_PHONE) {
00971       dest_num = strchr(dest_dev, '/');
00972       if (!dest_num) {
00973          ast_log(LOG_WARNING, "Cant determine destination number.\n");
00974          return -1;
00975       }
00976       *dest_num++ = 0x00;
00977    }
00978 
00979    if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
00980       ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
00981       return -1;
00982    }
00983 
00984    ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
00985 
00986    ast_mutex_lock(&pvt->lock);
00987    if (pvt->type == MBL_TYPE_PHONE) {
00988       if (hfp_send_atd(pvt->hfp, dest_num)) {
00989          ast_mutex_unlock(&pvt->lock);
00990          ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
00991          return -1;
00992       }
00993       pvt->hangupcause = 0;
00994       pvt->needchup = 1;
00995       msg_queue_push(pvt, AT_OK, AT_D);
00996    } else {
00997       if (hsp_send_ring(pvt->rfcomm_socket)) {
00998          ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
00999          ast_mutex_unlock(&pvt->lock);
01000          return -1;
01001       }
01002 
01003       if ((pvt->ring_sched_id = ast_sched_add(pvt->sched, 6000, headset_send_ring, pvt)) == -1) {
01004          ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
01005          ast_mutex_unlock(&pvt->lock);
01006          return -1;
01007       }
01008 
01009       pvt->outgoing = 1;
01010       pvt->needring = 1;
01011    }
01012    ast_mutex_unlock(&pvt->lock);
01013 
01014    return 0;
01015 
01016 }

static int mbl_devicestate ( const char *  data  )  [static]

Definition at line 1200 of file chan_mobile.c.

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

01201 {
01202 
01203    char *device;
01204    int res = AST_DEVICE_INVALID;
01205    struct mbl_pvt *pvt;
01206 
01207    device = ast_strdupa(S_OR(data, ""));
01208 
01209    ast_debug(1, "Checking device state for device %s\n", device);
01210 
01211    AST_RWLIST_RDLOCK(&devices);
01212    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
01213       if (!strcmp(pvt->id, device))
01214          break;
01215    }
01216    AST_RWLIST_UNLOCK(&devices);
01217 
01218    if (!pvt)
01219       return res;
01220 
01221    ast_mutex_lock(&pvt->lock);
01222    if (pvt->connected) {
01223       if (pvt->owner)
01224          res = AST_DEVICE_INUSE;
01225       else
01226          res = AST_DEVICE_NOT_INUSE;
01227 
01228       if (!mbl_has_service(pvt))
01229          res = AST_DEVICE_UNAVAILABLE;
01230    }
01231    ast_mutex_unlock(&pvt->lock);
01232 
01233    return res;
01234 
01235 }

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

Definition at line 1078 of file chan_mobile.c.

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

01079 {
01080    struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
01081 
01082    if (pvt->type == MBL_TYPE_HEADSET)
01083       return 0;
01084 
01085    ast_mutex_lock(&pvt->lock);
01086    if (hfp_send_dtmf(pvt->hfp, digit)) {
01087       ast_mutex_unlock(&pvt->lock);
01088       ast_debug(1, "[%s] error sending digit %c\n", pvt->id, digit);
01089       return -1;
01090    }
01091    msg_queue_push(pvt, AT_OK, AT_VTS);
01092    ast_mutex_unlock(&pvt->lock);
01093 
01094    ast_debug(1, "[%s] dialed %c\n", pvt->id, digit);
01095 
01096    return 0;
01097 }

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

Definition at line 1181 of file chan_mobile.c.

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

01182 {
01183 
01184    struct mbl_pvt *pvt = ast_channel_tech_pvt(newchan);
01185 
01186    if (!pvt) {
01187       ast_debug(1, "fixup failed, no pvt on newchan\n");
01188       return -1;
01189    }
01190 
01191    ast_mutex_lock(&pvt->lock);
01192    if (pvt->owner == oldchan)
01193       pvt->owner = newchan;
01194    ast_mutex_unlock(&pvt->lock);
01195 
01196    return 0;
01197 
01198 }

static int mbl_hangup ( struct ast_channel ast  )  [static]

Definition at line 1018 of file chan_mobile.c.

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

01019 {
01020 
01021    struct mbl_pvt *pvt;
01022 
01023    if (!ast_channel_tech_pvt(ast)) {
01024       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
01025       return 0;
01026    }
01027    pvt = ast_channel_tech_pvt(ast);
01028 
01029    ast_debug(1, "[%s] hanging up device\n", pvt->id);
01030 
01031    ast_mutex_lock(&pvt->lock);
01032    ast_channel_set_fd(ast, 0, -1);
01033    close(pvt->sco_socket);
01034    pvt->sco_socket = -1;
01035 
01036    if (pvt->needchup) {
01037       hfp_send_chup(pvt->hfp);
01038       msg_queue_push(pvt, AT_OK, AT_CHUP);
01039       pvt->needchup = 0;
01040    }
01041 
01042    pvt->outgoing = 0;
01043    pvt->incoming = 0;
01044    pvt->needring = 0;
01045    pvt->owner = NULL;
01046    ast_channel_tech_pvt_set(ast, NULL);
01047 
01048    ast_mutex_unlock(&pvt->lock);
01049 
01050    ast_setstate(ast, AST_STATE_DOWN);
01051 
01052    return 0;
01053 
01054 }

static int mbl_has_service ( struct mbl_pvt pvt  )  [static]

Check if a mobile device has service.

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

Definition at line 1355 of file chan_mobile.c.

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

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

01356 {
01357 
01358    if (pvt->type != MBL_TYPE_PHONE)
01359       return 1;
01360 
01361    if (!pvt->hfp->cind_map.service)
01362       return 1;
01363 
01364    if (pvt->hfp->cind_state[pvt->hfp->cind_map.service] == HFP_CIND_SERVICE_AVAILABLE)
01365       return 1;
01366 
01367    return 0;
01368 }

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

Load an adapter from the configuration file.

Parameters:
cfg the config to load the adapter from
cat the 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 4301 of file chan_mobile.c.

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

Referenced by mbl_load_config().

04302 {
04303    const char *id, *address;
04304    struct adapter_pvt *adapter;
04305    struct ast_variable *v;
04306    struct hci_dev_req dr;
04307    uint16_t vs;
04308 
04309    id = ast_variable_retrieve(cfg, cat, "id");
04310    address = ast_variable_retrieve(cfg, cat, "address");
04311 
04312    if (ast_strlen_zero(id) || ast_strlen_zero(address)) {
04313       ast_log(LOG_ERROR, "Skipping adapter. Missing id or address settings.\n");
04314       goto e_return;
04315    }
04316 
04317    ast_debug(1, "Reading configuration for adapter %s %s.\n", id, address);
04318 
04319    if (!(adapter = ast_calloc(1, sizeof(*adapter)))) {
04320       ast_log(LOG_ERROR, "Skipping adapter %s. Error allocating memory.\n", id);
04321       goto e_return;
04322    }
04323 
04324    ast_copy_string(adapter->id, id, sizeof(adapter->id));
04325    str2ba(address, &adapter->addr);
04326 
04327    /* attempt to connect to the adapter */
04328    adapter->dev_id = hci_devid(address);
04329    adapter->hci_socket = hci_open_dev(adapter->dev_id);
04330    if (adapter->dev_id < 0 || adapter->hci_socket < 0) {
04331       ast_log(LOG_ERROR, "Skipping adapter %s. Unable to communicate with adapter.\n", adapter->id);
04332       goto e_free_adapter;
04333    }
04334 
04335    /* check voice setting */
04336    hci_read_voice_setting(adapter->hci_socket, &vs, 1000);
04337    vs = htobs(vs);
04338    if (vs != 0x0060) {
04339       ast_log(LOG_ERROR, "Skipping adapter %s. Voice setting must be 0x0060 - see 'man hciconfig' for details.\n", adapter->id);
04340       goto e_hci_close_dev;
04341    }
04342 
04343    for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
04344       if (!strcasecmp(v->name, "forcemaster")) {
04345          if (ast_true(v->value)) {
04346             dr.dev_id = adapter->dev_id;
04347             if (hci_strtolm("master", &dr.dev_opt)) {
04348                if (ioctl(adapter->hci_socket, HCISETLINKMODE, (unsigned long) &dr) < 0) {
04349                   ast_log(LOG_WARNING, "Unable to set adapter %s link mode to MASTER. Ignoring 'forcemaster' option.\n", adapter->id);
04350                }
04351             }
04352          }
04353       } else if (!strcasecmp(v->name, "alignmentdetection")) {
04354          adapter->alignment_detection = ast_true(v->value);
04355       }
04356    }
04357 
04358    /* create io contexts */
04359    if (!(adapter->accept_io = io_context_create())) {
04360       ast_log(LOG_ERROR, "Unable to create I/O context for audio connection listener\n");
04361       goto e_hci_close_dev;
04362    }
04363 
04364    if (!(adapter->io = io_context_create())) {
04365       ast_log(LOG_ERROR, "Unable to create I/O context for audio connections\n");
04366       goto e_destroy_accept_io;
04367    }
04368 
04369    /* bind the sco listener socket */
04370    if (sco_bind(adapter) < 0) {
04371       ast_log(LOG_ERROR, "Skipping adapter %s. Error binding audio connection listerner socket.\n", adapter->id);
04372       goto e_destroy_io;
04373    }
04374 
04375    /* add the socket to the io context */
04376    if (!(adapter->sco_id = ast_io_add(adapter->accept_io, adapter->sco_socket, sco_accept, AST_IO_IN, adapter))) {
04377       ast_log(LOG_ERROR, "Skipping adapter %s. Error adding listener socket to I/O context.\n", adapter->id);
04378       goto e_close_sco;
04379    }
04380 
04381    /* start the sco listener for this adapter */
04382    if (ast_pthread_create_background(&adapter->sco_listener_thread, NULL, do_sco_listen, adapter)) {
04383       ast_log(LOG_ERROR, "Skipping adapter %s. Error creating audio connection listerner thread.\n", adapter->id);
04384       goto e_remove_sco;
04385    }
04386 
04387    /* add the adapter to our global list */
04388    AST_RWLIST_WRLOCK(&adapters);
04389    AST_RWLIST_INSERT_HEAD(&adapters, adapter, entry);
04390    AST_RWLIST_UNLOCK(&adapters);
04391    ast_debug(1, "Loaded adapter %s %s.\n", adapter->id, address);
04392 
04393    return adapter;
04394 
04395 e_remove_sco:
04396    ast_io_remove(adapter->accept_io, adapter->sco_id);
04397 e_close_sco:
04398    close(adapter->sco_socket);
04399 e_destroy_io:
04400    io_context_destroy(adapter->io);
04401 e_destroy_accept_io:
04402    io_context_destroy(adapter->accept_io);
04403 e_hci_close_dev:
04404    hci_close_dev(adapter->hci_socket);
04405 e_free_adapter:
04406    ast_free(adapter);
04407 e_return:
04408    return NULL;
04409 }

static int mbl_load_config ( void   )  [static]

Definition at line 4553 of file chan_mobile.c.

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

Referenced by load_module().

04554 {
04555    struct ast_config *cfg;
04556    const char *cat;
04557    struct ast_variable *v;
04558    struct ast_flags config_flags = { 0 };
04559 
04560    cfg = ast_config_load(MBL_CONFIG, config_flags);
04561    if (!cfg) {
04562       cfg = ast_config_load(MBL_CONFIG_OLD, config_flags);
04563    }
04564    if (!cfg)
04565       return -1;
04566 
04567    /* parse [general] section */
04568    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
04569       if (!strcasecmp(v->name, "interval")) {
04570          if (!sscanf(v->value, "%d", &discovery_interval)) {
04571             ast_log(LOG_NOTICE, "error parsing 'interval' in general section, using default value\n");
04572          }
04573       }
04574    }
04575 
04576    /* load adapters */
04577    for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
04578       if (!strcasecmp(cat, "adapter")) {
04579          mbl_load_adapter(cfg, cat);
04580       }
04581    }
04582 
04583    if (AST_RWLIST_EMPTY(&adapters)) {
04584       ast_log(LOG_ERROR,
04585          "***********************************************************************\n"
04586          "No adapters could be loaded from the configuration file.\n"
04587          "Please review mobile.conf. See sample for details.\n"
04588          "***********************************************************************\n"
04589              );
04590       ast_config_destroy(cfg);
04591       return -1;
04592    }
04593 
04594    /* now load devices */
04595    for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
04596       if (strcasecmp(cat, "general") && strcasecmp(cat, "adapter")) {
04597          mbl_load_device(cfg, cat);
04598       }
04599    }
04600 
04601    ast_config_destroy(cfg);
04602 
04603    return 0;
04604 }

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

Load a device from the configuration file.

Parameters:
cfg the config to load the device from
cat the device to load
Returns:
NULL on error, a pointer to the device that was loaded on success

Definition at line 4417 of file chan_mobile.c.

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

Referenced by mbl_load_config().

04418 {
04419    struct mbl_pvt *pvt;
04420    struct adapter_pvt *adapter;
04421    struct ast_variable *v;
04422    const char *address, *adapter_str, *port;
04423    ast_debug(1, "Reading configuration for device %s.\n", cat);
04424 
04425    adapter_str = ast_variable_retrieve(cfg, cat, "adapter");
04426    if(ast_strlen_zero(adapter_str)) {
04427       ast_log(LOG_ERROR, "Skipping device %s. No adapter specified.\n", cat);
04428       goto e_return;
04429    }
04430 
04431    /* find the adapter */
04432    AST_RWLIST_RDLOCK(&adapters);
04433    AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
04434       if (!strcmp(adapter->id, adapter_str))
04435          break;
04436    }
04437    AST_RWLIST_UNLOCK(&adapters);
04438    if (!adapter) {
04439       ast_log(LOG_ERROR, "Skiping device %s. Unknown adapter '%s' specified.\n", cat, adapter_str);
04440       goto e_return;
04441    }
04442 
04443    address = ast_variable_retrieve(cfg, cat, "address");
04444    port = ast_variable_retrieve(cfg, cat, "port");
04445    if (ast_strlen_zero(port) || ast_strlen_zero(address)) {
04446       ast_log(LOG_ERROR, "Skipping device %s. Missing required port or address setting.\n", cat);
04447       goto e_return;
04448    }
04449 
04450    /* create and initialize our pvt structure */
04451    if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
04452       ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", cat);
04453       goto e_return;
04454    }
04455 
04456    ast_mutex_init(&pvt->lock);
04457    AST_LIST_HEAD_INIT_NOLOCK(&pvt->msg_queue);
04458 
04459    /* set some defaults */
04460 
04461    pvt->type = MBL_TYPE_PHONE;
04462    ast_copy_string(pvt->context, "default", sizeof(pvt->context));
04463 
04464    /* populate the pvt structure */
04465    pvt->adapter = adapter;
04466    ast_copy_string(pvt->id, cat, sizeof(pvt->id));
04467    str2ba(address, &pvt->addr);
04468    pvt->timeout = -1;
04469    pvt->rfcomm_socket = -1;
04470    pvt->rfcomm_port = atoi(port);
04471    pvt->sco_socket = -1;
04472    pvt->monitor_thread = AST_PTHREADT_NULL;
04473    pvt->ring_sched_id = -1;
04474    pvt->has_sms = 1;
04475 
04476    /* setup the smoother */
04477    if (!(pvt->smoother = ast_smoother_new(DEVICE_FRAME_SIZE))) {
04478       ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame smoother.\n", cat);
04479       goto e_free_pvt;
04480    }
04481 
04482    /* setup the dsp */
04483    if (!(pvt->dsp = ast_dsp_new())) {
04484       ast_log(LOG_ERROR, "Skipping device %s. Error setting up dsp for dtmf detection.\n", cat);
04485       goto e_free_smoother;
04486    }
04487 
04488    /* setup the scheduler */
04489    if (!(pvt->sched = ast_sched_context_create())) {
04490       ast_log(LOG_ERROR, "Unable to create scheduler context for headset device\n");
04491       goto e_free_dsp;
04492    }
04493 
04494    ast_dsp_set_features(pvt->dsp, DSP_FEATURE_DIGIT_DETECT);
04495    ast_dsp_set_digitmode(pvt->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
04496 
04497    for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
04498       if (!strcasecmp(v->name, "type")) {
04499          if (!strcasecmp(v->value, "headset"))
04500             pvt->type = MBL_TYPE_HEADSET;
04501          else
04502             pvt->type = MBL_TYPE_PHONE;
04503       } else if (!strcasecmp(v->name, "context")) {
04504          ast_copy_string(pvt->context, v->value, sizeof(pvt->context));
04505       } else if (!strcasecmp(v->name, "group")) {
04506          /* group is set to 0 if invalid */
04507          pvt->group = atoi(v->value);
04508       } else if (!strcasecmp(v->name, "sms")) {
04509          pvt->has_sms = ast_true(v->value);
04510       } else if (!strcasecmp(v->name, "nocallsetup")) {
04511          pvt->no_callsetup = ast_true(v->value);
04512 
04513          if (pvt->no_callsetup)
04514             ast_debug(1, "Setting nocallsetup mode for device %s.\n", pvt->id);
04515       } else if (!strcasecmp(v->name, "blackberry")) {
04516          pvt->blackberry = ast_true(v->value);
04517          pvt->has_sms = 0;
04518       }
04519    }
04520 
04521    if (pvt->type == MBL_TYPE_PHONE) {
04522       if (!(pvt->hfp = ast_calloc(1, sizeof(*pvt->hfp)))) {
04523          ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", pvt->id);
04524          goto e_free_sched;
04525       }
04526 
04527       pvt->hfp->owner = pvt;
04528       pvt->hfp->rport = pvt->rfcomm_port;
04529       pvt->hfp->nocallsetup = pvt->no_callsetup;
04530    } else {
04531       pvt->has_sms = 0;
04532    }
04533 
04534    AST_RWLIST_WRLOCK(&devices);
04535    AST_RWLIST_INSERT_HEAD(&devices, pvt, entry);
04536    AST_RWLIST_UNLOCK(&devices);
04537    ast_debug(1, "Loaded device %s.\n", pvt->id);
04538 
04539    return pvt;
04540 
04541 e_free_sched:
04542    ast_sched_context_destroy(pvt->sched);
04543 e_free_dsp:
04544    ast_dsp_free(pvt->dsp);
04545 e_free_smoother:
04546    ast_smoother_free(pvt->smoother);
04547 e_free_pvt:
04548    ast_free(pvt);
04549 e_return:
04550    return NULL;
04551 }

static struct ast_channel * mbl_new ( int  state,
struct mbl_pvt pvt,
char *  cid_num,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor 
) [static, read]

Definition at line 840 of file chan_mobile.c.

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

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

00842 {
00843    struct ast_channel *chn;
00844 
00845    pvt->answered = 0;
00846    pvt->alignment_count = 0;
00847    pvt->alignment_detection_triggered = 0;
00848    if (pvt->adapter->alignment_detection)
00849       pvt->do_alignment_detection = 1;
00850    else
00851       pvt->do_alignment_detection = 0;
00852 
00853    ast_smoother_reset(pvt->smoother, DEVICE_FRAME_SIZE);
00854    ast_dsp_digitreset(pvt->dsp);
00855 
00856    chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context,
00857          assignedids, requestor, 0,
00858          "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
00859    if (!chn) {
00860       goto e_return;
00861    }
00862 
00863    ast_channel_tech_set(chn, &mbl_tech);
00864    ast_channel_nativeformats_set(chn, mbl_tech.capabilities);
00865    ast_channel_set_rawreadformat(chn, DEVICE_FRAME_FORMAT);
00866    ast_channel_set_rawwriteformat(chn, DEVICE_FRAME_FORMAT);
00867    ast_channel_set_writeformat(chn, DEVICE_FRAME_FORMAT);
00868    ast_channel_set_readformat(chn, DEVICE_FRAME_FORMAT);
00869    ast_channel_tech_pvt_set(chn, pvt);
00870 
00871    if (state == AST_STATE_RING)
00872       ast_channel_rings_set(chn, 1);
00873 
00874    ast_channel_language_set(chn, "en");
00875    pvt->owner = chn;
00876 
00877    if (pvt->sco_socket != -1) {
00878       ast_channel_set_fd(chn, 0, pvt->sco_socket);
00879    }
00880    ast_channel_unlock(chn);
00881 
00882    return chn;
00883 
00884 e_return:
00885    return NULL;
00886 }

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

Definition at line 1303 of file chan_mobile.c.

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

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

01304 {
01305    for (;;) {
01306       if (pvt->owner) {
01307          if (ast_channel_trylock(pvt->owner)) {
01308             DEADLOCK_AVOIDANCE(&pvt->lock);
01309          } else {
01310             ast_queue_control(pvt->owner, control);
01311             ast_channel_unlock(pvt->owner);
01312             break;
01313          }
01314       } else
01315          break;
01316    }
01317    return 0;
01318 }

static int mbl_queue_hangup ( struct mbl_pvt pvt  )  [static]

Definition at line 1320 of file chan_mobile.c.

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

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

01321 {
01322    for (;;) {
01323       if (pvt->owner) {
01324          if (ast_channel_trylock(pvt->owner)) {
01325             DEADLOCK_AVOIDANCE(&pvt->lock);
01326          } else {
01327             if (pvt->hangupcause != 0) {
01328                ast_channel_hangupcause_set(pvt->owner, pvt->hangupcause);
01329             }
01330             ast_queue_hangup(pvt->owner);
01331             ast_channel_unlock(pvt->owner);
01332             break;
01333          }
01334       } else
01335          break;
01336    }
01337    return 0;
01338 }

static struct ast_frame * mbl_read ( struct ast_channel ast  )  [static, read]

Definition at line 1099 of file chan_mobile.c.

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

01100 {
01101 
01102    struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
01103    struct ast_frame *fr = &ast_null_frame;
01104    int r;
01105 
01106    ast_debug(3, "*** mbl_read()\n");
01107 
01108    while (ast_mutex_trylock(&pvt->lock)) {
01109       CHANNEL_DEADLOCK_AVOIDANCE(ast);
01110    }
01111 
01112    if (!pvt->owner || pvt->sco_socket == -1) {
01113       goto e_return;
01114    }
01115 
01116    memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
01117    pvt->fr.frametype = AST_FRAME_VOICE;
01118    pvt->fr.subclass.format = DEVICE_FRAME_FORMAT;
01119    pvt->fr.src = "Mobile";
01120    pvt->fr.offset = AST_FRIENDLY_OFFSET;
01121    pvt->fr.mallocd = 0;
01122    pvt->fr.delivery.tv_sec = 0;
01123    pvt->fr.delivery.tv_usec = 0;
01124    pvt->fr.data.ptr = pvt->io_buf + AST_FRIENDLY_OFFSET;
01125 
01126    if ((r = read(pvt->sco_socket, pvt->fr.data.ptr, DEVICE_FRAME_SIZE)) == -1) {
01127       if (errno != EAGAIN && errno != EINTR) {
01128          ast_debug(1, "[%s] read error %d, going to wait for new connection\n", pvt->id, errno);
01129          close(pvt->sco_socket);
01130          pvt->sco_socket = -1;
01131          ast_channel_set_fd(ast, 0, -1);
01132       }
01133       goto e_return;
01134    }
01135 
01136    pvt->fr.datalen = r;
01137    pvt->fr.samples = r / 2;
01138 
01139    if (pvt->do_alignment_detection)
01140       do_alignment_detection(pvt, pvt->fr.data.ptr, r);
01141 
01142    fr = ast_dsp_process(ast, pvt->dsp, &pvt->fr);
01143 
01144    ast_mutex_unlock(&pvt->lock);
01145 
01146    return fr;
01147 
01148 e_return:
01149    ast_mutex_unlock(&pvt->lock);
01150    return fr;
01151 }

static struct ast_channel * mbl_request ( const char *  type,
struct ast_format_cap cap,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor,
const char *  data,
int *  cause 
) [static, read]

Definition at line 888 of file chan_mobile.c.

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

00890 {
00891 
00892    struct ast_channel *chn = NULL;
00893    struct mbl_pvt *pvt;
00894    char *dest_dev = NULL;
00895    char *dest_num = NULL;
00896    int group = -1;
00897 
00898    if (!data) {
00899       ast_log(LOG_WARNING, "Channel requested with no data\n");
00900       *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
00901       return NULL;
00902    }
00903 
00904    if (ast_format_cap_iscompatible_format(cap, DEVICE_FRAME_FORMAT) == AST_FORMAT_CMP_NOT_EQUAL) {
00905       struct ast_str *codec_buf = ast_str_alloca(64);
00906       ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
00907       *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED;
00908       return NULL;
00909    }
00910 
00911    dest_dev = ast_strdupa(data);
00912 
00913    dest_num = strchr(dest_dev, '/');
00914    if (dest_num)
00915       *dest_num++ = 0x00;
00916 
00917    if (((dest_dev[0] == 'g') || (dest_dev[0] == 'G')) && ((dest_dev[1] >= '0') && (dest_dev[1] <= '9'))) {
00918       group = atoi(&dest_dev[1]);
00919    }
00920 
00921    /* Find requested device and make sure it's connected. */
00922    AST_RWLIST_RDLOCK(&devices);
00923    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
00924       if (group > -1 && pvt->group == group && pvt->connected && !pvt->owner) {
00925          if (!mbl_has_service(pvt)) {
00926             continue;
00927          }
00928 
00929          break;
00930       } else if (!strcmp(pvt->id, dest_dev)) {
00931          break;
00932       }
00933    }
00934    AST_RWLIST_UNLOCK(&devices);
00935    if (!pvt || !pvt->connected || pvt->owner) {
00936       ast_log(LOG_WARNING, "Request to call on device %s which is not connected / already in use.\n", dest_dev);
00937       *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
00938       return NULL;
00939    }
00940 
00941    if ((pvt->type == MBL_TYPE_PHONE) && !dest_num) {
00942       ast_log(LOG_WARNING, "Can't determine destination number.\n");
00943       *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
00944       return NULL;
00945    }
00946 
00947    ast_mutex_lock(&pvt->lock);
00948    chn = mbl_new(AST_STATE_DOWN, pvt, NULL, assignedids, requestor);
00949    ast_mutex_unlock(&pvt->lock);
00950    if (!chn) {
00951       ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
00952       *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
00953       return NULL;
00954    }
00955 
00956    return chn;
00957 
00958 }

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

Definition at line 756 of file chan_mobile.c.

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

Referenced by load_module().

00757 {
00758 
00759    struct mbl_pvt *pvt;
00760    char *parse, *message;
00761 
00762    AST_DECLARE_APP_ARGS(args,
00763       AST_APP_ARG(device);
00764       AST_APP_ARG(dest);
00765       AST_APP_ARG(message);
00766    );
00767 
00768    if (ast_strlen_zero(data))
00769       return -1;
00770 
00771    parse = ast_strdupa(data);
00772 
00773    AST_STANDARD_APP_ARGS(args, parse);
00774 
00775    if (ast_strlen_zero(args.device)) {
00776       ast_log(LOG_ERROR,"NULL device for message -- SMS will not be sent.\n");
00777       return -1;
00778    }
00779 
00780    if (ast_strlen_zero(args.dest)) {
00781       ast_log(LOG_ERROR,"NULL destination for message -- SMS will not be sent.\n");
00782       return -1;
00783    }
00784 
00785    if (ast_strlen_zero(args.message)) {
00786       ast_log(LOG_ERROR,"NULL Message to be sent -- SMS will not be sent.\n");
00787       return -1;
00788    }
00789 
00790    AST_RWLIST_RDLOCK(&devices);
00791    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
00792       if (!strcmp(pvt->id, args.device))
00793          break;
00794    }
00795    AST_RWLIST_UNLOCK(&devices);
00796 
00797    if (!pvt) {
00798       ast_log(LOG_ERROR,"Bluetooth device %s wasn't found in the list -- SMS will not be sent.\n", args.device);
00799       goto e_return;
00800    }
00801 
00802    ast_mutex_lock(&pvt->lock);
00803    if (!pvt->connected) {
00804       ast_log(LOG_ERROR,"Bluetooth device %s wasn't connected -- SMS will not be sent.\n", args.device);
00805       goto e_unlock_pvt;
00806    }
00807 
00808    if (!pvt->has_sms) {
00809       ast_log(LOG_ERROR,"Bluetooth device %s doesn't handle SMS -- SMS will not be sent.\n", args.device);
00810       goto e_unlock_pvt;
00811    }
00812 
00813    message = ast_strdup(args.message);
00814 
00815    if (hfp_send_cmgs(pvt->hfp, args.dest)
00816       || msg_queue_push_data(pvt, AT_SMS_PROMPT, AT_CMGS, message)) {
00817 
00818       ast_log(LOG_ERROR, "[%s] problem sending SMS message\n", pvt->id);
00819       goto e_free_message;
00820    }
00821 
00822    ast_mutex_unlock(&pvt->lock);
00823 
00824    return 0;
00825 
00826 e_free_message:
00827    ast_free(message);
00828 e_unlock_pvt:
00829    ast_mutex_unlock(&pvt->lock);
00830 e_return:
00831    return -1;
00832 }

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

Definition at line 708 of file chan_mobile.c.

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

Referenced by load_module().

00709 {
00710 
00711    struct mbl_pvt *pvt;
00712    char *parse;
00713    int stat;
00714    char status[2];
00715 
00716    AST_DECLARE_APP_ARGS(args,
00717       AST_APP_ARG(device);
00718       AST_APP_ARG(variable);
00719    );
00720 
00721    if (ast_strlen_zero(data))
00722       return -1;
00723 
00724    parse = ast_strdupa(data);
00725 
00726    AST_STANDARD_APP_ARGS(args, parse);
00727 
00728    if (ast_strlen_zero(args.device) || ast_strlen_zero(args.variable))
00729       return -1;
00730 
00731    stat = 1;
00732 
00733    AST_RWLIST_RDLOCK(&devices);
00734    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
00735       if (!strcmp(pvt->id, args.device))
00736          break;
00737    }
00738    AST_RWLIST_UNLOCK(&devices);
00739 
00740    if (pvt) {
00741       ast_mutex_lock(&pvt->lock);
00742       if (pvt->connected)
00743          stat = 2;
00744       if (pvt->owner)
00745          stat = 3;
00746       ast_mutex_unlock(&pvt->lock);
00747    }
00748 
00749    snprintf(status, sizeof(status), "%d", stat);
00750    pbx_builtin_setvar_helper(ast, args.variable, status);
00751 
00752    return 0;
00753 
00754 }

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

Definition at line 1153 of file chan_mobile.c.

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

01154 {
01155 
01156    struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
01157    struct ast_frame *f;
01158 
01159    ast_debug(3, "*** mbl_write\n");
01160 
01161    if (frame->frametype != AST_FRAME_VOICE) {
01162       return 0;
01163    }
01164 
01165    while (ast_mutex_trylock(&pvt->lock)) {
01166       CHANNEL_DEADLOCK_AVOIDANCE(ast);
01167    }
01168 
01169    ast_smoother_feed(pvt->smoother, frame);
01170 
01171    while ((f = ast_smoother_read(pvt->smoother))) {
01172       sco_write(pvt->sco_socket, f->data.ptr, f->datalen);
01173    }
01174 
01175    ast_mutex_unlock(&pvt->lock);
01176 
01177    return 0;
01178 
01179 }

static void msg_queue_flush ( struct mbl_pvt pvt  )  [static]

Remove all itmes from the queue and free them.

Parameters:
pvt a mbl_pvt structure

Definition at line 2974 of file chan_mobile.c.

References msg_queue_free_and_pop(), and msg_queue_head().

Referenced by do_monitor_phone(), and unload_module().

02975 {
02976    struct msg_queue_entry *msg;
02977    while ((msg = msg_queue_head(pvt)))
02978       msg_queue_free_and_pop(pvt);
02979 }

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:
pvt a mbl_pvt structure

Definition at line 2960 of file chan_mobile.c.

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

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

02961 {
02962    struct msg_queue_entry *msg;
02963    if ((msg = msg_queue_pop(pvt))) {
02964       if (msg->data)
02965          ast_free(msg->data);
02966       ast_free(msg);
02967    }
02968 }

static struct msg_queue_entry * msg_queue_head ( struct mbl_pvt pvt  )  [static, read]

Get the head of a queue.

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

Definition at line 2986 of file chan_mobile.c.

References AST_LIST_FIRST, and mbl_pvt::msg_queue.

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

02987 {
02988    return AST_LIST_FIRST(&pvt->msg_queue);
02989 }

static struct msg_queue_entry * msg_queue_pop ( struct mbl_pvt pvt  )  [static, read]

Remove an item from the front of the queue.

Parameters:
pvt a mbl_pvt structure
Returns:
a pointer to the removed item

Definition at line 2951 of file chan_mobile.c.

References AST_LIST_REMOVE_HEAD, and mbl_pvt::msg_queue.

Referenced by msg_queue_free_and_pop().

02952 {
02953    return AST_LIST_REMOVE_HEAD(&pvt->msg_queue, entry);
02954 }

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:
pvt a mbl_pvt structure
expect the msg we expect to receive
response_to the message that was sent to generate the expected response

Definition at line 2910 of file chan_mobile.c.

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

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

02911 {
02912    struct msg_queue_entry *msg;
02913    if (!(msg = ast_calloc(1, sizeof(*msg)))) {
02914       return -1;
02915    }
02916    msg->expected = expect;
02917    msg->response_to = response_to;
02918 
02919    AST_LIST_INSERT_TAIL(&pvt->msg_queue, msg, entry);
02920    return 0;
02921 }

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:
pvt a mbl_pvt structure
expect the msg we expect to receive
response_to the message that was sent to generate the expected response
data data associated with this message, it will be freed when the message is freed

Definition at line 2932 of file chan_mobile.c.

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

Referenced by mbl_sendsms_exec().

02933 {
02934    struct msg_queue_entry *msg;
02935    if (!(msg = ast_calloc(1, sizeof(*msg)))) {
02936       return -1;
02937    }
02938    msg->expected = expect;
02939    msg->response_to = response_to;
02940    msg->data = data;
02941 
02942    AST_LIST_INSERT_TAIL(&pvt->msg_queue, msg, entry);
02943    return 0;
02944 }

static void rfcomm_append_buf ( char **  buf,
size_t  count,
size_t *  in_count,
char  c 
) [inline, static]

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

Definition at line 1494 of file chan_mobile.c.

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

01495 {
01496    if (*in_count < count) {
01497       (*in_count)++;
01498       *(*buf)++ = c;
01499    }
01500 }

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

Definition at line 1376 of file chan_mobile.c.

References ast_debug, and errno.

Referenced by do_discovery().

01377 {
01378 
01379    struct sockaddr_rc addr;
01380    int s;
01381 
01382    if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
01383       ast_debug(1, "socket() failed (%d).\n", errno);
01384       return -1;
01385    }
01386 
01387    memset(&addr, 0, sizeof(addr));
01388    addr.rc_family = AF_BLUETOOTH;
01389    bacpy(&addr.rc_bdaddr, &src);
01390    addr.rc_channel = (uint8_t) 0;
01391    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
01392       ast_debug(1, "bind() failed (%d).\n", errno);
01393       close(s);
01394       return -1;
01395    }
01396 
01397    memset(&addr, 0, sizeof(addr));
01398    addr.rc_family = AF_BLUETOOTH;
01399    bacpy(&addr.rc_bdaddr, &dst);
01400    addr.rc_channel = remote_channel;
01401    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
01402       ast_debug(1, "connect() failed (%d).\n", errno);
01403       close(s);
01404       return -1;
01405    }
01406 
01407    return s;
01408 
01409 }

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

Read one Hayes AT message from an rfcomm socket.

Parameters:
rsock the rfcomm socket to read from
buf the buffer to store the result in
count the 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:
0 end of file
-1 read error
-2 parse error
other the number of characters added to buf

Definition at line 1794 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().

01795 {
01796    ssize_t res;
01797    size_t in_count = 0;
01798    char c;
01799 
01800    if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) == 1) {
01801       res = rfcomm_read_result(rsock, &buf, count, &in_count);
01802    } else if (res == -2) {
01803       rfcomm_append_buf(&buf, count, &in_count, c);
01804       res = rfcomm_read_command(rsock, &buf, count, &in_count);
01805    }
01806 
01807    if (res < 1)
01808       return res;
01809    else
01810       return in_count;
01811 }

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

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

Definition at line 1530 of file chan_mobile.c.

References rfcomm_append_buf(), and rfcomm_read_and_expect_char().

Referenced by rfcomm_read_result(), and rfcomm_read_sms_prompt().

01531 {
01532    int res;
01533    char c;
01534 
01535    if (!result)
01536       result = &c;
01537 
01538    if ((res = rfcomm_read_and_expect_char(rsock, result, expected)) < 1) {
01539       return res;
01540    }
01541 
01542    rfcomm_append_buf(buf, count, in_count, *result);
01543    return 1;
01544 }

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

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

Definition at line 1506 of file chan_mobile.c.

References rfcomm_read_debug.

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

01507 {
01508    int res;
01509    char c;
01510 
01511    if (!result)
01512       result = &c;
01513 
01514    if ((res = read(rsock, result, 1)) < 1) {
01515       return res;
01516    }
01517    rfcomm_read_debug(*result);
01518 
01519    if (*result != expected) {
01520       return -2;
01521    }
01522 
01523    return 1;
01524 }

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

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

Referenced by rfcomm_read_result().

01693 {
01694    int res;
01695 
01696    /* append the \r\n that was stripped by the calling function */
01697    rfcomm_append_buf(buf, count, in_count, '\r');
01698    rfcomm_append_buf(buf, count, in_count, '\n');
01699 
01700    if ((res = rfcomm_read_until_ok(rsock, buf, count, in_count)) != 1) {
01701       ast_log(LOG_ERROR, "error reading +CMGR message on rfcomm socket\n");
01702    }
01703 
01704    return res;
01705 }

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

References rfcomm_append_buf(), and rfcomm_read_debug.

Referenced by rfcomm_read().

01750 {
01751    int res;
01752    char c;
01753 
01754    while ((res = read(rsock, &c, 1)) == 1) {
01755       rfcomm_read_debug(c);
01756       /* stop when we get to '\r' */
01757       if (c == '\r')
01758          break;
01759 
01760       rfcomm_append_buf(buf, count, in_count, c);
01761    }
01762    return res;
01763 }

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

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

Referenced by rfcomm_read().

01712 {
01713    int res;
01714    char c;
01715 
01716    if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) < 1) {
01717       goto e_return;
01718    }
01719 
01720    if ((res = rfcomm_read_and_append_char(rsock, buf, count, in_count, &c, '>')) == 1) {
01721       return rfcomm_read_sms_prompt(rsock, buf, count, in_count);
01722    } else if (res != -2) {
01723       goto e_return;
01724    }
01725 
01726    rfcomm_append_buf(buf, count, in_count, c);
01727    res = rfcomm_read_until_crlf(rsock, buf, count, in_count);
01728 
01729    if (res != 1)
01730       return res;
01731 
01732    /* check for CMGR, which contains an embedded \r\n pairs terminated by
01733     * an \r\nOK\r\n message */
01734    if (*in_count >= 5 && !strncmp(*buf - *in_count, "+CMGR", 5)) {
01735       return rfcomm_read_cmgr(rsock, buf, count, in_count);
01736    }
01737 
01738    return 1;
01739 
01740 e_return:
01741    ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket\n");
01742    return res;
01743 }

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

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

Referenced by rfcomm_read_result().

01580 {
01581    int res;
01582    if ((res = rfcomm_read_and_append_char(rsock, buf, count, in_count, NULL, ' ')) < 1)
01583           goto e_return;
01584 
01585    return 1;
01586 
01587 e_return:
01588    ast_log(LOG_ERROR, "error parsing SMS prompt on rfcomm socket\n");
01589    return res;
01590 }

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

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

Referenced by rfcomm_read_result(), and rfcomm_read_until_ok().

01551 {
01552    int res;
01553    char c;
01554 
01555    while ((res = read(rsock, &c, 1)) == 1) {
01556       rfcomm_read_debug(c);
01557       if (c == '\r') {
01558          if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) == 1) {
01559             break;
01560          } else if (res == -2) {
01561             rfcomm_append_buf(buf, count, in_count, '\r');
01562          } else {
01563             rfcomm_append_buf(buf, count, in_count, '\r');
01564             break;
01565          }
01566       }
01567 
01568       rfcomm_append_buf(buf, count, in_count, c);
01569    }
01570    return res;
01571 }

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

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

Referenced by rfcomm_read_cmgr().

01596 {
01597    int res;
01598    char c;
01599 
01600    /* here, we read until finding a \r\n, then we read one character at a
01601     * time looking for the string '\r\nOK\r\n'.  If we only find a partial
01602     * match, we place that in the buffer and try again. */
01603 
01604    for (;;) {
01605       if ((res = rfcomm_read_until_crlf(rsock, buf, count, in_count)) != 1) {
01606          break;
01607       }
01608 
01609       rfcomm_append_buf(buf, count, in_count, '\r');
01610       rfcomm_append_buf(buf, count, in_count, '\n');
01611 
01612       if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
01613          if (res != -2) {
01614             break;
01615          }
01616 
01617          rfcomm_append_buf(buf, count, in_count, c);
01618          continue;
01619       }
01620 
01621       if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
01622          if (res != -2) {
01623             break;
01624          }
01625 
01626          rfcomm_append_buf(buf, count, in_count, '\r');
01627          rfcomm_append_buf(buf, count, in_count, c);
01628          continue;
01629       }
01630       if ((res = rfcomm_read_and_expect_char(rsock, &c, 'O')) != 1) {
01631          if (res != -2) {
01632             break;
01633          }
01634 
01635          rfcomm_append_buf(buf, count, in_count, '\r');
01636          rfcomm_append_buf(buf, count, in_count, '\n');
01637          rfcomm_append_buf(buf, count, in_count, c);
01638          continue;
01639       }
01640 
01641       if ((res = rfcomm_read_and_expect_char(rsock, &c, 'K')) != 1) {
01642          if (res != -2) {
01643             break;
01644          }
01645 
01646          rfcomm_append_buf(buf, count, in_count, '\r');
01647          rfcomm_append_buf(buf, count, in_count, '\n');
01648          rfcomm_append_buf(buf, count, in_count, 'O');
01649          rfcomm_append_buf(buf, count, in_count, c);
01650          continue;
01651       }
01652 
01653       if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
01654          if (res != -2) {
01655             break;
01656          }
01657 
01658          rfcomm_append_buf(buf, count, in_count, '\r');
01659          rfcomm_append_buf(buf, count, in_count, '\n');
01660          rfcomm_append_buf(buf, count, in_count, 'O');
01661          rfcomm_append_buf(buf, count, in_count, 'K');
01662          rfcomm_append_buf(buf, count, in_count, c);
01663          continue;
01664       }
01665 
01666       if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
01667          if (res != -2) {
01668             break;
01669          }
01670 
01671          rfcomm_append_buf(buf, count, in_count, '\r');
01672          rfcomm_append_buf(buf, count, in_count, '\n');
01673          rfcomm_append_buf(buf, count, in_count, 'O');
01674          rfcomm_append_buf(buf, count, in_count, 'K');
01675          rfcomm_append_buf(buf, count, in_count, '\r');
01676          rfcomm_append_buf(buf, count, in_count, c);
01677          continue;
01678       }
01679 
01680       /* we have successfully parsed a '\r\nOK\r\n' string */
01681       return 1;
01682    }
01683 
01684    return res;
01685 }

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

Wait for activity on an rfcomm socket.

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

Definition at line 1465 of file chan_mobile.c.

References ast_waitfor_n_fd().

Referenced by do_monitor_headset(), and do_monitor_phone().

01466 {
01467    int exception, outfd;
01468    outfd = ast_waitfor_n_fd(&rsock, 1, ms, &exception);
01469    if (outfd < 0)
01470       outfd = 0;
01471 
01472    return outfd;
01473 }

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

Write to an rfcomm socket.

Parameters:
rsock the socket to write to
buf the null terminated buffer to write
This function will write characters from buf. The buffer must be null terminated.

Return values:
-1 error
0 success

Definition at line 1422 of file chan_mobile.c.

References rfcomm_write_full().

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

01423 {
01424    return rfcomm_write_full(rsock, buf, strlen(buf));
01425 }

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

Write to an rfcomm socket.

Parameters:
rsock the socket to write to
buf the buffer to write
count the 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:
-1 error
0 success

Definition at line 1440 of file chan_mobile.c.

References ast_debug, and errno.

Referenced by rfcomm_write().

01441 {
01442    char *p = buf;
01443    ssize_t out_count;
01444 
01445    ast_debug(1, "rfcomm_write() (%d) [%.*s]\n", rsock, (int) count, buf);
01446    while (count > 0) {
01447       if ((out_count = write(rsock, p, count)) == -1) {
01448          ast_debug(1, "rfcomm_write() error [%d]\n", errno);
01449          return -1;
01450       }
01451       count -= out_count;
01452       p += out_count;
01453    }
01454 
01455    return 0;
01456 }

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

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

Definition at line 1884 of file chan_mobile.c.

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

Referenced by mbl_load_adapter().

01885 {
01886    struct adapter_pvt *adapter = (struct adapter_pvt *) data;
01887    struct sockaddr_sco addr;
01888    socklen_t addrlen;
01889    struct mbl_pvt *pvt;
01890    socklen_t len;
01891    char saddr[18];
01892    struct sco_options so;
01893    int sock;
01894 
01895    addrlen = sizeof(struct sockaddr_sco);
01896    if ((sock = accept(fd, (struct sockaddr *)&addr, &addrlen)) == -1) {
01897       ast_log(LOG_ERROR, "error accepting audio connection on adapter %s\n", adapter->id);
01898       return 0;
01899    }
01900 
01901    len = sizeof(so);
01902    getsockopt(sock, SOL_SCO, SCO_OPTIONS, &so, &len);
01903 
01904    ba2str(&addr.sco_bdaddr, saddr);
01905    ast_debug(1, "Incoming Audio Connection from device %s MTU is %d\n", saddr, so.mtu);
01906 
01907    /* figure out which device this sco connection belongs to */
01908    pvt = NULL;
01909    AST_RWLIST_RDLOCK(&devices);
01910    AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
01911       if (!bacmp(&pvt->addr, &addr.sco_bdaddr))
01912          break;
01913    }
01914    AST_RWLIST_UNLOCK(&devices);
01915    if (!pvt) {
01916       ast_log(LOG_WARNING, "could not find device for incoming audio connection\n");
01917       close(sock);
01918       return 1;
01919    }
01920 
01921    ast_mutex_lock(&pvt->lock);
01922    if (pvt->sco_socket != -1) {
01923       close(pvt->sco_socket);
01924       pvt->sco_socket = -1;
01925    }
01926 
01927    pvt->sco_socket = sock;
01928    if (pvt->owner) {
01929       ast_channel_set_fd(pvt->owner, 0, sock);
01930    } else {
01931       ast_debug(1, "incoming audio connection for pvt without owner\n");
01932    }
01933 
01934    ast_mutex_unlock(&pvt->lock);
01935 
01936    return 1;
01937 }

static int sco_bind ( struct adapter_pvt adapter  )  [static]

Bind an SCO listener socket for the given adapter.

Parameters:
adapter an adapter_pvt
Returns:
-1 on error, non zero on success

Definition at line 1944 of file chan_mobile.c.

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

Referenced by mbl_load_adapter().

01945 {
01946    struct sockaddr_sco addr;
01947    int opt = 1;
01948 
01949    if ((adapter->sco_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
01950       ast_log(LOG_ERROR, "Unable to create sco listener socket for adapter %s.\n", adapter->id);
01951       goto e_return;
01952    }
01953 
01954    memset(&addr, 0, sizeof(addr));
01955    addr.sco_family = AF_BLUETOOTH;
01956    bacpy(&addr.sco_bdaddr, &adapter->addr);
01957    if (bind(adapter->sco_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
01958       ast_log(LOG_ERROR, "Unable to bind sco listener socket. (%d)\n", errno);
01959       goto e_close_socket;
01960    }
01961    if (setsockopt(adapter->sco_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
01962       ast_log(LOG_ERROR, "Unable to setsockopt sco listener socket.\n");
01963       goto e_close_socket;
01964    }
01965    if (listen(adapter->sco_socket, 5) < 0) {
01966       ast_log(LOG_ERROR, "Unable to listen sco listener socket.\n");
01967       goto e_close_socket;
01968    }
01969 
01970    return adapter->sco_socket;
01971 
01972 e_close_socket:
01973    close(adapter->sco_socket);
01974    adapter->sco_socket = -1;
01975 e_return:
01976    return -1;
01977 }

static int sco_connect ( bdaddr_t  src,
bdaddr_t  dst 
) [static]

Definition at line 1819 of file chan_mobile.c.

References ast_debug, and errno.

Referenced by do_monitor_headset().

01820 {
01821 
01822    struct sockaddr_sco addr;
01823    int s;
01824 
01825    if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
01826       ast_debug(1, "socket() failed (%d).\n", errno);
01827       return -1;
01828    }
01829 
01830 /* XXX this does not work with the do_sco_listen() thread (which also bind()s
01831  * to this address).  Also I am not sure if it is necessary. */
01832 #if 0
01833    memset(&addr, 0, sizeof(addr));
01834    addr.sco_family = AF_BLUETOOTH;
01835    bacpy(&addr.sco_bdaddr, &src);
01836    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
01837       ast_debug(1, "bind() failed (%d).\n", errno);
01838       close(s);
01839       return -1;
01840    }
01841 #endif
01842 
01843    memset(&addr, 0, sizeof(addr));
01844    addr.sco_family = AF_BLUETOOTH;
01845    bacpy(&addr.sco_bdaddr, &dst);
01846 
01847    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
01848       ast_debug(1, "sco connect() failed (%d).\n", errno);
01849       close(s);
01850       return -1;
01851    }
01852 
01853    return s;
01854 
01855 }

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

Definition at line 1857 of file chan_mobile.c.

References ast_debug, and errno.

Referenced by mbl_write().

01858 {
01859 
01860    int r;
01861 
01862    if (s == -1) {
01863       ast_debug(3, "sco_write() not ready\n");
01864       return 0;
01865    }
01866 
01867    ast_debug(3, "sco_write()\n");
01868 
01869    r = write(s, buf, len);
01870    if (r == -1) {
01871       ast_debug(3, "sco write error %d\n", errno);
01872       return 0;
01873    }
01874 
01875    return 1;
01876 
01877 }

static sdp_session_t* sdp_register ( void   )  [static]

Definition at line 3047 of file chan_mobile.c.

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

Referenced by load_module().

03048 {
03049    uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
03050    uint8_t rfcomm_channel = 1;
03051    const char *service_name = "Asterisk PABX";
03052    const char *service_dsc = "Asterisk PABX";
03053    const char *service_prov = "Asterisk";
03054 
03055    uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class1_uuid, svc_class2_uuid;
03056    sdp_list_t  *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
03057    sdp_data_t *channel = 0;
03058 
03059    sdp_session_t *session = 0;
03060 
03061    sdp_record_t *record = sdp_record_alloc();
03062 
03063    sdp_uuid128_create(&svc_uuid, &service_uuid_int);
03064    sdp_set_service_id(record, svc_uuid);
03065 
03066    sdp_uuid32_create(&svc_class1_uuid, GENERIC_AUDIO_SVCLASS_ID);
03067    sdp_uuid32_create(&svc_class2_uuid, HEADSET_PROFILE_ID);
03068 
03069    svc_uuid_list = sdp_list_append(0, &svc_class1_uuid);
03070    svc_uuid_list = sdp_list_append(svc_uuid_list, &svc_class2_uuid);
03071    sdp_set_service_classes(record, svc_uuid_list);
03072 
03073    sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
03074    root_list = sdp_list_append(0, &root_uuid);
03075    sdp_set_browse_groups( record, root_list );
03076 
03077    sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
03078    l2cap_list = sdp_list_append(0, &l2cap_uuid);
03079    proto_list = sdp_list_append(0, l2cap_list);
03080 
03081    sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
03082    channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
03083    rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
03084    sdp_list_append(rfcomm_list, channel);
03085    sdp_list_append(proto_list, rfcomm_list);
03086 
03087    access_proto_list = sdp_list_append(0, proto_list);
03088    sdp_set_access_protos(record, access_proto_list);
03089 
03090    sdp_set_info_attr(record, service_name, service_prov, service_dsc);
03091 
03092    if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
03093       ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
03094    else {
03095       if (sdp_record_register(session, record, 0) < 0) {
03096          ast_log(LOG_WARNING, "Failed to sdp_record_register error: %d\n", errno);
03097          return NULL;
03098       }
03099    }
03100 
03101    sdp_data_free(channel);
03102    sdp_list_free(rfcomm_list, 0);
03103    sdp_list_free(root_list, 0);
03104    sdp_list_free(access_proto_list, 0);
03105    sdp_list_free(svc_uuid_list, 0);
03106 
03107    return session;
03108 
03109 }

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

Definition at line 2999 of file chan_mobile.c.

References ast_debug, session, and status.

Referenced by handle_cli_mobile_search().

03000 {
03001 
03002    sdp_session_t *session = 0;
03003    bdaddr_t bdaddr;
03004    uuid_t svc_uuid;
03005    uint32_t range = 0x0000ffff;
03006    sdp_list_t *response_list, *search_list, *attrid_list;
03007    int status, port;
03008    sdp_list_t *proto_list;
03009    sdp_record_t *sdprec;
03010 
03011    str2ba(addr, &bdaddr);
03012    port = 0;
03013    session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
03014    if (!session) {
03015       ast_debug(1, "sdp_connect() failed on device %s.\n", addr);
03016       return 0;
03017    }
03018 
03019    sdp_uuid32_create(&svc_uuid, profile);
03020    search_list = sdp_list_append(0, &svc_uuid);
03021    attrid_list = sdp_list_append(0, &range);
03022    response_list = 0x00;
03023    status = sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
03024    if (status == 0) {
03025       if (response_list) {
03026          sdprec = (sdp_record_t *) response_list->data;
03027          proto_list = 0x00;
03028          if (sdp_get_access_protos(sdprec, &proto_list) == 0) {
03029             port = sdp_get_proto_port(proto_list, RFCOMM_UUID);
03030             sdp_list_free(proto_list, 0);
03031          }
03032          sdp_record_free(sdprec);
03033          sdp_list_free(response_list, 0);
03034       } else
03035          ast_debug(1, "No responses returned for device %s.\n", addr);
03036    } else
03037       ast_debug(1, "sdp_service_search_attr_req() failed on device %s.\n", addr);
03038 
03039    sdp_list_free(search_list, 0);
03040    sdp_list_free(attrid_list, 0);
03041    sdp_close(session);
03042 
03043    return port;
03044 
03045 }

static void set_unloading ( void   )  [inline, static]

Set the unloading flag.

Definition at line 4624 of file chan_mobile.c.

References ast_mutex_lock, ast_mutex_unlock, and unload_mutex.

Referenced by unload_module().

04625 {
04626    ast_mutex_lock(&unload_mutex);
04627    unloading_flag = 1;
04628    ast_mutex_unlock(&unload_mutex);
04629 }

static int start_monitor ( struct mbl_pvt pvt  )  [static]

Definition at line 4198 of file chan_mobile.c.

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

Referenced by do_discovery().

04199 {
04200 
04201    if (pvt->type == MBL_TYPE_PHONE) {
04202       pvt->hfp->rsock = pvt->rfcomm_socket;
04203 
04204       if (ast_pthread_create_background(&pvt->monitor_thread, NULL, do_monitor_phone, pvt) < 0) {
04205          pvt->monitor_thread = AST_PTHREADT_NULL;
04206          return 0;
04207       }
04208    } else {
04209       if (ast_pthread_create_background(&pvt->monitor_thread, NULL, do_monitor_headset, pvt) < 0) {
04210          pvt->monitor_thread = AST_PTHREADT_NULL;
04211          return 0;
04212       }
04213    }
04214 
04215    return 1;
04216 
04217 }

static int unload_module ( void   )  [static]

Definition at line 4631 of file chan_mobile.c.

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

04632 {
04633    struct mbl_pvt *pvt;
04634    struct adapter_pvt *adapter;
04635 
04636    /* First, take us out of the channel loop */
04637    ast_channel_unregister(&mbl_tech);
04638 
04639    /* Unregister the CLI & APP */
04640    ast_cli_unregister_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
04641    ast_unregister_application(app_mblstatus);
04642    ast_unregister_application(app_mblsendsms);
04643 
04644    /* signal everyone we are unloading */
04645    set_unloading();
04646 
04647    /* Kill the discovery thread */
04648    if (discovery_thread != AST_PTHREADT_NULL) {
04649       pthread_kill(discovery_thread, SIGURG);
04650       pthread_join(discovery_thread, NULL);
04651    }
04652 
04653    /* stop the sco listener threads */
04654    AST_RWLIST_WRLOCK(&adapters);
04655    AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
04656       pthread_kill(adapter->sco_listener_thread, SIGURG);
04657       pthread_join(adapter->sco_listener_thread, NULL);
04658    }
04659    AST_RWLIST_UNLOCK(&adapters);
04660 
04661    /* Destroy the device list */
04662    AST_RWLIST_WRLOCK(&devices);
04663    while ((pvt = AST_RWLIST_REMOVE_HEAD(&devices, entry))) {
04664       if (pvt->monitor_thread != AST_PTHREADT_NULL) {
04665          pthread_kill(pvt->monitor_thread, SIGURG);
04666          pthread_join(pvt->monitor_thread, NULL);
04667       }
04668 
04669       close(pvt->sco_socket);
04670       close(pvt->rfcomm_socket);
04671 
04672       msg_queue_flush(pvt);
04673 
04674       if (pvt->hfp) {
04675          ast_free(pvt->hfp);
04676       }
04677 
04678       ast_smoother_free(pvt->smoother);
04679       ast_dsp_free(pvt->dsp);
04680       ast_sched_context_destroy(pvt->sched);
04681       ast_free(pvt);
04682    }
04683    AST_RWLIST_UNLOCK(&devices);
04684 
04685    /* Destroy the adapter list */
04686    AST_RWLIST_WRLOCK(&adapters);
04687    while ((adapter = AST_RWLIST_REMOVE_HEAD(&adapters, entry))) {
04688       close(adapter->sco_socket);
04689       io_context_destroy(adapter->io);
04690       io_context_destroy(adapter->accept_io);
04691       hci_close_dev(adapter->hci_socket);
04692       ast_free(adapter);
04693    }
04694    AST_RWLIST_UNLOCK(&adapters);
04695 
04696    if (sdp_session)
04697       sdp_close(sdp_session);
04698 
04699    ao2_ref(mbl_tech.capabilities, -1);
04700    mbl_tech.capabilities = NULL;
04701    return 0;
04702 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Bluetooth Mobile Device Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 4761 of file chan_mobile.c.

char* app_mblsendsms = "MobileSendSMS" [static]

Definition at line 203 of file chan_mobile.c.

char* app_mblstatus = "MobileStatus" [static]

Definition at line 195 of file chan_mobile.c.

Definition at line 4761 of file chan_mobile.c.

int discovery_interval = 60 [static]

Definition at line 86 of file chan_mobile.c.

pthread_t discovery_thread = AST_PTHREADT_NULL [static]

Definition at line 87 of file chan_mobile.c.

struct hfp_hf hfp_our_brsf [static]

Definition at line 355 of file chan_mobile.c.

struct ast_cli_entry mbl_cli[] [static]

Definition at line 187 of file chan_mobile.c.

Referenced by load_module(), and unload_module().

struct ast_channel_tech mbl_tech [static]

Definition at line 472 of file chan_mobile.c.

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

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

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

Definition at line 204 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 197 of file chan_mobile.c.

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

Definition at line 196 of file chan_mobile.c.

sdp_session_t* sdp_session [static]

Definition at line 88 of file chan_mobile.c.

ast_mutex_t unload_mutex = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 90 of file chan_mobile.c.

Referenced by check_unloading(), and set_unloading().

int unloading_flag = 0 [static]

Definition at line 91 of file chan_mobile.c.


Generated on Thu Apr 16 06:29:44 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6