Index: chan_mobile.c =================================================================== --- chan_mobile.c (Revision 242086) +++ chan_mobile.c (Arbeitskopie) @@ -137,6 +137,7 @@ int ring_sched_id; struct ast_dsp *dsp; struct sched_context *sched; + int hangupcause; /* flags */ unsigned int outgoing:1; /*!< outgoing call */ @@ -162,6 +163,9 @@ 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_response_busy(struct mbl_pvt *pvt); +static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf); +static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf); static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf); /* CLI stuff */ @@ -331,6 +335,7 @@ struct hfp_cind cind_map; /*!< the cind name to index mapping for this AG */ int rsock; /*!< our rfcomm socket */ int rport; /*!< our rfcomm port */ + int sent_alerting; /*!< have we sent alerting? */ }; @@ -425,6 +430,10 @@ AT_CMER, AT_CIND_TEST, AT_CUSD, + AT_BUSY, + AT_NO_DIALTONE, + AT_NO_CARRIER, + AT_ECAM, } at_message_t; static int at_match_prefix(char *buf, char *prefix); @@ -975,6 +984,7 @@ ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id); return -1; } + pvt->hangupcause = 0; pvt->needchup = 1; msg_queue_push(pvt, AT_OK, AT_D); } else { @@ -1309,6 +1319,9 @@ if (ast_channel_trylock(pvt->owner)) { DEADLOCK_AVOIDANCE(&pvt->lock); } else { + if (pvt->hangupcause != 0) { + pvt->owner->hangupcause = pvt->hangupcause; + } ast_queue_hangup(pvt->owner); ast_channel_unlock(pvt->owner); break; @@ -2036,6 +2049,14 @@ return AT_VGS; } else if (at_match_prefix(buf, "+CUSD:")) { return AT_CUSD; + } else if (at_match_prefix(buf, "BUSY")) { + return AT_BUSY; + } else if (at_match_prefix(buf, "NO DIALTONE")) { + return AT_NO_DIALTONE; + } else if (at_match_prefix(buf, "NO CARRIER")) { + return AT_NO_CARRIER; + } else if (at_match_prefix(buf, "*ECAV:")) { + return AT_ECAM; } else { return AT_UNKNOWN; } @@ -2080,6 +2101,12 @@ return "SMS PROMPT"; case AT_CMS_ERROR: return "+CMS ERROR"; + case AT_BUSY: + return "BUSY"; + case AT_NO_DIALTONE: + return "NO DIALTONE"; + case AT_NO_CARRIER: + return "NO CARRIER"; /* at commands */ case AT_A: return "ATA"; @@ -2107,6 +2134,8 @@ return "AT+CIND=?"; case AT_CUSD: return "AT+CUSD"; + case AT_ECAM: + return "AT*ECAM"; } } @@ -2115,7 +2144,41 @@ * bluetooth handsfree profile helpers */ + /*! + * \brief Parse a ECAV event. + * \param hfp an hfp_pvt struct + * \param buf the buffer to parse (null terminated) + * \return -1 on error (parse error) or a ECAM value on success + * + * Example string: *ECAV: ,,[,] + * [,exitcause][,,] + * + * Example indicating busy: *ECAV: 1,7,1 + */ +static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf) +{ + int ccid = 0; + int ccstatus = 0; + int calltype = 0; + + if (!sscanf(buf, "*ECAV: %d,%d,%d", &ccid, &ccstatus, &calltype)) { + ast_debug(1, "[%s] error parsing ECAV event '%s'\n", pvt->id, buf); + return -1; + } + + return ccstatus; +} + /*! + * \brief Enable Sony Erricson extensions / indications. + * \param hfp an hfp_pvt struct + */ +static int hfp_send_ecam(struct hfp_pvt *hfp) +{ + return rfcomm_write(hfp->rsock, "AT*ECAM=1\r"); +} + +/*! * \brief Parse a CIEV event. * \param hfp an hfp_pvt struct * \param buf the buffer to parse (null terminated) @@ -3220,6 +3283,14 @@ break; case AT_CLIP: ast_debug(1, "[%s] caling line indication enabled\n", pvt->id); + if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) { + ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id); + goto e_return; + } + + break; + case AT_ECAM: + ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\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; @@ -3351,6 +3422,21 @@ ast_debug(1, "[%s] error setting CNMI\n", pvt->id); ast_debug(1, "[%s] no SMS support\n", pvt->id); break; + case AT_ECAM: + ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id); + + /* this is not a fatal error, let's continue with the initialization */ + + 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; /* end initialization stuff */ case AT_A: @@ -3446,6 +3532,9 @@ case HFP_CIND_CALLSETUP_NONE: if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) { if (pvt->owner) { + if (pvt->hfp->sent_alerting == 1) { + handle_response_busy(pvt); + } if (mbl_queue_hangup(pvt)) { ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id); return -1; @@ -3464,6 +3553,7 @@ break; case HFP_CIND_CALLSETUP_OUTGOING: if (pvt->outgoing) { + pvt->hfp->sent_alerting = 0; ast_debug(1, "[%s] outgoing call\n", pvt->id); } else { ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id); @@ -3474,6 +3564,7 @@ if (pvt->outgoing) { ast_debug(1, "[%s] remote alerting\n", pvt->id); mbl_queue_control(pvt, AST_CONTROL_RINGING); + pvt->hfp->sent_alerting = 1; } break; } @@ -3668,7 +3759,51 @@ return 0; } +/*! + * \brief Handle BUSY messages. + * \param pvt a mbl_pvt structure + * \retval 0 success + * \retval -1 error + */ +static int handle_response_busy(struct mbl_pvt *pvt) +{ + pvt->hangupcause = AST_CAUSE_USER_BUSY; + pvt->needchup = 1; + mbl_queue_control(pvt, AST_CONTROL_BUSY); + return 0; +} +/*! + * \brief Handle NO DIALTONE 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_no_dialtone(struct mbl_pvt *pvt, char *buf) +{ + ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id); + pvt->needchup = 1; + mbl_queue_control(pvt, AST_CONTROL_CONGESTION); + return 0; +} + +/*! + * \brief Handle NO CARRIER 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_no_carrier(struct mbl_pvt *pvt, char *buf) +{ + ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id); + pvt->needchup = 1; + mbl_queue_control(pvt, AST_CONTROL_CONGESTION); + return 0; +} + + static void *do_monitor_phone(void *data) { struct mbl_pvt *pvt = (struct mbl_pvt *)data; @@ -3826,6 +3961,40 @@ } ast_mutex_unlock(&pvt->lock); break; + case AT_BUSY: + ast_mutex_lock(&pvt->lock); + if (handle_response_busy(pvt)) { + ast_mutex_unlock(&pvt->lock); + goto e_cleanup; + } + ast_mutex_unlock(&pvt->lock); + break; + case AT_NO_DIALTONE: + ast_mutex_lock(&pvt->lock); + if (handle_response_no_dialtone(pvt, buf)) { + ast_mutex_unlock(&pvt->lock); + goto e_cleanup; + } + ast_mutex_unlock(&pvt->lock); + break; + case AT_NO_CARRIER: + ast_mutex_lock(&pvt->lock); + if (handle_response_no_carrier(pvt, buf)) { + ast_mutex_unlock(&pvt->lock); + goto e_cleanup; + } + ast_mutex_unlock(&pvt->lock); + break; + case AT_ECAM: + ast_mutex_lock(&pvt->lock); + if (hfp_parse_ecav(pvt, buf) == 7) { + if (handle_response_busy(pvt)) { + 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;