1205 lines
26 KiB
C
1205 lines
26 KiB
C
|
|
||
|
/*
|
||
|
*
|
||
|
* Copyright (c) 2001, Smart Link Ltd.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
*
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above
|
||
|
* copyright notice, this list of conditions and the following
|
||
|
* disclaimer in the documentation and/or other materials provided
|
||
|
* with the distribution.
|
||
|
* 3. Neither the name of the Smart Link Ltd. nor the names of its
|
||
|
* contributors may be used to endorse or promote products derived
|
||
|
* from this software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
* modem_at.c -- modem at command processor.
|
||
|
*
|
||
|
* Author: Sasha K (sashak@smlink.com)
|
||
|
* Seva (seva@smlink.com)
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/********************************************************************
|
||
|
*
|
||
|
* AT commands status. (p) - partiatly
|
||
|
*
|
||
|
* 1. Implemented:
|
||
|
*
|
||
|
* AT : A B C D E H I L M N O P Q S T V X Y Z
|
||
|
* AT&: C D E F H P R S F W
|
||
|
* AT\: A N
|
||
|
* AT%: C E
|
||
|
* AT+: MS FCLASS GCI GMI GMM GMR
|
||
|
* AT#: CID
|
||
|
*
|
||
|
********************************************************************
|
||
|
*
|
||
|
* 2. Not implemented yet:
|
||
|
*
|
||
|
* AT+: DSC DS DS44 DR
|
||
|
* FAE FTS FRS FTM FRM FRH FTH
|
||
|
* AT&: A K V Z
|
||
|
* AT\: B K
|
||
|
* AT*: B
|
||
|
* AT#: BDR RG TL CLS SPK UD
|
||
|
* VBS VBT VIP VIT VLS VRA VRN
|
||
|
* VRX VSD VSP VSR VSS VTD VTM
|
||
|
* VTS VGT VTX
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <ctype.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <modem.h>
|
||
|
#include <modem_debug.h>
|
||
|
|
||
|
#define AT_DBG(fmt...) // dprintf("at: " fmt)
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ */
|
||
|
/* prototypes from modem.c */
|
||
|
extern const char modem_author[];
|
||
|
extern const char modem_name[];
|
||
|
extern const char modem_version[];
|
||
|
extern const char modem_date[];
|
||
|
|
||
|
extern struct dp_driver modem_dp_drivers[];
|
||
|
|
||
|
extern int modem_send_to_tty(struct modem *m, const char *buf, int n);
|
||
|
extern int modem_answer(struct modem *m);
|
||
|
extern int modem_dial(struct modem *m);
|
||
|
extern int modem_hook(struct modem *m,unsigned hook_state);
|
||
|
extern int modem_online(struct modem *m);
|
||
|
extern int modem_reset(struct modem *m);
|
||
|
extern void modem_update_speaker(struct modem *m);
|
||
|
extern int modem_homolog_init(struct modem *m, int id, const char *name);
|
||
|
extern int modem_set_mode(struct modem *m, enum MODEM_MODE mode);
|
||
|
|
||
|
/* ------------------------------------------------------------ */
|
||
|
/*
|
||
|
* local util functions
|
||
|
*/
|
||
|
|
||
|
/* simple toupper + strncmp */
|
||
|
static int toupper_strncmp(char *s1, char *s2, int n)
|
||
|
{
|
||
|
int i;
|
||
|
for(i = 0 ; i < n ; i++)
|
||
|
if(toupper(s1[i]) != s2[i])
|
||
|
return s1[i] - s2[i];
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int set_sreg(struct modem *m, int num, char c, int low, int hi, int *len)
|
||
|
{
|
||
|
if (!isdigit(c)) {
|
||
|
*len = 0;
|
||
|
c = '0';
|
||
|
}
|
||
|
else
|
||
|
*len = 1;
|
||
|
if ( c >= low + '0' && c <= hi + '0' )
|
||
|
return modem_set_sreg(m,num,c - '0');
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* ------------------------------------------------------------ */
|
||
|
|
||
|
|
||
|
static int process_A(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
int ret;
|
||
|
AT_DBG("AT A command...\n");
|
||
|
ret = modem_answer(m);
|
||
|
if (ret)
|
||
|
return -1;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int process_B(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
AT_DBG("AT B command...\n");
|
||
|
MODEM_DP(m) = DP_V22;
|
||
|
MODEM_AUTOMODE(m) = 0;
|
||
|
m->min_rate = 1200;
|
||
|
m->max_rate = 1200;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int process_D(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
int ret;
|
||
|
AT_DBG("AT D command...\n");
|
||
|
switch (toupper(*p)) {
|
||
|
case 'T':
|
||
|
modem_set_sreg(m,SREG_TONE_OR_PULSE,1);
|
||
|
break;
|
||
|
case 'P':
|
||
|
#ifdef NO_PULSE_DIAL
|
||
|
return -1;
|
||
|
#endif
|
||
|
modem_set_sreg(m,SREG_TONE_OR_PULSE,0);
|
||
|
break;
|
||
|
case 'L':
|
||
|
if(m->dial_string) {
|
||
|
modem_send_to_tty(m,"Dialing ",8);
|
||
|
modem_send_to_tty(m,m->dial_string,
|
||
|
strlen(m->dial_string));
|
||
|
modem_send_to_tty(m,"...",3);
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
}
|
||
|
p = 0;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
if (p)
|
||
|
strncpy(m->dial_string,p,sizeof(m->dial_string));
|
||
|
ret = modem_dial(m);
|
||
|
if (ret)
|
||
|
return -1;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int process_H(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
int ret;
|
||
|
AT_DBG("AT H command...\n");
|
||
|
switch(*p) {
|
||
|
case '1':
|
||
|
*len = 1;
|
||
|
ret = modem_hook(m, MODEM_HOOK_OFF);
|
||
|
break;
|
||
|
case '0':
|
||
|
*len = 1;
|
||
|
p++;
|
||
|
default:
|
||
|
if (isdigit(*p))
|
||
|
return -1;
|
||
|
ret = modem_hook(m, MODEM_HOOK_ON);
|
||
|
break;
|
||
|
}
|
||
|
return ret ? -1 : 0;
|
||
|
}
|
||
|
|
||
|
static int process_I(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
const char *s;
|
||
|
int c,i;
|
||
|
char *end;
|
||
|
AT_DBG("AT I command...\n");
|
||
|
c = strtoul (p,&end,0);
|
||
|
*len = end - p;
|
||
|
switch(c) {
|
||
|
case 1:
|
||
|
case 2:
|
||
|
modem_send_to_tty(m,modem_name,strlen(modem_name));
|
||
|
modem_send_to_tty(m,", ",2);
|
||
|
modem_send_to_tty(m,modem_version,strlen(modem_version));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
modem_send_to_tty(m,modem_author,strlen(modem_author));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
#if 0
|
||
|
case 2:
|
||
|
s = "Modem Manufacturer: unknown (TBD)";
|
||
|
modem_send_to_tty(m,s,strlen(s));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
s = "Modem Provider: unknown (TBD)";
|
||
|
modem_send_to_tty(m,s,strlen(s));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
#endif
|
||
|
case 3:
|
||
|
s = m->dev_name ? m->dev_name : "unknown";
|
||
|
modem_send_to_tty(m, s, strlen(s));
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
s = m->driver.name ? m->driver.name : "unknown";
|
||
|
modem_send_to_tty(m, s, strlen(s));
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
case 4:
|
||
|
for (i=0;i<24;i++) {
|
||
|
char str[24];
|
||
|
snprintf(str,sizeof(str),"s%.2d=%.3d ",i,m->sregs[i]);
|
||
|
modem_send_to_tty(m,str,strlen(str));
|
||
|
if (!((i+1)%8))
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
}
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
case 5:
|
||
|
modem_send_to_tty(m,"Stored Profile 0:",17);
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
#if 0
|
||
|
s = load_profile(m,0);
|
||
|
if (s!=NULL)
|
||
|
ret = print_sregs(m,s);
|
||
|
#endif
|
||
|
break;
|
||
|
case 6:
|
||
|
modem_send_to_tty(m, "Stored Profile 1:",17);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
#if 0
|
||
|
s = load_profile(m,1);
|
||
|
if (s!=NULL)
|
||
|
ret = print_sregs (m,s);
|
||
|
#endif
|
||
|
break;
|
||
|
case 7:
|
||
|
s = m->homolog->name;
|
||
|
modem_send_to_tty(m,"Country: ",9);
|
||
|
modem_send_to_tty(m,s,strlen(s));
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
case 0:
|
||
|
modem_send_to_tty(m,modem_name,strlen(modem_name));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int process_O(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
int ret;
|
||
|
AT_DBG("AT O command...\n");
|
||
|
ret = modem_online(m);
|
||
|
if (ret)
|
||
|
return -1;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int process_S(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
unsigned n = 0;
|
||
|
int val;
|
||
|
char *end;
|
||
|
AT_DBG("AT S command...\n");
|
||
|
n = strtoul(p,&end,0);
|
||
|
*len = end - p + 1;
|
||
|
p = end;
|
||
|
if ( n >= sizeof(m->sregs)/sizeof(m->sregs[0]) )
|
||
|
return -1;
|
||
|
switch(*p++) {
|
||
|
case '?':
|
||
|
val = modem_get_sreg(m,n);
|
||
|
if (val < 0)
|
||
|
return -1;
|
||
|
else {
|
||
|
char strval[16];
|
||
|
int l = snprintf(strval,sizeof(strval),"%d",val);
|
||
|
modem_send_to_tty(m, strval,l);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
}
|
||
|
return 0;
|
||
|
case '=':
|
||
|
val = strtoul(p, &end, 0);
|
||
|
*len += end - p;
|
||
|
return modem_set_sreg(m,n,val);
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int process_Z(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
AT_DBG("AT Z command...\n");
|
||
|
#if 1
|
||
|
switch(*p) {
|
||
|
case '1':
|
||
|
case '2':
|
||
|
case '3':
|
||
|
case '0':
|
||
|
*len = 1;
|
||
|
break;
|
||
|
default:
|
||
|
*len = 0;
|
||
|
break;
|
||
|
}
|
||
|
modem_reset(m);
|
||
|
return 0;
|
||
|
#else
|
||
|
char *s;
|
||
|
int set_num;
|
||
|
set_num = strtoul (p,&s,0);
|
||
|
*len = s-p;
|
||
|
if (set_num < 0 || set_num > 4 )
|
||
|
return -1;
|
||
|
|
||
|
if (set_num == 0) { /* ATZ0 - load value defined by ATYn */
|
||
|
set_num = m->sregs[SREG_DEFAULT_SETTING];
|
||
|
}
|
||
|
else {
|
||
|
set_num--;
|
||
|
}
|
||
|
|
||
|
AT_DBG("AT Z command - going to load set %d\n",set_num);
|
||
|
s = load_profile (m,set_num);
|
||
|
AT_DBG("AT Z command - done\n");
|
||
|
if (s != NULL) {
|
||
|
/* FIXME: modem reset must be done instead */
|
||
|
/* ... */
|
||
|
memcpy (m->sregs,s,sizeof (m->sregs));
|
||
|
return 0;
|
||
|
}
|
||
|
return -1;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* AT+ commands
|
||
|
*/
|
||
|
|
||
|
static int process_plus_GCI(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
static const char gci_string[] = "+GCI:";
|
||
|
char strval[8];
|
||
|
const struct homolog_set *h;
|
||
|
char *end;
|
||
|
unsigned long n;
|
||
|
AT_DBG ("AT+GCI...\n");
|
||
|
switch (*p) {
|
||
|
case '=':
|
||
|
p++;
|
||
|
*len = 1;
|
||
|
if (*p == '?') { /* show all country codes */
|
||
|
*len += 1;
|
||
|
modem_send_to_tty(m,gci_string,strlen(gci_string));
|
||
|
modem_send_to_tty(m,"(",1);
|
||
|
for(h=homolog_set;h->name;h++) {
|
||
|
n = sprintf(strval,"%x,",h->id);
|
||
|
modem_send_to_tty(m,strval,n);
|
||
|
}
|
||
|
modem_send_to_tty(m,")",1);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
}
|
||
|
else {
|
||
|
n = strtoul (p,&end,16);
|
||
|
if(end == p) {
|
||
|
return -1;
|
||
|
}
|
||
|
*len += end - p; p = end;
|
||
|
/* set country n */
|
||
|
if(modem_homolog_init(m,n,NULL))
|
||
|
return -1;
|
||
|
}
|
||
|
break;
|
||
|
case '?':
|
||
|
n = sprintf(strval,"%x",m->homolog->id);
|
||
|
modem_send_to_tty(m, "+GCI:",5);
|
||
|
modem_send_to_tty(m, strval, n);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
*len = 1;
|
||
|
break;
|
||
|
default:
|
||
|
*len = 0;
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int process_plus_MS(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
char strval[32];
|
||
|
struct dp_driver *drv;
|
||
|
char *end;
|
||
|
unsigned long n;
|
||
|
unsigned int dp_id;
|
||
|
int auto_mode,min_rate,max_rate;
|
||
|
int is_found=0;
|
||
|
|
||
|
AT_DBG ("AT+MS...\n");
|
||
|
switch (*p) {
|
||
|
case '=':
|
||
|
p++;
|
||
|
*len = 1;
|
||
|
if (*p == '?') {
|
||
|
*len += 1;
|
||
|
modem_send_to_tty(m,"(",1);
|
||
|
for(drv = modem_dp_drivers ; drv->id ; drv++ ) {
|
||
|
if(!drv->code || !drv->op) continue;
|
||
|
if(is_found++>0) modem_send_to_tty(m,",",1);
|
||
|
sprintf(strval,"%d",drv->id);
|
||
|
modem_send_to_tty(m,strval,strlen(strval));
|
||
|
}
|
||
|
modem_send_to_tty(m,"),(0,1),",1+7);
|
||
|
sprintf(strval,"(%u-%u),",MODEM_MIN_RATE,MODEM_MAX_RATE);
|
||
|
modem_send_to_tty(m,strval,strlen(strval));
|
||
|
modem_send_to_tty(m,strval,strlen(strval)-1);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#define PARSE_MS_ITEM(p,len,item) { \
|
||
|
n = strtoul (p,&end,0); \
|
||
|
if (end != p) { item = n; } \
|
||
|
*len += end - p; p = end; \
|
||
|
if (*p != ',') goto setup_ms; \
|
||
|
*len += 1; p++; \
|
||
|
}
|
||
|
|
||
|
dp_id = MODEM_DP(m);
|
||
|
auto_mode= MODEM_AUTOMODE(m);
|
||
|
min_rate = m->min_rate;
|
||
|
max_rate = m->max_rate;
|
||
|
|
||
|
PARSE_MS_ITEM(p,len,dp_id);
|
||
|
PARSE_MS_ITEM(p,len,auto_mode);
|
||
|
PARSE_MS_ITEM(p,len,min_rate);
|
||
|
PARSE_MS_ITEM(p,len,max_rate);
|
||
|
setup_ms:
|
||
|
if(dp_id != MODEM_DP(m)) {
|
||
|
for(drv = modem_dp_drivers ; drv->id ; drv++ ) {
|
||
|
if(drv->op && drv->code && drv->id == dp_id) {
|
||
|
is_found++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(!is_found) return -1;
|
||
|
}
|
||
|
if((auto_mode != 0 && auto_mode != 1) || min_rate > max_rate ||
|
||
|
min_rate < MODEM_MIN_RATE || max_rate > MODEM_MAX_RATE )
|
||
|
return -1;
|
||
|
MODEM_DP(m) = dp_id;
|
||
|
MODEM_AUTOMODE(m) = auto_mode;
|
||
|
m->min_rate = min_rate;
|
||
|
m->max_rate = max_rate;
|
||
|
break;
|
||
|
case '?':
|
||
|
n = sprintf(strval,"%d,%d,%u,%u",MODEM_DP(m),MODEM_AUTOMODE(m),
|
||
|
m->min_rate,m->max_rate);
|
||
|
modem_send_to_tty(m, strval, n);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
*len = 1;
|
||
|
break;
|
||
|
default:
|
||
|
*len = 0;
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int process_plus_FCLASS(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
char ch;
|
||
|
if(*p == '=' ) {
|
||
|
p++;
|
||
|
*len += 2;
|
||
|
if(*p == '?') {
|
||
|
modem_send_to_tty(m, "0" , 1);
|
||
|
#ifdef MODEM_CONFIG_FAX_CLASS1
|
||
|
modem_send_to_tty(m, ",1" , 2);
|
||
|
#endif
|
||
|
#ifdef MODEM_CONFIG_VOICE
|
||
|
modem_send_to_tty(m, ",8" , 2);
|
||
|
#endif
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
}
|
||
|
else if (isdigit(*p)) {
|
||
|
int val = *p - '0';
|
||
|
if ( val != 0
|
||
|
#ifdef MODEM_CONFIG_FAX_CLASS1
|
||
|
&& val != 1
|
||
|
#endif
|
||
|
#ifdef MODEM_CONFIG_VOICE
|
||
|
&& val != 8
|
||
|
#endif
|
||
|
)
|
||
|
return -1;
|
||
|
return modem_set_mode(m, val);
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
else if (*p == '?') {
|
||
|
*len += 1;
|
||
|
ch = '0' + m->mode;
|
||
|
modem_send_to_tty(m, &ch , 1);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Caller ID
|
||
|
*/
|
||
|
|
||
|
#ifdef MODEM_CONFIG_CID
|
||
|
static int process_CID(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
char ch;
|
||
|
if(*p == '=' ) {
|
||
|
p++;
|
||
|
*len += 2;
|
||
|
if(*p == '?') {
|
||
|
modem_send_to_tty(m, "0,1,2" , 5);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
}
|
||
|
else if (isdigit(*p) && *p - '0' < 3) {
|
||
|
m->cid_requested = *p - '0';
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
else if (*p == '?') {
|
||
|
*len += 1;
|
||
|
ch = '0' + m->cid_requested;
|
||
|
modem_send_to_tty(m, &ch , 1);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Voice commands
|
||
|
*/
|
||
|
|
||
|
#ifdef MODEM_CONFIG_VOICE
|
||
|
|
||
|
extern int modem_voice_set_device(struct modem *m, unsigned device);
|
||
|
extern int modem_voice_command(struct modem *m, enum VOICE_CMD cmd);
|
||
|
extern int modem_voice_init(struct modem *m);
|
||
|
|
||
|
|
||
|
|
||
|
struct voice_param {
|
||
|
unsigned *val;
|
||
|
unsigned min, max;
|
||
|
};
|
||
|
|
||
|
static int set_voice_params(struct modem *m, char *p, const char *cmd,
|
||
|
struct voice_param *param, int *len,
|
||
|
const char *prefix, const char *suffix)
|
||
|
{
|
||
|
char strval[32];
|
||
|
unsigned val[3];
|
||
|
struct voice_param *prm;
|
||
|
int i;
|
||
|
char *end;
|
||
|
|
||
|
*len += 1;
|
||
|
if( *p == '=' ) {
|
||
|
p++;
|
||
|
if(*p == '?') {
|
||
|
*len += 1;
|
||
|
sprintf(strval, "+%s=", cmd);
|
||
|
modem_send_to_tty(m, strval, strlen(strval));
|
||
|
if(prefix)
|
||
|
modem_send_to_tty(m, prefix, strlen(prefix));
|
||
|
prm = param;
|
||
|
while(prm->val) {
|
||
|
sprintf(strval, "%d-%d", prm->min, prm->max);
|
||
|
modem_send_to_tty(m, strval, strlen(strval));
|
||
|
prm++;
|
||
|
if(prm->val)
|
||
|
modem_send_to_tty(m, ",", 1);
|
||
|
}
|
||
|
if(suffix)
|
||
|
modem_send_to_tty(m, suffix, strlen(suffix));
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if(prefix) {
|
||
|
if(strncmp(p,prefix,strlen(prefix)))
|
||
|
return -1;
|
||
|
p += strlen(prefix);
|
||
|
*len += strlen(prefix);
|
||
|
}
|
||
|
|
||
|
prm = param;
|
||
|
for (i = 0; prm->val && i < sizeof(val)/sizeof(val[0]) ; i++ ) {
|
||
|
val[i] = strtoul(p,&end,0);
|
||
|
if( (prm->min && val[i] < prm->min) ||
|
||
|
(prm->max && val[i] > prm->max) )
|
||
|
return -1;
|
||
|
*len += end - p;
|
||
|
p = end;
|
||
|
prm++;
|
||
|
if(prm->val) {
|
||
|
if(*p != ',')
|
||
|
return -1;
|
||
|
*len += 1;
|
||
|
p++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(suffix) {
|
||
|
if(strncmp(p,suffix,strlen(suffix)))
|
||
|
return -1;
|
||
|
*len += strlen(suffix);
|
||
|
}
|
||
|
|
||
|
prm = param;
|
||
|
for (i = 0; prm->val && i < sizeof(val)/sizeof(val[0]) ; i++ ) {
|
||
|
*prm->val = val[i];
|
||
|
prm++;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
else if ( *p == '?' ) {
|
||
|
sprintf(strval, "+%s=", cmd);
|
||
|
modem_send_to_tty(m, strval, strlen(strval));
|
||
|
if(prefix)
|
||
|
modem_send_to_tty(m, prefix, strlen(prefix));
|
||
|
prm = param;
|
||
|
while(prm->val) {
|
||
|
sprintf(strval, "%d", *prm->val);
|
||
|
modem_send_to_tty(m, strval, strlen(strval));
|
||
|
prm++;
|
||
|
if(prm->val)
|
||
|
modem_send_to_tty(m, ",", 1);
|
||
|
}
|
||
|
if(suffix)
|
||
|
modem_send_to_tty(m, suffix, strlen(suffix));
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static int process_voice_command(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
AT_DBG("voice cmd: %s\n", p);
|
||
|
*len += 2;
|
||
|
/* AT+VIP */
|
||
|
if(!toupper_strncmp(p,"IP",2)) {
|
||
|
return modem_voice_init(m);
|
||
|
}
|
||
|
/* AT+VNH=0,1 */
|
||
|
else if(!toupper_strncmp(p,"NH",2)) {
|
||
|
unsigned val = 0;
|
||
|
struct voice_param params[] = {
|
||
|
{&val,0,1}, {} };
|
||
|
return set_voice_params(m,p+2,"VNH",params,len,NULL,NULL);
|
||
|
}
|
||
|
/* AT+VGT=127 */
|
||
|
else if(!toupper_strncmp(p,"GT",2)) {
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.tx_gain,0,128}, {} };
|
||
|
return set_voice_params(m,p+2,"VGT",params,len,NULL,NULL);
|
||
|
}
|
||
|
/* AT+VGR=127 */
|
||
|
else if(!toupper_strncmp(p,"GR",2)) {
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.rx_gain,0,128}, {} };
|
||
|
return set_voice_params(m,p+2,"VGR",params,len,NULL,NULL);
|
||
|
}
|
||
|
/* AT+VIT= */
|
||
|
else if(!toupper_strncmp(p,"IT",2)) {
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.inactivity_timer,0,255}, {} };
|
||
|
return set_voice_params(m,p+2,"VIT",params,len,NULL,NULL);
|
||
|
}
|
||
|
/* AT+VSD=128,50 */
|
||
|
else if(!toupper_strncmp(p,"SD",2)) {
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.silence_detect_sensitivity,0,255},
|
||
|
{&m->voice_info.silence_detect_period,0,255},
|
||
|
{}
|
||
|
};
|
||
|
return set_voice_params(m,p+2,"VSD",params,len,NULL,NULL);
|
||
|
}
|
||
|
/* AT+VSM=1,8000 */
|
||
|
else if(!toupper_strncmp(p,"SM",2)) {
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.comp_method,0,1},
|
||
|
{&m->voice_info.sample_rate,8000,8000},
|
||
|
{}
|
||
|
};
|
||
|
return set_voice_params(m,p+2,"VSM",params,len,NULL,NULL);
|
||
|
}
|
||
|
/* AT+VLS=1 */
|
||
|
else if(!toupper_strncmp(p,"LS",2)) {
|
||
|
unsigned dev = (m->voice_obj != NULL);
|
||
|
struct voice_param params[] = {
|
||
|
{&dev,0,1}, {} };
|
||
|
int ret = set_voice_params(m,p+2,"VLS",params,len,NULL,NULL);
|
||
|
if(ret)
|
||
|
return ret;
|
||
|
return modem_voice_set_device(m, dev);
|
||
|
}
|
||
|
/* AT +VRX, +VTX, +VTR */
|
||
|
else if(!toupper_strncmp(p,"TX",2))
|
||
|
return modem_voice_command(m,VOICE_CMD_STATE_TX);
|
||
|
else if(!toupper_strncmp(p,"RX",2))
|
||
|
return modem_voice_command(m,VOICE_CMD_STATE_RX);
|
||
|
else if(!toupper_strncmp(p,"TR",2))
|
||
|
return modem_voice_command(m,VOICE_CMD_STATE_DUPLEX);
|
||
|
/* AT+VTS=[933,,150] */
|
||
|
else if(!toupper_strncmp(p,"TS",2)) {
|
||
|
unsigned orig_len;
|
||
|
int ret;
|
||
|
p += 2;
|
||
|
orig_len = *len;
|
||
|
{
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.tone1_freq,0,0},
|
||
|
{&m->voice_info.tone2_freq,0,0},
|
||
|
{&m->voice_info.tone_duration,0,6000},
|
||
|
{} };
|
||
|
if(*p == '?' || (*p == '=' && *(p+1) == '?' ))
|
||
|
return set_voice_params(m,p,"VTS",params,len,NULL,NULL);
|
||
|
|
||
|
ret = set_voice_params(m,p,"VTS",params,len,"[","]");
|
||
|
if(!ret)
|
||
|
return modem_voice_command(m, VOICE_CMD_BEEP);
|
||
|
}
|
||
|
{
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.dtmf_symbol,0,0},
|
||
|
{&m->voice_info.tone_duration,0,100},
|
||
|
{} };
|
||
|
*len = orig_len;
|
||
|
ret = set_voice_params(m,p,"VTS",params,len,"{","}");
|
||
|
if(!ret)
|
||
|
return modem_voice_command(m, VOICE_CMD_DTMF);
|
||
|
}
|
||
|
{
|
||
|
struct voice_param params[] = {
|
||
|
{&m->voice_info.dtmf_symbol,0,0}, {} };
|
||
|
*len = orig_len;
|
||
|
ret = set_voice_params(m,p,"VTS",params,len,NULL,NULL);
|
||
|
if(!ret)
|
||
|
return modem_voice_command(m, VOICE_CMD_DTMF);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
#else
|
||
|
#define process_voice_command(m,p,plen) (-1)
|
||
|
#endif /* MODEM_CONFIG_VOICE */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Fax commands
|
||
|
*/
|
||
|
|
||
|
#ifdef MODEM_CONFIG_FAX
|
||
|
extern int FAX_class1_command(void *obj, unsigned cmd, unsigned param);
|
||
|
|
||
|
|
||
|
static int process_fax_command(struct modem *m, char *p, int *len)
|
||
|
{
|
||
|
unsigned val; char *end;
|
||
|
AT_DBG("fax cmd: %s\n", p);
|
||
|
*len += 2;
|
||
|
/* +FTS= */
|
||
|
if(!toupper_strncmp(p,"TS=",3)) {
|
||
|
*len += 1;
|
||
|
p += 3;
|
||
|
val = strtoul(p,&end,0);
|
||
|
if(p == end)
|
||
|
return -1;
|
||
|
*len += end - p;
|
||
|
p = end;
|
||
|
return FAX_class1_command(m->fax_obj, FAX_CMD_FTS, val);
|
||
|
}
|
||
|
/* +FRS= */
|
||
|
else if(!toupper_strncmp(p,"RS=",3)) { // FIXME: abort on tty input
|
||
|
*len += 1;
|
||
|
p += 3;
|
||
|
val = strtoul(p,&end,0);
|
||
|
if(p == end)
|
||
|
return -1;
|
||
|
*len += end - p;
|
||
|
p = end;
|
||
|
return FAX_class1_command(m->fax_obj, FAX_CMD_FRS, val);
|
||
|
}
|
||
|
/* +FTM= */
|
||
|
else if(!toupper_strncmp(p,"TM=",3)) {
|
||
|
*len += 2;
|
||
|
p+= 3;
|
||
|
if(*p == '?') {
|
||
|
modem_send_to_tty(m,"24,48,72,73,74,96,97,98,121,122,145,146",39);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
return 0;
|
||
|
}
|
||
|
else {
|
||
|
val = strtoul(p,&end,0);
|
||
|
if(p == end)
|
||
|
return -1;
|
||
|
*len += end - p - 1;
|
||
|
p = end;
|
||
|
return FAX_class1_command(m->fax_obj, FAX_CMD_FTM, val);
|
||
|
}
|
||
|
}
|
||
|
/* +FRM= */
|
||
|
else if(!toupper_strncmp(p,"RM=",3)) {
|
||
|
*len += 2;
|
||
|
p+= 3;
|
||
|
if(*p == '?') {
|
||
|
modem_send_to_tty(m,"24,48,72,73,74,96,97,98,121,122,145,146",39);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
}
|
||
|
else {
|
||
|
val = strtoul(p,&end,0);
|
||
|
if(p == end)
|
||
|
return -1;
|
||
|
*len += end - p - 1;
|
||
|
p = end;
|
||
|
return FAX_class1_command(m->fax_obj, FAX_CMD_FRM, val);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
/* +FRH= */
|
||
|
else if(!toupper_strncmp(p,"RH=",3)) {
|
||
|
*len += 2;
|
||
|
p+= 3;
|
||
|
if(*p == '?') {
|
||
|
modem_send_to_tty(m,"3",1);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
return 0;
|
||
|
}
|
||
|
else if (isdigit(*p))
|
||
|
return FAX_class1_command(m->fax_obj, FAX_CMD_FRH, *p - '0');
|
||
|
return -1;
|
||
|
}
|
||
|
/* +FTH= */
|
||
|
else if(!toupper_strncmp(p,"TH=",3)) {
|
||
|
*len += 2;
|
||
|
p+= 3;
|
||
|
if(*p == '?') {
|
||
|
modem_send_to_tty(m,"3",1);
|
||
|
modem_send_to_tty(m, CRLF_CHARS(m), 2);
|
||
|
return 0;
|
||
|
}
|
||
|
else if (isdigit(*p))
|
||
|
return FAX_class1_command(m->fax_obj, FAX_CMD_FTH, *p - '0');
|
||
|
return -1;
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
#else
|
||
|
#define process_fax_command(m,p,plen) (-1)
|
||
|
#endif /* MODEM_CONFIG_FAX */
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ */
|
||
|
|
||
|
/*
|
||
|
* Main AT processor
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
int process_at_command(struct modem *m, char *cmd)
|
||
|
{
|
||
|
char c, *p = cmd;
|
||
|
int len = 0, ret = -1;
|
||
|
|
||
|
/* verify 'AT' */
|
||
|
if (toupper(*p++) != 'A' || toupper(*p++) != 'T')
|
||
|
return -1;
|
||
|
|
||
|
while(*p) {
|
||
|
c = toupper(*p++);
|
||
|
len = 0;
|
||
|
switch(c) {
|
||
|
|
||
|
case 'A': /* ATA */
|
||
|
ret = process_A(m,p,&len);
|
||
|
return ret;
|
||
|
case 'B': /* ATB */
|
||
|
ret = process_B(m,p,&len);
|
||
|
break;
|
||
|
case 'D': /* ATD */
|
||
|
ret = process_D(m,p,&len);
|
||
|
return ret;
|
||
|
case 'E': /* ATE */
|
||
|
ret = set_sreg(m,SREG_ECHO,*p,0,1,&len);
|
||
|
break;
|
||
|
case 'H': /* ATH */
|
||
|
ret = process_H(m,p,&len);
|
||
|
break;
|
||
|
case 'I': /* ATI */
|
||
|
ret = process_I(m,p,&len);
|
||
|
break;
|
||
|
case 'L': /* ATL */
|
||
|
ret = set_sreg(m,SREG_SPEAKER_VOLUME,*p,0,3,&len);
|
||
|
if(!ret) modem_update_speaker(m);
|
||
|
break;
|
||
|
case 'M': /* ATM */
|
||
|
ret = set_sreg(m,SREG_SPEAKER_CONTROL,*p,0,2,&len);
|
||
|
if(!ret) modem_update_speaker(m);
|
||
|
break;
|
||
|
case 'N': /* ATN */
|
||
|
ret = set_sreg(m,SREG_AUTOMODE,*p,0,1,&len);
|
||
|
break;
|
||
|
case 'O': /* ATO */
|
||
|
ret = process_O(m,p,&len);
|
||
|
break;
|
||
|
case 'P': /* ATP */
|
||
|
#ifdef NO_PULSE_DIAL
|
||
|
return -1;
|
||
|
#endif
|
||
|
ret = modem_set_sreg(m,SREG_TONE_OR_PULSE,0);
|
||
|
break;
|
||
|
case 'Q': /* ATQ */
|
||
|
ret = set_sreg(m,SREG_QUIET,*p,0,1,&len);
|
||
|
break;
|
||
|
case 'S': /* ATS */
|
||
|
ret = process_S(m,p,&len);
|
||
|
break;
|
||
|
case 'T': /* ATT */
|
||
|
ret = modem_set_sreg(m,SREG_TONE_OR_PULSE,1);
|
||
|
break;
|
||
|
case 'V': /* ATV */
|
||
|
ret = set_sreg(m,SREG_VERBOSE,*p,0,1,&len);
|
||
|
break;
|
||
|
case 'X': /* ATX */
|
||
|
ret = set_sreg(m,SREG_X_CODE,*p,0,4,&len);
|
||
|
break;
|
||
|
case 'Y': /* ATY */
|
||
|
ret = set_sreg(m,SREG_DEFAULT_SETTING,*p,0,3,&len);
|
||
|
break;
|
||
|
case 'Z': /* ATZ */
|
||
|
ret = process_Z(m,p,&len);
|
||
|
return ret;
|
||
|
|
||
|
case '#': /* AT# */
|
||
|
#ifdef MODEM_CONFIG_CID
|
||
|
if(!toupper_strncmp(p,"CID",3)) {
|
||
|
p+= 3;
|
||
|
ret = process_CID(m, p, &len);
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
ret = -1;
|
||
|
break;
|
||
|
case '%': /* AT% */
|
||
|
c = toupper(*p++);
|
||
|
switch (c) {
|
||
|
case 'C': /* AT%C */
|
||
|
ret = set_sreg(m,SREG_COMP,*p,0,3,&len);
|
||
|
break;
|
||
|
case 'E': /* AT%E */
|
||
|
ret = set_sreg(m,SREG_LINE_QUALITY_CONTROL,*p,0,2,&len);
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
} /* end AT% */
|
||
|
break;
|
||
|
case '&':
|
||
|
c = toupper(*p++);
|
||
|
switch (c) {
|
||
|
case 'A': /* AT&A */
|
||
|
ret = set_sreg(m,SREG_CONNNECT_MSG_FORMAT,*p,0,7,&len);
|
||
|
break;
|
||
|
case 'C': /* AT&C */
|
||
|
ret = set_sreg(m,SREG_CD,*p,0,1,&len);
|
||
|
break;
|
||
|
case 'D': /* AT&D */
|
||
|
case 'R': /* AT&R */
|
||
|
case 'S': /* AT&S */
|
||
|
len = isdigit(*p)?1:0; ret = 0;
|
||
|
break;
|
||
|
case 'E': /* AT&E */
|
||
|
ret = set_sreg(m,SREG_CONNNECT_MSG_SPEED_SRC,*p,0,1,&len);
|
||
|
break;
|
||
|
case 'F': /* AT&F */
|
||
|
len = isdigit(*p)?1:0; ret = 0;
|
||
|
break;
|
||
|
case 'H': /* AT&H */
|
||
|
ret = set_sreg(m,SREG_FLOW_CONTROL,*p,0,1,&len);
|
||
|
break;
|
||
|
case 'K': /* AT&K */
|
||
|
ret = set_sreg(m,SREG_COMP,*p,0,3,&len);
|
||
|
break;
|
||
|
case 'P': /* AT&P */
|
||
|
ret = set_sreg(m,SREG_PULSE_RATIO,*p,0,3,&len);
|
||
|
break;
|
||
|
case 'V': /* AT&V */
|
||
|
case 'W': /* AT&W */
|
||
|
ret = -1;
|
||
|
break;
|
||
|
#if 0
|
||
|
case 'Z': /* AT&Z */
|
||
|
c = toupper(*p++);
|
||
|
if (c == 'L'){
|
||
|
ret = print_last_dial_string (m);
|
||
|
break; /* ZL */
|
||
|
}
|
||
|
break; /* Z */
|
||
|
#endif
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
break;
|
||
|
case '*': /* AT* */
|
||
|
c = toupper(*p++);
|
||
|
switch(c) {
|
||
|
case 'B': /* AT*B */
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
break;
|
||
|
case '+':
|
||
|
c = toupper(*p++);
|
||
|
switch (c) {
|
||
|
#if 0
|
||
|
case 'D': /* AT+D */
|
||
|
c = toupper(*p++);
|
||
|
switch (c) {
|
||
|
case 'C': /* AT+DC */
|
||
|
break;
|
||
|
case 'S': /* AT+DS */
|
||
|
break;
|
||
|
case 'R': /* AT+DR */
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
case 'G': /* AT+G - generic DCE cntrl */
|
||
|
c = toupper(*p++);
|
||
|
switch (c) {
|
||
|
case 'C': /* AT+GCI[=|?|=?] */
|
||
|
if (toupper(*p++) == 'I')
|
||
|
ret = process_plus_GCI(m,p,&len);
|
||
|
else
|
||
|
return -1;
|
||
|
break;
|
||
|
case 'M': /* AT+GM[I|M|R] */
|
||
|
c = toupper(*p++);
|
||
|
switch (c) {
|
||
|
case 'I': /* AT+GMI */
|
||
|
modem_send_to_tty(m,modem_author,strlen(modem_author));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
case 'M': /* AT+GMM */
|
||
|
modem_send_to_tty(m,modem_name,strlen(modem_name));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
case 'R': /* AT+GMR */
|
||
|
modem_send_to_tty(m,modem_version,strlen(modem_version));
|
||
|
modem_send_to_tty(m,CRLF_CHARS(m),2);
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
ret = 0;
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
break;
|
||
|
case 'F': /* AT+F */
|
||
|
if(!toupper_strncmp(p,"CLASS",5)) {
|
||
|
p+= 5;
|
||
|
ret = process_plus_FCLASS(m, p, &len);
|
||
|
}
|
||
|
else
|
||
|
ret = process_fax_command(m, p, &len);
|
||
|
break;
|
||
|
#ifdef MODEM_CONFIG_VOICE
|
||
|
/* AT+IFC=2,2 */ /* TBD: flow control - not voice command */
|
||
|
case 'I':
|
||
|
// FIXME
|
||
|
if(!toupper_strncmp(p,"FC=2,2",6)) {
|
||
|
p+= 6;
|
||
|
ret = 0;
|
||
|
}
|
||
|
else
|
||
|
ret = -1;
|
||
|
break;
|
||
|
#endif
|
||
|
case 'M': /* AT+M */
|
||
|
c = toupper (*p++);
|
||
|
if (c == 'S')
|
||
|
ret = process_plus_MS(m,p,&len);
|
||
|
break;
|
||
|
case 'V':
|
||
|
if(m->mode != MODEM_MODE_VOICE)
|
||
|
return -1;
|
||
|
#ifdef MODEM_CONFIG_CID
|
||
|
if(!toupper_strncmp(p,"CID",3)) {
|
||
|
p+= 3;
|
||
|
ret = process_CID(m, p, &len);
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
ret = process_voice_command(m, p, &len);
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
break;
|
||
|
case '\\':
|
||
|
c = toupper(*p++);
|
||
|
switch (c) {
|
||
|
case 'A': /* AT\A */
|
||
|
if(isdigit(*p)) len++;
|
||
|
// ret = set_sreg(m,SREG_V42_BASEREG,*p,0,5,&len);
|
||
|
break;
|
||
|
#if 0
|
||
|
case 'B': /* AT\B */
|
||
|
break;
|
||
|
case 'K': /* AT\K */
|
||
|
break;
|
||
|
#endif
|
||
|
case 'N': /* AT\N */
|
||
|
ret = set_sreg(m,SREG_EC,*p,0,5,&len);
|
||
|
break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
AT_DBG("unknown command `%c` (%x).\n",c,c);
|
||
|
return -1;
|
||
|
}
|
||
|
if (ret) return ret;
|
||
|
p += len;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|