mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	This patch adds the ability to send a CUSD command to a bluetooth device.
(closes issue #15278) Reported by: Artem Patches: cusd5.patch uploaded by Artem (license 800) Tested by: mnicholson, Artem Review: https://reviewboard.asterisk.org/r/274/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@209484 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -161,17 +161,20 @@ static int handle_response_clip(struct mbl_pvt *pvt, char *buf); | ||||
| static int handle_response_ring(struct mbl_pvt *pvt, char *buf); | ||||
| static int handle_response_cmti(struct mbl_pvt *pvt, char *buf); | ||||
| static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf); | ||||
| static int handle_response_cusd(struct mbl_pvt *pvt, char *buf); | ||||
| static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf); | ||||
|  | ||||
| /* CLI stuff */ | ||||
| static char *handle_cli_mobile_show_devices(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_rfcomm(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); | ||||
| static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); | ||||
|  | ||||
| static struct ast_cli_entry mbl_cli[] = { | ||||
| 	AST_CLI_DEFINE(handle_cli_mobile_show_devices, "Show Bluetooth Cell / Mobile devices"), | ||||
| 	AST_CLI_DEFINE(handle_cli_mobile_search,       "Search for Bluetooth Cell / Mobile devices"), | ||||
| 	AST_CLI_DEFINE(handle_cli_mobile_rfcomm,       "Send commands to the rfcomm port for debugging"), | ||||
| 	AST_CLI_DEFINE(handle_cli_mobile_cusd,         "Send CUSD commands to the mobile"), | ||||
| }; | ||||
|  | ||||
| /* App stuff */ | ||||
| @@ -347,6 +350,7 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch | ||||
| 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 char *hfp_parse_cusd(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); | ||||
| @@ -370,6 +374,7 @@ static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message); | ||||
| static int hfp_send_chup(struct hfp_pvt *hfp); | ||||
| static int hfp_send_atd(struct hfp_pvt *hfp, const char *number); | ||||
| static int hfp_send_ata(struct hfp_pvt *hfp); | ||||
| static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code); | ||||
|  | ||||
| /* | ||||
|  * bluetooth headset profile helpers | ||||
| @@ -414,6 +419,7 @@ typedef enum { | ||||
| 	AT_CNMI, | ||||
| 	AT_CMER, | ||||
| 	AT_CIND_TEST, | ||||
| 	AT_CUSD, | ||||
| } at_message_t; | ||||
|  | ||||
| static int at_match_prefix(char *buf, char *prefix); | ||||
| @@ -620,6 +626,56 @@ e_return: | ||||
| 	return CLI_SUCCESS; | ||||
| } | ||||
|  | ||||
| static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | ||||
| { | ||||
| 	char buf[128]; | ||||
| 	struct mbl_pvt *pvt = NULL; | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case CLI_INIT: | ||||
| 		e->command = "mobile cusd"; | ||||
| 		e->usage = | ||||
| 			"Usage: mobile cusd <device ID> <command>\n" | ||||
| 			"       Send cusd <command> to the rfcomm port on the device\n" | ||||
| 			"       with the specified <device ID>.\n"; | ||||
| 		return NULL; | ||||
| 	case CLI_GENERATE: | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (a->argc != 4) | ||||
| 		return CLI_SHOWUSAGE; | ||||
|  | ||||
| 	AST_RWLIST_RDLOCK(&devices); | ||||
| 	AST_RWLIST_TRAVERSE(&devices, pvt, entry) { | ||||
| 		if (!strcmp(pvt->id, a->argv[2])) | ||||
| 			break; | ||||
| 	} | ||||
| 	AST_RWLIST_UNLOCK(&devices); | ||||
|  | ||||
| 	if (!pvt) { | ||||
| 		ast_cli(a->fd, "Device %s not found.\n", a->argv[2]); | ||||
| 		goto e_return; | ||||
| 	} | ||||
|  | ||||
| 	ast_mutex_lock(&pvt->lock); | ||||
| 	if (!pvt->connected) { | ||||
| 		ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]); | ||||
| 		goto e_unlock_pvt; | ||||
| 	} | ||||
|  | ||||
| 	snprintf(buf, sizeof(buf), "%s", a->argv[3]); | ||||
| 	if (hfp_send_cusd(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CUSD)) { | ||||
| 		ast_cli(a->fd, "[%s] error sending CUSD\n", pvt->id); | ||||
| 		goto e_unlock_pvt; | ||||
| 	} | ||||
|  | ||||
| e_unlock_pvt: | ||||
| 	ast_mutex_unlock(&pvt->lock); | ||||
| e_return: | ||||
| 	return CLI_SUCCESS; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  | ||||
| 	Dialplan applications implementation | ||||
| @@ -1827,6 +1883,8 @@ static at_message_t at_read_full(int rsock, char *buf, size_t count) | ||||
| 		return AT_VGM; | ||||
| 	} else if (at_match_prefix(buf, "AT+VGS=")) { | ||||
| 		return AT_VGS; | ||||
| 	} else if (at_match_prefix(buf, "+CUSD:")) { | ||||
| 		return AT_CUSD; | ||||
| 	} else { | ||||
| 		return AT_UNKNOWN; | ||||
| 	} | ||||
| @@ -1896,6 +1954,8 @@ static inline const char *at_msg2str(at_message_t msg) | ||||
| 		return "AT+CMER"; | ||||
| 	case AT_CIND_TEST: | ||||
| 		return "AT+CIND=?"; | ||||
| 	case AT_CUSD: | ||||
| 		return "AT+CUSD"; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -2066,6 +2126,62 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Parse a CUSD answer. | ||||
|  * \param hfp an hfp_pvt struct | ||||
|  * \param buf the buffer to parse (null terminated) | ||||
|  * @note buf will be modified when the CUSD string is parsed | ||||
|  * \return NULL on error (parse error) or a pointer to the cusd message | ||||
|  * information in buf | ||||
|  */ | ||||
| static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf) | ||||
| { | ||||
| 	int i, state, message_start, message_end; | ||||
| 	char *cusd; | ||||
| 	size_t s; | ||||
|  | ||||
| 	/* parse cusd message in the following format: | ||||
| 	 * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#." | ||||
| 	 */ | ||||
| 	state = 0; | ||||
| 	message_start = 0; | ||||
| 	message_end = 0; | ||||
| 	s = strlen(buf); | ||||
|  | ||||
| 	/* Find the start of the message (") */ | ||||
| 	for (i = 0; i < s; i++) { | ||||
| 		if (buf[i] == '"') { | ||||
| 			message_start = i + 1; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (message_start == 0 || message_start >= s) { | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* Find the end of the message (") */ | ||||
| 	for (i = s; i > 0; i--) { | ||||
| 		if (buf[i] == '"') { | ||||
| 			message_end = i; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (message_end == 0) { | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (message_start >= message_end) { | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	cusd = &buf[message_start]; | ||||
| 	buf[message_end] = '\0'; | ||||
|  | ||||
| 	return cusd; | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Convert a hfp_hf struct to a BRSF int. | ||||
|  * \param hf an hfp_hf brsf object | ||||
| @@ -2310,6 +2426,18 @@ static int hfp_send_ata(struct hfp_pvt *hfp) | ||||
| 	return rfcomm_write(hfp->rsock, "ATA\r"); | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Send CUSD. | ||||
|  * \param hfp an hfp_pvt struct | ||||
|  * \param code the CUSD code to send | ||||
|  */ | ||||
| static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code) | ||||
| { | ||||
| 	char cmd[128]; | ||||
| 	snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code); | ||||
| 	return rfcomm_write(hfp->rsock, cmd); | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Parse BRSF data. | ||||
|  * \param hfp an hfp_pvt struct | ||||
| @@ -2997,6 +3125,9 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf) | ||||
| 		case AT_VTS: | ||||
| 			ast_debug(1, "[%s] digit sent successfully\n", pvt->id); | ||||
| 			break; | ||||
| 		case AT_CUSD: | ||||
| 			ast_debug(1, "[%s] CUSD code sent successfully\n", pvt->id); | ||||
| 			break; | ||||
| 		case AT_UNKNOWN: | ||||
| 		default: | ||||
| 			ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to)); | ||||
| @@ -3093,6 +3224,9 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf) | ||||
| 		case AT_VTS: | ||||
| 			ast_debug(1, "[%s] error sending digit\n", pvt->id); | ||||
| 			break; | ||||
| 		case AT_CUSD: | ||||
| 			ast_verb(0, "[%s] error sending CUSD command\n", pvt->id); | ||||
| 			break; | ||||
| 		case AT_UNKNOWN: | ||||
| 		default: | ||||
| 			ast_debug(1, "[%s] received ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to)); | ||||
| @@ -3360,6 +3494,27 @@ static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Handle CUSD messages. | ||||
|  * \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_cusd(struct mbl_pvt *pvt, char *buf) | ||||
| { | ||||
| 	char *cusd; | ||||
|  | ||||
| 	if (!(cusd = hfp_parse_cusd(pvt->hfp, buf))) { | ||||
| 		ast_verb(0, "[%s] error parsing CUSD: %s\n", pvt->id, buf); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	ast_verb(0, "[%s] CUSD response: %s\n", pvt->id, cusd); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void *do_monitor_phone(void *data) | ||||
| { | ||||
| @@ -3510,6 +3665,14 @@ static void *do_monitor_phone(void *data) | ||||
| 			} | ||||
| 			ast_mutex_unlock(&pvt->lock); | ||||
| 			break; | ||||
| 		case AT_CUSD: | ||||
| 			ast_mutex_lock(&pvt->lock); | ||||
| 			if (handle_response_cusd(pvt, buf)) { | ||||
| 				ast_mutex_unlock(&pvt->lock); | ||||
| 				goto e_cleanup; | ||||
| 			} | ||||
| 			ast_mutex_unlock(&pvt->lock); | ||||
| 			break; | ||||
| 		case AT_UNKNOWN: | ||||
| 			ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf); | ||||
| 			break; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user