--- /dev/null
+# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# UDP_CMD_GET_CAT1VER = '0', // 获取 Cat1 版本号
+# UDP_CMD_DIAL_NUMB = '1', // 拨打电话
+# UDP_CMD_HUNGUP = '2', // 挂断电话
+# UDP_CMD_ANSWER = '3', // 接听电话
+# UDP_CMD_CAT1_OTA_UPDATE = '4', // 触发Cat1 OTA升级,mcu提供url
+# UDP_CMD_SEND_SMS = '5', // 发送SMS短信,mcu提供电话号及短信内容
+# UDP_CMD_GET_TIME = '6', // 获取Cat1 时间 ,YYYYMMDD HHmmss zone
+# UDP_CMD_GET_NETWORKSTAT = '7', //获取Cat1 信号信息,VOLTE信息,信号强度,SIM卡状态
+# UDP_MSG_SMS = '8', // CAT1接收到的SMS信息给MCU,包含电话号及短信内容
+# UDP_MSG_NETWORKSTAT = '9', // 内容同UDP_CMD_GET_NETWORKSTAT,CAT主动发给MCU
+# UDP_MSG_CALL_CONNECTED = 'A', // CAT1 电话接听消息
+# UDP_MSG_CALL_DISCONNECTED = 'B', // CAT1 电话挂断消息
+# UDP_MSG_COMMING_CALL = 'C' , // CAT1 来电消息,包含电话号
+# UDP_MSG_TIMESYNC = 'D' , // CAT1 来电消息,包含电话号
+# UDP_MSG_MAX = 'F' //
+
+# net.getNetMode()
+# (0, '460', '11', 7)
+
+# net.getSignal(1)
+# ([99, 99, 255, 255], [-84, -117, -15, 255, -3])
+
+# net.nitzTime()
+# ('24/02/26 11:17:42 8 0', 1708946262, 0)
+
+
+import usocket
+import log
+import utime
+import slip
+import audio
+from machine import UART
+import _thread
+from queue import Queue
+from machine import Pin
+from machine import ExtInt
+import dataCall
+import voiceCall
+import net
+import uping
+import example
+import osTimer
+import sim
+import modem
+import utime
+
+PROJECT_NAME = "Cat1SlipUDPService"
+PROJECT_VERSION = "V2"
+
+# 设置日志输出级别
+log.basicConfig(level=log.INFO)
+cat1service_log = log.getLogger("cat1service")
+timer = osTimer()
+audio.set_qdai_cfg(1,0,0,1,0,0,1,1)
+
+# GPIO21 - 86 KP_MKOUT1 唤醒主控
+# GPIO22 - 87 KP_MKIN 被主控唤醒
+def ExtIntfun(args):
+ print('### interrupt {} ###'.format(args)) # args[0]:gpio号 args[1]:上升沿或下降沿
+extint = ExtInt(ExtInt.GPIO22, ExtInt.IRQ_FALLING, ExtInt.PULL_PU, ExtIntfun)
+
+# 创建gpio对象
+gpioWakeBT = Pin(Pin.GPIO21, Pin.OUT, Pin.PULL_DISABLE, 1)
+# 设置输入输出模式
+gpioWakeBT.set_dir(Pin.OUT)
+
+# 设置引脚电平
+# gpioWakeBT.write(1)
+
+class Cat1Service:
+ AP = 0 # SLIP_INNER
+ STA = 1 # SLIP_OUTER
+
+ def __init__(self, uart=UART.UART4, mode=STA, callback=None):
+ self.__uart = uart
+ self.__mode = mode
+ self.__message = ''
+ self.__err = 0
+ self.__callback = callback
+ self.__value = None
+ self.__wait_resp = 0
+ slip.destroy()
+ print('slip uart={0}'.format (self.__uart))
+
+ ret = slip.construct(self.__uart, self.__mode, 0)
+ if ret != 0:
+ print('slip netif construct fail')
+ return None
+ print('slip network card create success')
+ self.__queue = Queue(1)
+ self.__sock = self.__socket_init()
+ self.__threadid = _thread.start_new_thread(self.__Socket_Thread, ())
+ return None
+
+ def __socket_init(self):
+ # 创建一个socket实例
+ sock = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM, usocket.TCP_CUSTOMIZE_PORT)
+ sock.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
+ # 绑定IP
+ bind_addr = ('172.16.1.2', 5000)
+ sock.bind(bind_addr)
+ sock.settimeout(10)
+ return sock
+
+ def __socket_reinit(self):
+ return self.__socket_init()
+
+
+ def btmcu_cmd_handler(self,cmd,parm):
+ print("btmcu_cmd_handler cmd {0} , args {1}".format(cmd,parm))
+ if cmd == "F0":
+ print(cmd)
+ # UDP_CMD_GET_CAT1VER
+ self.reply_cmd('FE',PROJECT_VERSION)
+ elif cmd == "F1":
+ print("{}{}".format(cmd,parm))
+ # UDP_CMD_DIAL_NUMB
+ voiceCall.callStart(parm)
+ elif cmd == "F2":
+ print(cmd)
+ # UDP_CMD_HUNGUP
+ voiceCall.callEnd()
+ elif cmd == "F3":
+ print(cmd)
+ # UDP_CMD_ANSWER
+ voiceCall.callAnswer()
+ elif cmd == "F4":
+ print(cmd)
+ # UDP_CMD_CAT1_OTA_UPDATE
+ example.exec("/usr/checkota.py")
+ elif cmd == "F5":
+ print(cmd)
+ # UDP_CMD_SEND_SMS
+ elif cmd == "F6":
+ print(cmd)
+ # UDP_CMD_GET_TIME
+ time=utime.localtime()
+ zone=utime.getTimeZone()
+ #(2024, 3, 2, 18, 31, 32, 5, 62),8
+ self.reply_cmd('FD',"{0},{1}".format(time,zone))
+ elif cmd == "F7":
+ print(cmd)
+ # UDP_CMD_GET_NETWORKSTAT
+ simstat = sim.getStatus()
+ imei = modem.getDevImei()
+ netstat = net.getSignal(1)
+ operator = net.operatorName()
+ print("imei:{0},sim:{1},oper:{2},net:{3}".format(imei,simstat,operator,netstat))
+ self.reply_cmd('F9',"imei:{0},sim:{1},oper:{2},net:{3}".format(imei,simstat,operator,netstat))
+ # 来电提醒
+ def notifyIncomingcall(self, incomming_numb):
+ self.clear_remain()
+ __head = 'FC'
+ self.__message = str(incomming_numb)
+ self.__Socket_UDP(__head, self.__message)
+ if self.__err == 1 or self.__value[2] != 'OK':
+ return -1
+ return 0
+
+ # 电话接听消息
+ def notifyConnecteCall(self):
+ self.clear_remain()
+ __head = 'FA'
+ self.__message = '0'
+ self.__Socket_UDP(__head, self.__message)
+ if self.__err == 1 or self.__value[2] != 'OK':
+ return -1
+ return 0
+
+ # 电话拒接消息
+ def notifyDisconnectCall(self):
+ self.clear_remain()
+ __head = 'FB'
+ self.__message = '0'
+ self.__Socket_UDP(__head, self.__message)
+ if self.__err == 1 or self.__value[2] != 'OK':
+ return -1
+ return 0
+
+
+
+ # 查询网卡状态
+ def timesync(self,_timesync):
+ self.clear_remain()
+ self.__message = str(_timesync)
+ self.__Socket_UDP('FD', self.__message)
+ if self.__err == 1 or self.__value[2] != 'OK':
+ return -1
+ return 0
+
+ # 查询网卡版本信息
+ def version(self):
+ self.clear_remain()
+ self.__Socket_UDP('F5', '0')
+ if self.__err == 1:
+ return -1
+ return self.__value[2]
+
+ def reply_timesync(self,_timesync):
+ self.clear_remain()
+ self.__message = str(_timesync)
+ self.__Socket_UDP_noreply('FD', self.__message)
+ return 0
+
+ def reply_cmd(self,cmd,_timesync):
+ self.clear_remain()
+ self.__message = str(_timesync)
+ self.__Socket_UDP_noreply(cmd, self.__message)
+ return 0
+
+ def clear_remain(self):
+ if self.__queue.empty() == False:
+ self.__queue.get()
+ self.__err = 0
+ self.__value = None
+ #添加路由信息
+ def router_add(self, ip='192.168.4.1', mask='255.255.255.0'):
+ self.ip = ip
+ self.mask = mask
+ return slip.router_add(self.ip, self.mask)
+
+ # 获取slip的网络配置
+ def ipconfig(self):
+ return slip.ipconfig()
+
+ # 设置dns服务器
+ def set_dns(self, pri_dns='8.8.8.8', sec_dns='114.114.114.114'):
+ self.pri_dns = pri_dns
+ self.sec_dns = sec_dns
+ return slip.set_dns(self.pri_dns,self.sec_dns)
+
+ # 设置默认网卡
+ def set_default_NIC(self, ip_str):
+ self.ip_str = ip_str
+ return slip.set_default_netif(self.ip_str)
+
+ # 释放slip网卡
+ def stop(self):
+ slip.destroy()
+ return 0
+
+
+ # 封装tlv数据包
+ def __pack_tlv_format(self, head, content):
+ self.head = head
+ self.content = content
+ if len(self.content) == 0 or len(self.content) > 9999 or len(self.head) != 2:
+ print('illegal pack tlv content')
+ return -1
+ len_str ='%04d' % len(self.content)
+ tlv_pack = self.head+len_str+self.content
+ return tlv_pack
+
+ # 解码tlv数据包
+ def __unpack_tlv_format(self, msg):
+ self.msg = str(msg)
+ tag = self.msg[0:2]
+ length = self.msg[2:6]
+ value = self.msg[6:]
+ len_str ='%04d' % len(value)
+ if len(value) == 0 or len(value) > 9999 or len(tag) != 2 or len_str != self.msg[2:6]:
+ print('illegal unpack tlv content')
+ return -1
+ unpack = (tag,length,value)
+ return unpack
+
+ # socket通信(UDP)模块
+ def __Socket_UDP(self, head, content):
+ try:
+ self.head = head
+ self.content = content
+
+ # 消息处理
+ msg = self.__pack_tlv_format(self.head, self.content)
+
+ # 向服务端发送消息
+ server_addr = ('172.16.1.5',1000)
+ print("send msg {}".format(msg))
+ self.__err = 0
+ self.__sock.sendto(msg,server_addr)
+ self.__wait_resp = 1
+ # data = self.__queue.get()
+ self.__wait_resp = 0
+ # return data
+ return 1
+ except Exception as error:
+ print(error)
+ return 0
+
+ def __Socket_UDP_noreply(self, head, content):
+ self.head = head
+ self.content = content
+ # 消息处理
+ msg = self.__pack_tlv_format(self.head, self.content)
+ # 向服务端发送消息
+ server_addr = ('172.16.1.5',1000)
+ print("send msg {}".format(msg))
+ self.__err = 0
+ self.__sock.sendto(msg,server_addr)
+ self.__wait_resp = 0
+ return 0
+
+ # socket通信(UDP)模块
+ def __Socket_Thread(self):
+ while True:
+ try:
+ print("recv====")
+ data=self.__sock.recv(1024)
+ print(data)
+ except Exception as recverr:
+ print(recverr)
+ if "110" in str(recverr):
+ self.__err = 1
+ if self.__wait_resp == 1:
+ self.__queue.put('0')
+ else:
+ utime.sleep(1)
+ self.__sock = self.__socket_reinit()
+
+ else :
+ value = self.__unpack_tlv_format(data.decode())
+ print('mode: {0}, recv {1} bytes, Data: {2}'.format (value[0],len(data), value[2]))
+ if value[0] == 'FF':
+ self.btmcu_cmd_handler(value[0],value[2])
+ else:
+ self.__value = value
+ self.__queue.put('1')
+ self.btmcu_cmd_handler(value[0],value[2])
+ print("End else Thread")
+
+ print("End Socket Thread")
+
+
+
+
+# UDP_CMD_GET_CAT1VER = '0', // 获取 Cat1 版本号
+# UDP_CMD_DIAL_NUMB = '1', // 拨打电话
+# UDP_CMD_HUNGUP = '2', // 挂断电话
+# UDP_CMD_ANSWER = '3', // 接听电话
+# UDP_CMD_CAT1_OTA_UPDATE = '4', // 触发Cat1 OTA升级,mcu提供url
+# UDP_CMD_SEND_SMS = '5', // 发送SMS短信,mcu提供电话号及短信内容
+# UDP_CMD_GET_TIME = '6', // 获取Cat1 时间 ,YYYYMMDD HHmmss zone
+# UDP_CMD_GET_NETWORKSTAT = '7', //获取Cat1 信号信息,VOLTE信息,信号强度,SIM卡状态
+# 下文进行系统配置
+print("Cat1Service start")
+
+cat1service = Cat1Service()
+Info = dataCall.getInfo(1,0)
+print("Info{}".format(Info))
+default_NIC_ip = Info[2][2] # 假设默认网卡ip地址为10.10.1.1,请根据实际情况更改
+segment_ip = '172.16.4.5' # 假设ap模式网段范围是[192.168.4.0 ~ 192.168.4.255],请根据实际情况更改
+mask = '255.255.255.0' # 假设子网掩码为255.255.255.0,请根据实际情况更改
+# 配置默认网卡,通过默认网卡进行网络转发
+cat1service.set_default_NIC(default_NIC_ip)
+print("default_NIC_ip {0} segment_ip {1}".format(default_NIC_ip,segment_ip))
+#添加路由规则,只有该网段IP才进行转发
+cat1service.router_add(segment_ip, mask)
+
+pri_dns = '8.8.8.8' # 假设DNS首选地址为8.8.8.8,请根据实际情况更改
+sec_dns = '114.114.114.114' # 假设DNS备选地址为114.114.114.114,请根据实际情况更改
+# 配置网卡DNS服务器
+cat1service.set_dns(pri_dns, sec_dns)
+# 网卡IP信息查询
+cat1service.ipconfig()
+
+
+#voice call callback function
+def voice_callback(args):
+ if args[0] == 10:
+ print('voicecall incoming call, PhoneNO: ', args[6])
+ # gpioWakeBT.write(1)
+ cat1service.notifyIncomingcall(args[6])
+ elif args[0] == 11:
+ print('voicecall connected, PhoneNO: ', args[6])
+ cat1service.notifyConnecteCall()
+ elif args[0] == 12:
+ print('voicecall disconnect')
+ cat1service.notifyDisconnectCall()
+ # gpioWakeBT.write(0)
+ elif args[0] == 13:
+ print('voicecall is waiting, PhoneNO: ', args[6])
+ elif args[0] == 14:
+ print('voicecall dialing, PhoneNO: ', args[6])
+ elif args[0] == 15:
+ print('voicecall alerting, PhoneNO: ', args[6])
+ elif args[0] == 16:
+ print('voicecall holding, PhoneNO: ', args[6])
+
+#电话消息反馈
+voiceCall.setCallback(voice_callback)
+
+
+def checknet_cb(arg):
+ print("start checktime!!")
+ time=utime.localtime()
+ zone=utime.getTimeZone()
+ #(2024, 3, 2, 18, 31, 32, 5, 62),8
+ cat1service.timesync("{0},{1}".format(time,zone))
+
+timer.start(200000,1,checknet_cb)
+
+
+# while True:
+# utime.sleep(5)
+
+
+# uping.ping("172.16.1.5")
+ # 获取网卡当前工作状态
+
+# gpioWakeBT.write(1)
+# utime.sleep(1)
+
+# timesync = net.nitzTime()
+# cat1service.timesync(timesync)
#include "common.h"
#endif
-
+#include "sys/time.h"
+#include "time.h"
uint32_t zh_get_sn(uint8_t *buf_sn, uint32_t *len_sn)
{
return ERRCODE_SUCC;
}
+#define BITS_PER_BYTE 8
+#define HEXADECIMAL 16
+#define DECIMAL 10
+#define TIME_YEAR_OFFSET 70
+#define TIME_ZONE_OFF (8 * 60)
+#define TIME_SECSPERMIN 60 /* second per minute */
+static uint32_t get_sec_time_from_cat1time(char* time , uint32_t *second , uint8_t *zone)
+{
+
+ struct tm tm = { 0 };
+ char* ptr = time;
+ char* tmp;
+
+ if (time==NULL || strlen(time) < 12)
+ {
+ printf("time==NULL || strlen(time) < 12 , format error, should like (2024, 3, 2, 18, 40, 1, 5, 62),8 ");
+ return 2;
+ }
+ // if (time[0] == '(' && time[1] == '\'')
+ // {
+ // printf("time format error, should like (2024, 3, 2, 18, 40, 1, 5, 62),8 ");
+ // return 3;
+ // }
+ // ptr += 2;
+
+ // 年
+ tmp = strchr(ptr, '(');
+ if (tmp == NULL) { return 1; }
+ ptr = tmp + 1;
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ *tmp = '\0';
+ // 年的计算需要减去1900
+ tm.tm_year = strtol(ptr, NULL, DECIMAL) - 1900;
+ if (tm.tm_year < TIME_YEAR_OFFSET) {
+ printf("ERR!year num must bigger than 1970!");
+ return 3;
+ }
+ ptr = tmp + 1;
+
+
+ // 月
+ if ( *ptr == ' ') { ptr = ptr + 1; }
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ *tmp = '\0';
+ // 月的计算需要减1
+ tm.tm_mon = strtol(ptr, NULL, DECIMAL) - 1;
+ ptr = tmp + 1;
+
+ // 日
+ if ( *ptr == ' ') { ptr = ptr + 1; }
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ *tmp = '\0';
+ tm.tm_mday = strtol(ptr, NULL, DECIMAL);
+ ptr = tmp + 1;
+
+ // 时
+ if ( *ptr == ' ') { ptr = ptr + 1; }
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ *tmp = '\0';
+ tm.tm_hour = strtol(ptr, NULL, DECIMAL);
+ ptr = tmp + 1;
+
+ // 分
+ if ( *ptr == ' ') { ptr = ptr + 1; }
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ *tmp = '\0';
+ tm.tm_min = strtol(ptr, NULL, DECIMAL);
+ ptr = tmp + 1;
+
+ // 秒
+ if ( *ptr == ' ') { ptr = ptr + 1; }
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ *tmp = '\0';
+ tm.tm_sec = strtol(ptr, NULL, DECIMAL);
+ ptr = tmp + 1;
+
+ //毫秒
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ ptr = tmp + 1;
+ //微妙
+ tmp = strchr(ptr, ',');
+ if (tmp == NULL) { return 1; }
+ ptr = tmp + 1;
+
+ //时区
+ if ( *ptr == ' ') { ptr = ptr + 1; }
+ *zone = strtol(ptr, NULL, DECIMAL);
+ *second = (uint32_t)__tm_to_secs(&tm);
+ *second -= *zone * 3600; //cat1获得的时间时当下时间,实际上要减去zone的时间
+
+ // printf("%04d-%02d-%02d %02d:%02d:%02d %d\n",tm.tm_year,tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,*zone);
+ return 0;
+}
+errcode_t uapi_set_time_from_cat1(char* cat1time)
+{
+ uint8_t zone = 0;
+ uint32_t sec = 0;
+ uint32_t ret = get_sec_time_from_cat1time(cat1time,&sec,&zone);
+
+ if (ret == 0 )
+ {
+ struct timeval tv = { 0 };
+ struct timezone tz = { 0 };
+
+ tv.tv_sec = sec;
+ tv.tv_usec = 0;
+ tz.tz_dsttime = 0;
+ tz.tz_minuteswest = zone*60;
+ settimeofday(&tv, &tz);
+
+
+ time_t rawtime;
+ struct tm* timeinfo;
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+
+ printf("%04d-%02d-%02d %02d:%02d:%02d %d\n",
+ timeinfo->tm_year + 1900,
+ timeinfo->tm_mon + 1,
+ timeinfo->tm_mday,
+ timeinfo->tm_hour,
+ timeinfo->tm_min,
+ timeinfo->tm_sec,zone);
+
+ printf("set time success %s !\n",cat1time);
+
+ }else{
+ printf("convert to time failed ret %d!\n",ret);
+ return ERRCODE_FAIL;
+ }
+
+
+
+ return ERRCODE_SUCC;
+}
#if 0