[svn-commits] mnicholson: branch 1.6.2 r1060 - /branches/1.6.2/channels/chan_mobile.c

SVN commits to the Digium repositories svn-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 svn-commits mailing list