[asterisk-addons-commits] mnicholson: branch 1.6.2 r1060 - /branches/1.6.2/channels/chan_mobile.c
SVN commits to the Asterisk addons project
asterisk-addons-commits at lists.digium.com
Mon Nov 23 15:54:08 CST 2009
Author: mnicholson
Date: Mon Nov 23 15:54:04 2009
New Revision: 1060
URL: http://svnview.digium.com/svn/asterisk-addons?view=rev&rev=1060
Log:
Backport of phone init code from trunk.
(closes issue #15628)
Reported by: ughnz
(closes issue #16087)
Reported by: ughnz
Modified:
branches/1.6.2/channels/chan_mobile.c
Modified: branches/1.6.2/channels/chan_mobile.c
URL: http://svnview.digium.com/svn/asterisk-addons/branches/1.6.2/channels/chan_mobile.c?view=diff&rev=1060&r1=1059&r2=1060
==============================================================================
--- branches/1.6.2/channels/chan_mobile.c (original)
+++ branches/1.6.2/channels/chan_mobile.c Mon Nov 23 15:54:04 2009
@@ -152,7 +152,7 @@
unsigned int needcallerid:1; /*!< we need callerid */
unsigned int needchup:1; /*!< we need to send a chup */
unsigned int needring:1; /*!< we need to send a RING */
- unsigned int answered:1; /*!< we sent/recieved an answer */
+ unsigned int answered:1; /*!< we sent/received an answer */
unsigned int connected:1; /*!< do we have an rfcomm connection to a device */
AST_LIST_ENTRY(mbl_pvt) entry;
@@ -252,6 +252,7 @@
#define HFP_AG_CONTROL (1 << 7)
#define HFP_AG_ERRORS (1 << 8)
+#define HFP_CIND_UNKNOWN -1
#define HFP_CIND_NONE 0
#define HFP_CIND_SERVICE 1
#define HFP_CIND_CALL 2
@@ -318,8 +319,7 @@
*/
struct hfp_pvt {
struct mbl_pvt *owner; /*!< the mbl_pvt struct that owns this struct */
- int connected:1; /*!< whether a service level connection exists or not */
- int blackberry:1; /*!< blackberry mode (send CMER before CIND=?) */
+ int initialized:1; /*!< whether a service level connection exists or not */
int nocallsetup:1; /*!< whether we detected a callsetup indicator */
struct hfp_ag brsf; /*!< the supported feature set of the AG */
int cind_index[16]; /*!< the cind/ciev index to name mapping for this AG */
@@ -344,13 +344,13 @@
};
-static int hfp_init(struct hfp_pvt *hfp);
-static int hfp_init_sms(struct hfp_pvt *hfp);
-static int hfp_wait(struct hfp_pvt *hfp);
static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value);
static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf);
static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf);
static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text);
+static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf);
+static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf);
+static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf);
static int hfp_brsf2int(struct hfp_hf *hf);
static struct hfp_ag *hfp_int2brsf(int brsf, struct hfp_ag *ag);
@@ -374,9 +374,6 @@
static int hfp_send_atd(struct hfp_pvt *hfp, const char *number);
static int hfp_send_ata(struct hfp_pvt *hfp);
-static int hfp_read_brsf(struct hfp_pvt *hfp);
-static int hfp_read_cind(struct hfp_pvt *hfp);
-static int hfp_read_cind_test(struct hfp_pvt *hfp);
/*
* bluetooth headset profile helpers
@@ -416,11 +413,14 @@
AT_VGM,
AT_VGS,
AT_VTS,
+ AT_CMGF,
+ AT_CNMI,
+ AT_CMER,
+ AT_CIND_TEST,
} at_message_t;
static int at_match_prefix(char *buf, char *prefix);
static at_message_t at_read_full(int rsock, char *buf, size_t count);
-static at_message_t at_read(int rsock);
static inline const char *at_msg2str(at_message_t msg);
struct msg_queue_entry {
@@ -908,6 +908,7 @@
ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
return -1;
}
+ pvt->needchup = 1;
msg_queue_push(pvt, AT_OK, AT_D);
} else {
if (hsp_send_ring(pvt->rfcomm_socket)) {
@@ -1813,6 +1814,8 @@
return AT_CIND;
} else if (at_match_prefix(buf, "+CLIP:")) {
return AT_CLIP;
+ } else if (at_match_prefix(buf, "+CMGR:")) {
+ return AT_CMGR;
} else if (at_match_prefix(buf, "+VGM:")) {
return AT_VGM;
} else if (at_match_prefix(buf, "+VGS:")) {
@@ -1824,20 +1827,6 @@
} else {
return AT_UNKNOWN;
}
-}
-
-/*!
- * \brief Read an AT message and clasify it.
- * \param rsock an rfcomm socket
- * \return the type of message received
- * \see at_read_full()
- */
-static at_message_t at_read(int rsock)
-{
- /* this buffer is small as we only need the first few chars to identify
- * the message */
- char buf[16];
- return at_read_full(rsock, buf, sizeof(buf));
}
/*!
@@ -1894,6 +1883,14 @@
return "AT+VGS";
case AT_VTS:
return "AT+VTS";
+ case AT_CMGF:
+ return "AT+CMGF";
+ case AT_CNMI:
+ return "AT+CNMI";
+ case AT_CMER:
+ return "AT+CMER";
+ case AT_CIND_TEST:
+ return "AT+CIND=?";
}
}
@@ -1901,112 +1898,6 @@
/*
* bluetooth handsfree profile helpers
*/
-
-/*!
- * \brief Initilize an HFP service level connection.
- * \param hfp an hfp_pvt struct
- *
- * This function brings up an HFP service level connection.
- *
- * \note This function expects a connected rfcomm socket and it expects the pvt
- * structure to be initilized with zeroes.
- */
-static int hfp_init(struct hfp_pvt *hfp)
-{
- /* send and receive BRSF data */
- if (hfp_send_brsf(hfp, &hfp_our_brsf) || !hfp_wait(hfp) || hfp_read_brsf(hfp)) {
- ast_debug(1, "[%s] error sending/receiving BRSF\n", hfp->owner->id);
- return -1;
- }
-
- /* if this is a blackberry, do CMER now */
- if (hfp->blackberry) {
- if (hfp_send_cmer(hfp, 1) || !hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK) {
- ast_debug(1, "[%s] error sending CMER, try setting 'blackberry=no'\n", hfp->owner->id);
- return -1;
- }
- }
-
- /* send CIND test */
- if (hfp_send_cind_test(hfp) || !hfp_wait(hfp) || hfp_read_cind_test(hfp)) {
- if (!hfp->blackberry)
- ast_debug(1, "[%s] error performing CIND test, try setting 'blackberry=yes'\n", hfp->owner->id);
- else
- ast_debug(1, "[%s] error performing CIND test\n", hfp->owner->id);
- return -1;
- }
-
- /* read current CIND state */
- if (hfp_send_cind(hfp) || !hfp_wait(hfp) || hfp_read_cind(hfp)) {
- ast_debug(1, "[%s] error getting CIND state\n", hfp->owner->id);
- return -1;
- }
-
- /* check if a call is active */
- if (hfp->cind_state[hfp->cind_map.call]) {
- ast_verb(3, "Bluetooth Device %s has a call in progress - delaying connection.\n", hfp->owner->id);
- return -1;
- }
-
- /* if this is not a blackberry send CMER now */
- if (!hfp->blackberry) {
- if (hfp_send_cmer(hfp, 1) || !hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK) {
- ast_debug(1, "[%s] error sending CMER\n", hfp->owner->id);
- return -1;
- }
- }
-
- /* enalbe calling line identification notification */
- if (hfp_send_clip(hfp, 1) || !hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK) {
- ast_debug(1, "[%s] error enabling calling line notification\n", hfp->owner->id);
- return -1;
- }
-
- /* send current gain levels */
- if (hfp_send_vgs(hfp, 15) || !hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK) {
- ast_debug(1, "[%s] error synchronizing gain settings\n", hfp->owner->id);
- return -1;
- }
-
- /* we now have a service level connection */
- hfp->connected = 1;
-
- if (hfp_init_sms(hfp)) {
- ast_debug(1, "[%s] no SMS support\n", hfp->owner->id);
- } else {
- hfp->owner->has_sms = 1;
- }
-
- return 0;
-}
-
-static int hfp_init_sms(struct hfp_pvt *hfp)
-{
- /* set the SMS operating mode to text mode */
- if (hfp_send_cmgf(hfp, 1) || !hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK) {
- ast_debug(1, "[%s] error setting CMGF\n", hfp->owner->id);
- return -1;
- }
-
- /* turn on SMS new message indication */
- if (hfp_send_cnmi(hfp) || !hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK) {
- ast_debug(1, "[%s] error setting CNMI\n", hfp->owner->id);
- return -1;
- }
-
- return 0;
-}
-
-
-/*!
- * \brief Wait a default timeout.
- * \return zero on timeout and non zero on data
- */
-static int hfp_wait(struct hfp_pvt *hfp)
-{
- int ms = 10000;
- return rfcomm_wait(hfp->rsock, &ms);
-}
/*!
* \brief Parse a CIEV event.
@@ -2042,13 +1933,12 @@
* \param buf the buffer to parse (null terminated)
* @note buf will be modified when the CID string is parsed
* \return NULL on error (parse error) or a pointer to the caller id
- * inforamtion in buf
- * success
+ * information in buf
*/
static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
{
int i, state;
- char *clip;
+ char *clip = NULL;
size_t s;
/* parse clip info in the following format:
@@ -2092,13 +1982,12 @@
*/
static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
{
- int index;
- char mem[8];
+ int index = -1;
/* parse cmti info in the following format:
* +CMTI: <mem>,<index>
*/
- if (!sscanf(buf, "+CMTI: %7s,%d", mem, &index)) {
+ if (!sscanf(buf, "+CMTI: %*[^,],%d", &index)) {
ast_debug(2, "[%s] error parsing CMTI event '%s'\n", hfp->owner->id, buf);
return -1;
}
@@ -2417,26 +2306,18 @@
}
/*!
- * \brief Read BRSF data.
+ * \brief Parse BRSF data.
* \param hfp an hfp_pvt struct
- */
-static int hfp_read_brsf(struct hfp_pvt *hfp)
+ * \param buf the buffer to parse (null terminated)
+ */
+static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf)
{
int brsf;
- char buf[128];
-
- /* read the BRSF data */
- if (at_read_full(hfp->rsock, buf, sizeof(buf)) != AT_BRSF)
- return -1;
if (!sscanf(buf, "+BRSF:%d", &brsf))
return -1;
hfp_int2brsf(brsf, &hfp->brsf);
-
- /* read the OK message */
- if (!hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK)
- return -1;
return 0;
}
@@ -2469,18 +2350,15 @@
/*!
* \brief Read the result of the AT+CIND? command.
* \param hfp an hfp_pvt struct
- * \note hfp_send_cind_test() and hfp_read_cind_test() should be called at
+ * \param 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.
*/
-static int hfp_read_cind(struct hfp_pvt *hfp)
+static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf)
{
int i, state, group;
size_t s;
- char buf[256];
- char *indicator;
-
- if (at_read_full(hfp->rsock, buf, sizeof(buf)) != AT_CIND)
- return -1;
+ char *indicator = NULL;
/* parse current state of all of our indicators. The list is in the
* following format:
@@ -2518,26 +2396,19 @@
if (state == 2)
hfp_parse_cind_indicator(hfp, group, indicator);
- /* read the OK message */
- if (!hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK)
- return -1;
-
return 0;
}
/*!
- * \brief Read the result of the AT+CIND=? command.
+ * \brief Parse the result of the AT+CIND=? command.
* \param hfp an hfp_pvt struct
- */
-static int hfp_read_cind_test(struct hfp_pvt *hfp)
+ * \param buf the buffer to parse (null terminated)
+ */
+static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
{
int i, state, group;
size_t s;
- char buf[512];
- char *indicator, *values;
-
- if (at_read_full(hfp->rsock, buf, sizeof(buf)) != AT_CIND)
- return -1;
+ char *indicator = NULL, *values;
hfp->nocallsetup = 1;
@@ -2614,6 +2485,7 @@
hfp->cind_map.battchg = group;
hfp->cind_index[group] = HFP_CIND_BATTCHG;
} else {
+ hfp->cind_index[group] = HFP_CIND_UNKNOWN;
ast_debug(2, "ignoring unknown CIND indicator '%s'\n", indicator);
}
} else {
@@ -2627,10 +2499,6 @@
hfp->owner->no_callsetup = hfp->nocallsetup;
- /* read the OK message */
- if (!hfp_wait(hfp) || at_read(hfp->rsock) != AT_OK)
- return -1;
-
return 0;
}
@@ -2697,19 +2565,18 @@
/*!
* \brief Add an item to the back of the queue.
* \param pvt a mbl_pvt structure
- * \param expect the msg we expect to recieve
+ * \param expect the msg we expect to receive
* \param response_to the message that was sent to generate the expected
* response
*/
static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
{
struct msg_queue_entry *msg;
- if (!(msg = ast_malloc(sizeof(*msg)))) {
+ if (!(msg = ast_calloc(1, sizeof(*msg)))) {
return -1;
}
msg->expected = expect;
msg->response_to = response_to;
- msg->data = NULL;
AST_LIST_INSERT_TAIL(&pvt->msg_queue, msg, entry);
return 0;
@@ -2718,7 +2585,7 @@
/*!
* \brief Add an item to the back of the queue with data.
* \param pvt a mbl_pvt structure
- * \param expect the msg we expect to recieve
+ * \param expect the msg we expect to receive
* \param response_to the message that was sent to generate the expected
* response
* \param data data associated with this message, it will be freed when the
@@ -2727,7 +2594,7 @@
static int msg_queue_push_data(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to, void *data)
{
struct msg_queue_entry *msg;
- if (!(msg = ast_malloc(sizeof(*msg)))) {
+ if (!(msg = ast_calloc(1, sizeof(*msg)))) {
return -1;
}
msg->expected = expect;
@@ -2780,7 +2647,7 @@
*/
static struct msg_queue_entry *msg_queue_head(struct mbl_pvt *pvt)
{
- return pvt->msg_queue.first;
+ return AST_LIST_FIRST(&pvt->msg_queue);
}
@@ -2908,6 +2775,83 @@
*/
/*!
+ * \brief Handle the BRSF response.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_brsf(struct mbl_pvt *pvt, char *buf)
+{
+ struct msg_queue_entry *entry;
+ if ((entry = msg_queue_head(pvt)) && entry->expected == AT_BRSF) {
+ if (hfp_parse_brsf(pvt->hfp, buf)) {
+ ast_debug(1, "[%s] error parsing BRSF\n", pvt->id);
+ goto e_return;
+ }
+
+ if (msg_queue_push(pvt, AT_OK, AT_BRSF)) {
+ ast_debug(1, "[%s] error handling BRSF\n", pvt->id);
+ goto e_return;
+ }
+
+ msg_queue_free_and_pop(pvt);
+ } else if (entry) {
+ ast_debug(1, "[%s] received unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+ } else {
+ ast_debug(1, "[%s] received unexpected AT message 'BRSF'\n", pvt->id);
+ }
+
+ return 0;
+
+e_return:
+ msg_queue_free_and_pop(pvt);
+ return -1;
+}
+
+/*!
+ * \brief Handle the CIND response.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_cind(struct mbl_pvt *pvt, char *buf)
+{
+ struct msg_queue_entry *entry;
+ if ((entry = msg_queue_head(pvt)) && entry->expected == AT_CIND) {
+ switch (entry->response_to) {
+ case AT_CIND_TEST:
+ if (hfp_parse_cind_test(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND_TEST)) {
+ ast_debug(1, "[%s] error performing CIND test\n", pvt->id);
+ goto e_return;
+ }
+ break;
+ case AT_CIND:
+ if (hfp_parse_cind(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND)) {
+ ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
+ goto e_return;
+ }
+ break;
+ default:
+ ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
+ goto e_return;
+ }
+ msg_queue_free_and_pop(pvt);
+ } else if (entry) {
+ ast_debug(1, "[%s] received unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+ } else {
+ ast_debug(1, "[%s] received unexpected AT message 'CIND'\n", pvt->id);
+ }
+
+ return 0;
+
+e_return:
+ msg_queue_free_and_pop(pvt);
+ return -1;
+}
+
+/*!
* \brief Handle OK AT messages.
* \param pvt a mbl_pvt structure
* \param buf a null terminated buffer containing an AT message
@@ -2919,6 +2863,113 @@
struct msg_queue_entry *entry;
if ((entry = msg_queue_head(pvt)) && entry->expected == AT_OK) {
switch (entry->response_to) {
+
+ /* initialization stuff */
+ case AT_BRSF:
+ ast_debug(1, "[%s] BSRF sent successfully\n", pvt->id);
+
+ /* If this is a blackberry do CMER now, otherwise
+ * continue with CIND as normal. */
+ if (pvt->blackberry) {
+ if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
+ ast_debug(1, "[%s] error sending CMER\n", pvt->id);
+ goto e_return;
+ }
+ } else {
+ if (hfp_send_cind_test(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND_TEST)) {
+ ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
+ goto e_return;
+ }
+ }
+ break;
+ case AT_CIND_TEST:
+ ast_debug(1, "[%s] CIND test sent successfully\n", pvt->id);
+
+ ast_debug(2, "[%s] call: %d\n", pvt->id, pvt->hfp->cind_map.call);
+ ast_debug(2, "[%s] callsetup: %d\n", pvt->id, pvt->hfp->cind_map.callsetup);
+
+ if (hfp_send_cind(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND)) {
+ ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
+ goto e_return;
+ }
+ break;
+ case AT_CIND:
+ ast_debug(1, "[%s] CIND sent successfully\n", pvt->id);
+
+ /* check if a call is active */
+ if (pvt->hfp->cind_state[pvt->hfp->cind_map.call]) {
+ ast_verb(3, "Bluetooth Device %s has a call in progress - delaying connection.\n", pvt->id);
+ goto e_return;
+ }
+
+ /* If this is NOT a blackberry proceed with CMER,
+ * otherwise send CLIP. */
+ if (!pvt->blackberry) {
+ if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
+ ast_debug(1, "[%s] error sending CMER\n", pvt->id);
+ goto e_return;
+ }
+ } else {
+ if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
+ ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
+ goto e_return;
+ }
+ }
+ break;
+ case AT_CMER:
+ ast_debug(1, "[%s] CMER sent successfully\n", pvt->id);
+
+ /* If this is a blackberry proceed with the CIND test,
+ * otherwise send CLIP. */
+ if (pvt->blackberry) {
+ if (hfp_send_cind_test(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND_TEST)) {
+ ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
+ goto e_return;
+ }
+ } else {
+ if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
+ ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
+ goto e_return;
+ }
+ }
+ break;
+ case AT_CLIP:
+ ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
+ if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
+ ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
+ goto e_return;
+ }
+
+ pvt->timeout = -1;
+ pvt->hfp->initialized = 1;
+ ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
+
+ break;
+ case AT_VGS:
+ ast_debug(1, "[%s] volume level synchronization successful\n", pvt->id);
+
+ /* set the SMS operating mode to text mode */
+ if (pvt->has_sms) {
+ if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
+ ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
+ goto e_return;
+ }
+ }
+ break;
+ case AT_CMGF:
+ ast_debug(1, "[%s] sms text mode enabled\n", pvt->id);
+ /* turn on SMS new message indication */
+ if (hfp_send_cnmi(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_CNMI)) {
+ ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
+ goto e_return;
+ }
+ break;
+ case AT_CNMI:
+ ast_debug(1, "[%s] sms new message indication enabled\n", pvt->id);
+ pvt->has_sms = 1;
+ break;
+ /* end initialization stuff */
+
case AT_A:
ast_debug(1, "[%s] answer sent successfully\n", pvt->id);
pvt->needchup = 1;
@@ -2927,6 +2978,7 @@
ast_debug(1, "[%s] dial sent successfully\n", pvt->id);
pvt->needchup = 1;
pvt->outgoing = 1;
+ mbl_queue_control(pvt, AST_CONTROL_PROGRESS);
break;
case AT_CHUP:
ast_debug(1, "[%s] successful hangup\n", pvt->id);
@@ -2944,16 +2996,20 @@
break;
case AT_UNKNOWN:
default:
- ast_debug(1, "[%s] recieved OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
+ ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
break;
}
msg_queue_free_and_pop(pvt);
} else if (entry) {
- ast_debug(1, "[%s] recieved AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+ ast_debug(1, "[%s] received AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
} else {
- ast_debug(1, "[%s] recieved unexpected AT message 'OK'\n", pvt->id);
+ ast_debug(1, "[%s] received unexpected AT message 'OK'\n", pvt->id);
}
return 0;
+
+e_return:
+ msg_queue_free_and_pop(pvt);
+ return -1;
}
/*!
@@ -2965,25 +3021,65 @@
*/
static int handle_response_error(struct mbl_pvt *pvt, char *buf)
{
- int res = 0;
struct msg_queue_entry *entry;
if ((entry = msg_queue_head(pvt))
&& (entry->expected == AT_OK
|| entry->expected == AT_ERROR
+ || entry->expected == AT_CMGR
|| entry->expected == AT_SMS_PROMPT)) {
switch (entry->response_to) {
+
+ /* initialization stuff */
+ case AT_BRSF:
+ ast_debug(1, "[%s] error reading BSRF\n", pvt->id);
+ goto e_return;
+ case AT_CIND_TEST:
+ ast_debug(1, "[%s] error during CIND test\n", pvt->id);
+ goto e_return;
+ case AT_CIND:
+ ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
+ goto e_return;
+ case AT_CMER:
+ ast_debug(1, "[%s] error during CMER request\n", pvt->id);
+ goto e_return;
+ case AT_CLIP:
+ ast_debug(1, "[%s] error enabling calling line indication\n", pvt->id);
+ goto e_return;
+ case AT_VGS:
+ ast_debug(1, "[%s] volume level synchronization failed\n", pvt->id);
+
+ /* this is not a fatal error, let's continue with initialization */
+
+ /* set the SMS operating mode to text mode */
+ if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
+ ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
+ goto e_return;
+ }
+ break;
+ case AT_CMGF:
+ pvt->has_sms = 0;
+ ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
+ ast_debug(1, "[%s] no SMS support\n", pvt->id);
+ break;
+ case AT_CNMI:
+ pvt->has_sms = 0;
+ ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
+ ast_debug(1, "[%s] no SMS support\n", pvt->id);
+ break;
+ /* end initialization stuff */
+
case AT_A:
ast_debug(1, "[%s] answer failed\n", pvt->id);
mbl_queue_hangup(pvt);
break;
case AT_D:
ast_debug(1, "[%s] dial failed\n", pvt->id);
+ pvt->needchup = 0;
mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
break;
case AT_CHUP:
ast_debug(1, "[%s] error sending hangup, disconnecting\n", pvt->id);
- res = -1;
- break;
+ goto e_return;
case AT_CMGR:
ast_debug(1, "[%s] error reading sms message\n", pvt->id);
pvt->incoming_sms = 0;
@@ -2997,17 +3093,21 @@
break;
case AT_UNKNOWN:
default:
- ast_debug(1, "[%s] recieved ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
+ ast_debug(1, "[%s] received ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
break;
}
msg_queue_free_and_pop(pvt);
} else if (entry) {
- ast_debug(1, "[%s] recieved AT message 'ERROR' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+ ast_debug(1, "[%s] received AT message 'ERROR' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
} else {
- ast_debug(1, "[%s] recieved unexpected AT message 'ERROR'\n", pvt->id);
- }
-
- return res;
+ ast_debug(1, "[%s] received unexpected AT message 'ERROR'\n", pvt->id);
+ }
+
+ return 0;
+
+e_return:
+ msg_queue_free_and_pop(pvt);
+ return -1;
}
/*!
@@ -3024,7 +3124,9 @@
case HFP_CIND_CALL:
switch (i) {
case HFP_CIND_CALL_NONE:
+ ast_debug(1, "[%s] line disconnected\n", pvt->id);
if (pvt->owner) {
+ ast_debug(1, "[%s] hanging up owner\n", pvt->id);
if (mbl_queue_hangup(pvt)) {
ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
return -1;
@@ -3109,6 +3211,8 @@
struct ast_channel *chan;
if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CLIP) {
+ msg_queue_free_and_pop(pvt);
+
pvt->needcallerid = 0;
if (!(clip = hfp_parse_clip(pvt->hfp, buf))) {
ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);
@@ -3121,13 +3225,15 @@
return -1;
}
+ /* from this point on, we need to send a chup in the event of a
+ * hangup */
+ pvt->needchup = 1;
+
if (ast_pbx_start(chan)) {
ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
mbl_ast_hangup(pvt);
return -1;
}
-
- msg_queue_free_and_pop(pvt);
}
return 0;
@@ -3162,7 +3268,13 @@
int index = hfp_parse_cmti(pvt->hfp, buf);
if (index > 0) {
ast_debug(1, "[%s] incoming sms message\n", pvt->id);
- hfp_send_cmgr(pvt->hfp, index);
+
+ if (hfp_send_cmgr(pvt->hfp, index)
+ || msg_queue_push(pvt, AT_CMGR, AT_CMGR)) {
+ ast_debug(1, "[%s] error sending CMGR to retrieve SMS message\n", pvt->id);
+ return -1;
+ }
+
pvt->incoming_sms = 1;
return 0;
} else {
@@ -3180,29 +3292,36 @@
*/
static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf)
{
- char *from_number, *text;
+ char *from_number = NULL, *text = NULL;
struct ast_channel *chan;
-
- if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)
- || msg_queue_push(pvt, AT_OK, AT_CMGR)) {
-
- ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
- return -1;
- }
-
- /* XXX this channel probably does not need to be associated with this pvt */
- if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL))) {
- ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
- return 0;
- }
-
- strcpy(chan->exten, "sms");
- pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
- pbx_builtin_setvar_helper(chan, "SMSTXT", text);
-
- if (ast_pbx_start(chan)) {
- ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming sms\n", pvt->id);
- mbl_ast_hangup(pvt);
+ struct msg_queue_entry *msg;
+
+ if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CMGR) {
+ msg_queue_free_and_pop(pvt);
+
+ if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)
+ || msg_queue_push(pvt, AT_OK, AT_CMGR)) {
+
+ ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
+ return -1;
+ }
+
+ /* XXX this channel probably does not need to be associated with this pvt */
+ if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL))) {
+ ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
+ return -1;
+ }
+
+ strcpy(chan->exten, "sms");
+ pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
+ pbx_builtin_setvar_helper(chan, "SMSTXT", text);
+
+ if (ast_pbx_start(chan)) {
+ ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming sms\n", pvt->id);
+ mbl_ast_hangup(pvt);
+ }
+ } else {
+ ast_debug(1, "[%s] got unexpected +CMGR message, ignoring\n", pvt->id);
}
return 0;
@@ -3247,16 +3366,22 @@
char buf[256];
int t;
at_message_t at_msg;
-
+ struct msg_queue_entry *entry;
+
+ /* Note: At one point the initialization procedure was neatly contained
+ * in the hfp_init() function, but that initialization method did not
+ * work with non standard devices. As a result, the initialization
+ * procedure is not spread throughout the event handling loop.
+ */
+
+ /* start initialization with the BRSF request */
ast_mutex_lock(&pvt->lock);
- if (hfp_init(hfp)) {
- ast_mutex_unlock(&pvt->lock);
- ast_verb(3, "Error initializing Bluetooth device %s.\n", pvt->id);
+ pvt->timeout = 10000;
+ if (hfp_send_brsf(hfp, &hfp_our_brsf) || msg_queue_push(pvt, AT_BRSF, AT_BRSF)) {
+ ast_debug(1, "[%s] error sending BRSF\n", hfp->owner->id);
goto e_cleanup;
}
ast_mutex_unlock(&pvt->lock);
-
- ast_verb(3, "Bluetooth Device %s initialised and ready.\n", pvt->id);
while (!check_unloading()) {
ast_mutex_lock(&pvt->lock);
@@ -3265,6 +3390,29 @@
if (!rfcomm_wait(pvt->rfcomm_socket, &t)) {
ast_debug(1, "[%s] timeout waiting for rfcomm data, disconnecting\n", pvt->id);
+ ast_mutex_lock(&pvt->lock);
+ if (!hfp->initialized) {
+ if ((entry = msg_queue_head(pvt))) {
+ switch (entry->response_to) {
+ case AT_CIND_TEST:
+ if (pvt->blackberry)
+ ast_debug(1, "[%s] timeout during CIND test\n", hfp->owner->id);
+ else
+ ast_debug(1, "[%s] timeout during CIND test, try setting 'blackberry=yes'\n", hfp->owner->id);
+ break;
+ case AT_CMER:
+ if (pvt->blackberry)
+ ast_debug(1, "[%s] timeout after sending CMER, try setting 'blackberry=no'\n", hfp->owner->id);
+ else
+ ast_debug(1, "[%s] timeout after sending CMER\n", hfp->owner->id);
+ break;
+ default:
+ 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));
+ break;
+ }
+ }
+ }
+ ast_mutex_unlock(&pvt->lock);
goto e_cleanup;
}
@@ -3279,6 +3427,22 @@
ast_debug(1, "[%s] %s\n", pvt->id, buf);
switch (at_msg) {
+ case AT_BRSF:
+ ast_mutex_lock(&pvt->lock);
+ if (handle_response_brsf(pvt, buf)) {
+ ast_mutex_unlock(&pvt->lock);
+ goto e_cleanup;
+ }
+ ast_mutex_unlock(&pvt->lock);
+ break;
+ case AT_CIND:
+ ast_mutex_lock(&pvt->lock);
+ if (handle_response_cind(pvt, buf)) {
+ ast_mutex_unlock(&pvt->lock);
+ goto e_cleanup;
+ }
+ ast_mutex_unlock(&pvt->lock);
+ break;
case AT_OK:
ast_mutex_lock(&pvt->lock);
if (handle_response_ok(pvt, buf)) {
@@ -3352,10 +3516,15 @@
case AT_READ_ERROR:
ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
goto e_cleanup;
+ default:
+ break;
}
}
e_cleanup:
+
+ if (!hfp->initialized)
+ ast_verb(3, "Error initializing Bluetooth device %s.\n", pvt->id);
ast_mutex_lock(&pvt->lock);
if (pvt->owner) {
@@ -3371,6 +3540,7 @@
msg_queue_flush(pvt);
pvt->connected = 0;
+ hfp->initialized = 0;
pvt->adapter->inuse = 0;
ast_mutex_unlock(&pvt->lock);
@@ -3584,7 +3754,7 @@
pvt->connected = 1;
adapter->inuse = 1;
manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Connect\r\nDevice: %s\r\n", pvt->id);
- ast_verb(3, "Bluetooth Device %s has connected, initilizing...\n", pvt->id);
+ ast_verb(3, "Bluetooth Device %s has connected, initializing...\n", pvt->id);
}
}
}
@@ -3821,6 +3991,7 @@
pvt->sco_socket = -1;
pvt->monitor_thread = AST_PTHREADT_NULL;
pvt->ring_sched_id = -1;
+ pvt->has_sms = 1;
/* setup the smoother */
if (!(pvt->smoother = ast_smoother_new(DEVICE_FRAME_SIZE))) {
@@ -3854,6 +4025,8 @@
} else if (!strcasecmp(v->name, "group")) {
/* group is set to 0 if invalid */
pvt->group = atoi(v->value);
+ } else if (!strcasecmp(v->name, "sms")) {
+ pvt->has_sms = ast_true(v->value);
} else if (!strcasecmp(v->name, "nocallsetup")) {
pvt->no_callsetup = ast_true(v->value);
@@ -3861,6 +4034,7 @@
ast_debug(1, "Setting nocallsetup mode for device %s.\n", pvt->id);
} else if (!strcasecmp(v->name, "blackberry")) {
pvt->blackberry = ast_true(v->value);
+ pvt->has_sms = 0;
}
}
@@ -3872,8 +4046,9 @@
pvt->hfp->owner = pvt;
pvt->hfp->rport = pvt->rfcomm_port;
- pvt->hfp->blackberry = pvt->blackberry;
pvt->hfp->nocallsetup = pvt->no_callsetup;
+ } else {
+ pvt->has_sms = 0;
}
AST_RWLIST_WRLOCK(&devices);
More information about the asterisk-addons-commits
mailing list