blob: 7c4618a32cda3dfbee8cf358c6ac6edcc14dac78 [file] [log] [blame]
/*
* modem_controller.c -- modem controller module
*
* (C) Copyright [2006-2008] Marvell International Ltd.
* All Rights Reserved
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <cutils/properties.h>
#include <termios.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/prctl.h>
#if 0// ndef BIONIC
#include <linux/prctl.h>
#endif
#include "pxa_dbg.h"
#include "ppprd_linux.h"
#include "modem_platform.h"
#include "modem_controller.h"
#include <linux/tty.h>
#include "utilities.h"
#include "ml_utils.h"
#include "cmux.h"
#include "utlTimer.h"
#ifdef PPP_WITHOUT_ATSRV
static int b_unlink_sent = 0;
#endif
int ppp_at_fd;
int ppp_modem_fd = 0;
int ppprd_fd;
int pipefd[2];
int ppp_cm_fd;
#ifdef ADDITIONAL_MODEM_DEVICE
int ppp_at_fd1;
int ppp_modem_fd1 = 0;
static struct at_channel_struct ppp_modem1;
static struct at_channel_struct ppp_at1;
#endif
#ifdef UART2_AT
int ppp_at_fd2;
int ppp_uart2_fd;
static struct at_channel_struct ppp_uart2;
static struct at_channel_struct ppp_at2;
#endif
#ifdef PPP_PSEUDO_DEVICE
int ppp_at_fd_pseudo = 0;
int ppp_modem_fd_pseudo = 0;
static struct at_channel_struct ppp_modem_pseudo;
static struct at_channel_struct ppp_at_pseudo;
#endif
int ppp_gsm_fd[MAX_MUX];
static struct at_channel_struct ppp_modem;
static struct at_channel_struct ppp_at;
static struct at_channel_struct ppp_gsm[MAX_MUX];
struct ml_fifo ppp_fifo;
unsigned int old_connected_ppp_cid = INVALID_CID;
modem_control_interface modem_if;
static bool ath_data;
static bool ato_data;
static speed_t baud_bits[] = {
0, B9600, B19200, B38400, B57600, B115200, B230400, B460800
};
static Serial serial;
pthread_mutex_t channelid_lock;
#define MODEM_AT_STATISTICS
#ifdef MODEM_AT_STATISTICS
struct modem_at_statistics {
int cmd_count;
int cmd_byte;
int rsp_count;
int rsp_byte;
};
struct modem_at_statistics at_statistics;
#endif
extern void setup_callback_funcs(ppp_cb_funcs *);
extern int get_modem_state(void);
char *get_ppp_apn()
{
return modem_if.pdp_params.apn;
}
char get_ppp_iptype()
{
return modem_if.pdp_params.ip_type;
}
int get_modem_data_mode_fd(void)
{
int i = 0;
for ( i = 0; i < MAX_MODEM_CHANNLE; i++)
{
if (modem_if.modem_state[i] == ACM_DATA_MODE)
break;
}
if (i < MAX_MODEM_CHANNLE)
return modem_if.modem_fd[i];
else
return ppp_modem_fd;
}
int get_modem_data_mode_at_fd(void)
{
int modem_fd = get_modem_data_mode_fd();
int at_fd = 0;
if (modem_fd == ppp_modem_fd)
at_fd = ppp_at_fd;
#ifdef ADDITIONAL_MODEM_DEVICE
else if (modem_fd == ppp_modem_fd1)
at_fd = ppp_at_fd1;
#endif
#ifdef UART2_AT
else if (modem_fd == ppp_uart2_fd)
at_fd = ppp_at_fd2;
#endif
#ifdef PPP_PSEUDO_DEVICE
else if (modem_fd == ppp_modem_fd_pseudo)
at_fd = ppp_at_fd_pseudo;
#endif
else {
int i = 0;
for ( i = 0; i <MAX_MUX -1; i++) {
if ( modem_fd == ppp_gsm_fd[i]) {
at_fd = ppp_gsm_fd[MAX_MUX - 1];
break;
}
}
}
if (at_fd == 0)
at_fd = ppp_at_fd;
return at_fd;
}
void set_modem_if_state(int fd, unsigned int state)
{
int i = 0;
INFOMSG("%s: fd %d, modem_state %d", __func__, fd, state);
if (fd == 0)
{
for ( i = 0; i < MAX_MODEM_CHANNLE; i++)
modem_if.modem_state[i] = state;
return;
}
for ( i = 0; i < MAX_MODEM_CHANNLE; i++)
{
if (modem_if.modem_fd[i] == fd)
break;
}
if (i < MAX_MODEM_CHANNLE)
{
modem_if.modem_state[i] = state;
INFOMSG("%s: update fd %d with modem_state %d", __func__, fd, state);
}
else
{
for ( i = 0; i < MAX_MODEM_CHANNLE; i++)
{
if (modem_if.modem_fd[i] == 0)
{
modem_if.modem_fd[i] = fd;
modem_if.modem_state[i] = state;
INFOMSG("%s: set fd %d with modem_state %d", __func__, fd, state);
break;
}
}
}
}
unsigned int get_modem_if_state(int fd)
{
int i = 0;
if (fd == 0)
{
for ( i = 0; i < MAX_MODEM_CHANNLE; i++)
{
if (modem_if.modem_state[i] == ACM_DATA_MODE)
break;
}
goto end;
}
for ( i = 0; i < MAX_MODEM_CHANNLE; i++)
{
if (modem_if.modem_fd[i] == fd)
break;
}
end:
if (i < MAX_MODEM_CHANNLE)
return modem_if.modem_state[i];
else
return ACM_CONTROL_MODE;
}
int modem_cmux_is_data_mode(void)
{
int i = 0;
for (i = 0; i < MAX_MUX - 1; i ++)
{
if (get_modem_if_state(ppp_gsm_fd[i]) == ACM_DATA_MODE)
break;
}
if (i < MAX_MUX - 1)
return TRUE;
else
return FALSE;
}
/**
* Reads data from the AT channel, save in chan->at_buffer.
* Assumes it has exclusive read access to the FD
*/
static int read_channel(struct at_channel_struct *chan)
{
ssize_t count = 0;
size_t len = chan->at_buffer_tail - chan->at_buffer_head;
if (len == 0)
{
/* empty buffer or full buffer */
chan->at_buffer_head = chan->at_buffer;
chan->at_buffer_tail = chan->at_buffer;
memset(chan->at_buffer, 0, AT_CMD_BUF_SIZE);
}
else if (len > 0 && len < AT_CMD_BUF_SIZE)
{
/* there's data in the buffer from the last get_line*/
memmove(chan->at_buffer, chan->at_buffer_head, len);
chan->at_buffer_head = chan->at_buffer;
chan->at_buffer_tail = chan->at_buffer_head + len;
memset(chan->at_buffer_tail, 0, AT_CMD_BUF_SIZE - len);
}
else
{
/* there's an at buffer pointer error */
DBGMSG("at channel pointer ERROR, reset at channel!\n");
chan->at_buffer_head = chan->at_buffer;
chan->at_buffer_tail = chan->at_buffer;
memset(chan->at_buffer, 0, AT_CMD_BUF_SIZE);
len = 0;
}
do
{
DBGMSG("begin read fd=%d, bufsize=%d\n", chan->tty_fd, AT_CMD_BUF_SIZE - len);
count = read(chan->tty_fd, chan->at_buffer_tail , AT_CMD_BUF_SIZE - len);
DBGMSG("after read fd=%d, count=%d\n", chan->tty_fd, count);
} while (count < 0 && errno == EINTR);
if (count > 0) {
INFOMSG("read_channel: receive[%d]:%s\n", count, chan->at_buffer_head);
}
if (count > 0)
{
#ifdef PPP_WITHOUT_ATSRV
b_unlink_sent = 0;
/* echo the received data from modem */
if (modem_if.echo_mode == MODEM_ECHO_MODE && chan == &ppp_modem)
writen(ppp_modem_fd, chan->at_buffer_tail, count);
#endif
chan->at_buffer_tail += count; /* relocate at_buffer_tail */
}
else
{
#ifdef PPP_WITHOUT_ATSRV
if(ioctl(ppp_at_fd, IOCTL_MODEM_STATUS, NULL) != STATE_ONLINE)
{
if (get_modem_if_state(chan->tty_fd) == ACM_DATA_MODE && !b_unlink_sent)
{
INFOMSG("%s: modem crash, send linkdown\n", __func__);
modem_parse_atcmd((U_CHAR *)("\r\n+CSQ:99,99\r\n"), strlen("\r\n+CSQ:99,99\r\n"), FALSE);
b_unlink_sent = 1;
}
sleep(1);
}
#endif
/* read error encountered or EOF reached */
if (count == 0)
{
DBGMSG("fd=%d: EOF reached", chan->tty_fd);
}
else
{
INFOMSG("fd=%d: read error %s", chan->tty_fd, strerror(errno));
}
}
return count;
}
/**
* returns NULL if there is no complete line
*/
static U_CHAR *find_next_eol(U_CHAR *cur, U_CHAR *end, int smsControlCharConsider)
{
if(!smsControlCharConsider)
{
while (cur < end && *cur != '\r' && *cur != '\n') cur++;
}
else
{
/*SMS control character: control-z(0x1a), escape(0x1b)*/
while (cur < end && *cur != '\r' && *cur != '\n' && *cur != 0x1a && *cur != 0x1b) cur++;
}
return cur == end ? NULL : cur;
}
/* get line from chan->at_buffer
* if not complete line in at_buffer, return NULL.
*/
static U_CHAR *get_line(struct at_channel_struct *chan, int smsControlCharConsider)
{
ssize_t count;
U_CHAR *p_sol = NULL;
U_CHAR *p_eol = NULL;
U_CHAR *ret = NULL;
if (chan->at_buffer_head == chan->at_buffer_tail) return NULL;
p_sol = chan->at_buffer_head;
/* skip over leading newlines if it is exist */
while(*p_sol == '\r' || *p_sol == '\n')
{
p_sol++;
}
/* meaningless, discard */
if (p_sol >= chan->at_buffer_tail)
{
chan->at_buffer_head = chan->at_buffer_tail;
return NULL;
}
p_eol = find_next_eol(p_sol, chan->at_buffer_tail, smsControlCharConsider);
if (p_eol)
{
/* a full line in the buffer. */
ret = chan->at_buffer_head;
if (*(p_eol + 1) == '\n' && (p_eol + 2 <= chan->at_buffer_tail))
chan->at_buffer_head = p_eol + 2;
else
chan->at_buffer_head = p_eol + 1;
/* remove unexpected '\0'*/
while (*ret == '\0' && ret < chan->at_buffer_head)
ret++;
chan->cur_line_len = chan->at_buffer_head - ret;
}
return ret;
}
struct ppp_cm_msg {
char enable;
char cid;
};
struct cm_ppp_msg {
char status;
};
static void send_msg_to_cm()
{
struct ppp_cm_msg msg;
msg.enable = 1;
msg.cid = modem_if.modem_current_cid;
writen(ppp_cm_fd, &msg, sizeof(struct ppp_cm_msg));
}
static int handle_msg_from_cm()
{
struct cm_ppp_msg msg;
int len;
len = read(ppp_cm_fd, &msg, sizeof(struct cm_ppp_msg));
if (len != sizeof(struct cm_ppp_msg)) {
return -1;
}
return 0;
}
static void handle_dial(int modem_fd)
{
char value[PROPERTY_VALUE_MAX] = { '\0' };
int simid = 0;
/* get the value of ppp used cid property */
property_get(PROP_PPP_CID, value, NULL);
if (atoi(value) > 0) /* means the last ppp have not disconnect data connection successfully */
old_connected_ppp_cid = atoi(value) - 1; /* when new ppp connected, the old one should be disconnected */
else
old_connected_ppp_cid = INVALID_CID; /* when new ppp connected, no old one should be disconnected */
memset(value, 0x00, PROPERTY_VALUE_MAX);
/* set a property to let up layer know the ppp cid */
sprintf(value, "%d", modem_if.modem_current_cid + 1);
property_set(PROP_PPP_CID, value);
/*send msg to CM to tear down the ccinet first if needed*/
//send_msg_cm();
/* reply "CONNECT" to PC, enter ACM_DATA_MODE */
writen(modem_fd, "\r\nCONNECT\r\n", strlen("\r\nCONNECT\r\n"));
set_modem_if_state(modem_fd, ACM_DATA_MODE);
INFOMSG(" enter ACM_DATA_MODE, cid is %u\n", modem_if.modem_current_cid);
modem_if.ppp_cbs.reset();
modem_if.ppp_cbs.set_cid(modem_if.modem_current_cid);
#ifdef ADDITIONAL_MODEM_DEVICE
if (modem_fd == ppp_modem_fd1)
simid = 1;
#endif
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPSIMID, simid);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPON, modem_if.modem_current_cid);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPSETCB);
}
static void store_configure_params(U_CHAR *line, int len)
{
char lineBuf[AT_CMD_BUF_SIZE] = {0};
int cid = 0, err = 0;
char *p, *apn, *ipType;
if (len >= AT_CMD_BUF_SIZE)
goto end;
memcpy(lineBuf, line, len);
p = lineBuf;
err = at_start_with_tok(&p, '=');
if (err < 0) goto end;
err = at_tok_nextint(&p, &cid);
if (err < 0) goto end;
err = at_tok_nextstr(&p, &ipType);
if (err < 0) goto end;
err = at_tok_nextstr(&p, &apn);
if (err < 0) goto end;
//(void)sscanf((const char *)line, "%*[^0-9]%d,\"%[^\"],\"%[^\"]", &cid, iptypePart, apnPart);
ERRMSG("%s:cid %d, iptype %s, apn %s", __func__, cid, ipType, apn);
modem_if.modem_current_cid = cid -1;
if (strlen(apn) > 0)
strncpy(modem_if.pdp_params.apn, apn, sizeof(modem_if.pdp_params.apn) -1);
if (strcasecmp(ipType,"IPV4V6") == 0)
modem_if.pdp_params.ip_type = 3;
else if (strcasecmp(ipType,"IPV6") == 0)
modem_if.pdp_params.ip_type = 2;
else if (strcasecmp(ipType,"IP") == 0)
modem_if.pdp_params.ip_type = 1;
end:
return;
}
static void store_auth_params(U_CHAR *line, int len UNUSED)
{
char usrPart[AT_CMD_BUF_SIZE] = {0};
char pswdPart[AT_CMD_BUF_SIZE] = {0};
int cid, type = 0;
(void)sscanf((const char *)line, "%*[^0-9]%d,%d%*[^\n]", &cid, &type);
if (type > 0)
(void)sscanf((const char *)line, "%*[^0-9]%d,%d,%[^,],%[^\n]", &cid, &type, usrPart, pswdPart);
/*delete '\r' if needed*/
if (pswdPart[strlen(pswdPart) - 1] == '\r')
pswdPart[strlen(pswdPart) - 1] =='\0';
ERRMSG("%s:cid %d, authType %d",__func__, cid, type);
if (type > 0)
ERRMSG("%s:username %s, password %s",__func__, usrPart, pswdPart);
if (modem_if.modem_current_cid != cid -1)
{
ERRMSG("%s: auth cid[%d] NOT for current cid[%d]",__func__, cid -1, modem_if.modem_current_cid);
return;
}
modem_if.pdp_params.auth_type = type;
strncpy(modem_if.pdp_params.username, usrPart, 63);
if (type > 0)
{
strncpy(modem_if.pdp_params.username, usrPart, 63);
strncpy(modem_if.pdp_params.password, pswdPart, 63);
}
else
{
memset(modem_if.pdp_params.username, 0, 64);
memset(modem_if.pdp_params.password, 0, 64);
}
}
static void store_configure_cid(U_CHAR *line, int len UNUSED)
{
char forepart[AT_CMD_BUF_SIZE] = {0};
char rearpart[AT_CMD_BUF_SIZE] = {0};
int cid = 0;
(void)sscanf((const char *)line, "%[^0-9]%d%[^\n]", forepart, &cid, rearpart);
modem_if.modem_current_cid = cid - 1;
}
int open_serial_device(Serial* serial, int baud)
{
unsigned int i;
struct termios newtio;
/* open the serial port */
if(0 > serial->fd){
open_port(&serial->fd, serial->devicename, O_RDWR | O_NOCTTY | O_NDELAY, 1);
}
tcgetattr(serial->fd, &newtio);
speed_t speed = baud_bits[baud];
cfsetispeed(&newtio, speed);
cfsetospeed(&newtio, speed);
tcflush(serial->fd, TCIFLUSH);
tcsetattr(serial->fd, TCSANOW, &newtio);
usleep(1000*100);
return 0;
}
int start_muxer(Serial* serial)
{
struct gsm_config c;
int ldisc = N_GSM0710;
/* use n_gsm line discipline */
ioctl(serial->fd, TIOCSETD, &ldisc);
/* get n_gsm configuration */
ioctl(serial->fd, GSMIOC_GETCONF, &c);
/* we are initiator and need encoding 0 (basic) */
c.initiator = 1;
c.encapsulation = serial->cmux_mode;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(serial->fd, GSMIOC_SETCONF, &c);
usleep(1000*1000);
return 0;
}
static int cmux_process(Serial * serial)
{
const char dev[128] = {0};
int i;
if (open_serial_device(serial, serial->baud) != 0) { //first use default settings to open serial
return 1;
}
if (start_muxer(serial) < 0) {
return 1;
}
for(i=1; i<MAX_MUX; i++){
sprintf(dev, "/dev/gsmtty%d", i);
open_port(&ppp_gsm_fd[i-1], dev, O_RDWR | O_NOCTTY | O_NDELAY, 1);
}
#ifdef PPP_WITHOUT_ATSRV
open_port(&ppp_gsm_fd[i-1], CMUX_GSM4_DEVICE, O_RDWR, 1);
#else
ppp_gsm_fd[i-1] = open_socket(CMUX_GSM4_SOCKET);
#endif
/* init channel */
for(i=0; i<MAX_MUX; i++){
init_channel_struct(&ppp_gsm[i], ppp_gsm_fd[i], i);
}
pxa_dbg("Starting multiplexing\r\n");
return 0;
}
static int cmux_set(int fd, int mode, int baud)
{
serial.cmux_mode = mode;
serial.baud = baud;
serial.fd = fd;
serial.devicename = MODEM_TERM_DEVICE;
cmux_process(&serial);
return 0;
}
static int cmux_off(void)
{
const char dev[128] = {0};
int i;
int ldisc = N_TTY;
pxa_dbg("Ending multiplexing\r\n");
/* collect resources */
for(i=0; i<MAX_MUX; i++){
tcflush(ppp_gsm_fd[i], TCIOFLUSH);
close(ppp_gsm_fd[i]);
memset(&ppp_gsm[i], 0x00, sizeof(struct at_channel_struct));
}
/* use n_tty line discipline */
ioctl(serial.fd, TIOCSETD, &ldisc);
serial.fd = -1;
return 0;
}
void configure_ppp_cid(int cid)
{
modem_if.modem_current_cid = (unsigned char)cid;
}
int ppp_parse_profile_id(char *dial_string)
{
int id = 0;
char *start = NULL, *end = NULL;
start = strstr(dial_string, "***");
if (start) {
end = strchr(start, '#');
if (end) {
end--;
if (*end >= '0' && *end <= '9')
id = *end - 0x30;
}
}
return id;
}
bool is_ppp_dial_string(char *line)
{
if((strncasecmp((char const *)line, "ATDT*99***", strlen("ATDT*99***")) == 0) ||
(strncasecmp((char const *)line, "ATDT*98***", strlen("ATDT*98***")) == 0) ||
(strncasecmp((char const *)line, "ATD*99***", strlen("ATD*99***")) == 0) ||
(strncasecmp((char const *)line, "ATD#777", strlen("ATD#777")) == 0) ||
(strncasecmp((char const *)line, "ATD*99#", strlen("ATD*99#")) == 0) ||
(strncasecmp((char const *)line, "ATDT*99#", strlen("ATDT*99#")) == 0))
return true;
else
return false;
}
void ppp_send_at_rsp_2host(char *at_rsp)
{
char rsp[128] = { 0 };
int size = 0;
size = snprintf(rsp, 127, "\r\n%s\r\n", at_rsp);
writen(ppp_modem_fd, rsp, size);
}
void ppp_ioctl_set_ipv6_addr(int type)
{
ip6_addr_t ppp_v6_addr;
if (type == 0)
memcpy(&ppp_v6_addr, ppp_get_ipv6_addr(), sizeof(ip6_addr_t));
else
memcpy(&ppp_v6_addr, ppp_get_ipv6_global_unicast(), sizeof(ip6_addr_t));
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPSETV6ADDR, &ppp_v6_addr);
ip6_addr_debug_print("ppp_ioctl_set_ipv6_addr: ppp ipv6", &ppp_v6_addr);
}
void ppp_ipcpv6_done(void)
{
ppp_ioctl_set_ipv6_addr(0);
/*send RS to network*/
ppp_ndisc_send_rs();
ERRMSG("%s: done", __func__);
}
void ppp_ipv6_receive_ra_done(void)
{
ppp_ioctl_set_ipv6_addr(1);
ERRMSG("%s: done", __func__);
}
#ifdef MODEM_AT_STATISTICS
void write_at_stat_2file(char *file_path, struct modem_at_statistics *statistics)
{
FILE *fp = NULL;
fp = fopen(file_path, "w");
if (!fp)
return;
fprintf(fp, "IN:%d,%d OUT:%d,%d\n", statistics->cmd_count, statistics->cmd_byte, statistics->rsp_count, statistics->rsp_byte);
fclose(fp);
}
#endif
bool wait_for_crlf = FALSE;
int wait_for_crlf_ticks = 100;
static utlTimerId_T wait_crlf_timer = 0;
static utlRelativeTime_T wait_crlf_timeout = { 0, 100000 };
int last_received_ticks, current_ticks;
static unsigned long get_system_clock_msec(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec/1000000);
}
static utlReturnCode_T wait_for_crlf_timer_cb(const utlTimerId_T id,
const unsigned long timeout_count,
void *arg_p,
const utlAbsoluteTime_P2c curr_time_p)
{
UNUSEDPARAM(id)
UNUSEDPARAM(timeout_count)
UNUSEDPARAM(curr_time_p)
int modem_fd = *(int *)arg_p;
if (wait_for_crlf == true)
{
wait_for_crlf = false;
INFOMSG("%s: +++CR received, fallback to ACM_CONTROL_MODE\n", __func__);
set_modem_if_state(modem_fd, ACM_CONTROL_MODE);
//modem_if.modem_current_cid = INVALID_CID;
modem_if.ppp_cbs.reset();
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPOFF, modem_if.modem_current_cid);
ath_data = true;
}
INFOMSG("%s: done\n", __func__);
return(utlSUCCESS);
}
static int ppp_check_control_mode_streams(int modem_fd, char *packet_buffer, int received)
{
static char switch_buffer[4] = { 0 };
if (received == 1)
{
if (wait_for_crlf)
{
INFOMSG("%s: data %x received after +++ in ticks(%d)\n", __func__, packet_buffer[0], wait_for_crlf_ticks);
if(wait_crlf_timer != 0)
{
utlStopTimer(wait_crlf_timer);
wait_crlf_timer = 0;
}
wait_for_crlf = FALSE;
memset(switch_buffer, 0, sizeof(switch_buffer));
last_received_ticks = get_system_clock_msec();
}
if (packet_buffer[0] == '+')
{
if (strlen(switch_buffer) == 0)
current_ticks = get_system_clock_msec();
if (strlen(switch_buffer) >=1)
{
/* after first '+' longer than 1s */
if (get_system_clock_msec() - current_ticks > 1000)
{
INFOMSG("%s: the + after first + longer than 1s\n", __func__);
memset(switch_buffer, 0, sizeof(switch_buffer));
last_received_ticks = current_ticks;
current_ticks = get_system_clock_msec();
}
}
if (strlen(switch_buffer) >= 2)
{
INFOMSG("%s: +++ received, current ticks %d last_received_ticks %d\n", __func__, current_ticks, last_received_ticks);
if (current_ticks - last_received_ticks > wait_for_crlf_ticks)
{
wait_for_crlf = true;
if (wait_crlf_timer == 0)
wait_crlf_timer = utlStartTimer(&wait_crlf_timeout, 1, &wait_for_crlf_timer_cb, (void *)&modem_fd);
}
memset(switch_buffer, 0, sizeof(switch_buffer));
last_received_ticks = get_system_clock_msec();
}
else
switch_buffer[strlen(switch_buffer)] = '+';
}
else
{
memset(switch_buffer, 0, sizeof(switch_buffer));
last_received_ticks = get_system_clock_msec();
}
}
else
{
if (received == 2 && packet_buffer[0] == '+' && packet_buffer[1] == '+' )
{
if (strlen(switch_buffer) == 1)
{
/*+, ++ received*/
INFOMSG("%s: +,++ received, current ticks %d last_received_ticks %d\n", __func__, current_ticks, last_received_ticks);
/* after first '+' longer than 1s */
if (get_system_clock_msec() - current_ticks > 1000)
{
INFOMSG("%s: the + after first + longer than 1s\n", __func__);
memset(switch_buffer, '+', 2);
last_received_ticks = current_ticks;
current_ticks = get_system_clock_msec();
}
else
{
if (current_ticks - last_received_ticks > wait_for_crlf_ticks)
{
wait_for_crlf = true;
if (wait_crlf_timer == 0)
wait_crlf_timer = utlStartTimer(&wait_crlf_timeout, 1, &wait_for_crlf_timer_cb, (void *)&modem_fd);
}
memset(switch_buffer, 0, sizeof(switch_buffer));
}
}
else if (strlen(switch_buffer) == 0)
{
/*++ received*/
memset(switch_buffer, '+', 2);
current_ticks = get_system_clock_msec();
}
else
memset(switch_buffer, 0, sizeof(switch_buffer));
}
else
memset(switch_buffer, 0, sizeof(switch_buffer));
}
/*check if the packet is ''+++"*/
if ((strlen(packet_buffer) == 3) && (strncasecmp(packet_buffer, "+++", strlen("+++")) == 0))
{
current_ticks = get_system_clock_msec();
if (current_ticks - last_received_ticks > wait_for_crlf_ticks)
{
INFOMSG("%s: only +++ received\n", __func__);
return true;
}
}
if (received > 1 && strlen(switch_buffer) != 2)
last_received_ticks = get_system_clock_msec();
return false;
}
void ppp_modem_receive_error(int mode, int received)
{
int modem_state = 0;
int count = 0;
modem_state = get_modem_state();
INFOMSG("mode [%d], ppp_modem_fd[%d], received[%d], modemState[%d],read error[%d] %s", mode, ppp_modem_fd, received, modem_state, errno, strerror(errno));
if (modem_state == 0) {
if (ppp_modem_fd > 0) {
if (close(ppp_modem_fd) < 0)
INFOMSG("ppp_modem_fd close failed\r\n");
ppp_modem_fd = 0;
}
#ifdef ADDITIONAL_MODEM_DEVICE
if (ppp_modem_fd1 > 0)
{
if (close(ppp_modem_fd1) < 0 )
INFOMSG("ppp_modem_fd1 close failed\r\n");
ppp_modem_fd1 = 0;
}
#endif
INFOMSG("ppp_modem_fd recv error! may be closed!\r\n");
}
else {
if (ENOENT == errno || EIO == errno) {
if (ppp_modem_fd > 0) {
if (close(ppp_modem_fd) < 0)
INFOMSG("ppp_modem_fd close failed\r\n");
ppp_modem_fd = 0;
}
#ifdef ADDITIONAL_MODEM_DEVICE
if (ppp_modem_fd1 > 0) {
if (close(ppp_modem_fd1) < 0 )
INFOMSG("ppp_modem_fd1 close failed\r\n");
ppp_modem_fd1 = 0;
}
#endif
INFOMSG("error happend with usb connected, will re-open port\r\n");
while (count < 5) {
sleep(1);
open_port(&ppp_modem_fd, MODEM_TERM_DEVICE, O_RDWR, 1);
if (ppp_modem_fd)
break;
}
if (count == 5)
{
INFOMSG(" re-open port failed\r\n");
}
}
}
}
int modem_cmux_router(void)
{
int received;
U_CHAR *line = NULL;
U_CHAR packet_buffer[PPP_FRAME_SIZE] = { '\0' };
int fdcount;
int nfds;
fd_set fds;
int i, cid;
for(i=0; i<MAX_MUX; i++){
FD_SET(ppp_gsm_fd[i], &fds);
if(ppp_gsm_fd[i] > nfds)
nfds = ppp_gsm_fd[i];
}
fdcount = select(nfds + 1, &fds, NULL, NULL, NULL);
if(fdcount < 0) /* error */
{
INFOMSG("select returned %d, errno %d, continue\r\n", fdcount, errno);
return 1;;
}
for(i=0; i<MAX_MUX-1; i++){
if(FD_ISSET(ppp_gsm_fd[i], &fds))
{ /* handler packet message from terminal */
FD_CLR(ppp_gsm_fd[i], &fds);
if (get_modem_if_state(ppp_gsm_fd[i]) == ACM_CONTROL_MODE) /* relay atcmd to ATCMDSRV: ppp_at_fd */
{
received = read_channel(&ppp_gsm[i]);
if(received > 0)
{
while (1)
{
line = get_line(&ppp_gsm[i], 1);
if (line == NULL) break;
dbg_dump_string("AT COMMAND (string), ppp_gsm modem_router\r\n", (char *)line, ppp_gsm[i].cur_line_len);
dbg_dump_buffer("AT COMMAND (buffer), ppp_gsm modem_router\r\n", (char *)line, ppp_gsm[i].cur_line_len);
if(is_ppp_dial_string(line)) {
cid = ppp_parse_profile_id(line);
if (cid)
configure_ppp_cid(cid -1);
handle_dial(ppp_gsm_fd[i]);
return 1;
}
if (strncasecmp((const char *)line, "ATH", sizeof("ATH") - 1) == 0 && ath_data) {
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_gsm_fd[i], RESP_OK, sizeof(RESP_OK) - 1);
ath_data = false;
return 1;
}
if(strncasecmp((char const *)line, "ATE0", strlen("ATE0")) == 0)
modem_if.echo_mode = MODEM_NORMAL_MODE;
if(strncasecmp((char const *)line, "ATE1", strlen("ATE1")) == 0)
modem_if.echo_mode = MODEM_ECHO_MODE;
if(strncasecmp((char const *)line, "AT+CGDCONT=", strlen("AT+CGDCONT=")) == 0) {
store_configure_params(line, ppp_gsm[i].cur_line_len);
}
if(strncasecmp((char const *)line, "ATO", strlen("ATO")) == 0 && ato_data) {
writen(ppp_gsm_fd[i], "\r\nOK\r\n", strlen("\r\nOK\r\n"));
set_modem_if_state(ppp_gsm_fd[i], ACM_DATA_MODE);
ato_data = false;
}
if(strncasecmp((char const *)line, "AT@POFF", strlen("AT@POFF")) == 0) {
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_gsm_fd[i], RESP_OK, sizeof(RESP_OK) - 1);
cmux_off();
return 0;
}else{
/* relay atcmd to ATCMDSRV */
pthread_mutex_lock(&channelid_lock);
ppp_gsm[3].id = i;
writen(ppp_gsm_fd[3], line, ppp_gsm[i].cur_line_len);
pthread_mutex_unlock(&channelid_lock);
}
}
}
}
else if (get_modem_if_state(ppp_gsm_fd[i]) == ACM_DATA_MODE)
{
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(ppp_gsm_fd[i], packet_buffer, PPP_FRAME_SIZE);
if(received > 0)
{
/* check if the packet is "+++", which is the signal to enter ACM_CONTROL_MODE */
if( ppp_check_control_mode_streams(ppp_gsm_fd[i], packet_buffer, received) &&
strncasecmp((char const *)packet_buffer, "+++", strlen("+++")) == 0)
{
set_modem_if_state(ppp_gsm_fd[i], ACM_CONTROL_MODE);
//modem_if.modem_current_cid = INVALID_CID;
modem_if.ppp_cbs.reset();
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPOFF, modem_if.modem_current_cid);
ath_data = true;
ato_data = true;
}
else
modem_if.ppp_cbs.rx_modem(packet_buffer, received);
}
}
}
}
if(FD_ISSET(ppp_gsm_fd[MAX_MUX-1], &fds))
{ /* received AT response */
FD_CLR(ppp_gsm_fd[MAX_MUX-1], &fds);
received = read_channel(&ppp_gsm[MAX_MUX-1]);
if(received > 0)
{
U_CHAR *p_sol = NULL;
int cur_count = 0;
p_sol = ppp_gsm[MAX_MUX-1].at_buffer_head;
while (1)
{
line = get_line(&ppp_gsm[MAX_MUX-1], 0);
if (line == NULL) break;
dbg_dump_string("AT RESPONSE (string), modem_router\r\n", (char *)line, ppp_gsm[MAX_MUX-1].cur_line_len);
dbg_dump_buffer("AT RESPONSE (buffer), modem_router\r\n", (char *)line, ppp_gsm[MAX_MUX-1].cur_line_len);
cur_count += ppp_gsm[MAX_MUX-1].cur_line_len;
if (modem_cmux_is_data_mode())
modem_parse_atcmd(line, ppp_gsm[MAX_MUX-1].cur_line_len, FALSE);
}
if (!modem_cmux_is_data_mode() && cur_count > 0) {
pthread_mutex_lock(&channelid_lock);
writen(ppp_gsm_fd[ppp_gsm[MAX_MUX-1].id], p_sol, cur_count);
pthread_mutex_unlock(&channelid_lock);
dbg_dump_string("AT RESPONSE (string) Write to UART, modem_router\r\n", (char *)p_sol, cur_count);
}
}
}
return 1;
}
/* router thread */
void modem_router(void)
{
int received;
U_CHAR *line = NULL;
U_CHAR packet_buffer[PPP_FRAME_SIZE] = { '\0' };
int fdcount;
fd_set fds;
int nfds, cid;
int cmux_flag = 0;
int modem_state = 0;
pthread_detach(pthread_self());
//TODO: need to allow pthread_setname_np for openwrt
//pthread_setname_np(pthread_self(), "PPP_ROUTER");
prctl(PR_SET_NAME, "PPP_ROUTER");
while(1)
{
nfds = 0;
FD_ZERO(&fds);
FD_SET(pipefd[0], &fds);
if(pipefd[0] > nfds)
nfds = pipefd[0];
FD_SET(ppp_at_fd, &fds);
if(ppp_at_fd > nfds)
nfds = ppp_at_fd;
if(ppp_modem_fd > 0){
FD_SET(ppp_modem_fd, &fds);
if(ppp_modem_fd > nfds)
nfds = ppp_modem_fd;
}
FD_SET(ppprd_fd, &fds);
if(ppprd_fd > nfds)
nfds = ppprd_fd;
#ifdef ADDITIONAL_MODEM_DEVICE
FD_SET(ppp_at_fd1, &fds);
if(ppp_at_fd1 > nfds)
nfds = ppp_at_fd1;
if (ppp_modem_fd1 > 0) {
FD_SET(ppp_modem_fd1, &fds);
if(ppp_modem_fd1 > nfds)
nfds = ppp_modem_fd1;
}
#endif
#ifdef UART2_AT
FD_SET(ppp_at_fd2, &fds);
if(ppp_at_fd2 > nfds)
nfds = ppp_at_fd2;
FD_SET(ppp_uart2_fd, &fds);
if(ppp_uart2_fd > nfds)
nfds = ppp_uart2_fd;
#endif
#ifdef PPP_PSEUDO_DEVICE
FD_SET(ppp_at_fd_pseudo, &fds);
if(ppp_at_fd_pseudo > nfds)
nfds = ppp_at_fd_pseudo;
FD_SET(ppp_modem_fd_pseudo, &fds);
if(ppp_modem_fd_pseudo > nfds)
nfds = ppp_modem_fd_pseudo;
#endif
if(cmux_flag)
{
cmux_flag = modem_cmux_router();
}else{
fdcount = select(nfds + 1, &fds, NULL, NULL, NULL);
if(fdcount < 0) /* error */
{
INFOMSG("select returned %d, errno %d, continue\r\n", fdcount, errno);
sleep(1);
continue;
}
if(FD_ISSET(ppp_at_fd, &fds))
{ /* received AT response */
FD_CLR(ppp_at_fd, &fds);
received = read_channel(&ppp_at);
if(received > 0)
{
U_CHAR *p_sol = NULL;
int cur_count = 0;
p_sol = ppp_at.at_buffer_head;
while (1)
{
line = get_line(&ppp_at, 0);
if (line == NULL) break;
dbg_dump_string("AT RESPONSE (string), modem_router\r\n", (char *)line, ppp_at.cur_line_len);
dbg_dump_buffer("AT RESPONSE (buffer), modem_router\r\n", (char *)line, ppp_at.cur_line_len);
cur_count += ppp_at.cur_line_len;
if (get_modem_if_state(ppp_modem_fd) == ACM_DATA_MODE)
modem_parse_atcmd(line, ppp_at.cur_line_len, FALSE);
}
if(get_modem_if_state(ppp_modem_fd) == ACM_CONTROL_MODE && cur_count > 0) {
if(ppp_modem_fd>0){
#ifdef MODEM_AT_STATISTICS
at_statistics.rsp_count++;
at_statistics.rsp_byte += cur_count;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_modem_fd, p_sol, cur_count);
dbg_dump_string("AT RESPONSE (string) Write to UART, modem_router\r\n", (char *)p_sol, cur_count);
}
}
}
}
if(FD_ISSET(ppp_modem_fd, &fds))
{ /* handler packet message from terminal */
FD_CLR(ppp_modem_fd, &fds);
if (get_modem_if_state(ppp_modem_fd) == ACM_CONTROL_MODE)
{
received = read_channel(&ppp_modem);
if(received > 0)
{
while (1)
{
line = get_line(&ppp_modem, 1);
if (line == NULL) break;
dbg_dump_string("AT COMMAND (string), modem_router\r\n", (char *)line, ppp_modem.cur_line_len);
dbg_dump_buffer("AT COMMAND (buffer), modem_router\r\n", (char *)line, ppp_modem.cur_line_len);
if(is_ppp_dial_string(line)) {
cid = ppp_parse_profile_id(line);
if (cid)
configure_ppp_cid(cid -1);
handle_dial(ppp_modem_fd);
continue;
}
if (strncasecmp((const char *)line, "ATH", sizeof("ATH") - 1) == 0 && ath_data) {
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_modem_fd, RESP_OK, sizeof(RESP_OK) - 1);
ath_data = false;
continue;
}
if(strncasecmp((char const *)line, "ATE0", strlen("ATE0")) == 0)
modem_if.echo_mode = MODEM_NORMAL_MODE;
if(strncasecmp((char const *)line, "ATE1", strlen("ATE1")) == 0)
modem_if.echo_mode = MODEM_ECHO_MODE;
if(strncasecmp((char const *)line, "AT+CGDCONT=", strlen("AT+CGDCONT=")) == 0) {
store_configure_params(line, ppp_modem.cur_line_len);
}
if(strncasecmp((char const *)line, "ATO", strlen("ATO")) == 0 && ato_data) {
writen(ppp_modem_fd, "\r\nOK\r\n", strlen("\r\nOK\r\n"));
set_modem_if_state(ppp_modem_fd, ACM_DATA_MODE);
ato_data = false;
}
#if 0
if(strncasecmp((char const *)line, "AT+CGDCONT?", strlen("AT+CGDCONT?")) == 0)
modem_if.get_ip = TRUE;
if(strncasecmp((char const *)line, "AT+CGCONTRDP", strlen("AT+CGCONTRDP")) == 0)
modem_if.get_ip = TRUE;
#endif
if(strncasecmp((char const *)line, "AT+CMUX=", strlen("AT+CMUX=")) == 0) {
int mode;
int baud;
(void)sscanf((const char *)line, "%*[^0-9]%d,%d", &mode, &baud);
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_modem_fd, RESP_OK, sizeof(RESP_OK) - 1);
cmux_set(ppp_modem_fd, mode, baud);
cmux_flag = 1;
} else {
/* relay atcmd to ATCMDSRV */
#ifdef MODEM_AT_STATISTICS
at_statistics.cmd_count++;
at_statistics.cmd_byte += ppp_modem.cur_line_len;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_at_fd, line, ppp_modem.cur_line_len);
}
}
}
else
ppp_modem_receive_error(ACM_CONTROL_MODE, received);
}
else if (get_modem_if_state(ppp_modem_fd) == ACM_DATA_MODE)
{
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(ppp_modem_fd, packet_buffer, PPP_FRAME_SIZE);
if(received > 0)
{
/* check if the packet is "+++", which is the signal to enter ACM_CONTROL_MODE */
if( ppp_check_control_mode_streams(ppp_modem_fd, packet_buffer, received) &&
strncasecmp((char const *)packet_buffer, "+++", strlen("+++")) == 0)
{
set_modem_if_state(ppp_modem_fd, ACM_CONTROL_MODE);
//modem_if.modem_current_cid = INVALID_CID;
INFOMSG(" Fallback to ACM_CONTROL_MODE, modem_current_cid is 0xFF\n");
modem_if.ppp_cbs.reset();
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPOFF, modem_if.modem_current_cid);
ath_data = true;
ato_data = true;
}
else
modem_if.ppp_cbs.rx_modem(packet_buffer, received);
}
else
ppp_modem_receive_error(ACM_DATA_MODE, received);
}
}
if(FD_ISSET(ppprd_fd, &fds))
{ /* received IP packet from CP through ppp router driver */
FD_CLR(ppprd_fd, &fds);
if (get_modem_if_state(0) == ACM_DATA_MODE)
{
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(ppprd_fd, packet_buffer, PPP_FRAME_SIZE);
ERRMSG("[<<<] ppprd port %d received: %d bytes data\n", ppprd_fd, received);
modem_if.ppp_cbs.rx_comm(packet_buffer, received);
}else{
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(ppprd_fd, packet_buffer, PPP_FRAME_SIZE);
ERRMSG(" ppprd port %d received: %d bytes data\n", ppprd_fd, received);
ERRMSG(" ppprd_fd modem_state not ACM_DATA_MODE,clean the data\n");
}
}
if(FD_ISSET(pipefd[0], &fds))
{ /* received terminate message */
FD_CLR(pipefd[0], &fds);
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(pipefd[0], packet_buffer, PPP_FRAME_SIZE);
ERRMSG(" received pipefd[%d] message[%s]\n",received,packet_buffer);
if(!strcmp(packet_buffer, "term")){
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ERRMSG(" reset PPPRD_IOCTL_TIOPPPRESETCB, loop again\n");
}else if(!strcmp(packet_buffer, "start")){
ERRMSG("[start]loop again to set ppp_modem_fd %d\n", ppp_modem_fd);
#ifdef ADDITIONAL_MODEM_DEVICE
ERRMSG("[start]ppp_modem_fd1 %d\n", ppp_modem_fd1);
#endif
}
#ifdef TERMINATE_ALL_RESOURCES
break;
#else
continue;
#endif
}
#ifdef ADDITIONAL_MODEM_DEVICE
if(FD_ISSET(ppp_at_fd1, &fds))
{ /* received AT response */
FD_CLR(ppp_at_fd1, &fds);
received = read_channel(&ppp_at1);
if(received > 0)
{
U_CHAR *p_sol = NULL;
int cur_count = 0;
p_sol = ppp_at1.at_buffer_head;
while (1)
{
line = get_line(&ppp_at1, 0);
if (line == NULL) break;
dbg_dump_string("AT RESPONSE1 (string), modem_router\r\n", (char *)line, ppp_at1.cur_line_len);
dbg_dump_buffer("AT RESPONSE1 (buffer), modem_router\r\n", (char *)line, ppp_at1.cur_line_len);
cur_count += ppp_at1.cur_line_len;
if (get_modem_if_state(ppp_modem_fd1) == ACM_DATA_MODE)
modem_parse_atcmd(line, ppp_at1.cur_line_len, FALSE);
}
if (get_modem_if_state(ppp_modem_fd1) == ACM_CONTROL_MODE && cur_count > 0) {
if(ppp_modem_fd1>0){
#ifdef MODEM_AT_STATISTICS
at_statistics.rsp_count++;
at_statistics.rsp_byte += cur_count;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_modem_fd1, p_sol, cur_count);
dbg_dump_string("AT RESPONSE1 (string) Write to UART, modem_router\r\n", (char *)p_sol, cur_count);
}
}
}
}
if(FD_ISSET(ppp_modem_fd1, &fds))
{ /* handler packet message from terminal */
FD_CLR(ppp_modem_fd1, &fds);
if (get_modem_if_state(ppp_modem_fd1) == ACM_CONTROL_MODE)
{
received = read_channel(&ppp_modem1);
if(received > 0)
{
while (1)
{
line = get_line(&ppp_modem1, 1);
if (line == NULL) break;
dbg_dump_string("AT COMMAND1 (string), modem_router\r\n", (char *)line, ppp_modem1.cur_line_len);
dbg_dump_buffer("AT COMMAND1 (buffer), modem_router\r\n", (char *)line, ppp_modem1.cur_line_len);
if(is_ppp_dial_string(line)) {
cid = ppp_parse_profile_id(line);
if (cid)
configure_ppp_cid(cid -1);
handle_dial(ppp_modem_fd1);
continue;
}
if (strncasecmp((const char *)line, "ATH", sizeof("ATH") - 1) == 0 && ath_data) {
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_modem_fd1, RESP_OK, sizeof(RESP_OK) - 1);
ath_data = false;
continue;
}
if(strncasecmp((char const *)line, "ATE0", strlen("ATE0")) == 0)
modem_if.echo_mode = MODEM_NORMAL_MODE;
if(strncasecmp((char const *)line, "ATE1", strlen("ATE1")) == 0)
modem_if.echo_mode = MODEM_ECHO_MODE;
if(strncasecmp((char const *)line, "AT+CGDCONT=", strlen("AT+CGDCONT=")) == 0) {
store_configure_params(line, ppp_modem1.cur_line_len);
}
if(strncasecmp((char const *)line, "ATO", strlen("ATO")) == 0 && ato_data) {
writen(ppp_modem_fd, "\r\nOK\r\n", strlen("\r\nOK\r\n"));
set_modem_if_state(ppp_modem_fd, ACM_DATA_MODE);
ato_data = false;
}
if(strncasecmp((char const *)line, "AT+CMUX=", strlen("AT+CMUX=")) == 0) {
int mode;
int baud;
(void)sscanf((const char *)line, "%*[^0-9]%d,%d", &mode, &baud);
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_modem_fd1, RESP_OK, sizeof(RESP_OK) - 1);
cmux_set(ppp_modem_fd1, mode, baud);
cmux_flag = 1;
} else {
/* relay atcmd to ATCMDSRV */
#ifdef MODEM_AT_STATISTICS
at_statistics.cmd_count++;
at_statistics.cmd_byte += ppp_modem1.cur_line_len;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_at_fd1, line, ppp_modem1.cur_line_len);
}
}
}
else
ppp_modem_receive_error(ACM_CONTROL_MODE, received);
}
else if(get_modem_if_state(ppp_modem_fd1) == ACM_DATA_MODE) /* relay packet to PPP server: message_queue */
{
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(ppp_modem_fd1, packet_buffer, PPP_FRAME_SIZE);
if(received > 0)
{
/* check if the packet is "+++", which is the signal to enter ACM_CONTROL_MODE */
if( ppp_check_control_mode_streams(ppp_modem_fd1, packet_buffer, received) &&
strncasecmp((char const *)packet_buffer, "+++", strlen("+++")) == 0)
{
set_modem_if_state(ppp_modem_fd1, ACM_CONTROL_MODE);
//modem_if.modem_current_cid = INVALID_CID;
INFOMSG(" Fallback to ACM_CONTROL_MODE, modem_current_cid is 0xFF\n");
modem_if.ppp_cbs.reset();
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPOFF, modem_if.modem_current_cid);
ath_data = true;
ato_data = true;
}
else
modem_if.ppp_cbs.rx_modem(packet_buffer, received);
}
else
ppp_modem_receive_error(ACM_DATA_MODE, received);
}
}
#endif
#ifdef UART2_AT
if(FD_ISSET(ppp_at_fd2, &fds))
{ /* received AT response */
FD_CLR(ppp_at_fd2, &fds);
received = read_channel(&ppp_at2);
if(received > 0)
{
U_CHAR *p_sol = NULL;
int cur_count = 0;
p_sol = ppp_at2.at_buffer_head;
while (1)
{
line = get_line(&ppp_at2, 0);
if (line == NULL) break;
dbg_dump_string("AT RESPONSE UART (string), modem_router\r\n", (char *)line, ppp_at2.cur_line_len);
dbg_dump_buffer("AT RESPONSE UART (buffer), modem_router\r\n", (char *)line, ppp_at2.cur_line_len);
cur_count += ppp_at2.cur_line_len;
if (get_modem_if_state(ppp_uart2_fd) == ACM_DATA_MODE)
modem_parse_atcmd(line, ppp_at2.cur_line_len, FALSE);
}
if (get_modem_if_state(ppp_uart2_fd) == ACM_CONTROL_MODE && cur_count > 0) {
#ifdef MODEM_AT_STATISTICS
at_statistics.rsp_count++;
at_statistics.rsp_byte += cur_count;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_uart2_fd, p_sol, cur_count);
dbg_dump_string("AT RESPONSE UART (string) Write to UART, modem_router\r\n", (char *)p_sol, cur_count); }
}
}
if(FD_ISSET(ppp_uart2_fd, &fds))
{ /* handler packet message from terminal */
FD_CLR(ppp_uart2_fd, &fds);
if (get_modem_if_state(ppp_uart2_fd) == ACM_CONTROL_MODE)
{
received = read_channel(&ppp_uart2);
if(received > 0)
{
while (1)
{
line = get_line(&ppp_uart2, 1);
if (line == NULL) break;
dbg_dump_string("AT COMMAND UART (string), modem_router\r\n", (char *)line, ppp_uart2.cur_line_len);
dbg_dump_buffer("AT COMMAND UART (buffer), modem_router\r\n", (char *)line, ppp_uart2.cur_line_len);
if(is_ppp_dial_string(line)) {
cid = ppp_parse_profile_id(line);
if (cid)
configure_ppp_cid(cid -1);
handle_dial(ppp_uart2_fd);
continue;
}
if (strncasecmp((const char *)line, "ATH", sizeof("ATH") - 1) == 0 && ath_data) {
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_uart2_fd, RESP_OK, sizeof(RESP_OK) - 1);
ath_data = false;
continue;
}
if(strncasecmp((char const *)line, "ATE0", strlen("ATE0")) == 0)
modem_if.echo_mode = MODEM_NORMAL_MODE;
if(strncasecmp((char const *)line, "ATE1", strlen("ATE1")) == 0)
modem_if.echo_mode = MODEM_ECHO_MODE;
if(strncasecmp((char const *)line, "AT+CGDCONT=", strlen("AT+CGDCONT=")) == 0) {
store_configure_params(line, ppp_uart2.cur_line_len);
}
if(strncasecmp((char const *)line, "ATO", strlen("ATO")) == 0 && ato_data) {
writen(ppp_uart2_fd, "\r\nOK\r\n", strlen("\r\nOK\r\n"));
set_modem_if_state(ppp_uart2_fd, ACM_DATA_MODE);
ato_data = false;
}
if(strncasecmp((char const *)line, "AT+CMUX=", strlen("AT+CMUX=")) == 0) {
int mode;
int baud;
(void)sscanf((const char *)line, "%*[^0-9]%d,%d", &mode, &baud);
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_uart2_fd, RESP_OK, sizeof(RESP_OK) - 1);
cmux_set(ppp_uart2_fd, mode, baud);
cmux_flag = 1;
} else {
/* relay atcmd to ATCMDSRV */
#ifdef MODEM_AT_STATISTICS
at_statistics.cmd_count++;
at_statistics.cmd_byte += ppp_uart2.cur_line_len;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_at_fd2, line, ppp_uart2.cur_line_len);
}
}
}
}
else if (get_modem_if_state(ppp_uart2_fd) == ACM_DATA_MODE) /* relay packet to PPP server: message_queue */
{
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(ppp_uart2_fd, packet_buffer, PPP_FRAME_SIZE);
if(received > 0)
{
/* check if the packet is "+++", which is the signal to enter ACM_CONTROL_MODE */
if( ppp_check_control_mode_streams(ppp_uart2_fd, packet_buffer, received) &&
strncasecmp((char const *)packet_buffer, "+++", strlen("+++")) == 0)
{
set_modem_if_state(ppp_uart2_fd, ACM_CONTROL_MODE);
//modem_if.modem_current_cid = INVALID_CID;
INFOMSG(" Fallback to ACM_CONTROL_MODE, modem_current_cid is 0xFF\n");
modem_if.ppp_cbs.reset();
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPOFF, modem_if.modem_current_cid);
ath_data = true;
ato_data = true;
}
else
modem_if.ppp_cbs.rx_modem(packet_buffer, received);
}
}
}
#endif
#ifdef PPP_PSEUDO_DEVICE
if(FD_ISSET(ppp_at_fd_pseudo, &fds))
{ /* received AT response */
FD_CLR(ppp_at_fd_pseudo, &fds);
received = read_channel(&ppp_at_pseudo);
if(received > 0)
{
U_CHAR *p_sol = NULL;
int cur_count = 0;
p_sol = ppp_at_pseudo.at_buffer_head;
while (1)
{
line = get_line(&ppp_at_pseudo, 0);
if (line == NULL) break;
dbg_dump_string("AT RESPONSE PSEUDO (string), modem_router\r\n", (char *)line, ppp_at_pseudo.cur_line_len);
dbg_dump_buffer("AT RESPONSE PSEUDO (buffer), modem_router\r\n", (char *)line, ppp_at_pseudo.cur_line_len);
cur_count += ppp_at_pseudo.cur_line_len;
if (get_modem_if_state(ppp_modem_fd_pseudo) == ACM_DATA_MODE)
modem_parse_atcmd(line, ppp_at_pseudo.cur_line_len, FALSE);
}
if (get_modem_if_state(ppp_modem_fd_pseudo) == ACM_CONTROL_MODE && cur_count > 0) {
#ifdef MODEM_AT_STATISTICS
at_statistics.rsp_count++;
at_statistics.rsp_byte += cur_count;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_modem_fd_pseudo, p_sol, cur_count);
dbg_dump_string("AT RESPONSE PSEUDO (string) Write to PSEUDO device, modem_router\r\n", (char *)p_sol, cur_count); }
}
}
if(FD_ISSET(ppp_modem_fd_pseudo, &fds))
{ /* handler packet message from terminal */
FD_CLR(ppp_modem_fd_pseudo, &fds);
if (get_modem_if_state(ppp_modem_fd_pseudo) == ACM_CONTROL_MODE)
{
received = read_channel(&ppp_modem_pseudo);
if(received > 0)
{
while (1)
{
line = get_line(&ppp_modem_pseudo, 1);
if (line == NULL) break;
dbg_dump_string("AT COMMAND PSEUDO (string), modem_router\r\n", (char *)line, ppp_modem_pseudo.cur_line_len);
dbg_dump_buffer("AT COMMAND PSEUDO (buffer), modem_router\r\n", (char *)line, ppp_modem_pseudo.cur_line_len);
if(is_ppp_dial_string(line)) {
cid = ppp_parse_profile_id(line);
if (cid)
configure_ppp_cid(cid -1);
handle_dial(ppp_modem_fd_pseudo);
continue;
}
if (strncasecmp((const char *)line, "ATH", sizeof("ATH") - 1) == 0 && ath_data) {
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_modem_fd_pseudo, RESP_OK, sizeof(RESP_OK) - 1);
ath_data = false;
continue;
}
if(strncasecmp((char const *)line, "ATE0", strlen("ATE0")) == 0)
modem_if.echo_mode = MODEM_NORMAL_MODE;
if(strncasecmp((char const *)line, "ATE1", strlen("ATE1")) == 0)
modem_if.echo_mode = MODEM_ECHO_MODE;
if(strncasecmp((char const *)line, "AT+CGDCONT=", strlen("AT+CGDCONT=")) == 0) {
store_configure_params(line, ppp_modem_pseudo.cur_line_len);
}
if(strncasecmp((char const *)line, "ATO", strlen("ATO")) == 0 && ato_data) {
writen(ppp_modem_fd_pseudo, "\r\nOK\r\n", strlen("\r\nOK\r\n"));
set_modem_if_state(ppp_modem_fd_pseudo, ACM_DATA_MODE);
ato_data = false;
}
if(strncasecmp((char const *)line, "AT+CMUX=", strlen("AT+CMUX=")) == 0) {
int mode;
int baud;
(void)sscanf((const char *)line, "%*[^0-9]%d,%d", &mode, &baud);
static const char RESP_OK[] = "\r\nOK\r\n";
writen(ppp_modem_fd_pseudo, RESP_OK, sizeof(RESP_OK) - 1);
cmux_set(ppp_modem_fd_pseudo, mode, baud);
cmux_flag = 1;
} else {
/* relay atcmd to ATCMDSRV */
#ifdef MODEM_AT_STATISTICS
at_statistics.cmd_count++;
at_statistics.cmd_byte += ppp_modem_pseudo.cur_line_len;
write_at_stat_2file("/tmp/modem_at_stat", &at_statistics);
#endif
writen(ppp_at_fd_pseudo, line, ppp_modem_pseudo.cur_line_len);
}
}
}
}
else if (get_modem_if_state(ppp_modem_fd_pseudo) == ACM_DATA_MODE) /* relay packet to PPP server: message_queue */
{
memset(packet_buffer, 0x00, PPP_FRAME_SIZE);
received = read(ppp_modem_fd_pseudo, packet_buffer, PPP_FRAME_SIZE);
if(received > 0)
{
/* check if the packet is "+++", which is the signal to enter ACM_CONTROL_MODE */
if( ppp_check_control_mode_streams(ppp_modem_fd_pseudo, packet_buffer, received) &&
strncasecmp((char const *)packet_buffer, "+++", strlen("+++")) == 0)
{
set_modem_if_state(ppp_modem_fd_pseudo, ACM_CONTROL_MODE);
//modem_if.modem_current_cid = INVALID_CID;
INFOMSG(" Fallback to ACM_CONTROL_MODE, modem_current_cid is 0xFF\n");
modem_if.ppp_cbs.reset();
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPOFF, modem_if.modem_current_cid);
ath_data = true;
ato_data = true;
}
else
modem_if.ppp_cbs.rx_modem(packet_buffer, received);
}
}
}
#endif
}
}
exit:
sem_post(&modem_if.router_exit);
}
void modem_reset_ppprd(void)
{
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPRESETCB);
ioctl(ppprd_fd, PPPRD_IOCTL_TIOPPPOFF, modem_if.modem_current_cid);
INFOMSG("%s OK\n", __func__);
return;
}
static void init_channel_struct(struct at_channel_struct *chan, int fd, int id)
{
chan->tty_fd = fd;
memset(chan->at_buffer, 0, sizeof(chan->at_buffer));
chan->at_buffer_head = chan->at_buffer;
chan->at_buffer_tail = chan->at_buffer;
chan->id = id;
}
static void open_port(int *fd_ptr, const char *file_path, int flag, int tty)
{
int fd;
while((fd = open(file_path, flag)) < 0)
{
DBGMSG("%s: open %s failed\n", __func__, file_path);
sleep(1);
}
if (tty) {
/* set newtio */
struct termios newtio;
memset(&newtio, 0, sizeof(newtio));
(void)fcntl(fd, F_SETFL, 0);
#ifdef UART2_AT
/* no flow control for uart by default */
newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
#else
newtio.c_cflag = BAUD | CRTSCTS | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
#endif
newtio.c_iflag = IGNPAR;
//newtio.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
newtio.c_oflag = 0;
newtio.c_lflag = 0; /* disable ECHO, ICANON, etc... */
newtio.c_cc[VERASE] = 0x8; /* del */
newtio.c_cc[VEOF] = 4; /* Ctrl-d */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
newtio.c_cc[VEOL] = 0xD; /* '\0' */
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
}
*fd_ptr = fd;
}
static int open_socket(const char* socketName)
{
int fd;
while((fd = connectUnixSocket(socketName)) < 0) {
DBGMSG("%s: open %s failed\n", __func__, socketName);
sleep(1);
}
return fd;
}
void modem_if_init()
{
set_modem_if_state(0, ACM_CONTROL_MODE);
modem_if.echo_mode = MODEM_ECHO_MODE;
modem_if.modem_nocarrier_query_cgcontrdp = INVALID_CID;
modem_clear_ip_update_flag();
ppp_set_nd_state(ND_STATE_INIT);
}
static int modem_init_status=0;
int get_modem_init_status(void)
{
#ifdef TERMINATE_ALL_RESOURCES
return 0;
#else
return modem_init_status;
#endif
}
int set_modem_init_status(int status)
{
modem_init_status = status;
return 0;
}
void modem_init(void)
{
static const char WELCOME_MSG[] = "\r\nMarvell AT server ready\r\n";
char cmd[32];
int init_done=get_modem_init_status();
int count = 0;
INFOMSG("%s: init done %d, usb state %d\n", __func__, init_done, get_modem_state());
if(!init_done){
/* call init ppp stack function*/
setup_callback_funcs(&modem_if.ppp_cbs);
}
if (modem_if.ppp_cbs.init)
modem_if.ppp_cbs.init();
if(!init_done){
/* init pipefd */
if (pipe(pipefd) == -1)
errExit("init pipe");
/* init router exit semaphore */
sem_init(&modem_if.router_exit, 0, 0);
}
/* init modem_if struct */
set_modem_if_state(0, ACM_CONTROL_MODE);
modem_if.modem_current_cid = INVALID_CID;
modem_if.modem_nocarrier_query_cgcontrdp = INVALID_CID;
if(!init_done){
sem_init(&modem_if.atcmd_if.atcmd_response, 0, 0);
modem_if.atcmd_if.atcmd_send = FALSE;
/* init at channel */
#ifdef PPP_WITHOUT_ATSRV
open_port(&ppp_at_fd, MODEM_ATCMD_DEVICE, O_RDWR, 1);
#else
ppp_at_fd = open_socket(MODEM_ATCMD_SOCKET);
#endif
init_channel_struct(&ppp_at, ppp_at_fd, 0);
}
/* init modem channel */
if(ppp_modem_fd==0 && get_modem_state()) {
INFOMSG("%s found ppp_modem_fd is 0\n", __func__);
open_port(&ppp_modem_fd, MODEM_TERM_DEVICE, O_RDWR, 1);
while (ppp_modem_fd == 0 && count < 5)
{
close(ppp_modem_fd);
sleep(1);
open_port(&ppp_modem_fd, MODEM_TERM_DEVICE, O_RDWR, 1);
count++;
}
init_channel_struct(&ppp_modem, ppp_modem_fd, 0);
set_modem_if_state(ppp_modem_fd, ACM_CONTROL_MODE);
INFOMSG("%s: ppp_modem_fd %d, ppp_at_fd %d", __func__, ppp_modem_fd, ppp_at_fd);
if(init_done)
writen(pipefd[1], "start", strlen("start"));
}
#ifdef ADDITIONAL_MODEM_DEVICE
if(!init_done) {
ppp_at_fd1 = open_socket(MODEM_ATCMD_SOCKET1);
init_channel_struct(&ppp_at1, ppp_at_fd1, 0);
}
if(ppp_modem_fd1==0 && get_modem_state()) {
INFOMSG("%s found ppp_modem_fd1 is 0\n", __func__);
open_port(&ppp_modem_fd1, MODEM_TERM_DEVICE1, O_RDWR, 1);
while (ppp_modem_fd == 0 && count < 5)
{
close(ppp_modem_fd);
sleep(1);
open_port(&ppp_modem_fd, MODEM_TERM_DEVICE, O_RDWR, 1);
count++;
}
init_channel_struct(&ppp_modem1, ppp_modem_fd1, 0);
set_modem_if_state(ppp_modem_fd1, ACM_CONTROL_MODE);
INFOMSG("%s: ppp_modem_fd1 %d, ppp_at_fd1 %d", __func__, ppp_modem_fd1, ppp_at_fd1);
if(init_done)
writen(pipefd[1], "start", strlen("start"));
}
#endif
#ifdef UART2_AT
if(!init_done){
ppp_at_fd2 = open_socket(MODEM_ATCMD_SOCKET2);
init_channel_struct(&ppp_at2, ppp_at_fd2, 0);
open_port(&ppp_uart2_fd, UART2_TERM_DEVICE, O_RDWR, 1);
init_channel_struct(&ppp_uart2, ppp_uart2_fd, 0);
set_modem_if_state(ppp_uart2_fd, ACM_CONTROL_MODE);
INFOMSG("%s: ppp_uart2_fd %d, ppp_at_fd2 %d", __func__, ppp_uart2_fd, ppp_at_fd2);
}
#endif
#ifdef PPP_PSEUDO_DEVICE
INFOMSG("%s int_done %d\n", __func__, init_done);
if(!init_done){
char *pts_name = NULL;
int pts_fd = 0;
ppp_at_fd_pseudo = open_socket(MODEM_PSEUDO_ATCMD_SOCKET);
init_channel_struct(&ppp_at_pseudo, ppp_at_fd_pseudo, 0);
INFOMSG("%s ppp_at_fd_pseudo %d, ppp_modem_fd_pseudo %d\n", __func__, ppp_at_fd_pseudo, ppp_modem_fd_pseudo);
if(ppp_modem_fd_pseudo == 0){
INFOMSG("%s found ppp_modem_fd_pseudo is 0\n", __func__);
//ppp_modem_fd_pseudo = open(MODEM_PSEUDO_TERM_DEVICE, O_RDWR | O_NOCTTY);
open_port(&ppp_modem_fd_pseudo, MODEM_PSEUDO_TERM_DEVICE, O_RDWR |O_NOCTTY, 1);
init_channel_struct(&ppp_modem_pseudo, ppp_modem_fd_pseudo, 6);
set_modem_if_state(ppp_modem_fd_pseudo, ACM_CONTROL_MODE);
INFOMSG("%s: ppp_modem_fd_pseudo %d", __func__, ppp_modem_fd_pseudo);
grantpt(ppp_modem_fd_pseudo);
unlockpt(ppp_modem_fd_pseudo);
pts_name = ptsname(ppp_modem_fd_pseudo);
pts_fd = open(pts_name, O_RDWR | O_NOCTTY);
INFOMSG("%s: pts_name %s, pts_fd %d", __func__, pts_name, pts_fd);
if(init_done)
writen(pipefd[1], "start", strlen("start"));
}
}
#endif
if(!init_done){
/* init ppprd */
open_port(&ppprd_fd, MODEM_COMM_DEVICE, O_RDWR, 0);
//ppp_cm_fd = open_socket(MODEM_CONN_CM_SOCKET);
}
/* by default configure echo to be on */
#ifdef AT_CONFIG_P701
modem_if.echo_mode = MODEM_NORMAL_MODE;
#else
modem_if.echo_mode = MODEM_ECHO_MODE;
#endif
writen(ppp_modem_fd, WELCOME_MSG, sizeof(WELCOME_MSG)-1);
//not in production mode
if (!InProduction_Mode())
{
memset(cmd,0,32);
snprintf(cmd, sizeof(cmd), "ATE%d\r", modem_if.echo_mode);
writen(ppp_at_fd, cmd, strlen(cmd));
//FixMe: Disable the unsolicited indication for Modem port in order to support GCF test ---201251225 Yhuang
/*shoule enable the unsolicited ind for modem port in ZTE project*/
memset(cmd,0,32);
#ifdef AT_CONFIG_P701
snprintf(cmd, sizeof(cmd), "AT*APPOWERIND=1;+CMEE=2\r");
#else
snprintf(cmd, sizeof(cmd), "AT*APPOWERIND=1\r");
#endif
writen(ppp_at_fd, cmd, strlen(cmd));
}
if(!init_done){
/* create modem router thread */
if(pthread_create(&modem_if.modem_router_ref, NULL, (void *)modem_router, NULL) != 0 )
errExit("pthread_create");
}
INFOMSG("%s OK\n", __func__);
}
void modem_deinit(void)
{
struct timespec ts;
if (modem_if.ppp_cbs.deinit)
modem_if.ppp_cbs.deinit();
/* hot plug usb line without a disconnect msg*/
if (get_modem_if_state(0) == ACM_DATA_MODE)
modem_ppp_terminate(modem_if.modem_current_cid);
writen(pipefd[1], "term", strlen("term"));
#ifdef TERMINATE_ALL_RESOURCES
INFOMSG("%s stop router thread\n", __func__);
/* stop router thread */
ts.tv_sec = time(NULL) + 10;
ts.tv_nsec = 0;
if (sem_timedwait(&modem_if.router_exit, &ts) == -1)
{
DBGMSG("%s: sem wait for router exit fail\n", __func__);
}
INFOMSG("%s stop router thread done\n", __func__);
/* collect resources */
tcflush(ppp_modem_fd, TCIOFLUSH);
close(ppp_modem_fd);
close(ppprd_fd);
tcflush(ppp_at_fd, TCIOFLUSH);
close(ppp_at_fd);
#ifdef ADDITIONAL_MODEM_DEVICE
tcflush(ppp_modem_fd1, TCIOFLUSH);
close(ppp_modem_fd1);
tcflush(ppp_at_fd1, TCIOFLUSH);
close(ppp_at_fd1);
#endif
#ifdef UART2_AT
tcflush(ppp_uart2_fd, TCIOFLUSH);
close(ppp_uart2_fd);
tcflush(ppp_at_fd2, TCIOFLUSH);
close(ppp_at_fd2);
#endif
#ifdef PPP_PSEUDO_DEVICE
close(ppp_modem_fd_pseudo);
close(ppp_at_fd_pseudo);
#endif
close(pipefd[0]);
close(pipefd[1]);
memset(&modem_if, 0x00, sizeof(modem_control_interface));
#endif
INFOMSG("%s OK\n", __func__);
}