commit 114e09893119525160d13768bcb8f5ee5e0ade32
parent 74fe540fa16843f13761680946601e1f4663ba79
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Sun, 13 Jun 2021 17:40:34 -0500
redo call status
Now we use AT+CLIP and AT+COLP to determine call status, rather than
issuing AT+CLCC. This is way simpler, as +CLIP effectively lets
us get the phone number from RING, and +COLP will tell us when the
other end has picked up.
In addition, handle_resp was completely broken, as it didn't
detect newlines properly, and wouldn't process a whole response,
causing it to fall behind. Now it processes everything that is in
the buffer as soon as it can.
Diffstat:
M | atc.c | | | 11 | ----------- |
M | atd.c | | | 152 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
M | atd.h | | | 11 | ++++------- |
M | encdec.c | | | 59 | +++++++++++++++++++---------------------------------------- |
M | encdec.h | | | 2 | +- |
5 files changed, 117 insertions(+), 118 deletions(-)
diff --git a/atc.c b/atc.c
@@ -7,8 +7,6 @@
#include "atd.h"
#include "encdec.h"
-struct call calls[MAX_CALLS];
-
int
main(int argc, char *argv[])
{
@@ -65,21 +63,12 @@ main(int argc, char *argv[])
char op;
read(sock, &op, 1);
- if (op == STATUS_CALL) {
- dec_call_status(sock, calls);
- }
if (op == STATUS_OK)
fprintf(stderr, "OK\n");
else if (op == STATUS_OK)
fprintf(stderr, "ERROR\n");
else if (op == STATUS_CALL) {
- for (int i = 0; i < MAX_CALLS; i++) {
- if (!calls[i].present)
- continue;
-
- fprintf(stderr, "status: %s, %d", calls[i].num, calls[i].status);
- }
}
sleep(1);
diff --git a/atd.c b/atd.c
@@ -66,8 +66,6 @@ struct fdbuf {
struct command currentcmd;
int cmd_progress;
bool active_command = false;
-bool check_call_status = false;
-bool handling_urc = false;
enum atcmd currentatcmd;
int calld = -1;
@@ -135,7 +133,7 @@ send_status(int fd, enum status status)
return 0;
}
-struct call
+void
parseclcc(char *start, size_t len)
{
unsigned char idx;
@@ -143,17 +141,17 @@ parseclcc(char *start, size_t len)
unsigned char stat;
unsigned char mode;
unsigned char mpty;
- char number[PHONE_NUMBER_MAX_LEN];
unsigned char type;
unsigned char alpha;
- struct call call = { .present = true };
+ struct call call;
int ret = sscanf(start, "+CLCC: %hhu,%hhu,%hhu,%hhu,%hhu,\"%[+1234567890ABCD]\",%hhu,%hhu", &idx, &dir, &call.status, &mode, &mpty, call.num, &type, &alpha);
fprintf(stderr, "clcc: got %d successful matches\n", ret);
- calls[idx] = call;
+ if (ret == 8)
+ calls[idx] = call;
}
/* [0] = STATUS_CALL
@@ -161,45 +159,79 @@ parseclcc(char *start, size_t len)
list of update entries follows
update entry is a callstatus, followed by a string containing the phone number */
int
-update_call_status()
+send_call_status(enum callstatus status, char *num)
{
- int status;
if (calld != -1) {
fprintf(stderr, "update call status\n");
- status = atd_status_call(fds[calld].fd, calls, MAX_CALLS);
+ return atd_status_call(fds[calld].fd, status, num);
}
- memset(calls, 0, MAX_CALLS*sizeof(calls[0]));
- return status;
+ return 0;
+}
+
+int
+send_clip(char *start, size_t len)
+{
+ char number[PHONE_NUMBER_MAX_LEN + 1];
+ int ret = sscanf(start, "+CLIP: \"%[+1234567890ABCD]\"", number);
+ if (ret != 1)
+ return -1;
+
+ return send_call_status(CALL_INCOMING, number);
+}
+
+int
+send_colp(char *start, size_t len)
+{
+ char number[PHONE_NUMBER_MAX_LEN + 1];
+ int ret = sscanf(start, "+COLP: \"%[+1234567890ABCD]\"", number);
+ if (ret != 1)
+ return -1;
+
+ return send_call_status(CALL_ANSWERED, number);
+}
+
+int
+lprint(char *buf, size_t len)
+{
+ for (int i = 0; i < len; i++) {
+ if (buf[i] == '\n') {
+ puts("<LF>");
+ } else if (buf[i] == '\r') {
+ puts("<CR>");
+ } else {
+ putchar(buf[i]);
+ }
+ }
}
size_t
handle_resp(int fd, int idx)
{
fprintf(stderr, "handle_resp start\n");
- char *start = fdbufs[idx].out, *ptr = memmem(fdbufs[idx].out, fdbufs[idx].outlen, "\r\n", 2);
+ char *start = fdbufs[idx].out, *ptr = memchr(fdbufs[idx].out, '\n', fdbufs[idx].outlen);
enum status status = 0;
+ lprint(fdbufs[idx].out, fdbufs[idx].outlen);
+
if (ptr == NULL)
return 0;
- // find next line with content
- while (start == ptr) {
- ptr += sizeof("\r\n") - 1;
- start = ptr;
- ptr = memmem(start, fdbufs[idx].outlen - (ptr - fdbufs[idx].out), "\r\n", 2);
- }
+ fprintf(stderr, "handle_resp ptr not null\n");
+
+ if (ptr - start == 1 && memcmp(start, "\n", 1) == 0)
+ return 1;
+ else if (ptr - start == 2 && memcmp(start, "\r\n", 2) == 0)
+ return 2;
+
+ fprintf(stderr, "handle_resp line has content\n");
if (strncmp(start, "OK", sizeof("OK") - 1) == 0) {
status = STATUS_OK;
active_command = false;
- if (handling_urc)
- handling_urc = false;
- if (currentatcmd == CLCC) {
- if (update_call_status() < 0)
- fprintf(stderr, "failed to update call status\n");
- check_call_status = false;
- return ptr - fdbufs[idx].out;
+ if (currentatcmd == ATD) {
+ if (send_call_status(CALL_DIALING, currentcmd.data.dial.num) < 0)
+ fprintf(stderr, "failed to send call status\n");
}
fprintf(stderr, "got OK\n");
} else if (strncmp(start, "ERROR", sizeof("ERROR") - 1) == 0) {
@@ -207,28 +239,36 @@ handle_resp(int fd, int idx)
active_command = false;
fprintf(stderr, "got ERROR\n");
} else if (strncmp(start, "NO CARRIER", sizeof("NO CARRIER") - 1) == 0) {
- check_call_status = true;
- fprintf(stderr, "got NO CARRIER\n");
+ if (currentcmd.op == CMD_ANSWER || currentcmd.op == CMD_DIAL) {
+ active_command = false;
+ status = STATUS_ERROR;
+ }
+
+ if (send_call_status(CALL_INACTIVE, "") < 0) {
+ fprintf(stderr, "failed to send call status\n");
+ }
} else if (strncmp(start, "RING", sizeof("RING") - 1) == 0) {
- check_call_status = true;
fprintf(stderr, "got RING\n");
} else if (strncmp(start, "CONNECT", sizeof("CONNECT") - 1) == 0) {
- check_call_status = true;
fprintf(stderr, "got CONNECT\n");
} else if (strncmp(start, "BUSY", sizeof("BUSY") - 1) == 0) {
- check_call_status = true;
fprintf(stderr, "got BUSY\n");
} else if (strncmp(start, "+CLCC", sizeof("+CLCC") - 1) == 0) {
+ assert(0);
fprintf(stderr, "got +CLCC\n");
- assert(check_call_status);
- struct call call = parseclcc(start, ptr - start);
+ parseclcc(start, ptr - start);
+ } else if (strncmp(start, "+CLIP", sizeof("+CLIP") - 1) == 0) {
+ fprintf(stderr, "got +CLIP\n");
+
+ send_clip(start, ptr - start);
}
+
if (status && fd > 0)
send_status(fd, status);
- ptr += 2;
+ ptr += 1;
fprintf(stderr, "handle_resp: %d\n", ptr - fdbufs[idx].out);
return ptr - fdbufs[idx].out;
@@ -265,13 +305,12 @@ bool
send_command(int idx, enum atcmd atcmd, union atdata atdata)
{
ssize_t ret;
- fprintf(stderr, "send command\n");
+ fprintf(stderr, "send command: %d\n", atcmd);
if (atcmd == ATD) {
ret = snprintf(fdbufs[idx].in, BUFSIZE, atcmds[atcmd], atdata.dial.num);
} else {
ret = snprintf(fdbufs[idx].in, BUFSIZE, atcmds[atcmd]);
}
- fprintf(stderr, "after data\n");
if (ret >= BUFSIZE) {
warn("AT command too long!");
return false;
@@ -284,7 +323,6 @@ send_command(int idx, enum atcmd atcmd, union atdata atdata)
warn("failed to write to backend!");
return false;
}
- fprintf(stderr, "done writing: %d\n", fdbufs[idx].inlen);
active_command = true;
currentatcmd = atcmd;
return true;
@@ -420,6 +458,7 @@ int main(int argc, char *argv[])
// much was left unparsed so we can move it to the beginning of
// the buffer.
ret = cmdadd(i);
+ fprintf(stderr, "currentcmd:\n", currentcmd.op);
if (ret != -1) {
assert(ret <= BUFSIZE);
fdbufs[i].outlen -= ret;
@@ -442,46 +481,34 @@ int main(int argc, char *argv[])
}
if (fds[BACKEND].revents & POLLIN) {
- fprintf(stderr, "len: %d\n", fdbufs[BACKEND].outlen);
ret = fdbuf_read(BACKEND);
if (ret == -1) {
warn("failed to read from backend:");
break;
}
+ }
- /* TODO should this be here? */
- if (check_call_status)
- POLLADD(fds[calld], POLLOUT);
-
+ while (fdbufs[BACKEND].outlen) {
ret = handle_resp(fds[cmd.index].fd, BACKEND);
+ if (ret == 0)
+ break;
+
memmove(fdbufs[BACKEND].out, fdbufs[BACKEND].out + ret, BUFSIZE - ret);
fdbufs[BACKEND].outlen -= ret;
fdbufs[BACKEND].outptr -= ret;
}
- /* note that this doesn't take effect until the next poll cycle...
- * maybe this can be replaced with something more integrated? */
- if ((cmdq.count || check_call_status) && !active_command)
- POLLADD(fds[BACKEND], POLLOUT);
- else
- POLLDROP(fds[BACKEND], POLLOUT);
-
/* send next command to modem */
if (fds[BACKEND].revents & POLLOUT) {
fprintf(stderr, "have a command!\n");
- if (check_call_status) {
- if (!send_command(BACKEND, CLCC, (union atdata){0}))
- break;
- handling_urc = true;
- } else {
- cmd = command_dequeue();
- fprintf(stderr, "op: %d\n", cmd.op);
- assert(cmd.op != CMD_NONE);
+ cmd = command_dequeue();
+ assert(cmd.op != CMD_NONE);
- if (!send_command(BACKEND, cmddata[cmd.op].atcmd, cmd.data))
- break;
- }
+ if (!send_command(BACKEND, cmddata[cmd.op].atcmd, cmd.data))
+ break;
+
+ currentcmd = cmd;
/* don't write any more until we hear back */
if (fdbufs[BACKEND].inlen == 0) {
@@ -508,6 +535,13 @@ int main(int argc, char *argv[])
break;
}
}
+
+ /* note that this doesn't take effect until the next poll cycle...
+ * maybe this can be replaced with something more integrated? */
+ if (cmdq.count && !active_command)
+ POLLADD(fds[BACKEND], POLLOUT);
+ else
+ POLLDROP(fds[BACKEND], POLLOUT);
}
error:
diff --git a/atd.h b/atd.h
@@ -20,9 +20,10 @@ enum callstatus {
CALL_ACTIVE,
CALL_HELD,
CALL_DIALING,
- CALL_ALERTING,
CALL_INCOMING,
- CALL_WAITING,
+ CALL_ANSWERED,
+ CALL_INACTIVE,
+ CALL_LAST,
};
enum status {
@@ -51,9 +52,8 @@ struct command {
};
struct call {
- bool present;
enum callstatus status;
- char num[PHONE_NUMBER_MAX_LEN];
+ char num[PHONE_NUMBER_MAX_LEN + 1];
};
@@ -69,7 +69,4 @@ struct command_args {
enum type type[MAX_PARAMS + 1];
};
-extern struct command_args cmddata[];
-extern char *atcmds[];
-
#endif
diff --git a/encdec.c b/encdec.c
@@ -109,69 +109,48 @@ atd_cmd_call_events(int fd)
}
int
-atd_status_call(int fd, struct call *calls, size_t len)
+atd_status_call(int fd, enum callstatus status, char *num)
{
- char buf[(PHONE_NUMBER_MAX_LEN + 3) * MAX_CALLS + 2];
+ char buf[4 + strlen(num)];
char *ptr;
ssize_t ret;
buf[0] = STATUS_CALL;
- buf[1] = 0;
+ buf[1] = status;
ptr = buf + 2;
-
- for (int i = 0; i < len; i++) {
- if (!(calls[i].present))
- continue;
-
- *(ptr++) = i;
- *(ptr++) = calls[i].status;
- ptr += enc_str(ptr, calls[i].num);
-
- buf[1]++;
- }
+ ptr += enc_str(ptr, num);
return xwrite(fd, buf, ptr - buf);
}
/* calls should be MAX_CALLS long */
int
-dec_call_status(int fd, struct call *calls)
+dec_call_status(int fd, struct call *call)
{
- char count = 0, idx = 0, status = 0;
+ char status = 0;
unsigned short len = 0;
ssize_t ret;
char buf[PHONE_NUMBER_MAX_LEN];
- ret = xread(fd, &count, 1);
- if (ret == -1 || count > MAX_CALLS)
+ ret = xread(fd, (char *) &call->status, 1);
+ if (ret == -1 || status >= CALL_LAST)
return -1;
- for (int i = 0; i < count; i++) {
- ret = xread(fd, &idx, 1);
- if (ret == -1 || idx > MAX_CALLS - 1)
- return -1;
-
- ret = xread(fd, &status, 1);
- if (ret == -1 || status > CALL_WAITING)
- return -1;
-
- ret = xread(fd, buf, 2);
- if (ret == -1)
- return -1;
+ ret = xread(fd, buf, 2);
+ if (ret == -1)
+ return -1;
- len = dec_short(buf);
- if (len > PHONE_NUMBER_MAX_LEN)
- return -1;
+ len = dec_short(buf);
+ if (len > PHONE_NUMBER_MAX_LEN)
+ return -1;
- ret = xread(fd, buf, len);
- if (ret == -1)
- return -1;
+ if (len == 0)
+ return 0;
- calls[idx].present = true;
- calls[idx].status = status;
- memcpy(calls[idx].num, buf, len);
- }
+ ret = xread(fd, call->num, len);
+ if (ret == -1)
+ return -1;
return 0;
}
diff --git a/encdec.h b/encdec.h
@@ -2,6 +2,6 @@ int atd_cmd_dial(int fd, char *num);
int atd_cmd_hangup(int fd);
int atd_cmd_answer(int fd);
int atd_cmd_call_events(int fd);
-int atd_status_call(int fd, struct call *calls, size_t len);
+int atd_status_call(int fd, enum callstatus status, char *num);
ssize_t dec_str(char *in, char **out);
int dec_call_status(int fd, struct call *calls);