⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atcmd.c

📁 Linux下gsm/gprs modem的看守程序。支持短信发送与接受。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* gsmd AT command interpreter / parser / constructor * * (C) 2006-2007 by OpenMoko, Inc. * Written by Harald Welte <laforge@openmoko.org> * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <termios.h>#include <sys/types.h>#include <common/linux_list.h>#include "gsmd.h"#include <gsmd/ts0705.h>#include <gsmd/ts0707.h>#include <gsmd/gsmd.h>#include <gsmd/atcmd.h>#include <gsmd/talloc.h>#include <gsmd/unsolicited.h>static void *__atcmd_ctx;static int remove_timer(struct gsmd_atcmd * cmd);enum final_result_codes {	GSMD_RESULT_OK = 0,	GSMD_RESULT_ERR = 1,	NUM_FINAL_RESULTS,};#if 0static const char *final_results[] = {	"OK",	"ERROR",	"+CME ERROR:",	"+CMS ERROR:",};#endif/* we basically implement a parse that can deal with * - receiving and queueing commands from higher level of libgmsd * - optionally combining them into one larger command (; appending) * - sending those commands to the TA, receiving and parsing responses * - calling back application on completion, or waiting synchronously *   for a response * - dealing with intermediate and unsolicited resultcodes by calling *   back into the application / higher levels */static inline int llparse_append(struct llparser *llp, char byte){	if (llp->cur < llp->buf + llp->len) {		*(llp->cur++) = byte;		return 0;	} else {		DEBUGP("llp->cur too big!!!\n");		return -EFBIG;	}}static inline void llparse_endline(struct llparser *llp){	/* re-set cursor to start of buffer */	llp->cur = llp->buf;	llp->state = LLPARSE_STATE_IDLE;	memset(llp->buf, 0, LLPARSE_BUF_SIZE);}static int llparse_byte(struct llparser *llp, char byte){	int ret = 0;	switch (llp->state) {	case LLPARSE_STATE_IDLE:	case LLPARSE_STATE_PROMPT_SPC:		if (llp->flags & LGSM_ATCMD_F_EXTENDED) {			if (byte == '\r')				llp->state = LLPARSE_STATE_IDLE_CR;			else if (byte == '>')				llp->state = LLPARSE_STATE_PROMPT;			else {#ifdef STRICT				llp->state = LLPARSE_STATE_ERROR;#else				llp->state = LLPARSE_STATE_RESULT;				ret = llparse_append(llp, byte);#endif			}		} else {			llp->state = LLPARSE_STATE_RESULT;			ret = llparse_append(llp, byte);		}		break;	case LLPARSE_STATE_IDLE_CR:		if (byte == '\n')			llp->state = LLPARSE_STATE_IDLE_LF;		else if (byte != '\r')			llp->state = LLPARSE_STATE_ERROR;		break;	case LLPARSE_STATE_IDLE_LF:		/* can we really go directly into result_cr ? */		if (byte == '\r')			llp->state = LLPARSE_STATE_RESULT_CR;		else if (byte == '>')			llp->state = LLPARSE_STATE_PROMPT;		else {			llp->state = LLPARSE_STATE_RESULT;			ret = llparse_append(llp, byte);		}		break;	case LLPARSE_STATE_RESULT:		if (byte == '\r')			llp->state = LLPARSE_STATE_RESULT_CR;		else if ((llp->flags & LGSM_ATCMD_F_LFCR) && byte == '\n')			llp->state = LLPARSE_STATE_RESULT_LF;		else			ret = llparse_append(llp, byte);		break;	case LLPARSE_STATE_RESULT_CR:		if (byte == '\n')			llparse_endline(llp);		break;	case LLPARSE_STATE_RESULT_LF:		if (byte == '\r')			llparse_endline(llp);		break;	case LLPARSE_STATE_PROMPT:		if (byte == ' ')			llp->state = LLPARSE_STATE_PROMPT_SPC;		else {			/* this was not a real "> " prompt */			llparse_append(llp, '>');			ret = llparse_append(llp, byte);			llp->state = LLPARSE_STATE_RESULT;		}		break;	case LLPARSE_STATE_ERROR:		break;	}	return ret;}static int llparse_string(struct llparser *llp, char *buf, unsigned int len){	while (len--) {		int rc = llparse_byte(llp, *(buf++));		if (rc < 0)			return rc;		/* if _after_ parsing the current byte we have finished,		 * let the caller know that there is something to handle */		if (llp->state == LLPARSE_STATE_RESULT_CR) {			/* FIXME: what to do with return value ? */			llp->cb(llp->buf, llp->cur - llp->buf, llp->ctx);		}		/* if a full SMS-style prompt was received, poke the select */		if (llp->state == LLPARSE_STATE_PROMPT_SPC)			llp->prompt_cb(llp->ctx);	}	return 0;}static int llparse_init(struct llparser *llp){	llp->state = LLPARSE_STATE_IDLE;	return 0;}#if 0/* mid-level parser */static int parse_final_result(const char *res){	int i;	for (i = 0; i < NUM_FINAL_RESULTS; i++) {		if (!strcmp(res, final_results[i]))			return i;	}		return -1;}#endifvoid atcmd_wake_pending_queue (struct gsmd *g) {        g->gfd_uart.when |= GSMD_FD_WRITE;}void atcmd_wait_pending_queue (struct gsmd *g) {        g->gfd_uart.when &= ~GSMD_FD_WRITE;}static int atcmd_done(struct gsmd *g, struct gsmd_atcmd *cmd, const char *buf){        int rc = 0;	/* remove timer if get respond before timeout */	remove_timer(cmd);        if (!cmd->cb) {                gsmd_log(GSMD_NOTICE, "command without cb!!!\n");        } else {                DEBUGP("Calling final cmd->cb()\n");                /* send final result code if there is no information                * response in mlbuf */                if (g->mlbuf_len) {                        cmd->resp = (char *) g->mlbuf;                        g->mlbuf[g->mlbuf_len] = 0;                } else {                        cmd->resp = (char *) buf;                }                rc = cmd->cb(cmd, cmd->ctx, cmd->resp);                DEBUGP("Clearing mlbuf\n");                memset(g->mlbuf, 0, MLPARSE_BUF_SIZE);                g->mlbuf_len = 0;        }                /* remove from list of currently executing cmds */        llist_del(&cmd->list);        talloc_free(cmd);                /* if we're finished with current commands, but still have pending        * commands: we want to WRITE again */        if (llist_empty(&g->busy_atcmds)) {                //g->clear_to_send = 1;                if (!llist_empty(&g->pending_atcmds)) {                        atcmd_wake_pending_queue(g);                }        }        return rc;}static int ml_parse(const char *buf, int len, void *ctx){	struct gsmd *g = ctx;	struct gsmd_atcmd *cmd = NULL;	int rc = 0;	int cme_error = 0;	int cms_error = 0;	DEBUGP("buf=`%s'(%d)\n", buf, len);	/* FIXME: This needs to be part of the vendor plugin. If we receive	 * an empty string or that 'ready' string, we need to init the modem */	if (strlen(buf) == 0 ||	    !strcmp(buf, "AT-Command Interpreter ready")) {		g->interpreter_ready = 1;		gsmd_initsettings(g);		gsmd_alive_start(g);		return 0;	}	/* responses come in order, so first response has to be for first	 * command we sent, i.e. first entry in list */	if (!llist_empty(&g->busy_atcmds))		cmd = llist_entry(g->busy_atcmds.next,				  struct gsmd_atcmd, list);	if (cmd && !strcmp(buf, cmd->buf)) {		DEBUGP("ignoring echo\n");		return 0;	}	/* we have to differentiate between the following cases:	 *	 * A) an information response ("+whatever: ...")	 *    we just pass it up the callback	 * B) an unsolicited message ("+whateverelse: ... ")	 *    we call the unsolicited.c handlers	 * C) a final response ("OK", "+CME ERROR", ...)	 *    in this case, we need to check whether we already sent some	 *    previous data to the callback (information response).  If yes,	 *    we do nothing.  If no, we need to call the callback.	 * D) an intermediate response ("CONNECTED", "BUSY", "NO DIALTONE")	 *    TBD	 */	if (buf[0] == '+' || strchr(g->vendorpl->ext_chars, buf[0])) {		/* an extended response */		const char *colon = strchr(buf, ':');		if (!colon) {			gsmd_log(GSMD_ERROR, "no colon in extd response `%s'\n",				buf);			return -EINVAL;		}		if (!strncmp(buf+1, "CME ERROR", 9)) {			/* Part of Case 'C' */			unsigned long err_nr;			err_nr = strtoul(colon+1, NULL, 10);			DEBUGP("error number %lu\n", err_nr);			if (cmd)				cmd->ret = err_nr;			cme_error = 1;			goto final_cb;		}		if (!strncmp(buf+1, "CMS ERROR", 9)) {			/* Part of Case 'C' */			unsigned long err_nr;			err_nr = strtoul(colon+1, NULL, 10);			DEBUGP("error number %lu\n", err_nr);			if (cmd)				cmd->ret = err_nr;			cms_error = 1;			goto final_cb;		}		if (!cmd || strncmp(buf, &cmd->buf[2], colon-buf)) {			/* Assuming Case 'B' */			DEBUGP("extd reply `%s' to cmd `%s', must be "			       "unsolicited\n", buf, cmd ? &cmd->buf[2] : "NONE");			colon++;			if (colon > buf+len)				colon = NULL;			rc = unsolicited_parse(g, buf, len, colon);			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");				g->mlbuf_len = len;				memcpy(g->mlbuf, buf, len);				g->mlunsolicited = 1;				return 0;			}			/* if unsolicited parser didn't handle this 'reply', then we 			 * need to continue and try harder and see what it is */			if (rc != -ENOENT) {				/* Case 'B' finished */				return rc;			}			/* contine, not 'B' */		}		if (cmd) {			if (cmd->buf[2] != '+' && strchr(g->vendorpl->ext_chars, cmd->buf[2]) == NULL) {				gsmd_log(GSMD_ERROR, "extd reply to non-extd command?\n");				return -EINVAL;			}			/* if we survive till here, it's a valid extd response			 * to an extended command and thus Case 'A' */			/* it might be a multiline response, so if there's a previous			   response, send out mlbuf and start afresh with an empty buffer */			if (g->mlbuf_len) {				if (!cmd->cb) {					gsmd_log(GSMD_NOTICE, "command without cb!!!\n");				} else {					DEBUGP("Calling cmd->cb()\n");					cmd->resp = (char *) g->mlbuf;					rc = cmd->cb(cmd, cmd->ctx, cmd->resp);					DEBUGP("Clearing mlbuf\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -