You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

536 lines
13 KiB
C

/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* 标准C库头文件. */
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <poll.h>
#include "cmd.h"
#include "mtimer.h"
#include "process.h"
#include "hwgpio.h"
#include "fifo.h"
#include "ca_dbg.h"
#include "ca_csg.h"
#include "ca_cau.h"
#include "ca_param.h"
#include "ca_network.h"
#include "debug.h"
#include "common.h"
extern int csg_reconn_times;
extern int mqtt_reconn_times;
/* Private define ------------------------------------------------------------*/
int _network_chat(int fd, const char *at, const char *expect, int timeout, char **response, bool IsPrintf)
{
int ret;
int read_len = 0;
static char buf[512];
int errNo = 0;
if (response)
{
*response = NULL;
}
tcflush(fd, TCIOFLUSH);
if (IsPrintf == 1)
{
LOG("chat --> %s", at);
}
do
{
ret = write(fd, at, strlen(at));
}
while (ret < 0 && errno == EINTR);
if (ret <= 0)
{
if (IsPrintf == 1)
{
errNo = errno;
LOG("chat write error on stdout: %s(%d) ", strerror(errNo), errNo);
}
return errno ? errno : EINVAL;
}
struct pollfd poll_fd = {fd, POLLIN, 0};
if (poll(&poll_fd, 1, timeout > 600 ? timeout : 600) <= 0)
{
if (errno != EINTR)
{
if (IsPrintf == 1)
{
errNo = errno;
LOG("chat poll error on stdin:[%d][%s] %s(%d) ", ret, at, strerror(errNo), errNo);
}
return errno ? errno : EINVAL;
}
}
if (poll_fd.revents && (poll_fd.revents & POLLIN))
{
memset(buf, 0, sizeof(buf));
usleep(100 * 1000);
if ((read_len = read(fd, buf, sizeof(buf) - 1)) <= 0)
{
if (IsPrintf == 1)
{
errNo = errno;
LOG("chat read error on stdin: %s(%d) ", strerror(errNo), errNo);
}
return errno ? errno : EINVAL;
}
if (IsPrintf == 1)
{
LOG("\nchat return ret=[%d] at=[%s]string.len = [%d] <----- [%s];expect:[%s]\n", ret, at, strlen(buf), buf, expect);
}
if (read_len >= 512)
{
LOG("chat read max len [read:%d--max:%d]\n", read_len, 512);
return -1;
}
if (strstr(buf, expect))
{
if (response)
{
*response = strstr(buf, expect);
}
return 0;
}
else
{
if (response)
{
*response = buf;
}
}
}
return errno ? errno : EINVAL;
}
int _network_AT_read_operation(const char *Devname, const char *cmd, \
const char *tag, char *response, int timeout)
{
int modem_fd = -1, fdflags;
struct termios ios;
int modembits = TIOCM_DTR;
char *TmpResponse;
int ret = 0;
if (Devname == NULL || response == NULL || tag == NULL)
{
return 3;
}
pthread_mutex_lock(&network_ctrl.m_mutex);
modem_fd = open (Devname, O_RDWR | O_NONBLOCK);
if (modem_fd == -1)
{
LOG("open AT Dev[%s] error\n", Devname);
pthread_mutex_unlock(&network_ctrl.m_mutex);
return 1;
}
fdflags = fcntl(modem_fd, F_GETFL);
if (fdflags != -1)
{
fcntl(modem_fd, F_SETFL, fdflags | O_NONBLOCK);
}
tcgetattr( modem_fd, &ios );
cfmakeraw(&ios);
ios.c_lflag = 0;
cfsetispeed(&ios, B115200);
cfsetospeed(&ios, B115200);
tcsetattr( modem_fd, TCSANOW, &ios );
ioctl(modem_fd, (0 ? TIOCMBIS : TIOCMBIC), &modembits);
ret = _network_chat(modem_fd, cmd, tag, timeout, &TmpResponse, 1);
if (0 != ret)
{
LOG("AT Error!!ret=%s, AT:[%s]----->response:[%s].", strerror(ret), cmd, TmpResponse);
close(modem_fd);
pthread_mutex_unlock(&network_ctrl.m_mutex);
return 2;
}
//_MSG("TmpResponse :%s, len = %d\n", TmpResponse, strlen(TmpResponse));
memcpy(response, TmpResponse, sizeof(char) * 512);
pthread_mutex_unlock(&network_ctrl.m_mutex);
return 0;
}
int _network_change_apn(const char *apn)
{
int i=0,num;
char str[100][256]={{0}};
char linedata[256]={0};
FILE *fp=fopen("/etc/ppp/peers/quectel-chat-connect","r");
if(NULL == fp)
{
LOG("fopen failed [%d:%s]", errno, strerror(errno));
return -1;
}
while (fgets(linedata,sizeof(linedata)-1,fp))
{
if (strstr(linedata,"AT+CGDCONT")!=NULL)
{
sprintf(str[i],"OK \\rAT+CGDCONT=1,\"IP\",\"%s\",,0,0\n",apn);
}
else
{
strcpy(str[i],linedata);
}
i++;
}
fclose(fp);
num=i;
FILE * fpw = fopen("/etc/ppp/peers/quectel-chat-connect","w");
for (i=0;i<num;i++)
{
fputs(str[i],fpw);
}
fflush(fpw);
fclose(fpw);
return 0;
}
void _network_usb_4g_power_on(void)
{
LOG("\n");
GPIO_USB_4G_PWR(ON);
GPIO_USB_4G_WAKEUP(ON);
sleep(5);
}
void _network_usb_4g_reset(void)
{
/* RST
____ ___ ____
| |
| |
|-------------------|
|<---150ms~460ms--->|
*
*/
LOG("\n");
GPIO_USB_4G_RST(1); // low
usleep(350*1000);
GPIO_USB_4G_RST(0); // high
sleep(30);
}
void _network_quectel_exec(void)
{
char cmd[250] = {0};
strcpy(cmd, "pppd call quectel-ppp &");
LOG("%s", cmd);
system(cmd);
sleep(20);
}
void _network_kill_ppp()
{
char cmd[250] = {0};
strcpy(cmd, "killall pppd");
LOG("%s", cmd);
system(cmd);
}
int _network_check_usb_exist(const char* iDevPath)
{
int iReturnCode = 0;
struct stat tmpstat;
if (NULL == iDevPath)
{
iReturnCode = 1;
}
else
{
if (stat(iDevPath, &tmpstat) != 0)
{
LOG("4G module USB not exist!\n");
iReturnCode = 1;
}
}
return iReturnCode;
}
int _network_ppp_check(void)
{
char cmd[100];
FILE *Read_fp;
int chars_read;
char buffer[1000];
static int ResetEC20Cnt = 0; //重启次数
memset(buffer,0,1000);
memset(cmd,0,100);
sprintf(cmd,"ifconfig | grep ppp0");
Read_fp = popen(cmd,"r");
if(Read_fp != NULL)
{
chars_read = fread(buffer,sizeof(char),1000-1,Read_fp);
pclose(Read_fp);
if(chars_read > 0)
{
ResetEC20Cnt = 0;
return 1;
}
else
{
ResetEC20Cnt++;
if(ResetEC20Cnt > 6)
{
ResetEC20Cnt = 0;
reboot_system(LOG_NETWORK, BOOT_PPP_NO_FOUND);
}
system("killall pppd");
_network_usb_4g_power_on();
_network_usb_4g_reset();
LOG("ppp0:No Found.EC20 掉线");
_network_quectel_exec();
}
}
return 0;
}
int _network_ppp_check_test(void)
{
char cmd[100];
FILE *Read_fp;
int chars_read;
char buffer[1000];
memset(buffer,0,sizeof(buffer));
memset(cmd,0,sizeof(cmd));
sprintf(cmd,"ifconfig | grep ppp0");
Read_fp = popen(cmd,"r");
if(Read_fp != NULL)
{
chars_read = fread(buffer,sizeof(char),1000-1,Read_fp);
pclose(Read_fp);
if(chars_read > 0)
{
//LOG("ppp0 success");
return 1;
}
}
LOG("not found ppp0");
return 0;
}
void _network_connect_4g()
{
int iReturnCode = -1;
char response[512] = {0};
if (network_ctrl.net_dev_stat == PPP_ON)
{
//if (_network_get_module_type() == WCDMA_EC20)
//{
// ret_code = _network_AT_read_operation(DEV_NAME_4G_QUECTEL, "AT+CSQ\r\n", "+CSQ:", response);
//}
if (_network_check_usb_exist(DEV_NAME_4G_QUECTEL) != 0)
{
network_ctrl.net_dev_stat = PPP_OFF;
}
//iReturnCode = _network_AT_read_operation(DEV_NAME_4G_QUECTEL, "AT+CSQ\r\n", "+CSQ:", response, 0);
//LOG("at return=%d", iReturnCode);
//LOG("response=%s", response);
}
else
{
//_network_usb_4g_reset();
//sleep(20);
_network_quectel_exec();
network_ctrl.net_dev_stat = PPP_ON;
sleep(20);
}
}
void _network_recovery_dial_file()
{
int i, num;
char src[128] = {0};
char cmd[256] = {0};
char file_path[128] = {0};
char file_name[][128] =
{
"quectel-chat-connect",
"quectel-chat-disconnect",
"quectel-dial",
"quectel-ppp"
};
num = sizeof(file_name)/sizeof(file_name[0]);
//LOG("num=%d\n", num);
for (i = 0; i < num; i++)
{
snprintf(file_path, 128, "%s/%s", DIAL_PPP_PATH, file_name[i]);
if (access(file_path, F_OK))
{
snprintf(src, 128, "%s/%s", DIAL_PPP_BAK_PATH, file_name[i]);
if (access(src, F_OK) == 0)
{
snprintf(cmd, 256, "cp -rf %s %s", src, DIAL_PPP_PATH);
system(cmd);
LOG("exec:%s\n", cmd);
usleep(100*1000);
}
}
}
}
void *_network_manage_thread(void *args)
{
//_network_connect_4g();
int reset_cnt = 0;
int ppp_not_found_cnt = 0;
int start_4g_flag = 0;
while (1)
{
if (pparam_config->gateway.radioType != 1)
{
DBG(DBG_M_CA_NETWORK, "radioType:%d", pparam_config->gateway.radioType);
sleep(1);
continue;
}
if (start_4g_flag == 0)
{
start_4g_flag = 1;
_network_usb_4g_power_on();
LOG("4G module power on");
sleep(15);
_network_quectel_exec();
}
if (access(DEV_NAME_4G_QUECTEL, F_OK) == 0)
{
reset_cnt = 0;
if (_network_ppp_check_test() == 0)
{
// not found ppp0
if (++ppp_not_found_cnt >= 6)
{
LOG("ppp0 not found > %d times, should reboot.", ppp_not_found_cnt);
ppp_not_found_cnt = 0;
reboot_system(LOG_NETWORK, BOOT_PPP_NO_FOUND);
}
_network_kill_ppp();
_network_usb_4g_power_on();
_network_usb_4g_reset();
_network_quectel_exec();
}
else
{
// found ppp0
ppp_not_found_cnt = 0;
// The connection still fails in the presence of ppp0 and needs to be restarted
if (pparam_config->gateway.CommunicationMode == 2)
{
if (mqtt_reconn_times > 6)
{
reboot_system(LOG_NETWORK, BOOT_PPP_FOUND_MQTT_LINK_FAIL);
}
}
else
{
if (csg_reconn_times > 10)
{
reboot_system(LOG_NETWORK, BOOT_PPP_FOUND_CSG_LINK_FAIL);
}
}
}
}
else
{
ppp_not_found_cnt = 0;
LOG("%s is not exist!!!! reset_cnt = %d\n", DEV_NAME_4G_QUECTEL, reset_cnt);
if (++reset_cnt >= 6)
{
reset_cnt = 0;
reboot_system(LOG_NETWORK, BOOT_TTYUSB_NO_FOUND);
}
_network_usb_4g_power_on();
_network_usb_4g_reset();
}
_network_recovery_dial_file();
sleep(1);
}
}
int _network_handle_init_common()
{
struct sched_param param;
pthread_attr_t attr;
pthread_t pid;
int32_t rv = 0;
/* 配置线程RR调度, 优先级72 */
pthread_attr_init(&attr);
param.sched_priority = 76;
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedparam(&attr, &param);
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
rv = pthread_create(&pid, &attr, _network_manage_thread, NULL);
if (rv != 0)
{
log_err(LOG_NETWORK, "PD can't create _network_manage_thread %d!", rv);
return E_ERROR;
}
else
{
thread_m_add("CA_NETWORK", pid);
}
pthread_attr_destroy(&attr);
return E_NONE;
}
/* Interface functions -------------------------------------------------------*/
/* 4G模块初始化. */
int network_handle_init(void)
{
//_network_usb_4g_power_on();
//LOG("4G module power on");
//sleep(15);
memset(&network_ctrl, 0, sizeof(network_ctrl));
network_ctrl.net_dev_stat = PPP_OFF;
pthread_mutex_init(&network_ctrl.m_mutex, NULL);
/* 初始化模块. */
LD_E_RETURN(DBG_M_CA_NETWORK_ERR, _network_handle_init_common());
return E_NONE;
}