diff options
-rw-r--r-- | include/gsmd/event.h | 1 | ||||
-rw-r--r-- | include/gsmd/state.h | 3 | ||||
-rw-r--r-- | src/gsmd/atcmd.c | 2 | ||||
-rw-r--r-- | src/gsmd/unsolicited.c | 70 | ||||
-rw-r--r-- | src/gsmd/usock.c | 18 |
5 files changed, 85 insertions, 9 deletions
diff --git a/include/gsmd/event.h b/include/gsmd/event.h index 5c73449..38cefae 100644 --- a/include/gsmd/event.h +++ b/include/gsmd/event.h @@ -51,6 +51,7 @@ enum gsmd_call_type { GSMD_CALL_DATA_SYNC = 5, GSMD_CALL_DATA_REL_ASYNC= 6, GSMD_CALL_DATA_REL_SYNC = 7, + GSMD_CALL_TIMEOUT = 8, __NUM_GSMD_CALL }; diff --git a/include/gsmd/state.h b/include/gsmd/state.h index 62cd710..65659ef 100644 --- a/include/gsmd/state.h +++ b/include/gsmd/state.h @@ -13,9 +13,10 @@ struct gsmd_device_state { unsigned int network_state_gsm; unsigned int network_state_gprs; } ciph_ind; - unsigned int on; unsigned int registered; + unsigned int ringing; + struct gsmd_timer *ring_check; }; #endif /* __GSMD__ */ diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c index c1d9324..356b637 100644 --- a/src/gsmd/atcmd.c +++ b/src/gsmd/atcmd.c @@ -404,7 +404,7 @@ static int ml_parse(const char *buf, int len, void *ctx) /* FIXME: handling of those special commands in response to * ATD / ATA */ - if (!strncmp(buf, "NO CARRIER", 11) || + if (!strncmp(buf, "NO CARRIER", 10) || ((g->flags & GSMD_FLAG_V0) && buf[0] == '3')) { /* Part of Case 'D' */ goto final_cb; diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c index b4bf260..6e96b35 100644 --- a/src/gsmd/unsolicited.c +++ b/src/gsmd/unsolicited.c @@ -92,17 +92,75 @@ int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt) return num_sent; } +static void state_ringing_timeout(struct gsmd_timer *timer, void *opaque) +{ + struct gsmd *gsmd = (struct gsmd *) opaque; + struct gsmd_ucmd *ucmd; + struct gsmd_evt_auxdata *aux; + + gsmd->dev_state.ring_check = 0; + gsmd_timer_free(timer); + + /* Update state */ + if (!gsmd->dev_state.ringing) + return; + gsmd->dev_state.ringing = 0; + + gsmd_log(GSMD_INFO, "an incoming call timed out\n"); + + /* Generate a timeout event */ + ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL, + sizeof(struct gsmd_evt_auxdata)); + if (!ucmd) + goto err; + + aux = (struct gsmd_evt_auxdata *) ucmd->buf; + aux->u.call.type = GSMD_CALL_TIMEOUT; + + if (usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CALL) < 0) + goto err; + return; +err: + gsmd_log(GSMD_ERROR, "event generation failed\n"); +} + +#define GSMD_RING_MAX_JITTER (200 * 1000) /* 0.2 s */ + +static void state_ringing_update(struct gsmd *gsmd) +{ + struct timeval tv; + + if (gsmd->dev_state.ring_check) + gsmd_timer_unregister(gsmd->dev_state.ring_check); + + /* Update state */ + gsmd->dev_state.ringing = 1; + + tv.tv_sec = 1; + tv.tv_usec = GSMD_RING_MAX_JITTER; + + if (gsmd->dev_state.ring_check) { + gsmd->dev_state.ring_check->expires = tv; + gsmd_timer_register(gsmd->dev_state.ring_check); + } else + gsmd->dev_state.ring_check = gsmd_timer_create(&tv, + &state_ringing_timeout, gsmd); +} + static int ring_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { - /* FIXME: generate ring event */ - struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL, - sizeof(struct gsmd_evt_auxdata)); + struct gsmd_ucmd *ucmd; struct gsmd_evt_auxdata *aux; + + state_ringing_update(gsmd); + ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL, + sizeof(struct gsmd_evt_auxdata)); + /* FIXME: generate ring event */ if (!ucmd) return -ENOMEM; - aux = (struct gsmd_evt_auxdata *)ucmd->buf; + aux = (struct gsmd_evt_auxdata *) ucmd->buf; aux->u.call.type = GSMD_CALL_UNSPEC; @@ -134,7 +192,9 @@ static int cring_parse(char *buf, int len, const char *param, struct gsmd *gsmd) /* FIXME: change event type to GPRS */ talloc_free(ucmd); return 0; - } + } else { + aux->u.call.type = GSMD_CALL_UNSPEC; + } /* FIXME: parse all the ALT* profiles, Chapter 6.11 */ return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CALL); diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c index b16aff5..fd602b5 100644 --- a/src/gsmd/usock.c +++ b/src/gsmd/usock.c @@ -200,6 +200,17 @@ static int voicecall_get_stat_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) cmd->id, sizeof(gcs), &gcs); } +static int usock_ringing_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + + /* If the incoming call answer/rejection succeeded then we + * know the modem isn't ringing and we update the state info. */ + if (cmd->ret == 0) + gu->gsmd->dev_state.ringing = 0; + return usock_cmd_cb(cmd, ctx, resp); +} + static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len) { @@ -223,7 +234,10 @@ static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, break; case GSMD_VOICECALL_HANGUP: /* ATH0 is not supported by QC, we hope ATH is supported by everone */ - cmd = atcmd_fill("ATH", 4, &usock_cmd_cb, gu, gph->id, NULL); + cmd = atcmd_fill("ATH", 4, + gu->gsmd->dev_state.ringing ? + usock_ringing_cb : usock_cmd_cb, + gu, gph->id,NULL); /* This command is special because it needs to be sent to * the MS even if a command is currently executing. */ @@ -232,7 +246,7 @@ static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, } break; case GSMD_VOICECALL_ANSWER: - cmd = atcmd_fill("ATA", 4, &usock_cmd_cb, gu, gph->id, NULL); + cmd = atcmd_fill("ATA", 4, &usock_ringing_cb, gu, gph->id,NULL); break; case GSMD_VOICECALL_DTMF: if (len < sizeof(*gph) + sizeof(*gd)) |