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

📄 at-emulator.c

📁 NOKIA手机开发包
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  $Id: at-emulator.c,v 1.38 2003/12/16 00:56:27 bozo Exp $  G N O K I I  A Linux/Unix toolset and driver for Nokia mobile phones.  This file is part of gnokii.  Gnokii 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.  Gnokii 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 gnokii; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  Copyright (C) 1999, 2000 Hugh Blemings & Pavel Jan韐 ml.  This file provides a virtual modem or "AT" interface to the GSM phone by  calling code in gsm-api.c. Inspired by and in places copied from the Linux  kernel AT Emulator IDSN code by Fritz Elfert and others.*/#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <grp.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <ctype.h>#ifndef WIN32#  include <termios.h>#endif#include "config.h"#include "misc.h"#include "gnokii.h"#include "data/at-emulator.h"#include "data/datapump.h"#define MAX_LINE_LENGTH 256#define	MAX_CMD_BUFFERS	(2)#define	CMD_BUFFER_LENGTH (100)/* Definition of some special Registers of AT-Emulator, pinched in   part from ISDN driver in Linux kernel */#define REG_RINGATA   0#define REG_RINGCNT   1#define REG_ESC       2#define REG_CR        3#define REG_LF        4#define REG_BS        5#define	S22          22#define S35          35#define REG_CTRLZ   100#define REG_ESCAPE  101#define REG_QUIET    14#define BIT_QUIET     4#define REG_VERBOSE  14#define BIT_VERBOSE   8#define REG_ECHO     14#define BIT_ECHO      2#define	MAX_MODEM_REGISTERS	102/* Message format definitions */#define PDU_MODE      0#define TEXT_MODE     1#define INTERACT_MODE 2/* Global variables */bool gn_atem_initialised = false;	/* Set to true once initialised */extern bool CommandMode;extern int ConnectCount;struct gn_statemachine *sm;gn_data data;static gn_sms sms;static gn_call_info callinfo;static 	char imei[64], model[64], revision[64], manufacturer[64];/* Local variables */static int	PtyRDFD;	/* File descriptor for reading and writing to/from */static int	PtyWRFD;	/* pty interface - only different in debug mode. */static u8	ModemRegisters[MAX_MODEM_REGISTERS];static char	CmdBuffer[MAX_CMD_BUFFERS][CMD_BUFFER_LENGTH];static int	CurrentCmdBuffer;static int	CurrentCmdBufferIndex;static int	IncomingCallNo;static int     MessageFormat;          /* Message Format (text or pdu) */	/* Current command parser */static void 	(*Parser)(char *); /* Current command parser *//* void 	(*Parser)(char *) = gn_atem_at_parse; */static gn_memory_type 	SMSType;static int 	SMSNumber;/* If initialised in debug mode, stdin/out is used instead   of ptys for interface. */bool gn_atem_initialise(int read_fd, int write_fd, struct gn_statemachine *vmsm){	PtyRDFD = read_fd;	PtyWRFD = write_fd;	gn_data_clear(&data);	memset(&sms, 0, sizeof(sms));	memset(&callinfo, 0, sizeof(callinfo));	data.sms = &sms;	data.call_info = &callinfo;	data.manufacturer = manufacturer;	data.model = model;	data.revision = revision;	data.imei = imei;	sm = vmsm;	/* Initialise command buffer variables */	CurrentCmdBuffer = 0;	CurrentCmdBufferIndex = 0;	/* Initialise registers */	gn_atem_registers_init();	/* Initial parser is AT routine */	Parser = gn_atem_at_parse;	/* Setup defaults for AT*C interpreter. */	SMSNumber = 1;	SMSType = GN_MT_ME;	/* Default message format is PDU */	MessageFormat = PDU_MODE;	/* Set the call passup so that we get notified of incoming calls */	data.call_notification = gn_atem_call_passup;	gn_sm_functions(GN_OP_SetCallNotification, &data, sm);	/* query model, revision and imei */	if (gn_sm_functions(GN_OP_Identify, &data, sm) != GN_ERR_NONE) return false;	/* We're ready to roll... */	gn_atem_initialised = true;	return (true);}/* Initialise the "registers" used by the virtual modem. */void	gn_atem_registers_init(void){	memset(ModemRegisters, 0, sizeof(ModemRegisters));	ModemRegisters[REG_RINGATA] = 0;	ModemRegisters[REG_RINGCNT] = 0;	ModemRegisters[REG_ESC] = '+';	ModemRegisters[REG_CR] = 10;	ModemRegisters[REG_LF] = 13;	ModemRegisters[REG_BS] = 8;	ModemRegisters[S35]=7;	ModemRegisters[REG_ECHO] |= BIT_ECHO;	ModemRegisters[REG_VERBOSE] |= BIT_VERBOSE;	ModemRegisters[REG_CTRLZ] = 26;	ModemRegisters[REG_ESCAPE] = 27;}static void  gn_atem_hangup_phone(void){	if (IncomingCallNo > 0) {		rlp_user_request_set(Disc_Req, true);		gn_sm_loop(10, sm);	}	if (IncomingCallNo > 0) {		data.call_info->call_id = IncomingCallNo;		gn_sm_functions(GN_OP_CancelCall, &data, sm);		IncomingCallNo = -1;	}	dp_Initialise(PtyRDFD, PtyWRFD);}static void  gn_atem_answer_phone(void){	/* For now we'll also initialise the datapump + rlp code again */	dp_Initialise(PtyRDFD, PtyWRFD);	data.call_notification = dp_CallPassup;	gn_sm_functions(GN_OP_SetCallNotification, &data, sm);	data.call_info->call_id = IncomingCallNo;	gn_sm_functions(GN_OP_AnswerCall, &data, sm);	CommandMode = false;}/* This gets called to indicate an incoming call */void gn_atem_call_passup(gn_call_status CallStatus, gn_call_info *CallInfo, struct gn_statemachine *state){	dprintf("gn_atem_call_passup called with %d\n", CallStatus);	switch (CallStatus) {	case GN_CALL_Incoming:		gn_atem_modem_result(MR_RING);		IncomingCallNo = CallInfo->call_id;		ModemRegisters[REG_RINGCNT]++;		if (ModemRegisters[REG_RINGATA] != 0) gn_atem_answer_phone();		break;	case GN_CALL_LocalHangup:	case GN_CALL_RemoteHangup:		IncomingCallNo = -1;		break;	default:		break;	}}/* Handler called when characters received from serial port.   calls state machine code to process it. */void	gn_atem_incoming_data_handle(char *buffer, int length){	int count;	unsigned char out_buf[3];	for (count = 0; count < length ; count++) {		/* If it's a command terminator character, parse what		   we have so far then go to next buffer. */		if (buffer[count] == ModemRegisters[REG_CR] ||		    buffer[count] == ModemRegisters[REG_LF] ||		    buffer[count] == ModemRegisters[REG_CTRLZ] ||		    buffer[count] == ModemRegisters[REG_ESCAPE]) {			/* Echo character if appropriate. */			if (buffer[count] == ModemRegisters[REG_LF] &&				(ModemRegisters[REG_ECHO] & BIT_ECHO)) {				gn_atem_string_out("\r\n");			}			/* Save CTRL-Z and ESCAPE for the parser */			if (buffer[count] == ModemRegisters[REG_CTRLZ] ||			    buffer[count] == ModemRegisters[REG_ESCAPE])				CmdBuffer[CurrentCmdBuffer][CurrentCmdBufferIndex++] = buffer[count];			CmdBuffer[CurrentCmdBuffer][CurrentCmdBufferIndex] = 0x00;			Parser(CmdBuffer[CurrentCmdBuffer]);			CurrentCmdBuffer++;			if (CurrentCmdBuffer >= MAX_CMD_BUFFERS) {				CurrentCmdBuffer = 0;			}			CurrentCmdBufferIndex = 0;		} else if (buffer[count] == ModemRegisters[REG_BS]) {			if (CurrentCmdBufferIndex > 0) {				/* Echo character if appropriate. */				if (ModemRegisters[REG_ECHO] & BIT_ECHO) {					gn_atem_string_out("\b \b");				}				CurrentCmdBufferIndex--;			}		} else {			/* Echo character if appropriate. */			if (ModemRegisters[REG_ECHO] & BIT_ECHO) {				out_buf[0] = buffer[count];				out_buf[1] = 0;				gn_atem_string_out(out_buf);			}			/* Collect it to command buffer */			CmdBuffer[CurrentCmdBuffer][CurrentCmdBufferIndex++] = buffer[count];			if (CurrentCmdBufferIndex >= CMD_BUFFER_LENGTH) {				CurrentCmdBufferIndex = CMD_BUFFER_LENGTH;			}		}	}}/* Parser for standard AT commands.  cmd_buffer must be null terminated. */void	gn_atem_at_parse(char *cmd_buffer){	char *buf;	int regno, val;	char str[256];	if (strncasecmp (cmd_buffer, "AT", 2) != 0) {		gn_atem_modem_result(MR_ERROR);		return;	}	for (buf = &cmd_buffer[2]; *buf;) {		switch (toupper(*buf)) {		case 'Z':			/* Reset modem */			buf++;			switch (gn_atem_num_get(&buf)) {			case -1:			case 0:	/* reset and load stored profile 0 */			case 1:	/* reset and load stored profile 1 */				gn_atem_hangup_phone();				gn_atem_registers_init();				break;			default:				gn_atem_modem_result(MR_ERROR);				return;			}			break;		case 'A':		        /* Answer call */			buf++;			gn_atem_answer_phone();			return;			break;		case 'D':			/* Dial Data :-) */			/* FIXME - should parse this better */			/* For now we'll also initialise the datapump + rlp code again */			dp_Initialise(PtyRDFD, PtyWRFD);			buf++;			if (toupper(*buf) == 'T' || toupper(*buf) == 'P') buf++;			while (*buf == ' ') buf++;			data.call_notification = dp_CallPassup;			gn_sm_functions(GN_OP_SetCallNotification, &data, sm);			snprintf(data.call_info->number, sizeof(data.call_info->number), "%s", buf);			if (ModemRegisters[S35] == 0)				data.call_info->type = GN_CALL_DigitalData;			else				data.call_info->type = GN_CALL_NonDigitalData;			data.call_info->send_number = GN_CALL_Default;			CommandMode = false;			if (gn_sm_functions(GN_OP_MakeCall, &data, sm) != GN_ERR_NONE) {				CommandMode = true;				dp_CallPassup(GN_CALL_RemoteHangup, NULL, NULL);			} else {				IncomingCallNo = data.call_info->call_id;				gn_sm_loop(10, sm);			}			return;			break;		case 'H':			/* Hang Up */			buf++;			switch (gn_atem_num_get(&buf)) {			case -1:			case 0:	/* hook off the phone */				gn_atem_hangup_phone();				break;			case 1:	/* hook on the phone */				break;			default:				gn_atem_modem_result(MR_ERROR);				return;			}			break;		case 'S':			/* Change registers */			buf++;			regno = gn_atem_num_get(&buf);			if (regno < 0 || regno >= MAX_MODEM_REGISTERS) {				gn_atem_modem_result(MR_ERROR);				return;			}			if (*buf == '=') {				buf++;				val = gn_atem_num_get(&buf);				if (val < 0 || val > 255) {					gn_atem_modem_result(MR_ERROR);					return;				}				ModemRegisters[regno] = val;			} else if (*buf == '?') {				buf++;				snprintf(str, sizeof(str), "%d\r\n", ModemRegisters[regno]);				gn_atem_string_out(str);			} else {				gn_atem_modem_result(MR_ERROR);				return;			}			break;		case 'E':		        /* E - Turn Echo on/off */			buf++;			switch (gn_atem_num_get(&buf)) {			case -1:			case 0:				ModemRegisters[REG_ECHO] &= ~BIT_ECHO;				break;			case 1:				ModemRegisters[REG_ECHO] |= BIT_ECHO;				break;			default:				gn_atem_modem_result(MR_ERROR);				return;			}			break;		case 'Q':		        /* Q - Turn Quiet on/off */			buf++;			switch (gn_atem_num_get(&buf)) {			case -1:			case 0:				ModemRegisters[REG_QUIET] &= ~BIT_QUIET;				break;			case 1:				ModemRegisters[REG_QUIET] |= BIT_QUIET;				break;			default:				gn_atem_modem_result(MR_ERROR);				return;			}			break;		case 'V':		        /* V - Turn Verbose on/off */			buf++;			switch (gn_atem_num_get(&buf)) {			case -1:			case 0:				ModemRegisters[REG_VERBOSE] &= ~BIT_VERBOSE;				break;			case 1:				ModemRegisters[REG_VERBOSE] |= BIT_VERBOSE;				break;			default:				gn_atem_modem_result(MR_ERROR);				return;			}			break;		case 'X':		        /* X - Set verbosity of the result messages */			buf++;			switch (gn_atem_num_get(&buf)) {			case -1:			case 0: val = 0x00; break;			case 1: val = 0x40; break;			case 2: val = 0x50; break;			case 3: val = 0x60; break;			case 4: val = 0x70; break;			case 5: val = 0x10; break;			default:				gn_atem_modem_result(MR_ERROR);				return;			}			ModemRegisters[S22] = (ModemRegisters[S22] & 0x8f) | val;			break;		case 'I':		        /* I - info */			buf++;			switch (gn_atem_num_get(&buf)) {			case -1:			case 0:	/* terminal id */				snprintf(str, sizeof(str), "%d\r\n", ModemRegisters[39]);				gn_atem_string_out(str);				break;			case 1:	/* serial number (IMEI) */				snprintf(str, sizeof(str), "%s\r\n", imei);				gn_atem_string_out(str);				break;			case 2: /* phone revision */				snprintf(str, sizeof(str), "%s\r\n", revision);				gn_atem_string_out(str);				break;			case 3: /* modem revision */				gn_atem_string_out("gnokiid " VERSION "\r\n");				break;			case 4: /* OEM string */				snprintf(str, sizeof(str), "%s %s\r\n", manufacturer, model);				gn_atem_string_out(str);				break;			default:				gn_atem_modem_result(MR_ERROR);				return;			}			break;		  /* Handle AT* commands (Nokia proprietary I think) */		case '*':			buf++;			if (!strcasecmp(buf, "NOKIATEST")) {				gn_atem_modem_result(MR_OK); /* FIXME? */				return;			} else {				if (!strcasecmp(buf, "C")) {					gn_atem_modem_result(MR_OK);					Parser = gn_atem_sms_parse;					return;				}			}			break;		/* + is the precursor to another set of commands */		case '+':			buf++;			switch (toupper(*buf)) {			case 'C':				buf++;				/* Returns true if error occured */				if (gn_atem_command_plusc(&buf) == true) {					return;				}				break;			case 'G':				buf++;				/* Returns true if error occured */				if (gn_atem_command_plusg(&buf) == true) {					return;				}				break;

⌨️ 快捷键说明

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