📄 atcmd.c
字号:
memset(g->mlbuf, 0, MLPARSE_BUF_SIZE); } g->mlbuf_len = 0; } /* the current buf will be appended to mlbuf below */ } } else { if (!strcmp(buf, "RING") || ((g->flags & GSMD_FLAG_V0) && buf[0] == '2')) { /* this is the only non-extended unsolicited return * code, part of Case 'B' */ return unsolicited_parse(g, buf, len, NULL); } if (!strcmp(buf, "ERROR") || ((g->flags & GSMD_FLAG_V0) && buf[0] == '4')) { /* Part of Case 'C' */ DEBUGP("unspecified error\n"); if (cmd) cmd->ret = 4; goto final_cb; } if (!strncmp(buf, "OK", 2) || ((g->flags & GSMD_FLAG_V0) && buf[0] == '0')) { /* Part of Case 'C' */ if (cmd) cmd->ret = 0; goto final_cb; } /* FIXME: handling of those special commands in response to * ATD / ATA */ if (!strncmp(buf, "NO CARRIER", 10) || ((g->flags & GSMD_FLAG_V0) && buf[0] == '3')) { /* Part of Case 'D' */ goto final_cb; } if (!strncmp(buf, "BUSY", 4) || ((g->flags & GSMD_FLAG_V0) && buf[0] == '7')) { /* Part of Case 'D' */ goto final_cb; } } /* we reach here, if we are at an information response that needs to be * passed on */ if (g->mlbuf_len) g->mlbuf[g->mlbuf_len ++] = '\n'; DEBUGP("Appending buf to mlbuf\n"); if (len > MLPARSE_BUF_SIZE - g->mlbuf_len) len = MLPARSE_BUF_SIZE - g->mlbuf_len; memcpy(g->mlbuf + g->mlbuf_len, buf, len); g->mlbuf_len += len; if (g->mlunsolicited) { rc = unsolicited_parse(g, (const char*) g->mlbuf, (int) g->mlbuf_len, strchr((const char*)g->mlbuf, ':') + 1); if (rc == -EAGAIN) { /* The parser wants one more line of * input. Wait for the next line, concatenate * and resumbit to unsolicited_parse(). */ DEBUGP("Multiline unsolicited code\n"); return 0; } g->mlunsolicited = 0; g->mlbuf_len = 0; } return rc;final_cb: /* if reach here, the final result code of a command has been reached */ if (!cmd) return rc; if (cmd && cme_error) generate_event_from_cme(g, cmd->ret); if (cmd && cms_error) generate_event_from_cms(g, cmd->ret); return atcmd_done(g, cmd, buf);}/* called when the modem asked for a new line of a multiline atcmd */static int atcmd_prompt(void *data){ struct gsmd *g = data; atcmd_wake_pending_queue(g); return 0;}/* callback to be called if [virtual] UART has some data for us */static int atcmd_select_cb(int fd, unsigned int what, void *data){ int len, rc; static char rxbuf[1024]; struct gsmd *g = data; char *cr; if (what & GSMD_FD_READ) { memset(rxbuf, 0, sizeof(rxbuf)); while ((len = read(fd, rxbuf, sizeof(rxbuf)))) { if (len < 0) { if (errno == EAGAIN) return 0; gsmd_log(GSMD_NOTICE, "ERROR reading from fd %u: %d (%s)\n", fd, len, strerror(errno)); return len; } rc = llparse_string(&g->llp, rxbuf, len); if (rc < 0) { gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc); return rc; } } } /* write pending commands to UART */ if ((what & GSMD_FD_WRITE) && g->interpreter_ready) { struct gsmd_atcmd *pos, *pos2; llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) { cr = strchr(pos->cur, '\n'); if (cr) len = cr - pos->cur; else len = pos->buflen - 1; /* assuming zero-terminated strings */ rc = write(fd, pos->cur, len); if (rc == 0) { gsmd_log(GSMD_ERROR, "write returns 0, aborting\n"); break; } else if (rc < 0) { gsmd_log(GSMD_ERROR, "error during write to fd %d: %d\n", fd, rc); return rc; } if (!cr || rc == len) rc ++; /* Skip the \n or \0 */ pos->buflen -= rc; pos->cur += rc; write(fd, "\r", 1); if (!pos->buflen) { /* success: create atcommand timeout timer */ pos->timeout = pos->create_timer_func(g); /* success: remove from global list of * to-be-sent atcmds */ llist_del(&pos->list); /* append to global list of executing atcmds */ llist_add_tail(&pos->list, &g->busy_atcmds); /* we only send one cmd at the moment */ break; } else { /* The write was short or the atcmd has more * lines to send after a "> ". */ if (rc < len) return 0; break; } } /* Either pending_atcmds is empty or a command has to wait */ atcmd_wait_pending_queue(g); } return 0;}static void discard_timeout(struct gsmd_timer *tmr, void *data) { struct gsmd *g=data; struct gsmd_atcmd *cmd=NULL; DEBUGP("discard time out!!\n"); if (!llist_empty(&g->busy_atcmds)) { cmd = llist_entry(g->busy_atcmds.next,struct gsmd_atcmd, list); } if (!cmd) { DEBUGP("ERROR!! busy_atcmds is NULL\n"); return; } if (cmd->timeout != tmr) { DEBUGP("ERROR!! cmd->timeout != tmr\n"); return; } gsmd_timer_free(cmd->timeout); cmd->timeout = NULL; if (cmd->cb) { cmd->resp = "Timeout"; cmd->cb(cmd, cmd->ctx, cmd->resp); } // discard the timeout at command llist_del(&cmd->list); talloc_free(cmd); // pass the next pending at command if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds)) { atcmd_wake_pending_queue(g); }}static struct gsmd_timer * discard_timer(struct gsmd *g){ struct timeval tv; tv.tv_sec = GSMD_ATCMD_TIMEOUT; tv.tv_usec = 0; DEBUGP("Create discard timer\n"); return gsmd_timer_create(&tv, &discard_timeout, g);}struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t cb, void *ctx, u_int16_t id, create_timer_t ct){ int buflen = strlen(cmd); struct gsmd_atcmd *atcmd; if (rlen > buflen) buflen = rlen; atcmd = talloc_size(__atcmd_ctx, sizeof(*atcmd)+ buflen); if (!atcmd) return NULL; atcmd->ctx = ctx; atcmd->id = id; atcmd->flags = 0; atcmd->ret = -255; atcmd->buflen = buflen; atcmd->buf[buflen-1] = '\0'; atcmd->cur = atcmd->buf; atcmd->cb = cb; atcmd->resp = NULL; atcmd->timeout = NULL; strncpy(atcmd->buf, cmd, buflen-1); if (!ct) atcmd->create_timer_func = discard_timer; else atcmd->create_timer_func = ct; return atcmd;}static int remove_timer(struct gsmd_atcmd * cmd){ if (cmd->timeout) { DEBUGP("Get respond before timeout, remove timer!\n"); gsmd_timer_unregister(cmd->timeout); gsmd_timer_free(cmd->timeout); cmd->timeout = NULL; } else { DEBUGP("ERROR!! The %s response comes too late!!\n", cmd->buf); } return 0;}/* submit an atcmd in the global queue of pending atcmds */int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd){ if (g->machinepl->ex_submit) { DEBUGP("extra-submiting command\n"); g->machinepl->ex_submit(g); } DEBUGP("submitting command `%s'\n", cmd->buf); llist_add_tail(&cmd->list, &g->pending_atcmds); if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds)) { atcmd_wake_pending_queue(g); } return 0;}/* cancel a currently executing atcmd by issuing the command given as * parameter, usually AT ot ATH. */int cancel_atcmd(struct gsmd *g, struct gsmd_atcmd *cmd){ struct gsmd_atcmd *cur; if (llist_empty(&g->busy_atcmds)) { return atcmd_submit(g, cmd); } cur = llist_entry(g->busy_atcmds.next, struct gsmd_atcmd, list); DEBUGP("cancelling command `%s' with an `%s'\n", cur->buf, cmd->buf); if (g->mlbuf_len) { DEBUGP("Discarding mlbuf: %.*s\n", g->mlbuf_len, g->mlbuf); g->mlbuf_len = 0; } llist_add(&cmd->list, &g->pending_atcmds); return atcmd_done(g, cur, "ERROR");}void atcmd_drain(int fd){ int rc; struct termios t; rc = tcflush(fd, TCIOFLUSH); rc = tcgetattr(fd, &t); DEBUGP("c_iflag = 0x%08x, c_oflag = 0x%08x, c_cflag = 0x%08x, c_lflag = 0x%08x\n", t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); t.c_iflag = t.c_oflag = 0; cfmakeraw(&t); rc = tcsetattr(fd, TCSANOW, &t);}/* init atcmd parser */int atcmd_init(struct gsmd *g, int sockfd){ __atcmd_ctx = talloc_named_const(gsmd_tallocs, 1, "atcmds"); g->gfd_uart.fd = sockfd; g->gfd_uart.when = GSMD_FD_READ; g->gfd_uart.data = g; g->gfd_uart.cb = &atcmd_select_cb; INIT_LLIST_HEAD(&g->pending_atcmds); INIT_LLIST_HEAD(&g->busy_atcmds); llparse_init (&g->llp); g->mlbuf_len = 0; g->mlunsolicited = 0; g->alive_responded = 0; g->llp.cur = g->llp.buf; g->llp.len = sizeof(g->llp.buf); g->llp.cb = &ml_parse; g->llp.prompt_cb = &atcmd_prompt; g->llp.ctx = g; g->llp.flags = LGSM_ATCMD_F_EXTENDED; return gsmd_register_fd(&g->gfd_uart);}/* remove from the queues any command whose .ctx matches given */int atcmd_terminate_matching(struct gsmd *g, void *ctx){ int num = 0; struct gsmd_atcmd *cmd, *pos; llist_for_each_entry_safe(cmd, pos, &g->busy_atcmds, list) if (cmd->ctx == ctx) { cmd->ret = -ESHUTDOWN; cmd->cb(cmd, cmd->ctx, "ERROR"); cmd->cb = NULL; cmd->ctx = NULL; num ++; } llist_for_each_entry_safe(cmd, pos, &g->pending_atcmds, list) if (cmd->ctx == ctx) { llist_del(&cmd->list); cmd->ret = -ESHUTDOWN; cmd->cb(cmd, cmd->ctx, "ERROR"); talloc_free(cmd); num ++; } return num;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -