summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortick <tick@99fdad57-331a-0410-800a-d7fa5415bdb3>2007-12-05 08:14:34 +0000
committertick <tick@99fdad57-331a-0410-800a-d7fa5415bdb3>2007-12-05 08:14:34 +0000
commitd5eeb704107cae77e346a99f78f4623e3395b502 (patch)
tree034b8a989b26fc4ac588c3ba8b5460824f059f7f
parent7793a2546dc9da89e4ec25e836b705478425d395 (diff)
gsmd: add "RING" timeout scheme, for those modem not have %CPI (like) supports (Andrzej Zaborowski)
git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@3572 99fdad57-331a-0410-800a-d7fa5415bdb3
-rw-r--r--include/gsmd/event.h1
-rw-r--r--include/gsmd/state.h3
-rw-r--r--src/gsmd/atcmd.c2
-rw-r--r--src/gsmd/unsolicited.c70
-rw-r--r--src/gsmd/usock.c18
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))
personal git repositories of Harald Welte. Your mileage may vary