atd

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/atd
Log | Files | Refs

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:
Matc.c | 11-----------
Matd.c | 152++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Matd.h | 11++++-------
Mencdec.c | 59+++++++++++++++++++----------------------------------------
Mencdec.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);