From: snickersun@163.com Date: Thu, 18 Sep 2025 14:28:02 +0000 (+0000) Subject: Merge #2303 into sdk650pathc0423 from refs/changes/2303/head X-Git-Tag: leiniao_debug_1.0.0_20250922_020716~48^2 X-Git-Url: http://git.snicker.com.cn/css/static/gitweb.css?a=commitdiff_plain;h=3a99c786f01a66f7bab6d9a827d750cdc97988a4;p=mirrors%2FFD230.git Merge #2303 into sdk650pathc0423 from refs/changes/2303/head Code review from snickersun@163.com * refs/changes/2303/head: (7 commits squashed) - ppp默认打印等级info,降级一些打印, - Merge branch 'sdk650pathc0423' of codeup.aliyun.com:64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423 - ssb也使用500000波特率打印日志 - 雷鸟兼容EG810的配置,cat1固件选择w9的固件,并更新cat1Service.py 优化ppp协议响应速度 - Merge branch 'sdk650pathc0423' of codeup.aliyun.com:64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423 - 添加雷鸟EG810 固件 - Merge branch 'sdk650pathc0423' of codeup.aliyun.com:64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423 Signed-off-by: snickersun@163.com Reviewed-by: snickersun@163.com Merged-by: snickersun@163.com CR-link: https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230/change/2303 --- diff --git a/cat1modem/leiniao/EG810MCNLAR06A01M08_VOLTE_OCPU_QPY_TEST0725_LN_PY_SRV_V23_20250918-2225.zip b/cat1modem/leiniao/EG810MCNLAR06A01M08_VOLTE_OCPU_QPY_TEST0725_LN_PY_SRV_V23_20250918-2225.zip new file mode 100644 index 000000000..87eb19b0a Binary files /dev/null and b/cat1modem/leiniao/EG810MCNLAR06A01M08_VOLTE_OCPU_QPY_TEST0725_LN_PY_SRV_V23_20250918-2225.zip differ diff --git a/cat1modem/src/LeiNiao/EventMesh.py b/cat1modem/src/LeiNiao/EventMesh.py new file mode 100644 index 000000000..7951835b2 --- /dev/null +++ b/cat1modem/src/LeiNiao/EventMesh.py @@ -0,0 +1,86 @@ +import _thread +import usys +import ql_fs +CHINA_TELECOM_DM_FUN_ENABLE = 1 #是否开启电信入库的功能 +CHINA_MOBILE_DM_FUN_ENABLE = 1 #开启移动入库功能 +class EventStore(object): + def __init__(self): + self.map = dict() + self.log = None + self.__filters = [] + + def add_filter(self, flt): + self.__filters.append(flt) + + def append(self, event, cb): + self.map[event] = cb + + def fire_async(self, event, msg,thread_size): + if event in self.map: + #print("fire_async:thread_size:{}".format(thread_size)) + if thread_size != None: + _thread.stack_size(thread_size) + #print("fire_async:thread_size:{}".format(thread_size)) + _thread.start_new_thread(self.map[event], (event, msg)) + if thread_size != None: + _thread.stack_size(8*1024) + if self.log: + self.log.info("ASYNC executed (event) -> {} (params) -> {} (result) -> {}".format(event, msg, None)) + + def fire_sync(self, event, msg): + res = None + try: + if event in self.map: + res = self.map[event](event, msg) + except Exception as e: + usys.print_exception(e) + if self.log: + self.log.info("ERROR executed (event) -> {} (params) -> {} (result) -> {}".format(event, msg, res)) + if event not in self.__filters: + if self.log: + self.log.info("SYNC executed (event) -> {} (params) -> {} (result) -> {}".format(event, msg, res)) + return res + + def subscribe(self,event, cb): + """ + subscribe event and cb + """ + return self.append(event, cb) + + + def publish(self,event, msg=None): + """ + publish event and msg + """ + return self.publish_sync(event, msg) + + + def publish_async(self,event, msg=None,thread_size = None): + """ + 异步发送 + """ + return self.fire_async(event, msg,thread_size) + + + def publish_sync(self,event, msg=None): + """ + 同步发送 + """ + return self.fire_sync(event, msg) + + + def set_log(self,log_adapter): + self,log = log_adapter + + + def add_filter(self,flt): + self.add_filter(flt) + +eventMesh = EventStore() + + + + + + + diff --git a/cat1modem/src/LeiNiao/cat1Service.py b/cat1modem/src/LeiNiao/cat1Service.py new file mode 100644 index 000000000..3f2f47af2 --- /dev/null +++ b/cat1modem/src/LeiNiao/cat1Service.py @@ -0,0 +1,1122 @@ +# 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. +# + + +# 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 +import checkNet +import atcmd +import fota +import request +import ql_fs +import pm +import sms +import ujson + +from usr.EventMesh import eventMesh + +from usr.httpota import httpota +from usr.telecom_dmp import telecomDmpCb +from usr.china_mobile_dmp import chinamobileCb + +from usr.china_mobile_ai_regulation import aiRegulation +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +clog = log.getLogger("cat1") + +def msg_cb(args): + index = args[1] + storage = args[2] + sms_data = sms.getSaveLoc() + if sms_data == -1: + return + sms_max = sms_data[0][2] + if index != -1: + eventMesh.publish("send_singal_data_toBle",index) + + if index >= sms_max-1:#删除短信 + eventMesh.publish("delete_sms_event")#删除短信 + +sms.setCallback(msg_cb)#sms注册回调 + +CAT1_SERVICE_HEAD = 'FE' #固定head + +PROJECT_NAME = "Cat1SlipUDPService" +PROJECT_VERSION = "PY_SRV_V23" +CONFIG_JSON="/usr/system_config.json" +CURRENT_APP_TYPE="pysrv" + + + + + + +#设置通话音量 +voiceCall.setVolume(10) +clog.info("voice call volume {}".format(voiceCall.getVolume())) +lpm_fd = pm.create_wakelock("system_lock", len("system_lock")) +# pm.autosleep(1) +pm.wakelock_lock(lpm_fd) +clog.info("create_wakelock {}".format(pm.get_wakelock_num())) +telecomTimerCount = 0 +def get_versionkeyname_by_py(app_type): + return str("{}version".format(app_type)) + +def get_default_versionvalue_by_py(app_type): + if (app_type == "pymain"): + return "PY_MAIN_V2" + elif (app_type == "pyota"): + return "PY_OTA_V14" + elif (app_type == "pysrv"): + return "PY_SRV_V16" + +#如果没有configfile则创建它 +if not ql_fs.path_exists(CONFIG_JSON): + data = {str(get_versionkeyname_by_py(CURRENT_APP_TYPE)):get_default_versionvalue_by_py(CURRENT_APP_TYPE)} + ql_fs.touch(CONFIG_JSON,data) + +def set_version_to_json_config(app_type,keyvalue): + try : + config_data = ql_fs.read_json(CONFIG_JSON) + config_data.update( {str(get_versionkeyname_by_py(app_type)):keyvalue}) + ql_fs.touch(CONFIG_JSON, config_data) + clog.info("{}={}".format(get_versionkeyname_by_py(app_type),keyvalue)) + clog.info("{}".format(config_data)) + except Exception as e: + clog.error("set_version_to_json_config") + +def get_version_from_json_config(app_type): + config_data = ql_fs.read_json(CONFIG_JSON) + keyvalue = config_data.get( get_versionkeyname_by_py(app_type),get_default_versionvalue_by_py(app_type)) + clog.info("{}={}".format(get_versionkeyname_by_py(app_type),keyvalue)) + return keyvalue + +set_version_to_json_config(CURRENT_APP_TYPE,PROJECT_VERSION) + + +audio.set_qdai_cfg(1,0,0,1,0,0,1,1) + +# GPIO21 - 引脚 86 KP_MKOUT1 唤醒主控 +# GPIO22 - 引脚 87 KP_MKIN 被主控唤醒 + +# GPIOn - GPIO号,int类型,点此查看GPIO引脚编号与物理引脚的映射关系。 + +# direction - 输入输出模式,int类型,IN - 输入模式,OUT - 输出模式。 + +# pullMode - 上下拉模式,int类型,说明如下: +# PULL_DISABLE - 浮空模式 +# PULL_PU - 上拉模式 +# PULL_PD - 下拉模式 + +# level - 引脚电平,int类型,0 - 设置引脚为低电平, 1- 设置引脚为高电平。 +# recvDataPin = Pin(Pin.GPIO22, Pin.IN, Pin.PULL_PU, 0) +def ExtIntfun(args): + # clog.info('### interrupt {} ###'.format(args)) # args[0]:gpio号 args[1]:上升沿或下降沿 + if args[1] == 0: + clog.info("disable autosleep") + # pm.autosleep(0) + pm.wakelock_lock(lpm_fd) + elif args[1] == 1: + clog.info("enable autosleep") + pm.wakelock_unlock(lpm_fd) + # pm.autosleep(1) + # clog.info("recvDataPin={}".format(recvDataPin.read())) +extint = ExtInt(ExtInt.GPIO22, ExtInt.IRQ_RISING_FALLING, ExtInt.PULL_DISABLE, ExtIntfun) +extint.enable() + + +# 创建gpio对象 +gpioWakeBT = Pin(Pin.GPIO21, Pin.OUT, Pin.PULL_DISABLE, 1) +# 设置输入输出模式 +gpioWakeBT.set_dir(Pin.OUT) + +# 设置引脚电平 +gpioWakeBT.write(0) + +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_RECV_NETWORKSTAT = '7' #获取Cat1 信号信息,VOLTE信息,信号强度,SIM卡状态 // 内容同UDP_CMD_GET_NETWORKSTAT,CAT主动发给MCU +UDP_MSG_SMS = '8' # CAT1接收到的SMS信息给MCU,包含电话号及短信内容 +UDP_CMD_ATCMD = '9' # 执行AT指令 +UDP_MSG_CALL_CONNECTED = 'A' # CAT1 电话接听消息 +UDP_MSG_CALL_DISCONNECTED = 'B' # CAT1 电话挂断消息 +UDP_MSG_COMMING_CALL = 'C' # CAT1 来电消息,包含电话号 +UDP_MSG_REPLY = 'F' # 返回值 +UDP_MSG_OTA = 'D' # 返回值 + +class Cat1Service: + AP = 0 # SLIP_INNER + STA = 1 # SLIP_OUTER + + def __init__(self, uart=UART.UART2, mode=AP): + + self.__uart = uart + self.__mode = mode + self.__message = '' + self.__err = 0 + self.__net_connected = 0 + # self.__value = None + self.__wait_resp = 0 + self.__waiting_netstat = 0 + slip.destroy() + clog.info('slip uart={0}'.format (self.__uart)) + + ret = slip.construct(self.__uart, self.__mode, 0) + if ret != 0: + clog.error('slip netif construct fail') + return None + clog.info('slip network card create success') + # self.__queue = Queue(1) + self.__sock = self.__socket_init() + self.__threadid = _thread.start_new_thread(self.__Socket_Thread, ()) + self.telecom_init_flag = 0 + self.telecomTimer = osTimer() + eventMesh.subscribe("cat1_reply_iccid_to_ble",self.cat1_reply_iccid_to_ble) + eventMesh.subscribe("cat1_reply_timesec_to_ble",self.cat1_reply_timesec_to_ble) + + self.iccid_data = "" + self.software_version = "" + self.deletSmsTimer = osTimer() + self.china_mobile_ai_init = 0 + self.volte_switch = 1 #默认是开启VOLTE通话功能 + eventMesh.subscribe("set_dmp_change_mode",self.set_dmp_change_mode) + eventMesh.subscribe("get_dmp_change_mode",self.get_dmp_change_mode) + eventMesh.subscribe("delete_sms_event",self.delete_sms_event) + eventMesh.subscribe("remove_all_sms_cb", self.remove_all_sms_cb)# + eventMesh.subscribe("send_sms_max_to_Ble",self.send_sms_max_to_Ble) + eventMesh.subscribe("get_all_sms_data",self.get_all_sms_data) #获取所有的短信内容 + eventMesh.subscribe("send_singal_data_toBle",self.send_singal_data_toBle) + eventMesh.subscribe("delete_sms_single_data",self.delete_sms_single_data) + + eventMesh.subscribe("get_factory_status",self.get_factory_status) + eventMesh.subscribe("set_factory_status",self.set_factory_status) + eventMesh.subscribe("send_dmp_cm_address_toBLE",self.send_dmp_cm_address_toBLE) + eventMesh.subscribe("set_volte_switch",self.set_volte_switch) + eventMesh.subscribe("get_volte_switch",self.get_volte_switch) + eventMesh.publish("delete_sms_event") + + + self.telecom_dmp_switch = 0 + + self.send_data = [] + self.code_old = 0 + self.code_old_num = 1 + self.tmp_data = [] + self.total_num = 0 + # + self.msg_nums = 0 + self.msg_nums_old = 0 + self.china_mobile_init = 0 + self.factory_status = 0 + self.send_data_q = Queue(100) + self.ack_sem=0 + _thread.start_new_thread(self.Socket_SEND_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(None) + return sock + + def __socket_reinit(self): + return self.__socket_init() + + def bootup_msg_to_bt(self): + modem_ver = modem.getDevFwVersion() + self.reply_cmd('0F',"BOOTUP@pyVer:{}@modemVer:{}".format(PROJECT_VERSION,modem_ver)) + self.reply_cmd('0F',"VOLUME:{}".format(voiceCall.getVolume())) + self.reply_cmd('0F',"PRODUCT:LEINIAO") + + def btmcu_cmd_handler(self,cmd,parm): + + # cmd = "" + # cmd_tmp= int(cmd_data)#将十进制数转换成int 再转换成十六进制 + # cell_data = hex(cmd_tmp) + # decimal_number = int(cell_data, 16) + # cmd = "%02x"%(decimal_number) # 使用两位表示,不足前面补0 + clog.info(cmd) # 输出: 07 + clog.info("btmcu_cmd_handler cmd {0} , args {1}".format(cmd,parm)) + if cmd == "00": + clog.info(cmd) + # UDP_CMD_GET_CAT1VER + modem_ver = modem.getDevFwVersion() + self.reply_cmd('00',"pyVer:{}@modemVer:{}".format(PROJECT_VERSION,modem_ver)) + elif cmd == "01": + # UDP_CMD_DIAL_NUMB + if eventMesh.publish("get_volte_switch") == 1: #只有BLE开了VOLTE才允许打电话 + ret = voiceCall.callStart(str(parm)) + # if ret != 0: + # ret = voiceCall.callStart(str(parm)) + clog.info("ret={} {} {}".format(ret,cmd,parm)) + if ret != 0: + self.reply_cmd('0F',"callcmd_fail") + else: + self.reply_cmd('0F',"callcmd_success") + else: + print("get_volte_switch NO") + self.reply_cmd('0F',"callcmd_fail") + elif cmd == "02": + clog.info(cmd) + # UDP_CMD_HUNGUP + ret = voiceCall.callEnd() + if ret != 0: + ret = voiceCall.callEnd() + if ret != 0: + self.reply_cmd('0F',"callend_fail") + else: + self.reply_cmd('0F',"callend_success") + elif cmd == "03": + clog.info(cmd) + # UDP_CMD_ANSWER + ret = voiceCall.callAnswer() + if ret != 0: + ret = voiceCall.callAnswer() + if ret != 0: + self.reply_cmd('0F',"callanswer_fail") + else: + self.reply_cmd('0F',"callanswer_success") + elif cmd == "04": + clog.info(cmd) + elif cmd == "05": + clog.info(cmd) + # UDP_CMD_SEND_SMS + elif cmd == "06": + clog.info(cmd) + # UDP_CMD_GET_TIME + time=utime.localtime() + zone=utime.getTimeZone() + #(2024, 3, 2, 18, 31, 32, 5, 62),8 + # 返回当前时间戳,参数为元组 + # timestamp = utime.mktime(time) + # clog.info(timestamp) + self.reply_cmd('06',"{0}@{1}".format(time,zone)) + elif cmd == "07": + clog.info("cmd ==== 07!") + # UDP_CMD_GET_RECV_NETWORKSTAT + simstat = sim.getStatus() + imei = modem.getDevImei() + netstat = "0,10,0,10" + netstat_ = net.getState() + if netstat_ != -1 : + netstat = "{},{},{},{}".format(netstat_[0][0],netstat_[0][3],netstat_[1][0],netstat_[1][3]) + # ([voice_state, voice_lac, voice_cid, voice_rat, voice_reject_cause, voice_psc], [data_state, data_lac, data_cid, data_rat, data_reject_cause, data_psc]) + operator = net.operatorName() + signal = net.csqQueryPoll() + clog.info("imei:{0},sim:{1},oper:{2},signal:{3},net:{4}".format(imei,simstat,operator,signal,netstat)) + self.reply_cmd('07',"imei:{0}@sim:{1}@oper:{2}@signal:{3}@net:{4}".format(imei,simstat,operator,signal,netstat)) + elif cmd == "09": + clog.info("{},{}".format(cmd,parm)) + # UDP_CMD_ATCMD + # net.setModemFun(0) + # net.setModemFun(1) + resp=bytearray(50) + ret=atcmd.sendSync("{}\r\n".format(parm),resp,'',10) + if ret == 0: + clog.info("reply:{},ret:{}".format(resp.decode(),ret)) + self.reply_cmd('09',"{}".format(resp.decode())) + else: + clog.info("cmd error ret:{}".format(ret)) + self.reply_cmd('09',"{}".format("at error")) + + elif cmd == "10" or cmd == "12" or cmd == "14": #获取固件版本号或者获取BT保存的SIM卡的ICCID BLE那边是否开启电信入库功能 + if 1: #CHINA_TELECOM_DM_FUN_ENABLE == 1 : + if eventMesh.publish("get_dmp_change_mode") == 1: + self.telecom_recv_cmd(cmd,parm) + else: + pass + + if 1:#CHINA_MOBILE_DM_FUN_ENABLE == 1: + if eventMesh.publish("get_dmp_change_mode") > 1: + self.china_mobile_recv_cmd(cmd,parm) + else: + pass + pass + elif cmd == "13": + on = int(parm) + clog.info("set_dmp_change_mode on:{}".format(on)) + eventMesh.publish("set_dmp_change_mode",on) + + elif cmd == "16": + if 1: #CHINA_MOBILE_DM_FUN_ENABLE == 1: + if eventMesh.publish("get_dmp_change_mode") > 1: + self.china_mobile_recv_cmd(cmd,parm) + else: + pass + elif cmd == "17": #用于CAT1恢复出厂需要清空数据的标识通用 + eventMesh.publish("set_factory_status",int(parm)) + elif cmd == "18": + eventMesh.publish("set_dmp_cm_address",str(parm)) + elif cmd == "19": #DTMF功能 + voiceCall.startDtmf(str(parm),100) #100ms 持续时间 100-1000 + elif cmd == "1A": + eventMesh.publish("set_volte_switch",int(parm)) + elif cmd == "1B": + print("fota {}".format(str(parm).split("and")[0])) + print("fota {}".format(str(parm).split("and")[-1])) + # httpota = httpota() + httpota.run( str(parm).split("and")[0], str(parm).split("and")[-1]) + # eventMesh.publish("set_volte_switch",int(parm)) + # UDP_MSG_OTA + elif cmd == "1C":# + self.read_dev_ai_id() + elif cmd == "AC":# + if self.ack_sem==1: + self.ack_sem=0 + + + + def telecom_recv_cmd(self,cmd,parm): + if cmd == "10": + self.software_version = str(parm) + eventMesh.publish("set_dev_version",self.software_version) + clog.info("software_version:{},{}".format(self.software_version,parm)) + elif cmd == "12": + pass + elif cmd == "14":# + pass + pass + + def set_volte_switch(self,event,msg): #设置VOLTE开关 + self.volte_switch = int(msg) + + + def get_volte_switch(self,event,msg): #获取VOLTE开关 + + return self.volte_switch + + + def china_mobile_recv_cmd(self,cmd,parm): #移动入库相关指令 + if cmd == "10": + self.software_version = str(parm) + eventMesh.publish("set_dev_version",self.software_version) + clog.info("software_version:{},{}".format(self.software_version,parm)) + elif cmd == "16": #获取BLE mac地址 + eventMesh.publish("set_dev_mac",str(parm)) + clog.info("parm:{}\r\n".format(parm)) + + pass + def get_factory_status(self,event,msg): + return self.factory_status + def set_factory_status(self,event,msg): + self.factory_status = int(msg) + if self.factory_status == 0: #只有为的时候才设置进去 1不再设置 + self.reply_cmd('17',"{}".format(1)) + + def send_dmp_cm_address_toBLE(self,event,msg): + buf_tmp = "address:"+str(msg) + self.reply_cmd('18',"{}".format(buf_tmp)) + + def set_dmp_change_mode(self,event,msg): + self.telecom_dmp_switch = msg + def delete_sms_single_data(self,event,msg): #删除单条信息 + sms.deleteMsg(int(msg)) + + def get_dmp_change_mode(self,event,msg): + return self.telecom_dmp_switch + def delete_sms_event(self,event,msg): + self.deletSmsTimer.start(2*1000,0,self.delete_sms_cb) + def delete_sms_cb(self,*argc): + eventMesh.publish_async("remove_all_sms_cb","",1*1024) + def remove_all_sms_cb(self, event, msg): + clog.info("remove_all_sms_cb\r\n") + msg_nums = sms.getMsgNums() #短信数量 + if msg_nums == -1: + msg_nums = 0 + sms_data = sms.getSaveLoc() + clog.info("{}\r\n".format(sms_data)) + if sms_data == -1: + return + sms_max = sms_data[0][2] #最大存储短信数量 + if sms_max >= msg_nums and sms_max > 0: + sms.deleteMsg(1,4) #删除所有的sms信息 + + def send_singal_data_toBle(self,event,msg): + msg_nums = sms.getMsgNums() #短信数量 + if msg_nums == -1: + msg_nums = 0 + sms_data = sms.getSaveLoc() + if sms_data == -1: + return + sms_max = sms_data[0][2] #最大存储短信数量 + clog.info("recv:{}".format(int(msg))) + message=self.sms_get_message_info(int(msg)) + if message == -1: #说明没有这条短信 + return + message_pdu = sms.decodePdu(message[5],20) + + if message_pdu != -1: #解码出来的内容 + + message_ref = message[0] #编码 + message_total_num = message[1] #总共条数 + message_seq = message[2] #当前第几条 + data = message[5] #内容 + data_len = len(data) #内容长度 + # ref :短信参考标识,同一个标识表明为同一条短信 + # total_num :此条长短信总条数 大于1属于长短信 + # seq :此条短信在长短信中的序号 + # print("message:{} {}\r\n".format(message,message_pdu)) + msg_total = "ref:"+str(message_ref)+"@total_num:"+str(message_total_num)+"@seq:"+str(message_seq)+"@data:"+str(message[5]) + self.reply_cmd('15',msg_total) + + eventMesh.publish("delete_sms_single_data",int(msg)) + + def sms_deal_phone_number(self,args): + data=enumerate(args) + data_str1="" + data_str2="" + data_str3="" + for index,value in data: + if index % 2 == 0: + data_str1=data_str1+value + else: + data_str2=data_str2+value + for i in range(0,len(data_str1)): + data_str3=data_str3+data_str2[i] + data_str3=data_str3+data_str1[i] + return data_str3 + def sms_get_message_info(self,index): + """ + :param index :短信索引值 + :tyoe index :整形 + + :return :元组类型 + 元组内容: + (message_ref,message_total_num,message_seq,sub_message_data,pdu_tye,sub_message_len) + + :message_ref :短信参考标识,同一个标识表明为同一条短信 + :message_total_num :此条长短信总条数 + :message_seq :此条短信在长短信中的序号 + :sub_message_data :词条短信的内容 + :pdu_tye :PDU类型,bit 6标记是否包含用户报文头,长短信需要 + :sub_message_len :此条短信内容长度 + + """ + + message0=sms.searchPduMsg(index) + #print("sms_get_message_info:message0:{}".format(message0)) + if message0 == -1: + return -1 + + sca_num = int(message0[0:2],16) - 1 + data_len = 2 + addr_type= message0[data_len:data_len+1*2] + data_len = data_len+1*2 + + sca = message0[data_len:data_len+sca_num*2] + # 电话号码高低位需要转换 + sca = self.sms_deal_phone_number(sca) + + # if sca_num % 2 == 1: + # print("Get SCA phone {}".format(sca[:-1])) + # else: + # print("Get SCA phone {}".format(sca)) + + data_len = data_len+sca_num*2 + + pdu_tye = int(message0[data_len:data_len+1*2],16) + data_len = data_len+1*2 + + oa_num = int(message0[data_len:data_len+1*2],16) + data_len = data_len+1*2 + oa_addr_type = message0[data_len:data_len+1*2] + data_len = data_len+1*2 + + if oa_num % 2 == 1: + oa_num_t = int((oa_num + 1)/2) + else: + oa_num_t = int((oa_num )/2) + + oa = message0[data_len:data_len+oa_num_t*2] + # 电话号码高低位需要转换 + oa = self.sms_deal_phone_number(oa) + + # if oa_num % 2 == 1: + # print("Get OA phone {}".format(oa[:-1])) + # else: + # print("get OA phone {}".format(oa)) + + data_len = data_len+oa_num_t*2 + pid = message0[data_len:data_len+1*2] + + data_len = data_len+1*2 + dcs = message0[data_len:data_len+1*2] + data_len = data_len+1*2 + scts = message0[data_len:data_len+7*2] + data_len = data_len+7*2 + sub_message_len = int(message0[data_len:data_len+1*2],16) + data_len = data_len+1*2 + sub_message_head = message0[data_len:data_len+6*2] + data_len = data_len+6*2 + + # 或短信用户数据 + sub_message_data = message0[data_len:data_len+sub_message_len*2] + + #长短信 + if ((pdu_tye & 0x40 ) >> 6) == 1: + #长短信,处理长短信用户报文头 + message_ref = int(sub_message_head[6:8],16) + message_total_num = int(sub_message_head[8:10],16) + message_seq = int(sub_message_head[10:12],16) + return [message_ref,message_total_num,message_seq,pdu_tye,sub_message_len,message0] + else: + # 短短信 + return [0,1,1,pdu_tye,sub_message_len,message0] + + + + def send_sms_max_to_Ble(self,event,msg): + msg_nums = sms.getMsgNums()#短信数量 + if msg_nums == -1: + msg_nums = 0 + sms_data = sms.getSaveLoc() + if sms_data != -1: + sms_max = sms_data[0][2]#最大存储短信数量 + self.reply_cmd('15',"@sms_max:"+str(sms_max)+"@current_num:"+str(msg_nums)) + pass + + def get_all_sms_data(self,event,msg): + msg_total = "" + SMS_lis={} + SMS_lis_count = 0 + sms_data = sms.getSaveLoc() + clog.info(sms_data) + if sms_data == -1: + return + sms_max = sms_data[0][2]#最大存储短信数量 + clog.info(sms_max) + self.msg_nums = sms.getMsgNums() + if self.msg_nums_old != self.msg_nums: + self.send_data = [] + self.msg_nums_old = self.msg_nums + if self.send_data == [] : + for i in range(self.msg_nums): + phonenum = "" + data ="" + time = "" + data_len = 0 + message=self.sms_get_message_info(self.msg_nums-i-1) + if message == -1: + break + data = message[5] + sms_data = [] + code = message[0]#编码 + num = message[1]#总共条数 + curren_num = message[2]#当前第几条 + data_len = message[4] + sms_data.append(code)#编码 编码相同是同一条短信的内容 + sms_data.append(num) + sms_data.append(curren_num) + sms_data.append(data) + sms_data.append(data_len) + self.send_data.append(sms_data) + count = len(self.send_data) + for i in range(count): + text = self.send_data[i] + clog.info("text:{} {} {}\r\n".format(text[0],text[1],text[2])) + + msg_total = "@code:"+str(text[0])+"@totalcodenum:"+str(text[1])+"@currcodeid:"+str(text[2])+"@data:"+str(text[3]) + self.reply_cmd('17',msg_total) + + # 来电提醒 + def notifyIncomingcall(self, incomming_numb): + self.clear_remain() + __head = '0C' + __message = str(incomming_numb) + self.__Socket_UDP(__head, __message) + # if self.__err == 1 or self.__value[2] != 'OK': + # return -1 + return 0 + + # 电话接听消息 + def notifyConnecteCall(self, phone_numb): + self.clear_remain() + __head = '0A' + __message = str(phone_numb) + self.__Socket_UDP(__head, __message) + # if self.__err == 1 or self.__value[2] != 'OK': + # return -1 + return 0 + + # 电话拒接消息 + def notifyDisconnectCall(self, phone_numb): + self.clear_remain() + __head = '0B' + __message = str(phone_numb) + self.__Socket_UDP(__head, __message) + # if self.__err == 1 or self.__value[2] != 'OK': + # return -1 + return 0 + + def wait_network_ready(self): + if(self.__waiting_netstat == 1): + return 0 + self.__waiting_netstat = 1 + stage, state = checkNet.waitNetworkReady(30) + pm.wakelock_unlock(lpm_fd) + if stage == 3 and state == 1: + clog.info('Network connection successful.') + self.set_network_config() + self.__net_connected = 1 + eventMesh.publish("set_network_state",self.__net_connected) + self.__waiting_netstat = 0 + return 0 + else: + clog.info('Network connection failed, stage={}, state={}'.format(stage, state)) + self.reset_network_config() + self.__net_connected = 0 + eventMesh.publish("set_network_state",self.__net_connected) + + self.__waiting_netstat = 0 + return -1 + + # 查询网卡状态 + def timesync(self,_timesync): + self.clear_remain() + message = str(_timesync) + self.__Socket_UDP('0D', message) + return 0 + + def reply_timesync(self,_timesync): + self.clear_remain() + message = str(_timesync) + self.__Socket_UDP_noreply('0D', message) + return 0 + + def reply_cmd(self,cmd,_timesync): + try : + clog.info('reply_cmd 1') + self.clear_remain() + message = str(_timesync) + clog.info('reply_cmd 2') + self.__Socket_UDP_noreply(cmd, message) + except: + clog.info('reply_cmd') + 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) + + def reset_network_config(self): + if (self.__net_connected == 0): + clog.info("skip reset_network_config") + return 0 + Info = dataCall.getInfo(1,0) + clog.info("Info{}".format(Info)) + default_NIC_ip = Info[2][2] # 假设默认网卡ip地址为10.10.1.1,请根据实际情况更改 + segment_ip = '172.16.4.0' # 假设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) + clog.info("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() + + def set_network_config(self): + + + if (self.__net_connected == 1) : + clog.info("skip set_network_config") + return 0 + Info = dataCall.getInfo(1,0) + clog.info("Info{}".format(Info)) + default_NIC_ip = Info[2][2] # 假设默认网卡ip地址为10.10.1.1,请根据实际情况更改 + segment_ip = '172.16.1.0' # 假设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) + clog.info("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() + if eventMesh.publish("get_dmp_change_mode") == 0:#入库功能关闭 + return + if 1: #CHINA_TELECOM_DM_FUN_ENABLE == 1:#电信入库功能 不使用设置 0 防止两边不同步修改 + if eventMesh.publish("get_dmp_change_mode") == 1: + eventMesh.publish("set_network_state",1) + telecomDmpCb.telecom_dmp_power_on_init() + if 1: #CHINA_MOBILE_DM_FUN_ENABLE == 1: + if eventMesh.publish("get_dmp_change_mode") == 2: + eventMesh.publish("set_network_state",1) + if self.china_mobile_init == 1: + return + self.china_mobile_init = 1 + #移动入库的初始化 + chinamobileCb.china_mobile_init() + if eventMesh.publish("get_dmp_change_mode") == 3: + if self.china_mobile_ai_init == 1: + return + self.china_mobile_ai_init = 1 + eventMesh.publish("set_network_state",1) + aiRegulation.AIRegulation_init() + + def cat1_reply_iccid_to_ble(self,event,msg): + ICCID_DATA = str("ICCID:")+str(msg) + self.reply_cmd('11',"{}".format(ICCID_DATA)) + pass + def cat1_reply_timesec_to_ble(self,event,msg): + + self.reply_cmd('14',"REGIST_TIME:{}".format(msg)) + pass + # 释放slip网卡 + def stop(self): + slip.destroy() + return 0 + + def read_dev_ai_id(self): + + IFEXIST = ql_fs.path_exists("/usr/cm_ai_regulation.json") # + if IFEXIST == True: #文件存在 + fileSize = ql_fs.path_getsize('usr/cm_ai_regulation.json') + if fileSize == 0: + + print("设备信息配置文件不存在\r\n") + else: + try: + with open("/usr/cm_ai_regulation.json","r",encoding='utf-8') as fd: + try: + config_data = ujson.load(fd) #转换成json格式 + if len(config_data) != 0: + if "deviceId" in config_data:# + deviceId = str(config_data["deviceId"]) #设备ID + self.reply_cmd('1C',"{}".format(deviceId)) + except Exception as error: + print("配置文件的内容不是json格式 保存数据的时候格式不对\r\n") + except Exception as error: + print("打开配置文件失败\r\n") + + + + + # 封装tlv数据包 + def __pack_tlv_format(self, head, content): + # self.head = head + # self.content = content + if len(content) == 0 or len(content) > 9999 or len(head) != 2: + clog.error('illegal pack tlv content') + return -1 + len_str ='%04d' % len(content) + tlv_pack = CAT1_SERVICE_HEAD+head+len_str+content + return tlv_pack + # 解码tlv数据包 + def __unpack_tlv_format(self, msg): + clog.info('__unpack_tlv_format {}\r\n'.format(msg)) + self.msg = str(msg)[2:]#这是去除head FE + 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]: + clog.error('__unpack_tlv_format err') + return -1 + clog.info('__unpack_tlv_format: {} {} {}\r\n'.format(tag,length,value)) + unpack = (tag,length,value) + return unpack + # socket通信(UDP)模块 + def __Socket_UDP(self, head, content): + # 0 则 __Socket_UDP_write + self.send_data_q.put([head,content]) + def Socket_SEND_Thread(self): + while True: + try: + clog.info("send====") + data=self.send_data_q.get() + self.ack_sem=1 + # # if data[2]: + # self.__Socket_UDP_noreply_write( data[0], data[1]) + # else : + self.__Socket_UDP_write( data[0], data[1]) + + + clog.info("Socket_SEND_Thread data:{} {}".format(data[0],data[1])) + count=20 + + while count & self.ack_sem : + utime.sleep_ms(1) + count=count-1 + # if data[2]: + # self.__Socket_UDP_noreply_write( data[0], data[1]) + # else : + self.__Socket_UDP_write( data[0], data[1]) + + clog.info("Socket_SEND_Thread while data:{} {}".format(data[0],data[1])) + + if data: + clog.info("data ok!!") + else: + clog.error("data error!!") + except Exception : + clog.error("sned Socket >>>") + + def __Socket_UDP_write(self, head, content): + try: + ##self.head = head + # self.content = content + gpioWakeBT.write(1) + utime.sleep_ms(2) + gpioWakeBT.write(0) + utime.sleep_ms(20) + # 消息处理 + msg = self.__pack_tlv_format(head, content) + + # 向服务端发送消息 + server_addr = ('172.16.1.5',1000) + clog.info("__Socket_UDP send msg {}".format(msg)) + self.__err = 0 + self.__sock.sendto(msg,server_addr) + clog.info("__Socket_UDP send 2") + self.__wait_resp = 1 + # data = self.__queue.get() + self.__wait_resp = 0 + # return data + return 1 + except Exception as error: + clog.error(error) + return 0 + + def __Socket_UDP_noreply(self, head, content): + # 1 则 __Socket_UDP_noreply_write + self.send_data_q.put([head,content]) + + def __Socket_UDP_noreply_write(self, head, content): + # self.head = head + # self.content = content + gpioWakeBT.write(1) + utime.sleep_ms(2) + gpioWakeBT.write(0) + utime.sleep_ms(20) + # 消息处理 + msg = self.__pack_tlv_format(head, content) + + # 向服务端发送消息 + server_addr = ('172.16.1.5',1000) + + clog.info("__Socket_UDP_noreply send msg {}".format(msg)) + self.__err = 0 + data_size = self.__sock.sendto(msg,server_addr) + clog.info("self.__sock data_size {}".format(data_size)) + self.__wait_resp = 0 + return 0 + + # socket通信(UDP)模块 + def __Socket_Thread(self): + while True: + try: + clog.info("recv====") + data=self.__sock.recv(1024) + clog.info("data:{}".format(data)) + if data: + value = self.__unpack_tlv_format(data.decode()) + if value != -1: + clog.info('mode: {0}, recv {1} bytes, Data: {2}'.format (value[0],len(data), value[2])) + if value[1] == '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]) + clog.info("End else Thread") + else: + clog.error("data error!!") + except Exception as recverr: + clog.error("recverr:{}\r\n".format(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() + + + + clog.info("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卡状态 +# 下文进行系统配置 +clog.info("Cat1Service start") + +cat1service = Cat1Service() + +#send_data_q = Queue(100) + +#voice call callback function +def voice_callback(args): + if args[0] == 10: + if eventMesh.publish("get_volte_switch") == 0: #关闭VOLTE功能 + clog.info('voicecall auto end:') + voiceCall.callEnd() + else: + # gpioWakeBT.write(1) + cat1service.notifyIncomingcall(args[6]) + elif args[0] == 11: + if eventMesh.publish("get_volte_switch") == 1: #开启VOLTE功能 + clog.info('voicecall connected, PhoneNO: \n'.format(args[6])) + cat1service.notifyConnecteCall(args[6]) + elif args[0] == 12: + clog.info('voicecall disconnect') + if eventMesh.publish("get_volte_switch") == 1: #开启VOLTE功能 + clog.info('voicecall disconnected, PhoneNO: \n'.format(args[6])) + cat1service.notifyDisconnectCall(args[6]) + elif args[0] == 13: + clog.info('voicecall is waiting, PhoneNO: \n'.format(args[6])) + elif args[0] == 14: + clog.info('voicecall dialing, PhoneNO: \n'.format(args[6])) + elif args[0] == 15: + clog.info('voicecall alerting, PhoneNO: \n'.format(args[6])) + elif args[0] == 16: + clog.info('voicecall holding, PhoneNO: \n'.format(args[6])) + else: + clog.info('voice_callback , args[0]: \n'.format(args[6])) + +#电话消息反馈 +voiceCall.setCallback(voice_callback) + + +def checknet_cb(arg): + clog.info("start checktime!!") + # if 1: #CHINA_TELECOM_DM_FUN_ENABLE == 1:#这是手表每30s检查一次 + # if eventMesh.publish("get_dmp_change_mode") == 1: + # telecomDmpCb.telecom_dmp_power_on_count() + + _thread.start_new_thread(cat1service.wait_network_ready, ()) + # time=utime.localtime() + # zone=utime.getTimeZone() + #(2024, 3, 2, 18, 31, 32, 5, 62),8 + # cat1service.timesync("{0},{1}".format(time,zone)) +# _thread.start_new_thread(cat1service.wait_network_ready, ()) +timer = osTimer() +# checknet_cb(()) +timer.start(30000,1,checknet_cb) + +def bootupmsg_cb(arg): + cat1service.bootup_msg_to_bt() + + +delaybootupmsg_timer = osTimer() +delaybootupmsg_timer.start(1000,0,bootupmsg_cb) + +# def checkpin_cb(arg): +# clog.info("recvDataPin={}".format(recvDataPin.read())) + +# timerCheckRevPin = osTimer() +# timerCheckRevPin.start(1000,1,checkpin_cb) + + + + + + +# while True: +# utime.sleep(5) + + +# uping.ping("172.16.1.5") + # 获取网卡当前工作状态 + +# gpioWakeBT.write(1) +# utime.sleep(1) + +# timesync = net.nitzTime() +# cat1service.timesync(timesync) + + +#url = "http://zzhc.vnet.cn:9998/" + + diff --git a/cat1modem/src/LeiNiao/checkota.py b/cat1modem/src/LeiNiao/checkota.py new file mode 100644 index 000000000..e5ef1f1ae --- /dev/null +++ b/cat1modem/src/LeiNiao/checkota.py @@ -0,0 +1,150 @@ +import app_fota +from misc import Power +import modem +import ujson +import request +import ql_fs +import checkNet +import sys + +#远程升级 + +import fota +import utime +import log +import uos + +PROJECT_VERSION="PY_OTA_V14" +CONFIG_JSON="/usr/system_config.json" +CURRENT_APP_TYPE="pyota" +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +fota_log = log.getLogger("Fota") + + +def get_versionkeyname_by_py(app_type): + return str("{}version".format(app_type)) + +def get_default_versionvalue_by_py(app_type): + if (app_type == "pyota"): + return "PY_OTA_V13" + + +#如果没有configfile则创建它 +if not ql_fs.path_exists(CONFIG_JSON): + data = {str(get_versionkeyname_by_py(CURRENT_APP_TYPE)):get_default_versionvalue_by_py(CURRENT_APP_TYPE)} + try: + ql_fs.touch(CONFIG_JSON,data) + except Exception as e: + print("checkota 创建出错 {}".format(e)) + +def set_version_to_json_config(app_type,keyvalue): + try: + config_data = ql_fs.read_json(CONFIG_JSON) + config_data.update( {str(get_versionkeyname_by_py(app_type)):keyvalue}) + + ql_fs.touch(CONFIG_JSON, config_data) + print("{}={}".format(get_versionkeyname_by_py(app_type),keyvalue)) + print("{}".format(config_data)) + except Exception as e: + print("checkota 创建出错 {}".format(e)) + +def get_version_from_json_config(app_type): + try: + config_data = ql_fs.read_json(CONFIG_JSON) + keyvalue = config_data.get( get_versionkeyname_by_py(app_type),get_default_versionvalue_by_py(app_type)) + print("{}={}".format(get_versionkeyname_by_py(app_type),keyvalue)) + return keyvalue + except Exception as e: + print("get_version_from_json_config出错 {}".format(e)) + return "" + +def result(args): + print('download status:',args[0],'download process:',args[1]) + +def check_fota(): + modem_ver = modem.getDevFwVersion() + imei = modem.getDevImei() + url = "http://icfota.snicker.com.cn:8089/fd230ota.jsp?product=FD230&pkgver={0}&imei={1}".format(modem_ver,imei) + response = request.get(url) + print(url) + data = response.json() + if(data['UptoDate'] == False): + print("Need update python application") + fota_obj = fota() # 创建Fota对象 + print("httpDownload...") + srcurl = data['url'] + #差分升级方式 + # res = fota_obj.httpDownload(url1="http://www.example.com/fota.bin",callback=result) + # mini fota方式 + print("{},{}".format("{}/dfota_1.bin".format(srcurl),"{}/dfota_2.bin".format(srcurl))) + res = fota_obj.httpDownload(url1="{}/dfota_1.bin".format(srcurl),url2="{}/dfota_2.bin".format(srcurl),callback=result) + #差分升级FTP方式 + #res = fota_obj.httpDownload(url1="ftp://user:password@ip:port/fota.bin",callback=result) #其中user,password,ip,port需要填写具体使用的FTP服务器信息 + if res != 0: + print("httpDownload error") + return + print("wait httpDownload update...") + else: + print("No need update python application") + +def do_app_update_internal(app_type): + fota = app_fota.new() + imei = modem.getDevImei() + pythonversion=get_version_from_json_config(app_type) + url = "http://icfota.snicker.com.cn:8089/fd230ota.jsp?product=FD230&pkgver={0}&imei={1}".format(pythonversion,imei) + try: + response = request.get(url) + print(url) + data = response.json() + if data['UptoDate'] == False: + print("Need update python application {}".format(data["appcount"])) + for app_update in data["apps"]: + srcurl = app_update['url'] + print("run start...") + targetpyname = app_update['OtaPackageName'] + version = app_update['OtaPackageVersion'] + tmpfile_path = "/usr/.updater/{}".format(targetpyname) + targetfile_path = "/usr/{}".format(targetpyname) + print("download {0} to {1}".format(srcurl,targetfile_path)) + if ql_fs.path_exists(tmpfile_path): + try: + uos.remove(tmpfile_path) + except Exception as e: + print("update remove出错 {}".format(e)) + ret = fota.download(srcurl,targetpyname) + if ret == 0 : + try: + ql_fs.file_copy(targetfile_path, tmpfile_path) + set_version_to_json_config(app_type,version) + print("ota success") + if ql_fs.path_exists(tmpfile_path): + try: + uos.remove(tmpfile_path) + except Exception as e: + print("update remove出错 {}".format(e)) + except Exception as e: + print("ota failed!") + else: + print("ota failed") + # 升级后重启 + Power.powerRestart() + else: + print("No need update python application") + except Exception as e: + print("nonetwork:{}".format(e)) + +if __name__ == '__main__': + print("check ota start!!!!!!!!!!") + set_version_to_json_config(CURRENT_APP_TYPE,PROJECT_VERSION) + stage, state = checkNet.waitNetworkReady(1) + if stage == 3 and state == 1: + print('Network connection successful.') + do_app_update_internal("pyota") + # check_fota() + else: + print('Network connection failed, stage={}, state={}'.format(stage, state)) + +# res = uos.statvfs("/usr") +# res = list(res) +# print('总ext空间:{} MB,剩余空间:{} MB'.format((((res[0] * res[2]) / 1024 / 1024)),((res[0] * res[3]) / 1024 / 1024))) \ No newline at end of file diff --git a/cat1modem/src/LeiNiao/china_mobile_ai_regulation.py b/cat1modem/src/LeiNiao/china_mobile_ai_regulation.py new file mode 100644 index 000000000..9cd4bf9a8 --- /dev/null +++ b/cat1modem/src/LeiNiao/china_mobile_ai_regulation.py @@ -0,0 +1,416 @@ +#AI 纳管对接文件 +import modem +import request +import utime +import osTimer +import ql_fs +from machine import RTC +from misc import Power +import uos +import ujson +import urandom +from usr.EventMesh import eventMesh +HEARBEAT_REPORT_TIMER_CONFIG = 60*60*12#60*60*12 #心跳上报时间间隔12小时可更改做测试 +REALY_TIME_COUNT = 60*60# #开启1小时实时定时器 +HEART_REPORT_ERROR_TIMER = 60 #心率上报错误定时器检测 按照1分钟检查 +PRODUCTID = "1927646275585744898" #产品ID +PRODUCTKEY = "iijgiGiTolCblSFE" #产品KEY 平台创建产品是生成的 +HEART_REPORT_ERR_MAX_NUM = 30 #连续上报错误次数最大值 30 网络异常或者哪里报错了 重启设备 可根据实际的用户的需求更改次数 +REPORT_MODE = 1 #上报方式 1 24小时内一定上报一次 2 12小时后上报一次 +class AIRegulation: + #定义全局变量 + def __init__(self): + self.timerStart = osTimer() + self.timerStartReportHr = osTimer() + self.productId = PRODUCTID + self.productKey = PRODUCTKEY + self.deviceId = "" #设备ID + self.deviceSecret = "" #设备私钥 + self.config_data = {} + self.getDevInforErrCount = 0 #获取设备信息错误次数累计 + self.report_state = 0 #超过24小时清0 + self.TimeSec = 0 #上报的时间戳 + self.startTimerState = 0 + self.software_version = "" + self.imei_new = "" + self.init_flag = 0 + self.net_work_state = 0 + self.dev_mac = "" + eventMesh.subscribe("get_dev_version",self.get_dev_version) + eventMesh.subscribe("set_dev_version",self.set_dev_version) + eventMesh.subscribe("get_dev_mac",self.get_dev_mac) + eventMesh.subscribe("set_dev_mac",self.set_dev_mac) + eventMesh.subscribe("get_network_state",self.get_network_state)#订阅消息 + eventMesh.subscribe("set_network_state",self.set_network_state)#订阅消息 + self.report_err_count = 0 #上报错误次数 30次 + + def set_network_state(self,event,msg): + self.net_work_state=int(msg) + + def get_network_state(self,event,msg): + return self.net_work_state + + def set_dev_version(self,event,msg): + self.software_version=str(msg) + + def get_dev_version(self,event,msg): + return self.software_version + def get_dev_mac(self,event,msg): + return self.dev_mac + def set_dev_mac(self,event,msg): + self.dev_mac = str(msg) + #要或者设备的mac 和设备的固件版本号 + + #读取存储设备的设备参数 包含设备imei 设备ID和设备私钥 同一个设备设备ID和设备私钥不变 + def read_dev_storage_param(self): + + IMEI = modem.getDevImei() #获取IMEI号 + result_ok = 0 #返回结果状态 + IFEXIST = ql_fs.path_exists("/usr/cm_ai_regulation.json") # + if IFEXIST == True: #文件存在 + fileSize = ql_fs.path_getsize('usr/cm_ai_regulation.json') + if fileSize == 0: + result_ok = 0 + print("设备信息配置文件不存在\r\n") + return result_ok + else: + try: + with open("/usr/cm_ai_regulation.json","r",encoding='utf-8') as fd: + try: + self.config_data = ujson.load(fd) #转换成json格式 + if len(self.config_data) != 0: + if "deviceId" in self.config_data:# + self.deviceId = str(self.config_data["deviceId"]) #设备ID + + #存在 + if "deviceSecret" in self.config_data: + self.deviceSecret = str(self.config_data["deviceSecret"]) + #存在 + if "TimeSec" in self.config_data: + self.TimeSec = self.config_data["TimeSec"] + if "IMEI" in self.config_data: + self.imei_new = self.config_data["IMEI"] + if str(self.imei_new) != str(IMEI): #设备IMEI不一样也要重新获取 + self.config_data["IMEI"] = str(IMEI) + self.write_config_msg_file(self.config_data) + result_ok = 0 + return result_ok + + if len(str(self.deviceId)) != 0 or len(str(self.deviceSecret)) != 0: + result_ok = 1 + else: #m没有存储数据 需要从平台上获取设备信息 + result_ok = 0 + except Exception as error: + print("配置文件的内容不是json格式 保存数据的时候格式不对\r\n") + result_ok = 0 + except Exception as error: + print("打开配置文件失败\r\n") + result_ok = 0 + else: + print("配置文件不存在!!!!\r\n") + result_ok = 0 + + print("cm_ai_regulation result_ok: {} self.config_data:{}\r\n".format(result_ok,self.config_data)) + return result_ok + #写文件信息 + def write_config_msg_file(self,msg): + + print("cm_ai_regulation msg:{}\r\n".format(msg)) + with open("/usr/cm_ai_regulation.json",'w+',encoding="utf-8") as fd: + ujson.dump(msg,fd) + def get_dev_info(self): #是否需要获取设备信息 + request_result = 0 + netWorkState = eventMesh.publish("get_network_state") + if netWorkState == 0: #网络异常 + request_result = 0 + return request_result + url = "https://ivs.chinamobiledevice.com:11443/v2/customer/device/secret/info" + #获取设备ID和设备私钥 + get_dev_storage = self.read_dev_storage_param() #返回1说明已经获取过设备信息 不需要再重新获取了只有 + if get_dev_storage == 0: #还没有获取设备信息需要获取一遍 + #获取设备设备信息地址 + IMEI = modem.getDevImei() #获取IMEI号 + + headers_T ={"Content-Type":"application/json"} + config_data ={ + "deviceNoType":"IMEI", + "deviceNo":str(IMEI), + "productKey":str(self.productKey), + "productId":str(self.productId), + } + print("ujson.dumps(config_data):{}".format(ujson.dumps(config_data))) + + result_json = "" + response = 0 + try: + response = request.post(url, data=ujson.dumps(config_data),headers =headers_T) + if response.status_code == 200: #服务器响应成功并返回数据 + try: + content = response.content + c = next(content) + result_json = ujson.loads(c) + print("response.json:{}".format(ujson.loads(c))) + code = "" + message = "" + success = False + if "code" in result_json: + code = result_json["code"] + if "message" in result_json: + message = result_json["message"] + if "success" in result_json: + success = result_json["success"] + if code == "200" and message == "成功" and success == True: + if "data" in result_json: + data_json = result_json["data"] + if "deviceId" in data_json: + self.deviceId = data_json["deviceId"] + if "deviceSecret" in data_json: + self.deviceSecret = data_json["deviceSecret"] + + if len(self.deviceId) != 0 or len(self.deviceSecret) != 0: #获取设备信息成功 保存数据 用做心跳上报 + request_result = 1 + self.config_data["deviceId"] = str(self.deviceId) + self.config_data["deviceSecret"] = str(self.deviceSecret) + IMEI = modem.getDevImei() #获取IMEI号 + self.config_data["IMEI"] = str(IMEI) + self.write_config_msg_file(self.config_data) + # { + # "code":"200", + # "message":"成功", + # "success": true, + # "data":{ + # "deviceId":"xxx", + # "deviceNo":"xxx", + # "productId":"xxx", + # "deviceSecret":"xxx" + # } + # } + else: + request_result = 0 + print("后台返回数据json字段里面没有data字段\r\n") + else: + request_result = 0 + print("后台返回数据失败 可能是设备没有加入产品或者产品私钥或者产品ID对不上\r\n") + except Exception as e: #不是json格式 + print("not json data:{}".format(e)) + request_result = 0 + else: + print("未响应 或者网络异常连接不上后台\r\n") + request_result = 0 + except Exception as e: + print("response error:{}".format(e)) + request_result = 0 + else: + request_result = 1 + return request_result + + #上报心跳数据 + def report_hr_data(self): #设备ID 设备私钥不为空才可以上报 + result_s = 0 + netWorkState = eventMesh.publish("get_network_state") + if netWorkState == 0: #网络异常 + result_s = 0 + return result_s + if len(str(self.deviceId)) != 0 and len(str(self.deviceSecret)) != 0: + + ######################################################### + # { + # "deviceId":"1927659130106658817", + # "deviceSecret":"xmvlRHbEaKPtCqHt", + # "productId":"1927646275585744898", + # "productKey":"iijgiGiTolCblSFE", + # "params": { + # "innerIp": [ + # "127.0.0.1" + # ], + # "netSpeed": "0Mbps", + # "netType": "4G", + # "platform": "RTOS", + # "sdkVersion": "ai_http_1.0", + # "firmwareVersion": "0.0.5.2", + # "imei": "860132060564184", + # "cmei": "", + # "mac": "" + # } + # } + IMEI = modem.getDevImei() #获取IMEI号 + tmp_mac = "" + if len(self.dev_mac) != 0: + tmp_mac = self.dev_mac.replace(':', '-') #将传过来的字符里面的:转换成- + #数据格式内容 + data_json = { + "deviceId":str(self.deviceId), #设备ID + "deviceSecret":str(self.deviceSecret), #设备私钥 + "productId":str(self.productId), #产品ID + "productKey":str(self.productKey), #产品私钥 + "params": { + "innerIp": [ + "127.0.0.1" + ], + "netSpeed": "0Mbps", + "netType": "4G", + "platform": "RTOS", + "sdkVersion": "ai_http_1.0", + "firmwareVersion":str(self.software_version), #设备固件版本号 + "imei": str(IMEI), #设备IMEI号 + "cmei": "", + "mac": str(tmp_mac) #设备MAC地址 + } + } + url = "https://ivs.chinamobiledevice.com:11443/v2/customer/device/report" #post请求上报数据心跳地址 + #获取设备ID和设备私钥 + try: + headers_T ={"Content-Type":"application/json"} #应用是json格式 + response = request.post(url, data=ujson.dumps(data_json),headers =headers_T) #post请求数据 + if response.status_code == 200: #服务器响应成功并返回数据 + try: + content = response.content + c = next(content) + result_json = ujson.loads(c) #将字符串转换成json格式 + print("response.json:{}".format(result_json)) + code = "" + message = "" + success = False + if "code" in result_json: + code = result_json["code"] + if "message" in result_json: + message = result_json["message"] + if "success" in result_json: + success = result_json["success"] + if code == "200" and message == "成功" and success == True: #上报成功返回 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp) #获取当前时间戳 用于下次时间判断上报心跳数据 + print("date_tmp :{} time_tmp:{}\r\n".format(date_tmp,time_tmp)) + self.report_state = 1 #表示上报成功 置标志1 12小时之内不清0 12小时之后再次上报清零 + self.TimeSec = str(time_tmp) + self.config_data["TimeSec"] = str(time_tmp) + IMEI = modem.getDevImei() #获取IMEI号 + self.config_data["IMEI"] = str(IMEI) + self.write_config_msg_file(self.config_data) + # { + # "code":"200", + # "message":"成功", + # "success": true, + # "data":{ + # "deviceId":"xxx", + # "protocolTypeTime":"xxx" + # } + # } + result_s = 1 + else: + result_s = 0 + except Exception as e: #不是json格式 + print("response:{}".format(e)) + result_s = 0 + else: + result_s = 0 + except Exception as e: + print("response:{}".format(e)) + result_s = 0 + if REPORT_MODE == 1: #上报方式1 + if result_s == 1: #当前上报数据成功 开启下一个上报心跳数据定时器 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp) + random_integer = urandom.randint(-15, 15) #两个时间戳相减大于24小时啧清0 + timerStart_init = HEARBEAT_REPORT_TIMER_CONFIG*1000+random_integer*1000*60 + print("timerStart_init {} random_integer:{}\r\n".format(timerStart_init,random_integer)) + self.timerStartReportHr.start(timerStart_init,0,self.timerStartReportHrCbOne)#重新开始 单次定时器 + else: #上报方式2 + if self.startTimerState == 0: + self.startTimerState = 1 + self.open_report_start_timer() + else: + result_s = 2 + self.AIRegulation_init() #重新初始化 + return result_s + return result_s + def timerStartReportHrCbOne(self,*argc): + reportStatus = self.report_hr_data() #上报心跳数据接口函数 + print("timerStartReportHrCbOne {}\r\n".format(reportStatus)) + if reportStatus == 0: #当前上报失败 开启1分钟的定时器检测 + self.timerStart.stop() + self.report_err_count = 0 + self.timerStart.start(HEART_REPORT_ERROR_TIMER*1000,1,self.oneMinTimerStartCb)#重新开始 + else: + self.timerStart.stop() + + def oneMinTimerStartCb(self,*argc): + reportStatus = self.report_hr_data() + print("oneMinTimerStartCb {}\r\n".format(reportStatus)) + if reportStatus != 0: # + self.timerStart.stop() + else: + self.report_err_count+=1 + if self.report_err_count >= HEART_REPORT_ERR_MAX_NUM: + self.report_err_count = 0 + self.timerStart.stop() + Power.powerRestart() #重启设备 可能网络异常或者哪里出错了 + + def timerStartReportHrCb(self,*argc): #上报心跳定时器回调 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp) + random_integer = urandom.randint(-15, 15) #-15 - +15上报时间随机值分钟单位 *60*1000 + data = RTC().datetime() + year = data[0] + month = data[1] + day = data[2] + + if self.report_state == 1: #上报过一次 就等下一个12小时再上报一次 + #当前时间大于上次记录时间加上12小时就上报一次 + next_alarm_time = utime.localtime(int(self.TimeSec)) + old_month = next_alarm_time[1] + old_day = next_alarm_time[2] + old_year = next_alarm_time[0] + # if 1: + # if old_year != year or old_month != month or old_day != day: + # self.report_state = 0 + # self.report_hr_data() + + # else: + if (time_tmp >= self.TimeSec + HEARBEAT_REPORT_TIMER_CONFIG*1000 + random_integer*60*1000) or (old_year != year or old_month != month or old_day != day): #or old_year != year or old_month != month or old_day != day: #上次上报时间戳+12小时时间戳 大于当前时间戳 上报一次 或者年 月 日不一致也上报一次 + self.report_state = 0 + self.report_hr_data() + else: #确保12小时之内上报一次 每一个小时上 + self.report_hr_data()#上报一次心跳数据 + + def open_report_start_timer(self): #1小时的定时器 + self.timerStartReportHr.start(REALY_TIME_COUNT*1000,1,self.timerStartReportHrCb)#1小时定时 + + def timerStartCb(self,*argc):#获取设备信息定时器回调 + getDevInfoState = self.get_dev_info() + if getDevInfoState == 0:# + self.getDevInforErrCount+=1 + if self.getDevInforErrCount >= 20: + self.getDevInforErrCount = 0 + self.timerStart.stop() + else: + self.getDevInforErrCount = 0 + self.timerStart.stop() + self.report_hr_data()#上报一次心跳数据 + + def AIRegulation_init(self):#AI 纳管 初始化 获取完设备数据后立马上报心跳数据 + status = eventMesh.publish("get_factory_status") + if status == None: + status = 0 + print("get_factory_status:{}\r\n".format(status)) + if status == 0:#恢复出厂或者新的机器需要清空不必要的数据 + if self.init_flag == 0:#只初始化一次 + IFEXIST = ql_fs.path_exists("/usr/cm_ai_regulation.json") + if IFEXIST == True: + uos.remove("/usr/cm_ai_regulation.json") + self.init_flag = 1 + self.report_state = 0 + self.getDevInforErrCount = 0 + self.report_err_count = 0 + self.timerStartReportHr.stop() + + self.startTimerState = 0 + getDevInfoState = self.get_dev_info() + if getDevInfoState == 0:#开机获取失败了再等30s重新获取 获取二十次都失败就等下次重启设备获取 + self.timerStart.stop() + self.timerStart.start(30*1000,1,self.timerStartCb)#重新开始 开机10分钟内没有获取到设备信息就不获取了需要手动重启设备 + else: #设备开机获取设备信息成功 立马上报一次心跳数据 + self.report_hr_data()#上报一次心跳数据 + +aiRegulation = AIRegulation() + diff --git a/cat1modem/src/LeiNiao/china_mobile_dmp.py b/cat1modem/src/LeiNiao/china_mobile_dmp.py new file mode 100644 index 000000000..8128328bd --- /dev/null +++ b/cat1modem/src/LeiNiao/china_mobile_dmp.py @@ -0,0 +1,842 @@ +import app_fota +from misc import Power +import modem +import ujson +import request +import ql_fs +import checkNet +import sys +import sim + +from queue import Queue +import usys +import _thread +import fota +import utime +import log +import uos +import osTimer +import net +import ql_fs +from ucryptolib import aes +import hashlib +from usr.EventMesh import eventMesh +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +fota_log = log.getLogger("china_mobile") +import modem +import base64 +import request +import ujson +import sim + +BLOCK_SIZE = 16 +NEED_SAVE_CONFIG_FILE = 0 #是否需要保存上报次数 异常重试次数 时间戳到配置文件 0不保存 1保存 +#中国移动入库 +class chinamobile: + def __init__(self): + self.multiDayResend_timer = osTimer()#12小时定时器 多日重发的机制 + + self.multimer_count = 0#多日重发机制周期Count + self.multimer_init = 0 + self.power_on_multiflag = 0 + self.timer_count = 0 + self.timerPowerNum = 0 + self.telecom_init_state = 0#初始化状态开机检查标识 + self.isRegistOk = 0#注册成功 + self.config_data = {} + + self.__net_connected = 0 + self.regist_timeSec = 0 + self.iccid_data = "" + self.software_version = "" + self.mac_data ="" + self.address = "a.fxltsbl.com" + + self.new_address = "a.fxltsbl.com" + + self.retryInterval = 10 + self.retryNum = 1#异常重试最大次数 + self.heartBeatTime = 1440#心跳上报频率 单位分钟 + self.reportTime = 1440#最大上报频率 自注册+心跳上报的频率次数不能大于最大上报频率次数 + self.reportNum = 8 #最大上报次数 + + + self.reportTime_Sec = 0 #保存本地 保存时间戳下一次开机使用 + self.report_Num_old = 0#保存本地 + self.retryNum_old = 0#保存本地 + self.init_flag = 0#初始化状态指初始化一次 + self.retryTimer = osTimer()#异常重试定时器 + self.retpoertTimerC = osTimer()#上报次数大于下一个周期再触发 + self.heartreportTimer = osTimer()#心跳上报定时器 + + eventMesh.subscribe("get_network_state",self.get_network_state)#订阅消息 + eventMesh.subscribe("set_network_state",self.set_network_state)#订阅消息 + + eventMesh.subscribe("set_dev_version",self.set_dev_version)#订阅消息 + eventMesh.subscribe("get_dev_version",self.get_dev_version)#订阅消息 + + eventMesh.subscribe("set_dev_mac",self.set_dev_mac)#订阅消息 + eventMesh.subscribe("get_dev_mac",self.get_dev_mac)#订阅消息 + + eventMesh.subscribe("set_dmp_cm_address",self.set_dmp_cm_address)#订阅消息 + eventMesh.subscribe("get_dmp_cm_address",self.get_dmp_cm_address)#订阅消息 + + pass + + def set_dmp_cm_address(self,event,msg):#设置网络是否正常 + self.address = str(msg) + self.new_address = str(msg) + + def get_dmp_cm_address(self,event,msg):#获取网络是否正常 + return self.address + + def set_network_state(self,event,msg):#设置网络是否正常 + self.__net_connected = int(msg) + + def get_network_state(self,event,msg):#获取网络是否正常 + return self.__net_connected + + def set_dev_version(self,event,msg):#获取固件版本号 + self.software_version = str(msg) + + def get_dev_version(self,event,msg):#获取固件版本号 + return self.software_version + + def set_dev_mac(self,event,msg):#设置BLE MAC地址 + self.mac_data = str(msg) + + def get_dev_mac(self,event,msg):#获取BLE MAC地址 + return self.mac_data + + def sha256_encode(self,key,data):#对数据进行AES256加密 + h = hashlib.sha256() + h.update(key) + crypto_key = h.digest() + #IV是偏移量 默认16个十六进制00 + IV = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + crypto = aes(crypto_key, 2, IV) + + #进行PKCS7Padding填充。 + block_num = len(data) // BLOCK_SIZE+1 + k = len(data) % BLOCK_SIZE + j = len(data) // BLOCK_SIZE + padding = BLOCK_SIZE - k + i = 0 + szDataIn = bytearray(data) + # print(szDataIn) + szDataIn = szDataIn+bytearray(block_num * BLOCK_SIZE -len(data)) + # print(szDataIn) + + for i in range(padding): + szDataIn[j * BLOCK_SIZE + k + i] = padding + # print("szDataIn:{} {} {}\r\n".format(szDataIn,j * BLOCK_SIZE + k + i,padding)) + + indata = bytes(szDataIn) + enc = crypto.encrypt(indata) + #最后将加密AES256的数据转换成base64的编码格式 + msg_tmp = base64.b64encode(enc) + data_encode = msg_tmp.decode('ascii')#转换成字符串 + return data_encode + + #写文件信息 + def write_config_msg_file(self,msg): + + print("write_config_msg_file msg:{}\r\n".format(msg)) + with open("/usr/china_mobie_config.json",'w+',encoding="utf-8") as fd: + ujson.dump(msg,fd) + #读文件信息 + def read_config_msg_file(self): + IFEXIST = ql_fs.path_exists("/usr/china_mobie_config.json") #不存在 + if IFEXIST == True: + with open("/usr/china_mobie_config.json","r",encoding='utf-8') as fd: + self.config_data = ujson.load(fd) + print("read_config_msg_file self.config_data:{}\r\n".format(self.config_data)) + + def china_mobile_first_get_config(self,url): + ##############第一步#######获取采集规则配置####### + # brand = "KUMI"#品牌 + # model = "Watch Soar"#型号 + # NWO N9 + brand = "NWO"#品牌 + model = "NWO N9"#型号 + + + appKey = "M100001131"#不需要就填***appKey 厂商标识 + sdkVersion = "***"#非SDK传输 + apiVersion = "4.0.1"#接口定义 固定4.0.1 + apiType = "I"#非Android + templateId = "TY000014"#根据产品分类在平台查询 + IMEI = modem.getDevImei() + imei1 = IMEI#IMEI1或者CMEI + imei2 = "***" + configType = "autoRegist"#自注册填autoRegist 心跳配置传输 keepAlive + preField1 = "***"#预留字段1 + preField2 = "***"#预留字段2 + preField3 = "***"#预留字段3 + + + + #配置拉取数据格式 + config_data = {"endpoint":"{}||{}||{}||{}||{}||{}||{}||{}||{}||{}||{}||{}".format(brand,model,appKey,sdkVersion,apiVersion,apiType,templateId,imei1,imei2,preField1,preField2,preField3),"configType":"{}".format(configType)} + + #配置拉取数据上报地址 + url = "https://{}//dm-multi-accept/multi/getMultiTerminalConfig".format(self.address) + headers_T ={"Content-Type":"application/json"} + print("ujson.dumps(config_data):{}".format(ujson.dumps(config_data))) + request_result = 0 + result_json = "" + try: + response = request.post(url, data=ujson.dumps(config_data),headers =headers_T) + request_result = 1 + if response.status_code == 200:#服务器响应成功并返回数据 + content = response.content + c = next(content) + result_json = ujson.loads(c) + print("response.json:{}".format(ujson.loads(c))) + except Exception as e: + print("response:{}".format(e)) + request_result = 0 + + + if request_result == 0: #请求出错了 + return "" + + + return result_json + + + def first_get_config_json(self):#开机上电获取配置信息 + getresult = 0 + print("first_get_config_json false",self.__net_connected) + network_state = eventMesh.publish("get_network_state") + if network_state != 1:#网络不正常 + print("网络不正常") + return getresult + url = "https://{}//dm-multi-accept/multi/getMultiTerminalConfig".format(self.address) + result_json = self.china_mobile_first_get_config(url) + + if result_json == "": + print("result_json == NULL") + return 0 + # { + # "reportTime":1440, + # "reportNum":8, + # "heartBeatTime":1440, + # "retryInterval":10, + # "retryNum":1 + # }#默认采集规则配置 + #默认参数 + + retryInterval = self.retryInterval + heartBeatTime = self.heartBeatTime + reportTime = self.reportTime + reportNum = self.reportNum + retryNum = self.retryNum + new_address = self.address + print("get_config_json old:{} {} {} {} {} {}\r\n".format(reportTime,heartBeatTime,reportNum,retryInterval,retryNum,new_address)) + if "rspCode" in result_json:#返回结课code 0000成功 其他参考文档 + rspCode = result_json["rspCode"] + rspCode_zh = result_json["rspMsg"] + if rspCode == "0000" or rspCode_zh == "成功": + getresult = 1 + if "result" in result_json: + msg_data = result_json["result"] #采集规则配置信息 + if "ruleConfig" in msg_data:#不存在就是空 + msg_data = msg_data["ruleConfig"] + msg_data = ujson.loads(msg_data)#转换成json格式 + if "reportTime" in msg_data: + self.reportTime = int(msg_data["reportTime"]) + if "heartBeatTime" in msg_data: + self.heartBeatTime = int(msg_data["heartBeatTime"]) + if "reportNum" in msg_data: + self.reportNum = int(msg_data["reportNum"]) + if "retryInterval" in msg_data: + self.retryInterval = int(msg_data["retryInterval"]) + if "retryNum" in msg_data: + self.retryNum = int(msg_data["retryNum"]) + if "address" in msg_data: + self.address = str(msg_data["address"]) + print("get_config_json new:{} {} {} {} {}\r\n".format(self.reportTime,self.heartBeatTime,self.reportNum,self.retryInterval,self.retryNum,self.address)) + + print("true") + else: + print("false") + + if getresult == 1:#请求配置文件成功 + if (self.retryInterval != retryInterval) or (self.retryNum != retryNum) or (self.heartBeatTime != heartBeatTime) or\ + (self.reportTime != reportTime) or (self.reportNum != reportNum) or (self.address != new_address): + #重新走注册流程 清空报错次数 记录当前时间戳 + print("new config not old config!!!\r\n")#拉取的配置文件和保存本地的不一致 + self.config_data["reportTime"] = self.reportTime + self.config_data["heartBeatTime"] = self.heartBeatTime + self.config_data["reportNum"] = self.reportNum + self.config_data["retryNum"] = self.retryNum + self.config_data["retryInterval"] = self.retryInterval + # self.config_data["address"] = str(self.address) + if new_address != self.address : #服务器下发和本地不一致需要用服务器下发的最新的IP 并把这个IP发送到BLE保存 + eventMesh.publish("send_dmp_cm_address_toBLE",str(self.address)) + + self.write_config_msg_file(self.config_data) #保存新的配置文件 + return 2 + return getresult #1 获取成功 0 获取失败 + + + def china_mobile_autoregist_infor(self,url,configType_data): + #########################第二步############自注册上报################### + #设备自注册上报 + dev_autoregist_result = 0 #默认是1成功 0是失败 + network_state = eventMesh.publish("get_network_state") + if network_state != 1:#网络不正常 + return dev_autoregist_result + #密钥 + key = "03816c12b6d24182981325e57670e478" + + brand = "{}".format("NWO")#品牌 + + # model = "Watch Soar"#型号 + model = "NWO N9"#型号 + + # -*- coding: UTF-8 -*- +#示例 + + + appKey = "M100001188"#不需要就填***appKey 厂商标识 + sdkVersion = "***"#非SDK传输 + apiVersion = "4.0.1"#接口定义 固定4.0.1 + apiType = "I"#非Android + templateId = "TY000014"#根据产品分类在平台查询 + IMEI = modem.getDevImei() + imei1 = IMEI#IMEI1或者CMEI + imei2 = "***" + configType = configType_data#自注册填autoRegist 心跳配置传输 keepAlive 暂时不用 + preField1 = "***"#预留字段1 + preField2 = "***"#预留字段2 + preField3 = "***"#预留字段3 + + + batteryCapacityCurr="***" + + + #不需要加密 #||分隔符不能超过11个 否则平台会解析出错 + config_data = "{}||{}||{}||{}||{}||{}||{}||{}||{}||{}||{}||{}".format(brand,model,appKey,sdkVersion,apiVersion,apiType,templateId,imei1,imei2,configType,preField1,preField2) + + #需要加密的数据明文 + mac_data="***"#eventMesh.publish("get_dev_mac") + + if (len(mac_data) == 0):#获取失败了 + mac_data = "***" + + imsi = sim.getImsi() + print("Get IMSI : {}".format(imsi)) + + MAC = mac_data + # base64_MAC = sha256_encode(key,MAC) + RAM = "***" + # base64_RAM = sha256_encode(key,RAM) + ROM = "***" + # base64_ROM = sha256_encode(key,ROM) + CPU = "***" + # base64_CPU = sha256_encode(key,CPU) + GPU = "***" + + imsi2="***" + + sysVersion = "***" + + board = "***" + + # base64_sysVersion = sha256_encode(key,sysVersion) + if (len(self.software_version) == 0):#获取失败了 + # self.software_version = "Watch Soar V1.0" + self.software_version = "NWO N9 V1.0" + + softwareVer = "NWO N9 V1.0" + # base64_softwareVer = sha256_encode(key,softwareVer) + # softwareName ="FD230" + softwareName ="***" + + sn="***" + + batteryCapacity="***" + + phoneNumber="***" + # base64_softwareName = sha256_encode(key,softwareName) + volte="***" #0:开;1:关;-1:不支持 + # base64_volte = sha256_encode(key,volte) + netType="***" + # base64_netType = sha256_encode(key,netType) + + resolution="466*466" + # base64_resolution = sha256_encode(key,resolution) + + screenSize = "1.43" + # base64_screenSize = sha256_encode(key,screenSize) + wearingStatus ="未佩戴" + # base64_wearingStatus = sha256_encode(key,wearingStatus) + + networkStatus ="***"#1:连接;0:未连接;-1:不支持 + + routerMac = "***" + + wifiMac = "***" + # base64_networkStatus = sha256_encode(key,networkStatus) + encyr_data = [MAC,RAM,ROM,CPU,sysVersion,softwareVer,softwareName,volte,netType,resolution,screenSize,wearingStatus,networkStatus,routerMac,wifiMac,imsi,GPU,imsi2,board,sn,batteryCapacity,phoneNumber,batteryCapacityCurr] + print(len(encyr_data)) + encyr_new_data=[] + for i in range(len(encyr_data)): + tmp_data = self.sha256_encode(key,encyr_data[i]) + encyr_new_data.append(tmp_data) + + # deviceInfo_tmp = { + # "bluetoothMac":"{}".format(base64_MAC),#mac地址可填可不填 + # "ram":"{}".format(base64_RAM),#ram信息 + # "rom":"{}".format(base64_ROM),#rom信息 + # "cpu":"{}".format(base64_CPU),#cpu信息 + # "sysVersion":"{}".format(base64_sysVersion),#操作系统版本号 + # "softwareVer":"{}".format(base64_softwareVer),#固件版本号 + # "softwareName":"{}".format(base64_softwareName),#固件名称 + # "volte":"{}".format(base64_volte),#volte开关 默认是开 + # "netType":"{}".format(base64_netType),#当前网络类型4G + # "resolution":"{}".format(base64_resolution),#屏幕分辨率466*466 + # "screenSize":"{}".format(base64_screenSize),#屏幕尺寸默认1.43 + # "wearingStatus":"{}".format(base64_wearingStatus),#佩戴状态不支持 + # "networkStatus":"{}".format(base64_networkStatus)#网络状态 + + # } + if configType_data=="keepAlive": + print("keepAlive :") + deviceInfo_tmp = { + "bluetoothMac":"{}".format(encyr_new_data[0]),#mac地址可填可不填 + "ram":"{}".format(encyr_new_data[1]),#ram信息 + "rom":"{}".format(encyr_new_data[2]),#rom信息 + "cpu":"{}".format(encyr_new_data[3]),#cpu信息 + "sysVersion":"{}".format(encyr_new_data[4]),#操作系统版本号 + "softwareVer":"{}".format(encyr_new_data[5]),#固件版本号 + "softwareName":"{}".format(encyr_new_data[6]),#固件名称 + "volte":"{}".format(encyr_new_data[7]),#volte开关 默认是开 + "netType":"{}".format(encyr_new_data[8]),#当前网络类型4G + "resolution":"{}".format(encyr_new_data[9]),#屏幕分辨率466*466 + "screenSize":"{}".format(encyr_new_data[10]),#屏幕尺寸默认1.43 + "wearingStatus":"{}".format(encyr_new_data[11]),#佩戴状态不支持 + "networkStatus":"{}".format(encyr_new_data[12]),#网络状态 + "routerMac":"{}".format(encyr_new_data[13]), #路由mac地址 *** + "mac":"{}".format(encyr_new_data[14]), #wifi mac + "imsi":"{}".format(encyr_new_data[15]), #imsi + "gpu":"{}".format(encyr_new_data[16]), #GPU + "imsi2":"{}".format(encyr_new_data[17]), #imsi2 + "board":"{}".format(encyr_new_data[18]), #board + "sn":"{}".format(encyr_new_data[19]), #board + "batteryCapacity":"{}".format(encyr_new_data[20]), #board + "phoneNumber":"{}".format(encyr_new_data[21]), #board + "batteryCapacityCurr":"{}".format(encyr_new_data[22]), #board + } + else : + deviceInfo_tmp = { + "bluetoothMac":"{}".format(encyr_new_data[0]),#mac地址可填可不填 + "ram":"{}".format(encyr_new_data[1]),#ram信息 + "rom":"{}".format(encyr_new_data[2]),#rom信息 + "cpu":"{}".format(encyr_new_data[3]),#cpu信息 + "sysVersion":"{}".format(encyr_new_data[4]),#操作系统版本号 + "softwareVer":"{}".format(encyr_new_data[5]),#固件版本号 + "softwareName":"{}".format(encyr_new_data[6]),#固件名称 + "volte":"{}".format(encyr_new_data[7]),#volte开关 默认是开 + "netType":"{}".format(encyr_new_data[8]),#当前网络类型4G + "resolution":"{}".format(encyr_new_data[9]),#屏幕分辨率466*466 + "screenSize":"{}".format(encyr_new_data[10]),#屏幕尺寸默认1.43 + "wearingStatus":"{}".format(encyr_new_data[11]),#佩戴状态不支持 + "networkStatus":"{}".format(encyr_new_data[12]),#网络状态 + "routerMac":"{}".format(encyr_new_data[13]), #路由mac地址 *** + "mac":"{}".format(encyr_new_data[14]), #wifi mac + "imsi":"{}".format(encyr_new_data[15]), #imsi + "gpu":"{}".format(encyr_new_data[16]), #GPU + "imsi2":"{}".format(encyr_new_data[17]), #imsi2 + "board":"{}".format(encyr_new_data[18]), #board + "sn":"{}".format(encyr_new_data[19]), #board + "batteryCapacity":"{}".format(encyr_new_data[20]), #board + "phoneNumber":"{}".format(encyr_new_data[21]), #board + + } + json_data = ujson.dumps(deviceInfo_tmp)#需要转义的字符串 + + + + + send_autoregist = { + "endpoint":config_data, + "deviceInfo":"{}".format(json_data) + } + + test_data = ujson.dumps(send_autoregist)#需要转义的字符串 + print("test_data:{}".format(test_data)) + headers_T ={"Content-Type":"application/json"} + request_result = 0 + print("shangbao address:{}\r\n".format(url)) + try: + response = request.post(url, data=ujson.dumps(send_autoregist),headers =headers_T) + request_result = 1 + result_json = "" + print("response success:response.status_code{}\r\n".format(response.status_code)) + if response.status_code == 200: + dev_autoregist_result = 1 + content = response.content + c = next(content) + result_json = ujson.loads(c)#解析成json格式 + else: + dev_autoregist_result = 0 + + + if "rspCode" in result_json: + rspCode = result_json["rspCode"] + rspMsg = result_json["rspMsg"] + print("response success:rspCode{} {}\r\n".format(rspMsg,rspCode)) + if rspCode == "0000" or rspMsg == "成功": + dev_autoregist_result = 1 + else: + dev_autoregist_result = 0 + else: + dev_autoregist_result = 0 + print("response success:\r\n") + return dev_autoregist_result + + except Exception as e: + print("response:{}".format(e)) + request_result = 0 + + if request_result == 0:#请求出错了 + dev_autoregist_result = 0 + return dev_autoregist_result + + + def read_config_file(self):#获取配置文件,一开机是没有配置文件的 + + self.read_config_msg_file()#读文件信息 + if self.config_data != {}: + if "retryInterval" in self.config_data: + self.retryInterval = int(self.config_data["retryInterval"]) + if "retryNum" in self.config_data: + self.retryNum = int(self.config_data["retryNum"]) + if "heartBeatTime" in self.config_data: + self.heartBeatTime = int(self.config_data["heartBeatTime"]) + if "reportTime" in self.config_data: + self.reportTime = int(self.config_data["reportTime"]) + if "reportNum" in self.config_data: + self.reportNum = int(self.config_data["reportNum"]) + if "address" in self.config_data: + self.address = str(self.config_data["address"]) + + #终端本地需要保存本地的数据 + # self.reportTime_Sec = 0 #保存本地 保存时间戳下一次开机使用 + # self.report_Num_old = 0#保存本地 + # self.retryNum_old = 3#保存本地 + if NEED_SAVE_CONFIG_FILE == 1: + if "reportTime_Sec" in self.config_data: + self.reportTime_Sec = int(self.config_data["reportTime_Sec"]) + if "report_Num_old" in self.config_data: + self.report_Num_old = int(self.config_data["report_Num_old"]) + if "retryNum_old" in self.config_data: + self.retryNum_old = int(self.config_data["retryNum_old"]) + + print("read_config_file self.config_data:{} ".format(self.config_data)) + def retryTimerCb(self,*argc):#异常重试机制定时器回调 + #保存本地 + self.retryNum_old+=1 #1 self.reportNum = 1 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["retryNum_old"] = self.retryNum_old + self.write_config_msg_file(self.config_data) + print("retryTimerCb self.retryNum_old:{}\r\n".format(self.retryNum_old)) + self.search_report_num_step() + pass + def reportTimerIntervalError(self): + self.retryNum_old = 0#保存 + self.report_Num_old = 0#保存 定时清空数据 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + self.reportTime_Sec = time_tmp+self.reportTime*60 #(记录时间+reportTime)标识旧的时间 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["reportTime_Sec"] = self.reportTime_Sec + self.config_data["retryNum_old"] = self.retryNum_old + self.config_data["report_Num_old"] = self.report_Num_old + self.write_config_msg_file(self.config_data) + self.search_report_num_step()#重新查询 + pass + def error_retryNum_step(self):#判读报错次数是否大于self.retryNum 步骤 + print("error_retryNum_step:self.retryNum_oldd:{} self.retryNum:{} self.reportTime:{}\r\n".format(self.retryNum_old,self.retryNum,self.reportTime)) + + if self.retryNum_old >= self.retryNum and self.retryNum_old != 0:#self.retryNum_old > 10#结束HTPP下一个最大频率周期时间间隔流程 + print("error_retryNum_step:self.retryNum_old >= self.retryNum\r\n") + self.reportTimerIntervalError() + # self.retpoertTimerC.start(self.reportTime*60*1000,0,self.reportTimerIntervalError)#重新开始 需要清空数据 + else: + get_result = self.first_get_config_json()#发起向服务端请求配置信息下发到设备端 + if get_result == 0:#获取失败或者没有网络 走异常重试机制 + self.report_Num_old+=1#请求错误请求失败都要保存上报次数 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["report_Num_old"] = self.report_Num_old + self.write_config_msg_file(self.config_data) + print("error_retryNum_step:self.retryTimer.start :{} {} {}\r\n".format(self.retryInterval,self.report_Num_old,self.reportNum)) + self.checkMaxReportNum()#检查上报最大次数 + self.retryTimer.start(self.retryInterval*60*1000,0,self.retryTimerCb) + pass + else:# + + #第一步触发自注册 + if get_result == 2:#请求的配置文件和本地不一致重启 + self.retryNum_old = 0#保存本地 配置文件不同重启模组 清空异常重试的报错次数 + # self.report_Num_old+=1#请求错误请求失败都要保存上报次数 + # if NEED_SAVE_CONFIG_FILE == 1: + # self.config_data["report_Num_old"] = self.report_Num_old + # self.config_data["retryNum_old"] = self.retryNum_old + # self.write_config_msg_file(self.config_data) + + self.china_mobile_init_param()#重新走流程读配置文件->判断上报总数->判断报错次数->获取配置文件 + self.search_report_num_step() + return + + self.report_Num_old+=1#请求错误请求失败都要保存上报次数 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["report_Num_old"] = self.report_Num_old + self.write_config_msg_file(self.config_data) + print("error_retryNum_step self.report_Num_old:{}\r\n".format(self.report_Num_old)) + if self.checkMaxReportNum() == 1:#检查上报最大次数 + self.search_report_num_step()#重新查询 + return + report_result = self.onself_regist_report_cb()#注册 + + #第二步触发心跳上报次数 + if report_result == 1:#注册完成之后根据服务端下发的配置 间隔上报心跳 + self.heartreportTimer.stop() + self.heartreportTimer.start(self.heartBeatTime*60*1000,1,self.heartreportTimerCb) + + def heartreportTimerCb(self,*argc): + self.heart_report_cb() + + def retpoertTimerClear(self): + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + print("retpoertTimerCB time_tmp -self.reportTime_Sec:{} time_tmp :{} self.reportTime_Sec:{}\r\n".format(self.reportTime_Sec-time_tmp,time_tmp,self.reportTime_Sec)) + self.report_Num_old = 0#清空上报总次数 #保存本地 + self.retryNum_old = 0#清空上报错误次数 #保存本地 + self.reportTime_Sec = time_tmp+self.reportTime*60#记录当前时间+reportTime的时间用于下次错判断 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["reportTime_Sec"] = self.reportTime_Sec + self.config_data["retryNum_old"] = self.retryNum_old + self.config_data["report_Num_old"] = self.report_Num_old + self.write_config_msg_file(self.config_data) + self.retpoertTimerC.stop()#关闭定时器 + self.error_retryNum_step()#清空报错次数重新走判断报错次数 + pass + def check_current_time(self):#检测当前时间是否超过self.reportTime 超过清空报错次数 清空上报总次数 + # + date_tmp = utime.localtime() + currentTime = utime.mktime(date_tmp)#获取时间戳 + reportTime = self.reportTime_Sec + print("check_current_time:time_tmp - self.reportTime_Sec:{} currentTime:{} self.reportTime*60:{}".format(reportTime, currentTime,self.reportTime*60)) + if currentTime >= reportTime:#当前时间是否大于上次记录的时间 currentTime >= reportTime 直接清空 不超过定时清空数据不再上报数据 + #在规定时间内上报次数大于8次就要等下一个10分钟 或者1440分了开个定时器 + print("currentTime >= reportTime:\r\n") + self.retpoertTimerClear() + else:#否则次数置零,记录一下(当前时间+reportTime)时间 + time_count = (reportTime - currentTime) #self.reportTime_Sec永远比time_tmp大 + print("time_count:{}".format(time_count)) + print("currentTime < reportTime:\r\n") + self.retpoertTimerC.start(time_count*1000,0,self.retpoertTimerCB) + + + # 第一次请求的时候,记录一下(当前时间+reportTime)时间与次数,如果次数小于最大次数,直接返回true。 + # 如果次数大于最大次数,则判断一下当前时间是否超过上次设置的时间,如果超过了,则表示超过最大次数;否则次数置零,记录一下(当前时间+reportTime)时间。 + def retpoertTimerCB(self,*argc):#按照剩余的时间做定时器 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + print("retpoertTimerCB time_tmp -self.reportTime_Sec:{} time_tmp :{} self.reportTime_Sec:{}\r\n".format(self.reportTime_Sec-time_tmp,time_tmp,self.reportTime_Sec)) + self.report_Num_old = 0#清空上报总次数 #保存本地 + self.retryNum_old = 0#清空上报错误次数 #保存本地 + self.reportTime_Sec = time_tmp+self.reportTime*60#记录当前时间+reportTime的时间用于下次错判断 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["reportTime_Sec"] = self.reportTime_Sec + self.config_data["retryNum_old"] = self.retryNum_old + self.config_data["report_Num_old"] = self.report_Num_old + self.write_config_msg_file(self.config_data) + self.error_retryNum_step()#清空报错次数重新走判断报错次数 + + + def search_report_num_step(self):#查询上报总数步骤 + print("search_report_num_step:self.retryInterval:{} self.retryNum:{}".format(self.report_Num_old,self.reportNum)) + if self.report_Num_old >= self.reportNum and self.report_Num_old != 0:#查询上报的总次数是否大于存储上报总次数 + self.check_current_time()#检测当前时间是否超过self.reportTime 超过清空报错次数 清空上报总次数 + else:# + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + self.reportTime_Sec = time_tmp+self.reportTime*60 #(记录时间+reportTime)标识旧的时间 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["reportTime_Sec"] = self.reportTime_Sec + self.write_config_msg_file(self.config_data) + self.error_retryNum_step()#查询上报错误次数 + + def search_report_num_step_init(self):#查询上报总数步骤 + print("search_report_num_step:self.retryInterval:{} self.retryNum:{} self.reportTime_Sec:{}\r\n".format(self.report_Num_old,self.reportNum,self.reportTime_Sec)) + if self.report_Num_old >= self.reportNum and self.report_Num_old != 0:#查询上报的总次数是否大于存储上报总次数 + self.check_current_time()#检测当前时间是否超过self.reportTime 超过清空报错次数 清空上报总次数 + else:# + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + if self.reportTime_Sec == 0: + self.reportTime_Sec = time_tmp+self.reportTime*60 #(记录时间+reportTime)标识旧的时间 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["reportTime_Sec"] = self.reportTime_Sec + self.write_config_msg_file(self.config_data) + self.error_retryNum_step()#查询上报错误次数 + + + def reportTimerIntervalCb(self,*argc):#最大上报频率时间间隔定时器 要清空数据 + print("reportTimerIntervalCb\r\n") + self.search_report_num_step()#重新查询 + + def onself_regist_report_cb(self):#自注册上报信息 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + print("onself_regist_report_cb:self.report_Num_old:{} self.reportNum:{} self.reportTime_Sec:{}\r\n".format(self.report_Num_old,self.reportNum,self.reportTime_Sec)) + self.report_Num_old+=1 ##保存本地 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["report_Num_old"] = self.report_Num_old + self.write_config_msg_file(self.config_data) + #设备自注册上报信息 + print("onself_regist_report_cb:self.china_mobile_autoregist_infor") + url = "https://{}//dm-multi-accept/multi/acceptMultiTerminalRegInfo".format(self.address)#上报地址 + confing_type = "autoRegist"#上报传输配置 + result = self.china_mobile_autoregist_infor(url,confing_type) + + + if result != 1: + #触发异常重试进制 + self.checkMaxReportNum()#检查上报最大次数 + if self.checkMaxRetryNum() == 1: + print("retryTimerCb timer22")#异常重试过多重新间隔reportTime注册流程 关闭所有的定时器 + self.search_report_num_step()#重新查询 + return 0 + self.retryTimer.start(self.retryInterval*60*1000,0,self.retryTimerCb) + return 0 + else: + if self.checkMaxReportNum() == 1: + self.search_report_num_step()#重新查询 + # self.retpoertTimerC.start(self.reportTime*60*1000,0,self.reportTimerIntervalCb) + return 0 + else: + return 1 + def checkMaxReportNum(self):#检查上报次数最大值 + print("checkMaxReportNum :self.reportNum :{} self.report_Num_old:{}\r\n".format(self.reportNum,self.report_Num_old)) + if self.report_Num_old >= self.reportNum and self.report_Num_old != 0: + self.retryTimer.stop()#关定时器 + self.retpoertTimerC.stop() + self.heartreportTimer.stop() + return 1 + else: + return 0 + + def checkMaxRetryNum(self):#检查上报错误次数 + print("checkMaxRetryNum :self.retryNum:{} self.retryNum_old:{}\r\n".format(self.retryNum_old,self.retryNum)) + if self.retryNum_old >= self.retryNum and self.retryNum_old != 0:#异常重试过多重新间隔reportTime注册流程 + self.retryTimer.stop()#关定时器 + self.retpoertTimerC.stop() + self.heartreportTimer.stop()#关闭心跳定时器 + return 1 + else: + return 0 + + def heart_report_cb(self):#心跳上报信息 + + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + self.report_Num_old+=1#保存本地 + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["report_Num_old"] = self.report_Num_old + self.write_config_msg_file(self.config_data) + print("heart_report_cb:self.report_Num_old:{} self.reportNum:{} self.reportTime:{} self.reportTime_Sec:{}\r\n".format(self.report_Num_old,self.reportNum,self.reportTime,self.reportTime_Sec)) + + url = "https://{}//dm-multi-accept/multi/acceptMultiTerminalHeartbeatInfo".format(self.address)#上报地址 + confing_type = "keepAlive"#上报传输配置 + print("heart_report_cb:self.china_mobile_autoregist_infor") + result = self.china_mobile_autoregist_infor(url,confing_type) + if result != 1: + #触发异常重试进制 + self.checkMaxReportNum() + if self.checkMaxRetryNum() == 1:#异常重试过多重新间隔reportTime注册流程 + self.search_report_num_step()#重新查询 + return + self.retryTimer.start(self.retryInterval*60*1000,0,self.retryTimerCb) + return + if self.checkMaxReportNum() == 1:#上报次数大于8次 + self.search_report_num_step()#重新查询 + return + + def china_mobile_init_param(self):#初始化 + + status = eventMesh.publish("get_factory_status") + if status == None: + status = 0 + print("get_factory_status:{}\r\n".format(status)) + if status == 0:#恢复出厂或者新的机器需要清空不必要的数据 + if self.init_flag == 0:#只初始化一次 + IFEXIST = ql_fs.path_exists("/usr/telecom_config.json") #不存在 + if IFEXIST == True: + uos.remove("/usr/telecom_config.json") + isStorage = ql_fs.path_exists("/usr/china_mobie_config.json")#移动入库的配置文件移除 + if isStorage == True: + uos.remove("/usr/china_mobie_config.json") + #先清空再写入默认参数 + self.init_flag = 1 + self.retryInterval = 10 + self.retryNum = 1#异常重试最大次数 + self.heartBeatTime = 1440#心跳上报频率 单位分钟 + self.reportTime = 1440#最大上报频率 自注册+心跳上报的频率次数不能大于最大上报频率次数 + self.reportNum = 8 #最大上报次数 + + self.reportTime_Sec = 0 #保存本地 保存时间戳下一次开机使用 + self.report_Num_old = 0#保存本地 + self.retryNum_old = 0#保存本地 + get_address = eventMesh.publish("get_dmp_cm_address") + if get_address == None:#获取出来地址是空的使用适配地址 + self.address = "a.fxltsbl.com"#默认 + else: #恢复出厂使用BLE传送过来的地址 + self.address = str(eventMesh.publish("get_dmp_cm_address")) + + self.config_data["retryInterval"] = self.retryInterval + self.config_data["retryNum"] = self.retryNum + self.config_data["heartBeatTime"] = self.heartBeatTime + self.config_data["reportTime"] = self.reportTime + self.config_data["reportNum"] = self.reportNum + # self.config_data["address"] = self.address + if NEED_SAVE_CONFIG_FILE == 1: + self.config_data["reportTime_Sec"] = self.reportTime_Sec + self.config_data["report_Num_old"] = self.report_Num_old + self.config_data["retryNum_old"] = self.retryNum_old + + self.write_config_msg_file(self.config_data) + #读配置文件 + self.read_config_file()#只读一下配置文件 + + self.retryTimer.stop()#关定时器 + self.retpoertTimerC.stop() + self.heartreportTimer.stop() + def china_mobile_init(self): + self.china_mobile_init_param() + #查询上报总数流程 + self.search_report_num_step_init() + + + + +chinamobileCb = chinamobile() + + + + + + + + + + + + diff --git a/cat1modem/src/LeiNiao/httpota.py b/cat1modem/src/LeiNiao/httpota.py new file mode 100644 index 000000000..1f7ff897c --- /dev/null +++ b/cat1modem/src/LeiNiao/httpota.py @@ -0,0 +1,43 @@ +#远程升级 + +import fota +import utime +import log +import checkNet + +import app_fota +from misc import Power +import modem +import ujson +import request +import ql_fs +import checkNet +import sys + +#远程升级 +import uos + + +# 设置日志输出级别 + +class httpota: + def __init__(self): + print("httpota init") + + + def run(url_1,url_2): + print("httpDownload...{}".format(url_1)) + print("httpDownload...{}".format(url_2)) + # format(str(url_2))) + fota_obj = fota() # 创建Fota对象 + # res = fota_obj.httpDownload(str(url_1),str(url_2)) + res = fota_obj.httpDownload(url1="{}".format(url_1),url2="{}".format(url_2)) + if res != 0: + print.error("httpDownload error") + return + print("wait httpDownload update...") + utime.sleep(2) + # Power.powerRestart() + +# httpota = httpota() +# httpota.run("http://snicker.com.cn:8089/FD230/V18-V19OTA") \ No newline at end of file diff --git a/cat1modem/src/LeiNiao/main.py b/cat1modem/src/LeiNiao/main.py new file mode 100644 index 000000000..a5bea573d --- /dev/null +++ b/cat1modem/src/LeiNiao/main.py @@ -0,0 +1,27 @@ +import example +import log +from machine import UART + +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +# 设置输出到debug口 +uart = UART(UART.UART0, 115200, 8, 0, 1, 0) +# log.set_output(uart) +clog = log.getLogger("cat1") + +main_flag = 1 + + +try: + example.exec('/usr/main_init.py') + clog.info("启动main_init成功!!!!!\r\n") +except Exception as e: + main_flag = 0 + clog.error("启动失败!!!!!\r\n".format(e)) + +try: + example.exec('/usr/tcpserver.py') + clog.info("启动tcpserver成功!!!!!\r\n") +except Exception as e: + clog.error("启动失败!!!!!\r\n".format(e)) + diff --git a/cat1modem/src/LeiNiao/main_init.py b/cat1modem/src/LeiNiao/main_init.py new file mode 100644 index 000000000..4eb63593f --- /dev/null +++ b/cat1modem/src/LeiNiao/main_init.py @@ -0,0 +1,101 @@ +import example +import osTimer +import ql_fs +import log +import sms +from misc import Power +ota_flag = 0 +try: + try: + from usr.EventMesh import eventMesh + print("检测文件成功!!!!!!!\r\n",'eventMesh') + except Exception as e: + print("检测文件失败!!!!!!!{}\r\n",'eventMesh') + + try: + from usr.telecom_dmp import telecomDmpCb + print("检测文件成功!!!!!!!\r\n",'telecomDmpCb') + except Exception as e: + print("检测文件失败!!!!!!!{}\r\n",'telecomDmpCb') + + try: + from usr.china_mobile_dmp import chinamobileCb + print("检测文件成功!!!!!!!\r\n",'chinamobileCb') + except Exception as e: + print("检测文件失败!!!!!!!{}\r\n",'chinamobileCb') + try: + from usr.china_mobile_ai_regulation import aiRegulation + print("检测文件成功!!!!!!!\r\n",'aiRegulation') + except Exception as e: + print("检测文件失败!!!!!!!{}\r\n",'aiRegulation') + try: + from usr.cat1Service import cat1service + print("检测文件成功!!!!!!!\r\n",'cat1service') + except Exception as e: + print("检测文件失败!!!!!!!{}\r\n",'cat1service') + + ota_flag = 1 + print("检测文件成功!!!!!!!\r\n") +except Exception as e: + print("检测文件失败!!!!!!!{}\r\n".format(e)) + ota_flag = 0 +tmp_dir = ql_fs.path_exists("/usr/TmpPyFile") #临时存放的文件夹 +if tmp_dir == True: + try: + ql_fs.rmdirs("/usr/TmpPyFile") + print("移除 TmpPyFile 成功!!!!!!!\r\n") + except Exception as e: + print("移除 TmpPyFile 失败!!!!!!!{}\r\n".format(e)) + +sms_get = sms.getSaveLoc() +if(sms_get != -1): + sms_lacv = sms_get[0][0] + if sms_lacv != 'SM': #每次开机设置一下短信的存储位置 + sms.setSaveLoc('SM', 'SM', 'SM') + +PROJECT_VERSION = "PY_MAIN_V3" +CONFIG_JSON="/usr/system_config.json" +CURRENT_APP_TYPE="pymain" + + +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +cat1service_log = log.getLogger("pymain") + + +def get_versionkeyname_by_py(app_type): + return str("{}version".format(app_type)) + +def get_default_versionvalue_by_py(app_type): + if (app_type == "pymain"): + return "PY_MAIN_V2" + elif (app_type == "pyota"): + return "PY_OTA_V2" + elif (app_type == "pysrv"): + return "PY_SRV_V2" + +#如果没有configfile则创建它 +if not ql_fs.path_exists(CONFIG_JSON): + data = {str(get_versionkeyname_by_py(CURRENT_APP_TYPE)):get_default_versionvalue_by_py(CURRENT_APP_TYPE)} + ql_fs.touch(CONFIG_JSON,data) + +def set_version_to_json_config(app_type,keyvalue): + config_data = ql_fs.read_json(CONFIG_JSON) + config_data.update( {str(get_versionkeyname_by_py(app_type)):keyvalue}) + ql_fs.touch(CONFIG_JSON, config_data) + cat1service_log.info("{}={}".format(get_versionkeyname_by_py(app_type),keyvalue)) + cat1service_log.info("{}".format(config_data)) + +set_version_to_json_config(CURRENT_APP_TYPE,PROJECT_VERSION) + + +def checkota_cb(arg): + print("start checkota!!") + example.exec('/usr/checkota.py') +# 创建os定时器 + +timer = osTimer() +# 启动定时器,参数依次为时间、是否循环、回调函数 定时器超时的时间(单位ms) +# 开机delay 20秒后执行一次ota升级 +timer.start(20000,0,checkota_cb) +print("checkota py end!!") diff --git a/cat1modem/src/LeiNiao/tcpserver.py b/cat1modem/src/LeiNiao/tcpserver.py new file mode 100644 index 000000000..afe23b2c1 --- /dev/null +++ b/cat1modem/src/LeiNiao/tcpserver.py @@ -0,0 +1,602 @@ +from misc import Power +import usocket +import log +import utime +from machine import UART +import _thread +from queue import Queue +from machine import Pin +from machine import ExtInt +import osTimer +import utime +import ql_fs +import binascii +import ujson +import uos + + +log.basicConfig(level=log.INFO) +clog = log.getLogger("cat1") + +USR_FILE_PATH = "/usr" # +BAK_FILE_PATH = "{}/TmpPyFile".format(USR_FILE_PATH) +BAK_FILE_TMP = "_bak" +CAT1_SERVICE_HEAD = "FE" +CAT1_FILE_DATA_HEAD = "FF" +CAT1_REPLAY_STATE="00" +CAT1_CREAT_DIR_FAILE= "01" +CAT1_CREAT_DIR_OK= "02" +CAT1_NO_REPLAY_OTA_OK= "03" +CAT1_WRITE_FILE_SUCC= "04" +CAT1_WRITE_FILE_ERROR = "05" +CAT1_CRC_ERROR = "06" +CAT1_SEND_HEAD_ERR = "07" +CAT1_OTA_TIMEOUT_BLE_NO_REPLAY = "08" +CAT1_CREAT_FILE_ERROR = "09" +CAT1_CREAT_FILE_SUCC = "0A" +CAT1_ALLPY_FILE_TRANSFER_END = "0B" +CAT1_REPLAY_OTA_SUCC = "0C" +CAT1_REPLAY_OTA_FALIE = "0D" +CAT1_REPLAY_FILE_SIZE_OK = "0E" +CAT1_REPLAY_FILE_SIZE_ERR = "0F" +CAT1_REPLAY_OTA_END_FAILE = "10" +CAT1_NEED_UPDATE_OTA = "11" +CAT1_TCP_STOP_OTA = 0 +CAT1_TCP_START_OTA = 1 +CAT1_TCP_START_SEND_SINGLE_FILE_INFO= 2 +CAT1_TCP_START_SEND_FILE_DATA= 3 +CAT1_TCP_START_OTA_FAILE = 4 +CAT1_TCP_START_OTA_SUCC = 5 +CAT1_TCP_START_SEND_ALLFILE_FINESH = 6 +CAT1_TCP_SEND_SINGLE_FINESH = 7 +CAT1_TCP_START_ERROR_INFO = 255 + +gpioWakeBT = Pin(Pin.GPIO21, Pin.OUT, Pin.PULL_DISABLE, 1) +gpioWakeBT.set_dir(Pin.OUT) +gpioWakeBT.write(0) +FILE_TRANSFER_TIMEOUT=60 +class TcpServiceInit: + AP = 0 + STA = 1 + + def __init__(self, uart=UART.UART4, mode=AP): + self.__uart = uart + self.__mode = mode + self.Cat1FileState = 0 + self.Cat1FileReplayBle = 0 + self.Cat1TimeCount = 0 + self.Cat1PyFileTimout = FILE_TRANSFER_TIMEOUT + self.Cat1FileTransTimer = osTimer() + self.Cat1OtaTimeOut = osTimer() + self.crc_err = 0 + self.allPyRecvFlag = 0 + self.ota_state =0 + self.ota_bstate =0 + self.fileNameTmp = "" + self.fileNameList = [] + self.fileSizeList = [] + self.fileSize = 0 + self.updateTimer = osTimer() + self.updateTimerCount = 0 + self.updateTimerFlag = 0 + self.sock = None + self.bakFlag = "0" + self.conn= None + self.__sock_file = None + self.__sock_file = self.__socket_file_init() + self.__thread_file = _thread.start_new_thread(self.__Socket_File_Thread, ()) + self.conn_thread=_thread.start_new_thread(self._client_conn_proc, ()) + + def __pack_tlv_format(self, head, content): + head1 = head + content1 = content + if len(content1) == 0 or len(content1) > 9999 or len(head1) != 2: + return -1 + len_str ='%04d' % len(content1) + tlv_pack = CAT1_SERVICE_HEAD+head1+len_str+content1 + return tlv_pack + + def __unpack_tlv_format(self, msg): + msg_tmp = str(msg)[2:] + tag = msg_tmp[0:2] + length = msg_tmp[2:6] + value = msg_tmp[6:] + len_str ='%04d' % len(value) + if len(value) == 0 or len(value) > 9999 or len(tag) != 2 or len_str != msg_tmp[2:6]: + return -1 + unpack = (tag,length,value) + return unpack + + def __socket_file_init(self): + self.sock = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM, usocket.IPPROTO_TCP_SER) + self.sock.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1) + bind_addr = ('172.16.1.2', 5001) + self.sock.bind(bind_addr) + self.sock.listen(10) + return self.sock + + def __Socket_TCP_file_noreply(self, head, content): + head1 = head + content1 = content + gpioWakeBT.write(1) + utime.sleep_ms(2) + gpioWakeBT.write(0) + utime.sleep_ms(20) + msg = self.__pack_tlv_format(head1,content1) + if msg == -1: + return 0 + try: + self.conn.send(msg) + except Exception as e: + clog.info("self.__sock_file error {}".format(e)) + return 0 + + def _client_conn_proc(self): + while True: + if self.conn==None: + utime.sleep_ms(20) + continue + try: + data = self.conn.recv(1024) + if not data: + clog.info("__Socket_File_Thread data null:\r\n") + else: + self.src_data(data.decode('uft-8')) + except: + self.conn.close() + break + + def __Socket_File_Thread(self): + while True: + try : + cli_conn, cli_ip_addr, cli_port = self.__sock_file.accept() + self.conn=cli_conn + clog.info('[serveice] accept a client: %s, %s' % (cli_ip_addr, cli_port)) + except : + utime.sleep_ms(20) + + def cat1FileTimerCb(self,*argc): + clog.info("timer test\r\n") + if self.Cat1PyFileTimout > 0: + self.Cat1PyFileTimout-=1 + if self.Cat1PyFileTimout == 0: + self.Cat1PyFileTimout = 0 + self.Cat1FileState = 0 + self.deleteTmpFile() + self.deleteUsrTmpFile() + self.__Socket_TCP_file_noreply(CAT1_OTA_TIMEOUT_BLE_NO_REPLAY,"ota error") #结束文件接收不完整的 + self.Cat1FileTransTimer.stop() + pass + + def crc_cal(self,msg): + bytes_data = msg.encode('utf-8') + hex_data = binascii.hexlify(bytes_data) + hex_data = hex_data.decode() + data = hex_data + crcValue = 0 + j = 0 + i = 0 + json_state = 0 + crcbuf = 0 + data_len = len(str(data)) + try: + if data_len % 2 != 0: + json_state = 0 + return [json_state,crcbuf] + except Exception as e: + json_state = 0 + for i in range(data_len): + if j >= data_len: + break + try: + decimal_number = int(str(data[j:j+2]), 16) + crcValue=crcValue+decimal_number + crcValue = crcValue&0xff + except Exception as e: + clog.info("crc_cal") + j+=2 + crcbuf = crcValue%256 + crcbuf = 256-crcbuf + crcbuf = crcbuf%256 + return [json_state,"%02x"%(crcbuf)] + def deleteTmpFile(self): + tmp_dir = ql_fs.path_exists(BAK_FILE_PATH) + if tmp_dir == True: + ql_fs.rmdirs(BAK_FILE_PATH) + + def deleteUsrTmpFile(self): + return + + def src_data(self,data): + if self.updateTimerFlag == 0: + self.updateTimerFlag = 1 + self.updateTimer.stop() + msg = "" + json_state = 0 + try: + msg = ujson.loads(data) + json_state = 1 + except Exception as e: + json_state = 0 + if json_state == 0: + value = self.__unpack_tlv_format(data) + self.cmd_data(value[0],value[2]) + return + else: + self.file_data(msg) + pass + def cmd_data(self,cmd,parm): + if cmd == "01": + self.bakFlag = str(parm) + pass + def file_data(self,msg): + if "Code" in msg: + Code = int(msg["Code"]) + if Code == CAT1_TCP_STOP_OTA: + self.allPyRecvFlag = 0 + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.deleteTmpFile() + self.deleteUsrTmpFile() + pass + elif Code == CAT1_TCP_START_OTA: + self.ota_state =0 + self.ota_bstate =0 + self.allPyRecvFlag = 0 + self.fileNameList = [] + self.fileSizeList = [] + self.allPyRecvFlag = 0 + self.Cat1FileState = 0 + self.deleteUsrTmpFile() + self.Cat1OtaTimeOut.stop() + check_dir = ql_fs.path_exists(BAK_FILE_PATH) + mk_dir_state = 0 + if check_dir == True: + try: + self.deleteTmpFile() + except Exception as e: + clog.info("移除失败\r\n") + check_dir = ql_fs.path_exists(BAK_FILE_PATH) + if check_dir == False: + try: + ql_fs.mkdirs(BAK_FILE_PATH) + mk_dir_state = 1 + except Exception as e: + mk_dir_state = 0 + else: + mk_dir_state = 1 + if mk_dir_state == 0: + self.__Socket_TCP_file_noreply(CAT1_CREAT_DIR_FAILE,"creat dir error!") + else: + self.Cat1FileState = 1 + self.fileNameList = [] + self.fileSizeList = [] + self.Cat1PyFileTimout = FILE_TRANSFER_TIMEOUT + self.Cat1FileTransTimer.stop() + self.Cat1FileTransTimer.start(1000,1,self.cat1FileTimerCb) + self.__Socket_TCP_file_noreply(CAT1_CREAT_DIR_OK,"creat dir success!") + + elif Code == CAT1_TCP_START_SEND_SINGLE_FILE_INFO and self.Cat1FileState == 1: + self.Cat1PyFileTimout = FILE_TRANSFER_TIMEOUT + self.fileNameTmp = str(msg["fileName"]) + self.fileSize = msg["fileSize"] + self.fileNameList = msg["fileNameList"] + path = "{}/{}".format(BAK_FILE_PATH,self.fileNameTmp) + check_touch = ql_fs.path_exists("{}/{}".format(BAK_FILE_PATH,self.fileNameTmp)) + if check_touch == True: + try: + uos.remove("{}/{}".format(BAK_FILE_PATH,self.fileNameTmp)) + except Exception as e: + clog.info("移除文件失败\r\n") + try: + with open(path,"w+") as fd: + fd.write("") + fd.close() + self.__Socket_TCP_file_noreply(CAT1_CREAT_FILE_SUCC,"1creat file or dir success!") + except Exception as e: + self.__Socket_TCP_file_noreply(CAT1_CREAT_FILE_ERROR,"1creat file or dir err!") + else: + try: + with open(path,"w+") as fd: + fd.write("") + fd.close() + self.crc_err = 0 + + self.__Socket_TCP_file_noreply(CAT1_CREAT_FILE_SUCC,"2creat file or dir success!") + except Exception as e: + self.__Socket_TCP_file_noreply(CAT1_CREAT_FILE_ERROR,"2creat file or dir err!") + + + elif Code == CAT1_TCP_START_SEND_FILE_DATA and self.Cat1FileState == 1: + self.Cat1PyFileTimout = FILE_TRANSFER_TIMEOUT + if len(self.fileNameTmp) == 0: + return + data = msg["data"] + if len(data) == 0: + return + tmpdata = str(data) + head = tmpdata[0:2] + if head != CAT1_FILE_DATA_HEAD or len(tmpdata) <= 8: + clog.info("head {}\r\n".format(head)) + self.__Socket_TCP_file_noreply(CAT1_SEND_HEAD_ERR,"head error!") + return + datalen = str(tmpdata[2:6]) + datalen = int("0x" + datalen, 16) + data_buf = tmpdata[6:] + data_buf = data_buf[:-2] + crc = tmpdata[-2:] + if len(str(data_buf)) == 0 or len(str(data_buf)) != datalen: + self.__Socket_TCP_file_noreply(CAT1_WRITE_FILE_ERROR,"crc error or data null!") + return + data = str(data_buf) + path = "{}/{}".format(BAK_FILE_PATH,str(self.fileNameTmp)) + try: + with open(path,"a") as fd: + fd.write(data) + fd.close() + self.__Socket_TCP_file_noreply(CAT1_WRITE_FILE_SUCC,"write file success!") + + except Exception as e: + self.__Socket_TCP_file_noreply(CAT1_WRITE_FILE_ERROR,"write file error!") + + elif Code == CAT1_TCP_START_OTA_FAILE and self.Cat1FileState == 1: + self.allPyRecvFlag = 0 + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"OTA FAILE") + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.deleteTmpFile() + self.deleteUsrTmpFile() + pass + elif Code == CAT1_TCP_START_SEND_ALLFILE_FINESH and self.Cat1FileState == 1: + if self.bakFlag == "0": + if self.allPyRecvFlag == 1: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"ota success!") + else: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"ota success!") + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.Cat1OtaTimeOut.stop() + self.Cat1TimeCount = 0 + self.ota_state = 1 + self.allPyRecvFlag = 1 + self.Cat1OtaTimeOut.start(5000,0,self.otaTimeOut) + return + tmp_dir = ql_fs.path_exists(BAK_FILE_PATH) + if tmp_dir == True: + filenamesList = uos.listdir(BAK_FILE_PATH) + list1 = sorted(filenamesList) + list2 = sorted(self.fileNameList) + if list1 != list2: + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.deleteUsrTmpFile() + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota end faile!") + return + try: + copy_state = 1 + compare_flag = 1 + copy_flag = 0 + filenamesList = uos.listdir(BAK_FILE_PATH) + for tmp in filenamesList: + dst_path = "{}/{}".format(USR_FILE_PATH,tmp) + src_path = "{}/{}".format(BAK_FILE_PATH,tmp) + ret = False + file_size = 0 + try: + ret = ql_fs.file_copy(dst_path,src_path) + + if ret == True: + dstfile_size = ql_fs.path_getsize(dst_path) + srcfile_size = ql_fs.path_getsize(src_path) + if dstfile_size != srcfile_size: + compare_flag = 0 + break + else: + try: + compare_flag = 1 + uos.remove(src_path) + filenamesList = uos.listdir(BAK_FILE_PATH) + except Exception as e: + clog.info("copy file \r\n") + else: + compare_flag = 0 + break + except Exception as e: + clog.info("copy file \r\n") + + if copy_state == 0 or compare_flag == 0 : + self.deleteUsrTmpFile() + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota faile!22") + return + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"ota success!") + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.Cat1OtaTimeOut.stop() + self.Cat1TimeCount = 0 + self.ota_state = 1 + self.allPyRecvFlag = 1 + self.Cat1OtaTimeOut.start(5000,0,self.otaTimeOut) + except Exception as e: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota faile!33") + self.deleteUsrTmpFile() + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + else: + if self.ota_state == 1: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"ota success!") + pass + else: + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.deleteUsrTmpFile() + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota end faile!") + + elif Code == CAT1_TCP_START_OTA_SUCC and self.Cat1FileState == 1: + if self.bakFlag == "0": + self.deleteUsrTmpFile() + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + if self.allPyRecvFlag == 1: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"ota success!") + else: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota end faile!") + return + + if self.allPyRecvFlag == 0: + self.deleteTmpFile() + self.deleteUsrTmpFile() + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota end faile!") + return + tmp_dir = ql_fs.path_exists(BAK_FILE_PATH) + if tmp_dir == True: + filenamesList = uos.listdir(BAK_FILE_PATH) + list1 = sorted(filenamesList) + list2 = sorted(self.fileNameList) + if list1 != list2: + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.deleteUsrTmpFile() + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota end faile!") + return + + try: + copy_state = 1 + compare_flag = 1 + filenamesList = uos.listdir(BAK_FILE_PATH) + for tmp in filenamesList: + dst_path = "{}/{}".format(USR_FILE_PATH,tmp) + src_path = "{}/{}".format(BAK_FILE_PATH,tmp) + ret = False + file_size = 0 + try: + ret = ql_fs.file_copy(dst_path,src_path) + if ret == True: + dstfile_size = ql_fs.path_getsize(dst_path) + srcfile_size = ql_fs.path_getsize(src_path) + if dstfile_size != srcfile_size: + compare_flag = 0 + break + else: + try: + compare_flag = 1 + uos.remove(src_path) + filenamesList = uos.listdir(BAK_FILE_PATH) + except Exception as e: + clog.info("file\r\n") + else: + compare_flag = 0 + break + + except Exception as e: + clog.info("file\r\n") + if copy_state == 0 or compare_flag == 0 : + self.deleteUsrTmpFile() + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota faile!22") + return + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"ota success!") + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.Cat1OtaTimeOut.stop() + self.Cat1TimeCount = 0 + self.ota_bstate = 1 + self.conn.close() + self.Cat1OtaTimeOut.start(10000,0,self.otaTimeOut) + except Exception as e: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota faile!33") + self.deleteUsrTmpFile() + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + else: + if self.ota_bstate == 1: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"ota success!") + pass + else: + self.deleteTmpFile() + self.Cat1FileState = 0 + self.Cat1FileTransTimer.stop() + self.deleteUsrTmpFile() + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_FALIE,"ota end faile!") + + elif Code == CAT1_TCP_SEND_SINGLE_FINESH and self.Cat1FileState == 1: + self.Cat1PyFileTimout = FILE_TRANSFER_TIMEOUT + tmp_dir = ql_fs.path_exists(BAK_FILE_PATH) + if tmp_dir == True: + tmp_file = ql_fs.path_exists("{}/{}".format(BAK_FILE_PATH,self.fileNameTmp)) + if tmp_file == True: + file_size = ql_fs.path_getsize("{}/{}".format(BAK_FILE_PATH,self.fileNameTmp)) + if self.fileSize != file_size: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_FILE_SIZE_ERR,"file size err") + else: + if self.bakFlag == "0": + dst_path = "{}/{}".format(USR_FILE_PATH,self.fileNameTmp) + src_path = "{}/{}".format(BAK_FILE_PATH,self.fileNameTmp) + ret = False + try: + ret = ql_fs.file_copy(dst_path,src_path) + if ret == True: + dstfile_size = ql_fs.path_getsize(dst_path) + srcfile_size = ql_fs.path_getsize(src_path) + if dstfile_size != srcfile_size: + src_file = ql_fs.path_exists(src_path) + if src_file == True: + try: + uos.remove(src_path) + except Exception as e: + clog.info("copy 文件异常出错 yichu!{}:\r\n".format(e)) + self.__Socket_TCP_file_noreply(CAT1_REPLAY_FILE_SIZE_ERR,"file size err") + return + else: + src_file = ql_fs.path_exists(src_path) + if src_file == True: + try: + uos.remove(src_path) + except Exception as e: + clog.info("copy 文件异常出错!!!!!!!!!!{}:\r\n".format(e)) + self.__Socket_TCP_file_noreply(CAT1_REPLAY_FILE_SIZE_OK,"file size ok") + return + else: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_FILE_SIZE_ERR,"file copy err") + except Exception as e: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_FILE_SIZE_ERR,"file copy err") + else: + self.__Socket_TCP_file_noreply(CAT1_REPLAY_FILE_SIZE_OK,"file copy ok") + else: + self.__Socket_TCP_file_noreply(CAT1_CREAT_FILE_ERROR,"creat file or dir err!") + pass + else: + self.__Socket_TCP_file_noreply(CAT1_CREAT_DIR_FAILE,"creat file or dir error!") + pass + else: + if self.Cat1FileState == 0: + if self.Cat1FileReplayBle == 1: + return + self.Cat1FileReplayBle = 1 + self.__Socket_TCP_file_noreply(CAT1_REPLAY_OTA_SUCC,"reset start!") + self.Cat1FileState == 0 + self.Cat1FileTransTimer.stop() + self.Cat1PyFileTimout = 0 + self.fileNameList=[] + self.deleteTmpFile() + self.deleteUsrTmpFile() + + def otaTimeOut(self,*argc): + clog.info("重启成功!!!!!!!!\r\n") + +TcpService = TcpServiceInit() + + diff --git a/cat1modem/src/LeiNiao/telecom_dmp.py b/cat1modem/src/LeiNiao/telecom_dmp.py new file mode 100644 index 000000000..289ba2b79 --- /dev/null +++ b/cat1modem/src/LeiNiao/telecom_dmp.py @@ -0,0 +1,438 @@ +import app_fota +from misc import Power +import modem +import ujson +import request +import ql_fs +import checkNet +import sys +import sim + +from queue import Queue +import usys +import _thread +import fota +import utime +import log +import uos +import osTimer +import net +import ql_fs +from usr.EventMesh import eventMesh,CHINA_TELECOM_DM_FUN_ENABLE +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +fota_log = log.getLogger("telecom_dmp") +import modem +import base64 +import request +import ujson +REGIST_MAX_NUM=10 #自注册的最大次数 现在是默认是10次 +REGIST_INTERVAL_TIMER=60*60 #自注册失败的间隔时间 1小时 +REGIST_POWER_ON_TIME=5*60 #开机5分钟内就必须自注册触发 +MULTI_DAY_RESEND_T = 30*24*60*60-12*60*60#多日重发的机制的周期T 30天 +MULTI_DAY_RESEND_t = 12*60*60#多日重发的机制的周期t 0.5天 +def get_report_url_website(mode = None):#获取上报网址 + url = "https://zzhc.vnet.cn/pi/"#上报网址 + return url + +class telecomDmp: + def __init__(self): + self.config_data = {} + self.check_timer = osTimer()#1小时定时器 + self.multiDayResend_timer = osTimer()#12小时定时器 多日重发的机制 + self.telecomTimer = osTimer() + self.multimer_count = 0#多日重发机制周期Count + self.multimer_init = 0 + self.power_on_multiflag = 0 + self.timer_count = 0 + self.timerPowerNum = 0 + self.telecom_init_state = 0#初始化状态开机检查标识 + self.isRegistOk = 0#注册成功 + eventMesh.subscribe("get_telecom_init_state",self.get_telecom_init_state) + eventMesh.subscribe("set_telecom_init_state",self.set_telecom_init_state) + + eventMesh.subscribe("set_dmp_power_num",self.set_dmp_power_num) + eventMesh.subscribe("get_dmp_power_num",self.get_dmp_power_num) + + eventMesh.subscribe("get_dmp_power_timer_count",self.get_dmp_power_timer_count) + + self.regist_queue = Queue() + _thread.stack_size(10*1024) + _thread.start_new_thread(self.regist_queue_thread, ()) + _thread.stack_size(8*1024) + + eventMesh.subscribe("publish_message_event_registinfor",self.publish_message_event_registinfor) + self.__net_connected = 0 + eventMesh.subscribe("get_network_state",self.get_network_state)#订阅消息 + eventMesh.subscribe("set_network_state",self.set_network_state)#订阅消息 + + eventMesh.subscribe("set_dev_version",self.set_dev_version)#订阅消息 + eventMesh.subscribe("get_dev_version",self.get_dev_version)#订阅消息 + + eventMesh.subscribe("save_iccid_data",self.save_iccid_data)#订阅消息 保存ICCID + eventMesh.subscribe("get_iccid_data",self.get_iccid_data)#订阅消息 保存ICCID + + eventMesh.subscribe("set_regist_time",self.set_regist_time)#订阅消息 保存ICCID + eventMesh.subscribe("get_regist_time",self.get_regist_time)#订阅消息 保存ICCID + + self.regist_timeSec = 0 + self.iccid_data = "" + self.software_version = "" + self.mulit_day_timesec = 0#多日重发的开始的时间戳 + pass + def regist_queue_thread(self): + while True: + data = self.regist_queue.get() + #EventMesh.debug_log("regist_queue:data = {}".format(data)) + if data != None: + try: + data["func"](data["data"]) + except Exception as e: + print("regist_queue:ERROR:{}".format(e)) + usys.print_exception(e) + def publish_message_event_registinfor(self,event,msg): + self.regist_queue.put(msg) + + def publish_regist_event_cb(self, *args, **kwargs): + eventMesh.publish("publish_message_event_registinfor",{"func":self.timer_cb,"data":0}) + + def set_network_state(self,event,msg):#设置网络是否正常 + self.__net_connected = int(msg) + + def get_network_state(self,event,msg):#获取网络是否正常 + return self.__net_connected + + def set_dev_version(self,event,msg):#获取固件版本号 + self.software_version = str(msg) + + def get_dev_version(self,event,msg):#获取固件版本号 + return self.software_version + + def save_iccid_data(self,event,msg): + self.iccid_data = str(msg)[6:]#ICCID: + print("write_config_msg_file msg:{}\r\n".format(msg)) + self.config_data["ICCID"]=self.iccid_data + with open("/usr/telecom_config.json",'w+',encoding="utf-8") as fd: + ujson.dump(self.config_data,fd) + #读文件信息 + def get_iccid_data(self,event,msg): + + IFEXIST = ql_fs.path_exists("/usr/telecom_config.json") #不存在 + if IFEXIST == True: + with open("/usr/telecom_config.json","r",encoding='utf-8') as fd: + self.config_data = ujson.load(fd) + print("get_iccid_data self.config_data:{}\r\n".format(self.config_data)) + if self.config_data != {}: + if "ICCID" in self.config_data: + value = self.config_data["ICCID"] + self.iccid_data = str(value) + else: + self.iccid_data = "" + print("get_iccid_data self.config_data end:{}\r\n".format(self.config_data)) + return self.iccid_data + + def set_regist_time(self,event,msg):# + self.regist_timeSec = str(msg)[7:]#REGIST: + print("set_regist_time msg:{}\r\n".format(msg)) + self.config_data["REGIST"]=self.regist_timeSec + with open("/usr/telecom_config.json",'w+',encoding="utf-8") as fd: + ujson.dump(self.config_data,fd) + + def get_regist_time(self,event,msg):# + IFEXIST = ql_fs.path_exists("/usr/telecom_config.json") #不存在 + if IFEXIST == True: + with open("/usr/telecom_config.json","r",encoding='utf-8') as fd: + self.config_data = ujson.load(fd) + print("get_regist_time self.config_data:{}\r\n".format(self.config_data)) + if self.config_data != {}: + if "REGIST" in self.config_data: + value = self.config_data["REGIST"] + self.regist_timeSec = int(value) + else: + self.regist_timeSec = 0 + return self.regist_timeSec + + + def get_sim_state(self):#获取sim状态 不为1是sim异常 + return sim.getStatus() + + def get_sim_iccid(self):#获取sim的iccid + return sim.getIccid() + + def get_sim_imsi(self):#获取sim的imsi + return sim.getImsi() + def get_dev_imei(self):#获取设备的imei号 + return modem.getDevImei() + + def telecom_regeist_infor(self):#自注册信息 可变更 + network_state = eventMesh.publish("get_network_state") + print("telecom_regeist_infor :",network_state,self.isRegistOk,REGIST_INTERVAL_TIMER,MULTI_DAY_RESEND_T,MULTI_DAY_RESEND_t,REGIST_POWER_ON_TIME) + if network_state == 0:# 第一次进入网络不正常就需要开启1小时定时器 等待下一个周期判断网络是否正常 需要判断网络是否正常 不正常就不去触发自注册了 就等待下一次 如果10次都不成功 就等一下次开机再去自注册 + self.timer_count+=1 + print("self.timer_count:{}".format(self.timer_count)) + if self.timer_count < REGIST_MAX_NUM:#总共是10次 10次结束还没有自注册成功就等下一次开机自注册 + self.check_timer.start(REGIST_INTERVAL_TIMER*1000,0,self.publish_regist_event_cb)#不需要循环定时器 + else: + self.multiple_day_resend() + return + iccid = self.get_sim_iccid() + read_iccid = eventMesh.publish("get_iccid_data") + if read_iccid == None: + read_iccid = "" + + print("iccid!!!!!!!!!!iccid {} read_iccid:{}".format(iccid,read_iccid)) + if read_iccid != "": + if str(read_iccid) == str(iccid):#两者相同 并且本地有保存 不再自注册了 说明已经自注册过了 + print("already registed!!!!!!") #已自注册过 + self.isRegistOk = 1 + + if self.isRegistOk == 1: + print("multiple_day_resend!!!!!!\r\n") + self.multiple_day_resend() + return + self.telecom_regist_infor_init()#自注册初始化函数 + if self.isRegistOk == 0: + self.timer_count+=1 + print("self.timer_count:{}".format(self.timer_count)) + if self.timer_count < REGIST_MAX_NUM:#总共是10次 10次结束还没有自注册成功就等下一次开机自注册 + self.check_timer.start(REGIST_INTERVAL_TIMER*1000,0,self.publish_regist_event_cb)#不需要循环定时器 + else: + self.multiple_day_resend() + + def telecom_regist_infor_init(self):#自注册的数据部分 + iccid = self.get_sim_iccid() + read_iccid = eventMesh.publish("get_iccid_data") + if read_iccid == None: + read_iccid = "" + url = get_report_url_website(None)#上报网址 根据需要更改上报网址 + if iccid == -1: + iccid = str("FF")#为空就填写FF + + IMSI = self.get_sim_imsi() + if IMSI == -1:#没有卡 则填FF + IMSI = str("FF") + imei = self.get_dev_imei() + if imei == -1: + imei = str("FF") + + data_tmp = net.getCellInfo() #会适当卡个3-5s + i = 0 + cell_data = 0 + if(len(data_tmp) >= 1): + for cell in data_tmp: + if i == 2:#在list里面最多就三个元素 最后一个是LTE的数据 + if cell != []: + for tup in cell: + print("tup:{}".format(tup)) + if tup[0] == 0 and len(tup) > 0:#第0个代表当前服务的小区CELLID 7位16进制数 + cell_data = tup[1]#这个是十进制数需要自行转换成十六进制数 + print(cell_data) + break + i+=1 + # cell_data = 0 + cell_data = "%07x"%(cell_data)#7位16进制数不够前面补0 + print(cell_data) + sendCellid = "{}".format(cell_data) + REGVER = "12.0"#当前数据域协议版本号 + + # MODEL = "TXB-Watch Soar"#机型字段 -前面是厂商名 -后面是设备名 + + MODEL = "KNZ-NWO N9"#机型字段 -前面是厂商名 -后面是设备名 + + get_dev_version = eventMesh.publish("get_dev_version")#订阅消息 + if get_dev_version == None: + get_dev_version = "" + SWVER = "NWO N9 V1.0"#get_dev_version #软件版本号 + UETYPE = "12"#终端类型 12是智能手表 11是儿童手表 + SIM1ICCID = iccid + SIM1LTEIMSI = IMSI + MACID = ""#可用WALN的地址 终端布支持WLAN 就是不可上网 + OSVER = "OHOS 5.0"#操作系统版本号 + IMEI1 = imei#"876226002021717"#imei + SIM1CELLID = sendCellid#下发的小区ID + data = { + "REGVER":REGVER, + "MODEL":MODEL, + "SWVER":SWVER, + "UETYPE":UETYPE, + "SIM1ICCID":SIM1ICCID, + "SIM1LTEIMSI":IMSI, + "MACID":MACID, + "OSVER":OSVER, + "IMEI1":IMEI1, + "SIM1CELLID":SIM1CELLID, + # "NETWORKTYPE":4 + "NWTYPE1":4, + } + data_infor=ujson.dumps(data)#将字典转换成json格式 + json_bytes = bytes(data_infor, 'utf-8')#转换成字节数 + data_encode = base64.b64encode(json_bytes)#再转换成base64的编码格式 密文 + print("data_infor:{} data:{}".format(data_encode,data)) + headers_T = {'Content-Type':'application/encrypted-json'} #请求头信息 按照实际要求填写 + request_result = 0 + try: + # https://zzhc.vnet.cn/pi + response = request.post("https://zzhc.vnet.cn/pi/", data=data_encode,headers =headers_T) + request_result = 1 + if response.status_code == 200 : #返回状态码 200服务器正常解析数据 + content = response.content#后台返回的结果 + c = next(content) + + jsload_data = ujson.loads(c) + print("jsload_data:{}".format(ujson.loads(c))) #{"resultCode": "0","resultDesc": "Success"} + if "resultCode" in jsload_data or "resultDesc" in jsload_data:#返回结果码值 + resultCode = jsload_data["resultCode"]#结果解析 "0" 成功 "1" 解码错误 "2" 校验错误 + resultDesc = jsload_data["resultDesc"]#Success 表示自注册成功 + + if resultCode == "0" or resultDesc == "Success":#注册成功退出当前注册 保存当前的ICCID 不在进行自注册了 + iccid = self.get_sim_iccid()#获取当前SIM的ICCID + if iccid != -1:#读到ICCID + self.timer_count = 0 + self.check_timer.stop() + self.isRegistOk = 1#已完成自注册的标识 + iccid_buf =str("ICCID:")+str(str(iccid)) + eventMesh.publish("save_iccid_data",iccid_buf) + self.multiple_day_resend() + #上报成功后 需要29.5或者30.5天后重发 初始值为0.5也就是12小时 30天后再重发一次也是一个月后重发数据自注册域 + print("regist success:!!!!!") + return 1 + if resultCode == "1": + print("Decode error")#解码错误 设备编码不正确 + return 0 + + if resultCode == "2":# + print("Check error")#校验错误 设备里面数据不正确 有些数据不应该为空 + return 0 + + except Exception as e: + print("response:{}".format(e)) + request_result = 0 + return 0 + + def timer_cb(self,data):#定时器回调 + self.telecom_regeist_infor()#重新进行自注册 + pass + # 多日重发功能要求: + # 1) 多日重发是指:在重发周期 T 内,如果没有功能性触发数据域自注册(触发发送且发送成功), + # 则终端应根据当前终端实时信息组织数据域自注册(不能直接拿上一周期的内容不变而重发)内容 + # 并发送的过程; + # 2) 多日重发的时间间隔周期 T 设置为 30 天; + # 3) 多日重发的过程应设置为:功能性(比如换卡等)触发数据域自注册后,立即启动定时器 t(t + # 的初始值应设为 0.5 天)开始重发计时,以后每当 t 时间等于 T 的整数倍(t=N*T)时,终端就进 + # 行数据域自注册发送,发送后 t 不要清零不要初始化,只有当功能性触发数据域自注册后,t 才初 + # 始化,t 的初始化值为 0.5 天。 + # Multiple day resend + def multiple_day_resend(self):#多日重发机制函数 没有发送数据域或者发送成功 + + t = 12 #计时周期 按照0.5天 也就是12小时来计算 + T = 30*24 #周期为30天 计算30天的总共小时数 + # t = N*T#只有t为T的整数倍就需要重发数据域自注册 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)#获取时间戳 + if self.multimer_init == 1:#已注册过或者开机5分钟之内没有注册 或者注册成功就开始出发多日重发机制 + self.mulit_day_timesec = time_tmp+MULTI_DAY_RESEND_t#初始值多加12小时 #初始化t = 0.5天 + REGIST_buf = str("REGIST:")+str(self.mulit_day_timesec) + eventMesh.publish("set_regist_time",REGIST_buf) + return + self.multimer_init = 1 + #设置开始时间戳 + get_timesec = eventMesh.publish("get_regist_time")#一开机初始化为0 没有保存过数据 如果保存过就用保存的时间 + if get_timesec == 0: + self.mulit_day_timesec = time_tmp+MULTI_DAY_RESEND_t + REGIST_buf = str("REGIST:")+str(self.mulit_day_timesec) + eventMesh.publish("set_regist_time",REGIST_buf) + else: + self.mulit_day_timesec = get_timesec + self.multiDayResend_timer.start(60*60*1000,1,self.multiDayResendTimer_Cb)#一分钟计时 + + def multiDayResendTimer_Cb(self,*argc):#多日重发机制定时器回调函数 + T = 30*24*60*60 + date_tmp = utime.localtime() + time_tmp = utime.mktime(date_tmp)+MULTI_DAY_RESEND_t#获取时间戳 + + if time_tmp < self.mulit_day_timesec:#如果当前时间戳小于保存的时间戳 + self.mulit_day_timesec = time_tmp + print("time_tmp: self.mulit_day_timesec:\r\n",time_tmp,self.mulit_day_timesec) + + if time_tmp - self.mulit_day_timesec >= MULTI_DAY_RESEND_T:#一个周期的时间到了重发注册一次 + network_state = eventMesh.publish("get_network_state") + print("get_network_state:\r\n",network_state) + if network_state == 0:#网络不正常就不需要重发了等下一个周期 + return + result = self.telecom_regist_infor_init()#要自注册数据域信息发送完才初始化t + if result == 0: #上报出错了 + return + self.mulit_day_timesec = time_tmp+MULTI_DAY_RESEND_t # 重发后 初始化t = 0.5天 + REGIST_buf = str("REGIST:")+str(self.mulit_day_timesec) + eventMesh.publish("set_regist_time",REGIST_buf) + + + def set_telecom_init_state(self,event,msg):#开机5分钟内检查是否有联网 有一次联网就关闭检查 + self.telecom_init_state = msg + + def get_telecom_init_state(self,event,msg): + return self.telecom_init_state + + def get_dmp_power_timer_count(self,event,msg):#开机后限定5分钟内完成自注册 + return REGIST_POWER_ON_TIME + + def get_dmp_power_num(self,event,msg):#开机限定次数最多十次 十次不成功就等下一次开机 或者多日重发机制 + print("get_dmp_power_num:{}".format(self.timerPowerNum)) + return self.timerPowerNum + + def set_dmp_power_num(self,event,msg): + print("set_dmp_power_num:{}".format(msg)) + self.timerPowerNum = msg + def clear_storage_data(self): + IFEXIST = ql_fs.path_exists("/usr/telecom_config.json") #不存在 + if IFEXIST == True: + uos.remove("/usr/telecom_config.json") + isStorage = ql_fs.path_exists("/usr/china_mobie_config.json")#移动入库的配置文件移除 + if isStorage == True: + uos.remove("/usr/china_mobie_config.json") + print("clear_storage_data;{} {}".format(IFEXIST,isStorage)) + + + def telecom_dmp_power_on_init(self):#开机初始化一次检测 + if eventMesh.publish("get_telecom_init_state") == 1:#发送消息获取对应的值 + return + if eventMesh.publish("get_dmp_power_num") < (eventMesh.publish("get_dmp_power_timer_count")*1000)/30000:#开机检查 + if eventMesh.publish("get_telecom_init_state") == 0:#开机初始化一次 + status = eventMesh.publish("get_factory_status") + if status == None: + status = 0 + if status == 0:#恢复出厂过需要清空存储数据 + self.clear_storage_data() + pass + self.telecomTimer.start(1*1000,0,self.fun_cb) + eventMesh.publish("set_telecom_init_state",1) + + def fun_cb(self,*argc): + self.telecom_regeist_infor()#开机初始一次自注册信息 + pass + def telecom_dmp_power_on_count(self):#开机计时判断最多十次 + if eventMesh.publish("get_telecom_init_state") != 1:#在开机五分钟之内只要一次联网正常就不需要再检查是否网络正常去自注册了 + if eventMesh.publish("get_dmp_power_num") < (eventMesh.publish("get_dmp_power_timer_count")*1000)/30000:#10+1 + num = eventMesh.publish("get_dmp_power_num") #开机计时 如果开机5分钟内没有一次网络正常的话 当前开机自注册不生效 等待下一次开机自注册触发 或者触发多日重发机制 + num+=1 + eventMesh.publish("set_dmp_power_num",num)#次数累计加一 + else: + if self.power_on_multiflag == 1: + return + self.power_on_multiflag = 1 + self.multiple_day_resend() + pass + +telecomDmpCb = telecomDmp() + + + + + + + + + + + + diff --git a/cat1modem/src/LeiNiao/vfsstat.py b/cat1modem/src/LeiNiao/vfsstat.py new file mode 100644 index 000000000..0951d5a8f --- /dev/null +++ b/cat1modem/src/LeiNiao/vfsstat.py @@ -0,0 +1,23 @@ +import gc +import uos + +usr = uos.statvfs("/usr") + +print('获取usr目录状态信息:', usr) +print('f_bsize – 文件系统块大小,单位字节:', usr[0]) +print('f_bfree – 可用块数:', usr[3]) +print('usr剩下总空间 {} 字节'.format(usr[0] * usr[3])) +print('usr剩下总空间 {} KB'.format((usr[0] * usr[3])/1024)) +print('usr剩下总空间 {} MB'.format((usr[0] * usr[3]) / 1024 / 1024)) + +bak = uos.statvfs("/bak") + +print('获取bak目录状态信息:', bak) +print('f_bsize – 文件系统块大小,单位字节:', bak[0]) +print('f_bfree – 可用块数:', bak[3]) +print('bak剩下总空间 {} 字节'.format(bak[0] * bak[3])) +print('bak剩下总空间 {} KB'.format((bak[0] * bak[3])/1024)) +print('bak剩下总空间 {} MB'.format((bak[0] * bak[3]) / 1024 / 1024)) + +mem = gc.mem_free() +print('剩余可用RAM空间:{}KB'.format(mem / 1024)) \ No newline at end of file diff --git a/code/sdk/build/config/target_config/brandy/config.py b/code/sdk/build/config/target_config/brandy/config.py index 7f176807a..e95859f5b 100644 --- a/code/sdk/build/config/target_config/brandy/config.py +++ b/code/sdk/build/config/target_config/brandy/config.py @@ -463,6 +463,8 @@ target = { "zhihui_ai_old", #音频相关配置 "audio_manager", + #AI桩函数 + "ai_stub", "producttest", "ppg_hal", @@ -1229,9 +1231,6 @@ target = { 'BOARD_LEINIAO', # cat1 相关配置 'FT_SINGLE_UART', - # 'ENABLE_SLIP', - # 'SUPPORT_CAT1_SERVICE', - 'SUPPORT_TCPIP', 'CONFIG_EFUSE_READ_TO_RAM', 'CUSTOM_UTILS', @@ -1297,7 +1296,13 @@ target = { "thunderbird_toys",#雷鸟 "leiniaoMediaService", #cat1 相关配置 + #有方需要开启 PPP "ppp", + + #EG810 需要开启 cat1Service 和 cat1Test + # "cat1Service", + # "cat1Test", + #websocket 相关配置 "zhihui_websocket", #ai 相关配置 @@ -1305,6 +1310,8 @@ target = { "aiService", #ai_old相关配置 "zhihui_ai_old", + #ai_stub 专门解决ai_old和ai_service的依赖问题 + "ai_stub", #音频相关配置 "audio_manager", # "CustomUIcomponentTool", diff --git a/code/sdk/drivers/chips/brandy/porting/include/uart_porting.h b/code/sdk/drivers/chips/brandy/porting/include/uart_porting.h index d4a03eb19..faf39b38c 100644 --- a/code/sdk/drivers/chips/brandy/porting/include/uart_porting.h +++ b/code/sdk/drivers/chips/brandy/porting/include/uart_porting.h @@ -26,8 +26,10 @@ extern "C" { * @{ */ -#define SW_UART_BAUDRATE 115200UL -#define UART_L_BAUDRATE 115200UL +#define SW_UART_BAUDRATE 500000UL +// #define SW_UART_BAUDRATE 115200UL +// #define UART_L_BAUDRATE 115200UL +#define UART_L_BAUDRATE 500000UL #define UART_BUS_MAX_NUM UART_BUS_MAX_NUMBER /* Uart FIFO Level corresponding number of passes */ diff --git a/code/sdk/drivers/chips/brandy/porting/uart/uart_porting.c b/code/sdk/drivers/chips/brandy/porting/uart/uart_porting.c index be6daf1df..ae391ccc0 100644 --- a/code/sdk/drivers/chips/brandy/porting/uart/uart_porting.c +++ b/code/sdk/drivers/chips/brandy/porting/uart/uart_porting.c @@ -62,6 +62,8 @@ * 2000000 可以加快下载文件速度 */ #define CUSTOM_UART_RATE 500000 +#define CUSTOM_UART_RATE_SSB 500000 +// #define CUSTOM_UART_RATE_SSB 115200 typedef struct { pin_mode_t tx_pin_mode; pin_mode_t rx_pin_mode; @@ -125,7 +127,7 @@ static uart_config_t g_uart_config[UART_BUS_MAX_NUMBER] = { (osal_irq_handler)irq_uart0_handler, NULL, { - .baud_rate = 115200, + .baud_rate = CUSTOM_UART_RATE_SSB, .data_bits = UART_DATA_BIT_8, .parity = UART_PARITY_NONE, .stop_bits = UART_STOP_BIT_1, @@ -153,7 +155,7 @@ static uart_config_t g_uart_config[UART_BUS_MAX_NUMBER] = { (osal_irq_handler)irq_uart1_handler, NULL, { - .baud_rate = 115200, + .baud_rate = CUSTOM_UART_RATE_SSB, .data_bits = UART_DATA_BIT_8, .parity = UART_PARITY_NONE, .stop_bits = UART_STOP_BIT_1, @@ -185,7 +187,7 @@ static uart_config_t g_uart_config[UART_BUS_MAX_NUMBER] = { (osal_irq_handler)irq_uart0_handler, NULL, { - .baud_rate = 115200, + .baud_rate = CUSTOM_UART_RATE_SSB, .data_bits = UART_DATA_BIT_8, .parity = UART_PARITY_NONE, .stop_bits = UART_STOP_BIT_1, diff --git a/code/sdk/zhihui/4g/cat1Service/Service/cat1_ctl.c b/code/sdk/zhihui/4g/cat1Service/Service/cat1_ctl.c index d57dc28a8..d96883871 100644 --- a/code/sdk/zhihui/4g/cat1Service/Service/cat1_ctl.c +++ b/code/sdk/zhihui/4g/cat1Service/Service/cat1_ctl.c @@ -73,10 +73,10 @@ static ctl_pin_4g_t g_cat1_ctl_pins={ S_AGPIO_L23, // pwr_pin 1, S_AGPIO_L24,//reset_pin - 0, - PIN_NONE,//ring_pin - 0, - PIN_NONE,//wakemodem_pin + 1, //电路中 控制gpio拉高,reset才拉低 + S_MGPIO21,//ring_pin + 2, + S_MGPIO22,//wakemodem_pin 0, #else PIN_NONE, //bat_pin @@ -112,14 +112,14 @@ errcode_t cat1_register_ctl_pin(ctl_pin_4g_t ctl_pin) return ERRCODE_SUCC; } -uint32_t cat1_api_cat1_bat_on(uint32_t pwron) +uint32_t cat1_api_bat_pin(uint32_t pwron) { pin_t en_pin = g_cat1_ctl_pins.bat_pin; uint8_t en_value = g_cat1_ctl_pins.bat_pin_en_value; if (en_pin == PIN_NONE) { - printf("cat1_api_cat1_bat_on en_pin is none\r\n"); + printf("cat1_api_bat_pin en_pin is none\r\n"); return 0xff; } @@ -147,14 +147,14 @@ uint32_t cat1_api_cat1_bat_on(uint32_t pwron) } return 0; } -uint32_t cat1_api_cat1_pwrkey_on(uint32_t pwron) +uint32_t cat1_api_power_pin(uint32_t pwron) { pin_t en_pin = g_cat1_ctl_pins.pwr_pin; uint8_t en_value = g_cat1_ctl_pins.pwr_pin_en_value; if (en_pin == PIN_NONE) { - printf("cat1_api_cat1_pwrkey_on en_pin is none\r\n"); + printf("cat1_api_power_pin en_pin is none\r\n"); return 0xff; } if( pwron == 0) @@ -181,7 +181,7 @@ uint32_t cat1_api_cat1_pwrkey_on(uint32_t pwron) } return 0; } -uint32_t cat1_api_cat1_reset(uint32_t pwron) +uint32_t cat1_api_reset_pin(uint32_t pwron) { pin_t en_pin = g_cat1_ctl_pins.reset_pin; @@ -189,7 +189,7 @@ uint32_t cat1_api_cat1_reset(uint32_t pwron) if (en_pin == PIN_NONE) { - printf("cat1_api_cat1_reset en_pin is none\r\n"); + printf("cat1_api_reset_pin en_pin is none\r\n"); return 0xff; } @@ -235,10 +235,10 @@ bool cat1_api_is_cat1_enabled(void) } if ( en_value == uapi_gpio_get_output_val(en_pin)) { - printf("cat1_api_is_cat1_enabled en_value is %d\r\n",en_value); + // printf("cat1_api_is_cat1_enabled en_value is %d\r\n",en_value); return true; }else{ - printf("cat1_api_is_cat1_enabled en_value is %d\r\n",en_value); + // printf("cat1_api_is_cat1_enabled en_value is %d\r\n",en_value); return false; } } @@ -246,14 +246,20 @@ bool cat1_api_is_cat1_enabled(void) void cat1_api_power_on_cat1(void) { #if defined(BOARD_FD230) - cat1_api_cat1_pwrkey_on(1); - cat1_api_cat1_reset(0); - #elif (defined(BOARD_W9) || defined(BOARD_N9) || defined(BOARD_LEINIAO)) - cat1_api_cat1_reset(0); - cat1_api_cat1_pwrkey_on(1); - cat1_api_cat1_bat_on(1); + cat1_api_power_pin(1); + cat1_api_reset_pin(0); + #elif (defined(BOARD_W9) || defined(BOARD_N9) ) + cat1_api_reset_pin(0); + cat1_api_power_pin(1); + cat1_api_bat_pin(1); osDelay(900); - cat1_api_cat1_pwrkey_on(0); + cat1_api_power_pin(0); + #elif defined(BOARD_LEINIAO) + cat1_api_reset_pin(0); + cat1_api_power_pin(1); + cat1_api_bat_pin(1); + osDelay(900); + cat1_api_power_pin(0); #endif } @@ -261,12 +267,16 @@ void cat1_api_power_on_cat1(void) void cat1_api_power_off_cat1(void) { #if defined(BOARD_FD230) - cat1_api_cat1_reset(1); - cat1_api_cat1_pwrkey_on(0); - #elif (defined(BOARD_W9) || defined(BOARD_N9) || defined(BOARD_LEINIAO)) - cat1_api_cat1_bat_on(0); - cat1_api_cat1_reset(1); - cat1_api_cat1_pwrkey_on(1); + cat1_api_reset_pin(1); + cat1_api_power_pin(0); + #elif (defined(BOARD_W9) || defined(BOARD_N9) ) + cat1_api_bat_pin(0); + cat1_api_reset_pin(1); + cat1_api_power_pin(1); + #elif defined(BOARD_LEINIAO) + cat1_api_bat_pin(0); + cat1_api_reset_pin(1); + cat1_api_power_pin(1); #endif } diff --git a/code/sdk/zhihui/4g/cat1Service/include/cat1_ctl.h b/code/sdk/zhihui/4g/cat1Service/include/cat1_ctl.h index cb385087b..b79bbf80d 100644 --- a/code/sdk/zhihui/4g/cat1Service/include/cat1_ctl.h +++ b/code/sdk/zhihui/4g/cat1Service/include/cat1_ctl.h @@ -23,11 +23,11 @@ extern "C" { void cat1_api_uart_init(void); /**set powerpin 1/0*/ -uint32_t cat1_api_cat1_pwrkey_on(uint32_t pwron); +uint32_t cat1_api_power_pin(uint32_t pwron); /**set resetpin 0/1*/ -uint32_t cat1_api_cat1_reset(uint32_t pwron); +uint32_t cat1_api_reset_pin(uint32_t pwron); -uint32_t cat1_api_cat1_bat_on(uint32_t pwron); +uint32_t cat1_api_bat_pin(uint32_t pwron); /**set powerpin 1 ,set resetpin 0*/ void cat1_api_power_on_cat1(void); diff --git a/code/sdk/zhihui/CMakeLists.txt b/code/sdk/zhihui/CMakeLists.txt index ba5faf93b..39e2cc58c 100644 --- a/code/sdk/zhihui/CMakeLists.txt +++ b/code/sdk/zhihui/CMakeLists.txt @@ -21,6 +21,7 @@ endif() add_subdirectory_if_exist(4gTest) add_subdirectory_if_exist(ai) add_subdirectory_if_exist(ai_old) +add_subdirectory_if_exist(ai_stub) add_subdirectory_if_exist(ai/media) add_subdirectory_if_exist(websocket) add_subdirectory_if_exist(4gTestcpp) diff --git a/code/sdk/zhihui/ai_stub/CMakeLists.txt b/code/sdk/zhihui/ai_stub/CMakeLists.txt new file mode 100644 index 000000000..3cadb1dea --- /dev/null +++ b/code/sdk/zhihui/ai_stub/CMakeLists.txt @@ -0,0 +1,59 @@ +#=============================================================================== +# @brief AI Stub Functions CMakeLists +# Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. +#=============================================================================== + +# 设置模块名称 +set(COMPONENT_NAME "ai_stub") + +# 源文件列表 +set(SOURCES + src/ppp_stub_functions.c +) + +# 头文件目录 +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +set(PRIVATE_HEADER +) + +# 包含目录 +set(INCLUDE_DIRS + include +) + +# AI桩函数编译时配置 +set(PUBLIC_DEFINES + SUPPORT_AI_STUB +) + +set(PRIVATE_DEFINES +) + +# 编译选项 +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS + -Wall + -Wextra + -Werror + -O2 + -ffunction-sections + -fdata-sections +) + +# 是否整体链接 +set(WHOLE_LINK + true +) + +# 是否为主组件 +set(MAIN_COMPONENT + false +) + +# 构建组件 +build_component() \ No newline at end of file diff --git a/code/sdk/zhihui/ppp/src/ppp_stub_functions.c b/code/sdk/zhihui/ai_stub/src/ppp_stub_functions.c similarity index 72% rename from code/sdk/zhihui/ppp/src/ppp_stub_functions.c rename to code/sdk/zhihui/ai_stub/src/ppp_stub_functions.c index 1f73edaac..cc4caa5be 100644 --- a/code/sdk/zhihui/ppp/src/ppp_stub_functions.c +++ b/code/sdk/zhihui/ai_stub/src/ppp_stub_functions.c @@ -9,6 +9,8 @@ #include #include +#ifndef SUPPORT_CAT1_SERVICE + /** * @brief HTTP客户端文件下载桩函数 * @param url 下载URL @@ -25,7 +27,7 @@ int httpc_get_file_dns_to_disk(const char *url, const char *file_path, int timeo // 桩函数 - 不实现实际功能 return -1; } - +#endif /** * @brief AI流式录音发送桩函数 * @param data 音频数据 @@ -47,12 +49,14 @@ int streamingRecordAndSend_AI(void *data, int len, const char *session_id) * @brief AI消息队列发送桩函数 * @param msg_data 消息数据 * @param data_len 数据长度 + * @param type 消息类型 * @return 总是返回失败(-1) */ -int send_msg_data_into_Ai_msg_queue(void *msg_data, int data_len) +int send_msg_data_into_Ai_msg_queue(void *msg_data, uint16_t data_len, uint16_t type) { (void)msg_data; (void)data_len; + (void)type; // 桩函数 - 不实现实际功能 return -1; @@ -61,29 +65,41 @@ int send_msg_data_into_Ai_msg_queue(void *msg_data, int data_len) /** * @brief 蓝牙设置AI回答字符串桩函数 * @param answer_str AI回答字符串 - * @return 总是返回失败(-1) + * @param type 消息类型 */ -int ble_set_ai_Answer_str(const char *answer_str) +void ble_set_ai_Answer_str(char *answer_str, uint8_t type) { (void)answer_str; + (void)type; // 桩函数 - 不实现实际功能 - return -1; } /** * @brief 蓝牙设置AI问题字符串桩函数 * @param question_str AI问题字符串 - * @return 总是返回失败(-1) */ -int ble_set_ai_Question_str(const char *question_str) +void ble_set_ai_Question_str(char *question_str) { (void)question_str; // 桩函数 - 不实现实际功能 - return -1; } +#ifdef SUPPORT_CAT1_SERVICE + +/** + * @brief PPP环境初始化桩函数 + * @return 总是返回成功(0) + */ +int ppp_env_init(void) +{ + // 桩函数 - 简单返回成功 + // 注意:实际的ppp_env_init实现在ppp_example.c中 + // 如果需要完整功能,请确保ppp_example.c被正确编译和链接 + return 0; +} +#endif /* * 注意:这些桩函数仅用于解决链接问题,不提供实际功能 * 如果需要使用相关功能,请实现对应的真实函数 diff --git a/code/sdk/zhihui/ppp/CMakeLists.txt b/code/sdk/zhihui/ppp/CMakeLists.txt index 4e83333a7..48f198def 100644 --- a/code/sdk/zhihui/ppp/CMakeLists.txt +++ b/code/sdk/zhihui/ppp/CMakeLists.txt @@ -23,7 +23,6 @@ set(SOURCES src/ppp_debug_manager.c src/ppp_power_ctl.c src/ppp_cat1_api.c - src/ppp_stub_functions.c ${PPP_AT_CMD_SOURCE} ) diff --git a/code/sdk/zhihui/ppp/include/ppp_config.h b/code/sdk/zhihui/ppp/include/ppp_config.h index 188bdb67b..65730f15a 100644 --- a/code/sdk/zhihui/ppp/include/ppp_config.h +++ b/code/sdk/zhihui/ppp/include/ppp_config.h @@ -63,7 +63,7 @@ extern "C" { /* 调试配置 */ #define PPP_DEBUG_ENABLE 1 // 启用调试输出 -#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_WARN // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG) +#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_INFO // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG) /* * 调试级别说明: diff --git a/code/sdk/zhihui/ppp/include/ppp_performance_config.h b/code/sdk/zhihui/ppp/include/ppp_performance_config.h new file mode 100644 index 000000000..1a52d2320 --- /dev/null +++ b/code/sdk/zhihui/ppp/include/ppp_performance_config.h @@ -0,0 +1,176 @@ +/** + * @file ppp_performance_config.h + * @brief PPP性能优化配置 + * + * 本文件包含针对PPP协商性能问题的优化配置参数 + * 主要解决LCP协商缓慢、Magic Number冲突、超时参数不当等问题 + * + * 注意:当前这些宏定义主要用作参考和文档说明 + * 实际的优化参数已直接在相关源文件中定义和使用: + * - ppp_lwip.c: PPP协商超时参数和Magic Number生成 + * - ppp_serial.c: UART通信超时参数 + */ + +#ifndef PPP_PERFORMANCE_CONFIG_H +#define PPP_PERFORMANCE_CONFIG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ================================ PPP协商超时优化 ================================ */ + +/** + * @brief PPP FSM超时时间优化 (秒) + * 默认值: 6秒 -> 优化值: 3秒 + * 说明: 减少LCP/IPCP协商的单次超时时间,提高协商响应速度 + */ +#define PPP_OPTIMIZED_FSM_TIMEOUT 3 + +/** + * @brief PPP最大Configure-Request重传次数优化 + * 默认值: 10次 -> 优化值: 6次 + * 说明: 减少不必要的重传,避免过长的协商时间 + */ +#define PPP_OPTIMIZED_MAX_CONF_REQ 6 + +/** + * @brief PPP最大NAK循环次数优化 + * 默认值: 5次 -> 优化值: 3次 + * 说明: 减少NAK循环,加快协商收敛 + */ +#define PPP_OPTIMIZED_MAX_NAK_LOOPS 3 + +/** + * @brief PPP Terminate-Request重传次数 + * 默认值: 2次 -> 保持: 2次 + * 说明: 连接终止重传次数保持不变 + */ +#define PPP_OPTIMIZED_MAX_TERM_REQ 2 + +/* ================================ UART通信优化 ================================ */ + +/** + * @brief UART写操作超时优化 (毫秒) + * 默认值: 1000ms -> 优化值: 200ms + * 说明: 减少UART写操作超时,提高PPP帧传输效率 + */ +#define PPP_OPTIMIZED_UART_WRITE_TIMEOUT 200 + +/** + * @brief UART读操作超时优化 (毫秒) + * 默认值: 200ms -> 优化值: 100ms + * 说明: 减少PPP数据模式下的读取超时,提高协商响应速度 + */ +#define PPP_OPTIMIZED_UART_READ_TIMEOUT 100 + +/* ================================ Magic Number优化 ================================ */ + +/** + * @brief Magic Number基础种子值 + * 说明: 用于生成唯一Magic Number的基础种子 + */ +#define PPP_MAGIC_NUMBER_SEED 0x12345678 + +/** + * @brief Magic Number异或掩码 + * 说明: 增加Magic Number随机性的固定异或值 + */ +#define PPP_MAGIC_NUMBER_XOR_MASK 0xDEADBEEF + +/** + * @brief Magic Number备用值 + * 说明: 当生成的Magic Number为0时使用的备用值 + */ +#define PPP_MAGIC_NUMBER_FALLBACK 0xCAFEBABE + +/* ================================ 性能监控配置 ================================ */ + +/** + * @brief PPP阶段切换超时阈值 (毫秒) + * 说明: 超过此时间的阶段切换将被标记为性能问题 + */ +#define PPP_PHASE_TIMEOUT_THRESHOLD 5000 + +/** + * @brief PPP协商总超时阈值 (毫秒) + * 说明: PPP完整协商过程的最大允许时间 + */ +#define PPP_NEGOTIATION_TOTAL_TIMEOUT 30000 + +/* ================================ 调试配置 ================================ */ + +/** + * @brief 启用PPP性能监控 + * 说明: 启用后会监控PPP阶段切换时间和性能指标 + */ +#define PPP_ENABLE_PERFORMANCE_MONITORING 1 + +/** + * @brief 启用Magic Number增强随机性 + * 说明: 启用后使用多重随机源生成Magic Number + */ +#define PPP_ENABLE_ENHANCED_MAGIC_NUMBER 1 + +/* ================================ 性能优化函数声明 ================================ */ + +/** + * @brief 应用PPP性能优化配置 + * @param ppp_pcb PPP控制块指针 + * @return 0成功,非0失败 + */ +int ppp_apply_performance_config(void *ppp_pcb); + +/** + * @brief 生成优化的Magic Number + * @param base_counter 基础计数器值 + * @param pcb_addr PCB地址用于增加随机性 + * @return 生成的Magic Number + */ +uint32_t ppp_generate_optimized_magic_number(uint32_t base_counter, void *pcb_addr); + +/** + * @brief 检查PPP性能指标 + * @param phase_duration 阶段持续时间(毫秒) + * @param phase_id 阶段ID + * @return 1表示性能正常,0表示性能异常 + */ +int ppp_check_performance_metrics(uint32_t phase_duration, int phase_id); + +/* ================================ 性能优化建议 ================================ */ + +/* + * PPP协商性能优化建议: + * + * 1. Magic Number冲突解决: + * - 使用多重随机源(时间戳、PCB地址、栈地址) + * - 避免Magic Number为0 + * - 增加位旋转和异或操作 + * + * 2. 超时参数优化: + * - FSM超时从6秒减少到3秒 + * - 最大重传次数从10减少到6 + * - NAK循环从5减少到3 + * + * 3. UART通信优化: + * - 写超时从1000ms减少到200ms + * - 读超时从200ms减少到100ms + * + * 4. 性能监控: + * - 监控阶段切换时间 + * - 检测异常缓慢的协商过程 + * - 提供性能诊断信息 + * + * 5. 预期效果: + * - LCP协商时间从30秒减少到5-10秒 + * - 减少Magic Number冲突导致的重协商 + * - 提高整体PPP连接建立速度 + */ + +#ifdef __cplusplus +} +#endif + +#endif /* PPP_PERFORMANCE_CONFIG_H */ \ No newline at end of file diff --git a/code/sdk/zhihui/ppp/include/ppp_power_ctl.h b/code/sdk/zhihui/ppp/include/ppp_power_ctl.h index 487bf0b82..b00eff95c 100644 --- a/code/sdk/zhihui/ppp/include/ppp_power_ctl.h +++ b/code/sdk/zhihui/ppp/include/ppp_power_ctl.h @@ -47,21 +47,21 @@ void ppp_api_uart_init(void); * @param pwron 1-开启电源,0-关闭电源 * @return 0-成功,其他-失败 */ -uint32_t ppp_api_cat1_power_on(uint32_t pwron); +uint32_t ppp_api_cat1_power_pin(uint32_t pwron); /** * @brief PPP模块设置复位引脚状态 * @param pwron 1-复位,0-释放复位 * @return 0-成功,其他-失败 */ -uint32_t ppp_api_cat1_reset(uint32_t pwron); +uint32_t ppp_api_cat1_reset_pin(uint32_t pwron); /** * @brief PPP模块设置电池引脚状态 * @param pwron 1-开启电池,0-关闭电池 * @return 0-成功,其他-失败 */ -uint32_t ppp_api_cat1_bat_on(uint32_t pwron); +uint32_t ppp_api_cat1_bat_pin(uint32_t pwron); /** * @brief PPP模块4G上电序列 @@ -73,6 +73,11 @@ void ppp_power_on_cat1(void); */ void ppp_power_off_cat1(void); +/** + * @brief PPP模块4G重置序列 + */ +void ppp_power_reset_cat1(void); + /** * @brief PPP模块检查4G是否使能 * @return true-已使能,false-未使能 diff --git a/code/sdk/zhihui/ppp/src/ppp_api.c b/code/sdk/zhihui/ppp/src/ppp_api.c index 245be7acf..5c2335ff5 100644 --- a/code/sdk/zhihui/ppp/src/ppp_api.c +++ b/code/sdk/zhihui/ppp/src/ppp_api.c @@ -58,7 +58,8 @@ errcode_t ppp_api_power_init(void) .pwr_pin_en_value = 1, .reset_pin = S_AGPIO_L24, .reset_pin_en_value = 1, //电路中 控制gpio拉高,reset才拉低 - .ring_pin = S_MGPIO21, //CTS cat1 wakeup mcu + .ring_pin = PIN_NONE, //CTS cat1 wakeup mcu modem还没实现,暂时不使用 + // .ring_pin = S_MGPIO21, //CTS cat1 wakeup mcu .ring_pin_en_value = 2, //2 双边沿中断 , 1 上升沿中断 , 0 下降沿中断 .wakemodem_pin = S_MGPIO22, //RTS mcu wakeup cat1 .wakemodem_pin_en_value = 0 //0 唤醒cat1 , 1 休眠cat1 @@ -139,10 +140,8 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config) ppp_api_power_init(); ppp_api_power_control(true); - - // 额外等待时间,让调制解调器完全稳定(特别是在硬件复位后) - PPP_DEBUG_PRINT("Waiting for modem stabilization after power control...\n"); - osal_msleep(5000); // 等待5秒让调制解调器完全稳定 +#define PPP_SERIAL_INIT 1 //外接串口调试模组时,串口要设置input防止干扰。 +#if PPP_SERIAL_INIT // 3. UART初始化 PPP_DEBUG_PRINT("Step 3: Initializing UART for AT mode\n"); @@ -157,7 +156,6 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config) .rx_callback = NULL, .rx_callback_arg = NULL }; - ppp_error_t ret = ppp_serial_init(&serial_config); if (ret != PPP_ERR_OK) { PPP_DEBUG_PRINT("Failed to initialize serial for AT mode: %d\n", ret); @@ -207,15 +205,21 @@ errcode_t zhihui_ppp_init(const ppp_config_t *config) } else { PPP_DEBUG_PRINT("AT communication test succeeded\n"); } - +#else + ppp_api_leiniao_serial_pin_to_gpio_input(); +#endif + PPP_DEBUG_PRINT("Waiting for modem stabilization after power control...\n"); + // 额外等待时间,让调制解调器完全稳定(特别是在硬件复位后) + osal_msleep(5000); // 等待5秒让调制解调器完全稳定 g_ppp_state = PPP_STATE_INITIALIZED; PPP_DEBUG_PRINT("PPP module initialized successfully\n"); return ERRCODE_SUCC; - +#if PPP_SERIAL_INIT init_failed: +#endif // 初始化失败,关闭4G电源 // ppp_api_power_control(false); return ERRCODE_FAIL; @@ -246,17 +250,16 @@ static void ppp_lwip_event_callback(const ppp_lwip_event_t *event, void *arg) (lwip_info.local_ip >> 16) & 0xFF, (lwip_info.local_ip >> 24) & 0xFF); } else { - PPP_DEBUG_INFO("PPP network info not immediately available, IPCP negotiation may still be in progress"); + PPP_DEBUG_DEBUG("PPP network info not immediately available, IPCP negotiation may still be in progress"); // 确保网络接口处于激活状态 struct netif *ppp_netif = ppp_lwip_get_netif(); if (ppp_netif) { netif_set_up(ppp_netif); netif_set_link_up(ppp_netif); - PPP_DEBUG_INFO("Ensured netif is up, flags: 0x%02x", ppp_netif->flags); - + PPP_DEBUG_DEBUG("Ensured netif is up, flags: 0x%02x", ppp_netif->flags); /* 启动异步检查任务 - 在后台检查IP地址分配 */ - PPP_DEBUG_INFO("Will rely on netif status callback for default interface setting"); + PPP_DEBUG_DEBUG("Will rely on netif status callback for default interface setting"); } } @@ -315,8 +318,8 @@ errcode_t ppp_start_dial(void) } PPP_DEBUG_CRITICAL("PPP dial started successfully (async mode)"); - PPP_DEBUG_INFO("Use AT^PPPSTATUS to check connection status"); - PPP_DEBUG_INFO("Connection will be established in background"); + PPP_DEBUG_DEBUG("Use AT^PPPSTATUS to check connection status"); + PPP_DEBUG_DEBUG("Connection will be established in background"); PPP_DEBUG_PRINT("Starting PPP dial sequence\n"); ppp_error_t ret = PPP_ERR_OK; @@ -417,7 +420,7 @@ errcode_t ppp_start_dial(void) g_ppp_state = PPP_STATE_CONNECTING; PPP_DEBUG_PRINT("PPP dial completed successfully - now in data mode\n"); PPP_DEBUG_CRITICAL("PPP dial completed - now in data mode"); - PPP_DEBUG_INFO("PPP negotiation will start automatically..."); + PPP_DEBUG_DEBUG("PPP negotiation will start automatically..."); return ERRCODE_SUCC; @@ -582,9 +585,7 @@ errcode_t ppp_stop_dial(void) // 第二步:短暂断电复位(更温和的方式) PPP_DEBUG_INFO("Step 2: Brief power cycle..."); - ppp_api_cat1_reset(1); - osal_msleep(500); // 减少断电时间到1秒 - ppp_api_cat1_reset(0); + ppp_power_reset_cat1(); osal_msleep(5000); // 等待2秒让调制解调器启动 PPP_DEBUG_INFO("Gentle 4G modem reset completed - modem should be stable now"); @@ -646,20 +647,21 @@ errcode_t ppp_stop_dial(void) PPP_DEBUG_ERROR("AT communication failed after 5 attempts - modem may need manual intervention"); // 不返回错误,继续执行,让上层决定如何处理 } - + // reset方式 停止ppp,因此不必再发送AT挂断命令 + // 8. 发送AT挂断命令确保PPP连接完全断开 - if (at_communication_ok) { - PPP_DEBUG_INFO("Sending AT hangup command to ensure PPP disconnection..."); - ppp_error_t hangup_ret = ppp_at_hangup_ppp(); - if (hangup_ret != PPP_ERR_OK) { - PPP_DEBUG_WARN("AT hangup command failed: %d", hangup_ret); - // 不作为致命错误,因为PPP可能已经通过其他方式断开 - } else { - PPP_DEBUG_INFO("AT hangup command completed successfully"); - } - } else { - PPP_DEBUG_WARN("Skipping AT hangup command due to communication issues"); - } + // if (at_communication_ok) { + // PPP_DEBUG_INFO("Sending AT hangup command to ensure PPP disconnection..."); + // ppp_error_t hangup_ret = ppp_at_hangup_ppp(); + // if (hangup_ret != PPP_ERR_OK) { + // PPP_DEBUG_WARN("AT hangup command failed: %d", hangup_ret); + // // 不作为致命错误,因为PPP可能已经通过其他方式断开 + // } else { + // PPP_DEBUG_INFO("AT hangup command completed successfully"); + // } + // } else { + // PPP_DEBUG_WARN("Skipping AT hangup command due to communication issues"); + // } PPP_DEBUG_CRITICAL("=== PPP Stop Dial Completed ==="); diff --git a/code/sdk/zhihui/ppp/src/ppp_at_handler.c b/code/sdk/zhihui/ppp/src/ppp_at_handler.c index a11e2c42e..d8877aa31 100644 --- a/code/sdk/zhihui/ppp/src/ppp_at_handler.c +++ b/code/sdk/zhihui/ppp/src/ppp_at_handler.c @@ -108,16 +108,14 @@ ppp_error_t ppp_at_baudrate_handshake(void) PPP_DEBUG_INFO("Starting baudrate handshake (prove 2000000 not working, then try auto handshake)"); // 1. 先reset模组,证明2000000没有正常工作 - PPP_DEBUG_INFO("Resetting module to prove 2000000 baudrate is not working..."); - ppp_api_cat1_reset(1); - osal_msleep(50); - ppp_api_cat1_reset(0); + PPP_DEBUG_DEBUG("Resetting module to prove 2000000 baudrate is not working..."); + ppp_power_reset_cat1(); osal_msleep(5000); // 2. 依次尝试自动波特率列表 for (int i = 0; i < PPP_BAUDRATE_AUTO_COUNT; i++) { uint32_t baudrate = g_auto_baudrates[i]; - PPP_DEBUG_INFO("=== Trying Baudrate %u (index %d/%d) ===", baudrate, i + 1, PPP_BAUDRATE_AUTO_COUNT); + PPP_DEBUG_DEBUG("=== Trying Baudrate %u (index %d/%d) ===", baudrate, i + 1, PPP_BAUDRATE_AUTO_COUNT); // 配置串口波特率 uart_attr_t uart_attr = { @@ -130,7 +128,7 @@ ppp_error_t ppp_at_baudrate_handshake(void) PPP_DEBUG_WARN("Failed to set baudrate %u", baudrate); continue; } - PPP_DEBUG_INFO("UART configured for baudrate %u", baudrate); + PPP_DEBUG_DEBUG("UART configured for baudrate %u", baudrate); // 清空接收缓冲区 PPP_DEBUG_DEBUG("Clearing UART RX buffer before AT test..."); @@ -146,7 +144,7 @@ ppp_error_t ppp_at_baudrate_handshake(void) // 3次重试AT ppp_error_t ret = PPP_ERR_AT_FAILED; for (int retry = 0; retry < 3; retry++) { - PPP_DEBUG_INFO("--- AT Test at %u baud, retry %d/3 ---", baudrate, retry + 1); + PPP_DEBUG_DEBUG("--- AT Test at %u baud, retry %d/3 ---", baudrate, retry + 1); // 再次清空缓冲区,防止上次残留 while (uapi_uart_read(g_at_ctx.uart_bus, dummy_buffer, sizeof(dummy_buffer), 100) > 0) {} @@ -160,7 +158,7 @@ ppp_error_t ppp_at_baudrate_handshake(void) // 在当前波特率下,设置AT+IPR=2000000 char ipr_cmd[32]; snprintf_s(ipr_cmd, sizeof(ipr_cmd), sizeof(ipr_cmd) - 1, "AT+IPR=2000000"); - PPP_DEBUG_INFO("Setting module baudrate to 2000000 with: %s", ipr_cmd); + PPP_DEBUG_DEBUG("Setting module baudrate to 2000000 with: %s", ipr_cmd); ppp_at_response_t ipr_response; ppp_error_t ipr_ret = ppp_at_send_command(ipr_cmd, "OK", 3000, &ipr_response); @@ -172,10 +170,8 @@ ppp_error_t ppp_at_baudrate_handshake(void) ppp_at_set_baudrate(PPP_UART_BAUDRATE); // 再次reset模组,让其自动工作在2000000波特率下 - PPP_DEBUG_INFO("Resetting module again to switch to 2000000 baudrate..."); - ppp_api_cat1_reset(1); - osal_msleep(50); - ppp_api_cat1_reset(0); + PPP_DEBUG_DEBUG("Resetting module again to switch to 2000000 baudrate..."); + ppp_power_reset_cat1(); osal_msleep(5000); PPP_DEBUG_INFO("Baudrate handshake successful, now at 2000000 baud"); return PPP_ERR_OK; @@ -244,7 +240,7 @@ ppp_error_t ppp_at_set_baudrate(uint32_t baudrate) g_at_ctx.current_baudrate = baudrate; g_at_ctx.auto_baudrate_mode = false; - PPP_DEBUG_INFO("Baudrate set bus(%d) to %u (fixed)",g_at_ctx.uart_bus, baudrate); + PPP_DEBUG_DEBUG("Baudrate set bus(%d) to %u (fixed)",g_at_ctx.uart_bus, baudrate); return PPP_ERR_OK; } @@ -260,10 +256,10 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon osal_mutex_lock(&g_at_ctx.at_mutex); - PPP_DEBUG_INFO("=== AT Command Send ==="); - PPP_DEBUG_INFO("Command: %s", command); - PPP_DEBUG_INFO("Expected: %s", expected_response ? expected_response : "None"); - PPP_DEBUG_INFO("Timeout: %u ms", timeout); + PPP_DEBUG_DEBUG("=== AT Command Send ==="); + PPP_DEBUG_DEBUG("Command: %s", command); + PPP_DEBUG_DEBUG("Expected: %s", expected_response ? expected_response : "None"); + PPP_DEBUG_DEBUG("Timeout: %u ms", timeout); /* 清空响应缓冲区 */ memset_s(response, sizeof(ppp_at_response_t), 0, sizeof(ppp_at_response_t)); @@ -304,7 +300,7 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon } } printable_cmd[j] = '\0'; - PPP_DEBUG_INFO("Send String: %s", printable_cmd); + PPP_DEBUG_DEBUG("Send String: %s", printable_cmd); free(printable_cmd); if (uapi_uart_write(g_at_ctx.uart_bus, (const uint8_t *)cmd_with_crlf, cmd_len, 0) != cmd_len) { @@ -313,15 +309,15 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon return PPP_ERR_UART; } - PPP_DEBUG_INFO("AT command sent successfully bus(%d)",g_at_ctx.uart_bus); + PPP_DEBUG_DEBUG("AT command sent successfully bus(%d)",g_at_ctx.uart_bus); /* 等待响应 */ ppp_error_t ret = ppp_at_wait_response(response, timeout); /* 打印响应结果 */ - PPP_DEBUG_INFO("=== AT Command Response ==="); + PPP_DEBUG_DEBUG("=== AT Command Response ==="); if (ret == PPP_ERR_OK) { - PPP_DEBUG_INFO("Response received (%u bytes):", response->length); + PPP_DEBUG_DEBUG("Response received (%u bytes):", response->length); /* 打印接收的原始数据(十六进制) */ // for (uint32_t i = 0; i < response->length; i++) { @@ -348,10 +344,10 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon } } printable_resp[j] = '\0'; - PPP_DEBUG_INFO("Response String: %s", printable_resp); + PPP_DEBUG_DEBUG("Response String: %s", printable_resp); free(printable_resp); } - PPP_DEBUG_INFO("Raw Response: %s", response->response); + PPP_DEBUG_DEBUG("Raw Response: %s", response->response); } else { PPP_DEBUG_ERROR("No response received (error: %d)", ret); } @@ -365,7 +361,7 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon response->error_code = PPP_ERR_AT_FAILED; ret = PPP_ERR_AT_FAILED; } else { - PPP_DEBUG_INFO("Response validation successful - Expected: %s", expected_response); + PPP_DEBUG_DEBUG("Response validation successful - Expected: %s", expected_response); response->success = true; response->error_code = PPP_ERR_OK; } @@ -379,7 +375,7 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon response->error_code = ret; } - PPP_DEBUG_INFO("=== AT Command Complete (Result: %s) ===", ret == PPP_ERR_OK ? "SUCCESS" : "FAILED"); + PPP_DEBUG_DEBUG("=== AT Command Complete (Result: %s) ===", ret == PPP_ERR_OK ? "SUCCESS" : "FAILED"); osal_mutex_unlock(&g_at_ctx.at_mutex); return ret; @@ -390,7 +386,7 @@ ppp_error_t ppp_at_send_command(const char *command, const char *expected_respon */ static ppp_error_t ppp_at_skip_startup_logs(void) { - PPP_DEBUG_INFO("Skipping startup logs..."); + PPP_DEBUG_DEBUG("Skipping startup logs..."); // 清空接收缓冲区,跳过开机时的各种日志输出 uint8_t dummy_buffer[256]; @@ -416,7 +412,7 @@ static ppp_error_t ppp_at_skip_startup_logs(void) osal_msleep(100); } while (retry_count < max_retries); - PPP_DEBUG_INFO("Startup logs skipped"); + PPP_DEBUG_DEBUG("Startup logs skipped"); return PPP_ERR_OK; } @@ -461,7 +457,7 @@ ppp_error_t ppp_at_complete_dial_sequence(const char *apn) PPP_DEBUG_ERROR("Modem not responding to AT - may already be in data mode"); // 这可能是正常的,如果调制解调器已经在数据模式 } else { - PPP_DEBUG_INFO("Modem still in AT mode, proceeding with dial sequence"); + PPP_DEBUG_DEBUG("Modem still in AT mode, proceeding with dial sequence"); } // 4. 设置PDP上下文 (对应chat文件: OK 'AT+CGDCONT=3,"IP"') @@ -500,7 +496,7 @@ ppp_error_t ppp_at_complete_dial_sequence(const char *apn) // 4.7. 检查网络状态 ret = ppp_at_send_command("AT+CREG?", "OK", 5000, &response); if (ret == PPP_ERR_OK) { - PPP_DEBUG_INFO("Network registration status: %s", response.response); + PPP_DEBUG_DEBUG("Network registration status: %s", response.response); } // 5. 发送PPP拨号指令 - 使用Neoway N706A特有的XIIC命令 diff --git a/code/sdk/zhihui/ppp/src/ppp_lwip.c b/code/sdk/zhihui/ppp/src/ppp_lwip.c index 75fd6cea2..6f5b61e4b 100644 --- a/code/sdk/zhihui/ppp/src/ppp_lwip.c +++ b/code/sdk/zhihui/ppp/src/ppp_lwip.c @@ -6,6 +6,7 @@ #include "ppp_power_ctl.h" // 添加电源控制头文件 #include "securec.h" #include "osal_addr.h" // 添加OSAL内存管理头文件 +#include "osal_timer.h" // 添加OSAL时间函数头文件 #include /* lwIP相关头文件 - 需要在编译时确保PPP支持已启用 */ @@ -41,6 +42,13 @@ typedef struct { static ppp_lwip_context_t g_lwip_ctx = {0}; /* 内部函数声明 */ +static uint32_t ppp_lwip_get_time_ms(void); +static uint32_t ppp_lwip_get_time_ms(void) +{ + osal_timeval tv = {0}; + osal_gettimeofday(&tv); + return (uint32_t)(tv.tv_sec * 1000 + tv.tv_usec / 1000); +} #ifdef LWIP_PPP_SUPPORT static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx); static void ppp_lwip_link_status_callback(ppp_pcb *pcb, int err_code, void *ctx); @@ -81,7 +89,7 @@ ppp_error_t ppp_lwip_init(const ppp_lwip_config_t *config) memset_s(g_lwip_ctx.netif, sizeof(struct netif), 0, sizeof(struct netif)); /* 创建PPPoS接口 - 使用线程安全的API */ - PPP_DEBUG_INFO("Creating PPPoS interface using thread-safe API..."); + PPP_DEBUG_DEBUG("Creating PPPoS interface using thread-safe API..."); g_lwip_ctx.ppp_pcb = pppapi_pppos_create(g_lwip_ctx.netif, ppp_lwip_output_callback, ppp_lwip_link_status_callback, @@ -96,15 +104,15 @@ ppp_error_t ppp_lwip_init(const ppp_lwip_config_t *config) /* 设置认证信息 */ if (config->username && config->password) { ppp_set_auth(g_lwip_ctx.ppp_pcb, PPPAUTHTYPE_PAP, config->username, config->password); - PPP_DEBUG_INFO("PPP authentication configured (PAP)"); + PPP_DEBUG_DEBUG("PPP authentication configured (PAP)"); } else { /* 如果没有用户名密码,设置为无认证 */ ppp_set_auth(g_lwip_ctx.ppp_pcb, PPPAUTHTYPE_NONE, "", ""); - PPP_DEBUG_INFO("PPP authentication disabled (NONE)"); + PPP_DEBUG_DEBUG("PPP authentication disabled (NONE)"); } /* 配置IPCP选项 - 启用IP地址协商 */ - PPP_DEBUG_INFO("Configuring IPCP options..."); + PPP_DEBUG_DEBUG("Configuring IPCP options..."); /* 请求对端分配IP地址 (0.0.0.0表示请求分配) */ ppp_set_ipcp_ouraddr(g_lwip_ctx.ppp_pcb, IP4_ADDR_ANY); @@ -116,7 +124,7 @@ ppp_error_t ppp_lwip_init(const ppp_lwip_config_t *config) ppp_set_usepeerdns(g_lwip_ctx.ppp_pcb, 1); /* 使用标准IPCP协商选项 */ - PPP_DEBUG_INFO("Setting standard IPCP negotiation options..."); + PPP_DEBUG_DEBUG("Setting standard IPCP negotiation options..."); /* 启用基本的IP地址协商 */ g_lwip_ctx.ppp_pcb->ipcp_wantoptions.neg_addr = 1; @@ -128,8 +136,21 @@ ppp_error_t ppp_lwip_init(const ppp_lwip_config_t *config) g_lwip_ctx.ppp_pcb->ipcp_wantoptions.req_dns2 = 1; #endif - PPP_DEBUG_INFO("IPCP configuration completed with standard options"); + PPP_DEBUG_DEBUG("IPCP configuration completed with standard options"); + /* 优化PPP协商超时参数 - 运行时覆盖编译时默认值以获得更好性能 */ + g_lwip_ctx.ppp_pcb->settings.fsm_timeout_time = 3; /* 减少FSM超时从6秒到3秒 */ + g_lwip_ctx.ppp_pcb->settings.fsm_max_conf_req_transmits = 6; /* 减少最大重传次数从10到6 */ + g_lwip_ctx.ppp_pcb->settings.fsm_max_term_transmits = 2; /* 保持terminate重传为2 */ + g_lwip_ctx.ppp_pcb->settings.fsm_max_nak_loops = 3; /* 减少NAK循环从5到3 */ + + /* 优化LCP相关参数以提高连接稳定性 */ + g_lwip_ctx.ppp_pcb->settings.lcp_loopbackfail = 5; /* 减少loopback检测次数从10到5 */ + g_lwip_ctx.ppp_pcb->settings.lcp_echo_interval = 0; /* 禁用LCP echo请求以减少开销 */ + g_lwip_ctx.ppp_pcb->settings.lcp_echo_fails = 3; /* 保持echo失败容忍度为3 */ + + PPP_DEBUG_INFO("PPP parameters optimized: FSM(timeout=3s, max_conf_req=6, max_nak_loops=3), LCP(loopback_fail=5, echo_interval=0)"); + /* 设置状态回调 */ ppp_set_notify_phase_callback(g_lwip_ctx.ppp_pcb, ppp_lwip_status_callback); @@ -137,20 +158,36 @@ ppp_error_t ppp_lwip_init(const ppp_lwip_config_t *config) netif_set_status_callback(g_lwip_ctx.netif, ppp_lwip_netif_status_callback); /* 使用标准PPP/LCP配置 */ - PPP_DEBUG_INFO("Using standard PPP/LCP configuration..."); + PPP_DEBUG_DEBUG("Using standard PPP/LCP configuration..."); /* 配置LCP Magic Number以避免loopback检测问题 */ - /* 使用简单的随机数生成唯一的Magic Number */ - static uint32_t magic_counter = 0x12345678; + /* 使用增强的随机数生成算法确保唯一性 */ + #define PPP_MAGIC_NUMBER_SEED 0x12345678 + #define PPP_MAGIC_NUMBER_XOR_MASK 0xDEADBEEF + #define PPP_MAGIC_NUMBER_FALLBACK 0xCAFEBABE + + static uint32_t magic_counter = PPP_MAGIC_NUMBER_SEED; uint32_t magic_number = magic_counter++; - magic_number ^= (uint32_t)g_lwip_ctx.ppp_pcb; /* 使用PCB地址增加随机性 */ + + /* 增加多重随机性源 */ + magic_number ^= (uint32_t)g_lwip_ctx.ppp_pcb; /* PCB地址 */ + magic_number ^= (uint32_t)ppp_lwip_get_time_ms(); /* 当前时间戳 */ + magic_number ^= (uint32_t)&magic_number; /* 栈地址 */ + magic_number = (magic_number << 16) | (magic_number >> 16); /* 位旋转 */ + magic_number ^= PPP_MAGIC_NUMBER_XOR_MASK; /* 使用配置的异或掩码 */ + + /* 确保Magic Number不为0(避免协商问题) */ + if (magic_number == 0) { + magic_number = PPP_MAGIC_NUMBER_FALLBACK; /* 使用配置的备用值 */ + } + g_lwip_ctx.ppp_pcb->lcp_wantoptions.neg_magicnumber = 1; g_lwip_ctx.ppp_pcb->lcp_wantoptions.magicnumber = magic_number; g_lwip_ctx.ppp_pcb->lcp_allowoptions.neg_magicnumber = 1; - PPP_DEBUG_INFO("LCP Magic Number configured: 0x%08X", magic_number); + PPP_DEBUG_INFO("LCP Magic Number configured: 0x%08X (enhanced randomness)", magic_number); /* 使用标准PPP/LCP配置 */ - PPP_DEBUG_INFO("Using standard PPP/LCP configuration..."); + PPP_DEBUG_DEBUG("Using standard PPP/LCP configuration..."); /* 保存回调函数 */ g_lwip_ctx.event_callback = config->event_callback; @@ -182,39 +219,39 @@ void ppp_lwip_deinit(void) /* 清理网络接口 */ if (g_lwip_ctx.netif) { - PPP_DEBUG_INFO("Cleaning up PPP network interface..."); + PPP_DEBUG_DEBUG("Cleaning up PPP network interface..."); /* 如果PPP接口是默认接口,清除默认接口设置 */ if (netif_default == g_lwip_ctx.netif) { - PPP_DEBUG_INFO("Clearing PPP interface as default"); + PPP_DEBUG_DEBUG("Clearing PPP interface as default"); netif_set_default(NULL); } /* 设置接口为down状态 */ if (netif_is_up(g_lwip_ctx.netif)) { - PPP_DEBUG_INFO("Setting PPP interface down"); + PPP_DEBUG_DEBUG("Setting PPP interface down"); netif_set_down(g_lwip_ctx.netif); } /* 设置链路为down状态 */ if (netif_is_link_up(g_lwip_ctx.netif)) { - PPP_DEBUG_INFO("Setting PPP link down"); + PPP_DEBUG_DEBUG("Setting PPP link down"); netif_set_link_down(g_lwip_ctx.netif); } /* 从lwIP网络接口列表中移除 */ - PPP_DEBUG_INFO("Removing PPP interface from lwIP interface list"); + PPP_DEBUG_DEBUG("Removing PPP interface from lwIP interface list"); netif_remove(g_lwip_ctx.netif); /* 释放网络接口内存 */ - PPP_DEBUG_INFO("Freeing PPP interface memory"); + PPP_DEBUG_DEBUG("Freeing PPP interface memory"); osal_kfree(g_lwip_ctx.netif); g_lwip_ctx.netif = NULL; } /* 删除PPP控制块 */ if (g_lwip_ctx.ppp_pcb) { - PPP_DEBUG_INFO("Freeing PPP control block"); + PPP_DEBUG_DEBUG("Freeing PPP control block"); pppapi_free(g_lwip_ctx.ppp_pcb); g_lwip_ctx.ppp_pcb = NULL; } @@ -399,8 +436,11 @@ static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx) { (void)pcb; (void)ctx; + + static int last_phase = -1; + static uint32_t phase_start_time = 0; - PPP_DEBUG_INFO("PPP status callback: err_code=%d", err_code); + PPP_DEBUG_DEBUG("PPP status callback: err_code=%d", err_code); /* 这里只处理PPP阶段变化,不处理错误 */ const char* phase_str = "UNKNOWN"; @@ -420,7 +460,28 @@ static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx) case PPP_PHASE_DISCONNECT: phase_str = "DISCONNECT"; break; default: phase_str = "OTHER"; break; } - PPP_DEBUG_INFO("PPP Phase: %s (%d)", phase_str, err_code); + + /* 监控阶段切换时间以诊断性能问题 */ + uint32_t current_time = ppp_lwip_get_time_ms(); + if (last_phase != err_code) { + if (last_phase != -1) { + uint32_t phase_duration = current_time - phase_start_time; + PPP_DEBUG_INFO("PPP Phase transition: %d -> %s (%d) [duration: %ums]", + last_phase, phase_str, err_code, phase_duration); + + /* 检测异常缓慢的阶段 */ + if (phase_duration > 5000) { /* 超过5秒 */ + PPP_DEBUG_WARN("PPP Phase %d took too long: %ums (potential performance issue)", + last_phase, phase_duration); + } + } else { + PPP_DEBUG_INFO("PPP Phase: %s (%d) [initial]", phase_str, err_code); + } + last_phase = err_code; + phase_start_time = current_time; + } + + PPP_DEBUG_DEBUG("PPP Phase: %s (%d)", phase_str, err_code); ppp_lwip_event_t event; memset_s(&event, sizeof(event), 0, sizeof(event)); @@ -433,11 +494,11 @@ static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx) PPP_DEBUG_CRITICAL("PPP connection established successfully"); /* 获取IP地址信息 */ if (g_lwip_ctx.netif) { - PPP_DEBUG_INFO("PPP netif available, checking IP addresses..."); - PPP_DEBUG_INFO("netif->ip_addr: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->ip_addr)); - PPP_DEBUG_INFO("netif->gw: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->gw)); - PPP_DEBUG_INFO("netif->netmask: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->netmask)); - PPP_DEBUG_INFO("netif flags: 0x%02x", g_lwip_ctx.netif->flags); + PPP_DEBUG_DEBUG("PPP netif available, checking IP addresses..."); + PPP_DEBUG_DEBUG("netif->ip_addr: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->ip_addr)); + PPP_DEBUG_DEBUG("netif->gw: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->gw)); + PPP_DEBUG_DEBUG("netif->netmask: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->netmask)); + PPP_DEBUG_DEBUG("netif flags: 0x%02x", g_lwip_ctx.netif->flags); g_lwip_ctx.local_ip = ip4_addr_get_u32(&g_lwip_ctx.netif->ip_addr); g_lwip_ctx.remote_ip = ip4_addr_get_u32(&g_lwip_ctx.netif->gw); @@ -447,11 +508,11 @@ static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx) const ip_addr_t *dns2 = dns_getserver(1); if (dns1) { g_lwip_ctx.primary_dns = ip4_addr_get_u32(ip_2_ip4(dns1)); - PPP_DEBUG_INFO("DNS1: 0x%08x", g_lwip_ctx.primary_dns); + PPP_DEBUG_DEBUG("DNS1: 0x%08x", g_lwip_ctx.primary_dns); } if (dns2) { g_lwip_ctx.secondary_dns = ip4_addr_get_u32(ip_2_ip4(dns2)); - PPP_DEBUG_INFO("DNS2: 0x%08x", g_lwip_ctx.secondary_dns); + PPP_DEBUG_DEBUG("DNS2: 0x%08x", g_lwip_ctx.secondary_dns); } PPP_DEBUG_INFO("PPP connected - Local IP: %u.%u.%u.%u", @@ -467,12 +528,12 @@ static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx) /* 设置PPP接口为默认网络接口 */ if (g_lwip_ctx.netif->ip_addr.addr != 0) { - PPP_DEBUG_INFO("Setting PPP interface as default..."); + PPP_DEBUG_DEBUG("Setting PPP interface as default..."); netif_set_default(g_lwip_ctx.netif); PPP_DEBUG_INFO("PPP interface set as default network interface"); } else { - PPP_DEBUG_INFO("PPP IP address is 0, IPCP negotiation may still be in progress"); - PPP_DEBUG_INFO("Network interface will be set as default when IP is assigned via netif callback"); + PPP_DEBUG_DEBUG("PPP IP address is 0, IPCP negotiation may still be in progress"); + PPP_DEBUG_DEBUG("Network interface will be set as default when IP is assigned via netif callback"); netif_set_up(g_lwip_ctx.netif); netif_set_link_up(g_lwip_ctx.netif); } diff --git a/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c b/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c index 854fb3fa1..5eb0bb238 100644 --- a/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c +++ b/code/sdk/zhihui/ppp/src/ppp_lwip_thread.c @@ -30,7 +30,7 @@ static void ppp_lwip_receive_thread(void *arg) { (void)arg; - PPP_DEBUG_INFO("PPP lwIP receive thread started (slipif-style)"); + PPP_DEBUG_DEBUG("PPP lwIP receive thread started (slipif-style)"); /* 动态分配接收缓冲区以避免栈溢出 */ uint8_t *rx_buffer = (uint8_t *)malloc(PPP_RX_BUFFER_SIZE); @@ -57,11 +57,11 @@ static void ppp_lwip_receive_thread(void *arg) uint32_t frame_start = 0; /* 当前帧开始位置 */ uint32_t complete_frames = 0; /* 完整帧计数 */ - PPP_DEBUG_INFO("PPP lwIP thread: allocated %d bytes RX buffer + %d bytes stream buffer", + PPP_DEBUG_DEBUG("PPP lwIP thread: allocated %d bytes RX buffer + %d bytes stream buffer", PPP_RX_BUFFER_SIZE, PPP_RX_BUFFER_SIZE * 2); PPP_DEBUG_CRITICAL("PPP receive thread started and entering main loop"); - PPP_DEBUG_INFO("Thread will read from serial in PPP data mode"); + PPP_DEBUG_DEBUG("Thread will read from serial in PPP data mode"); /* 主接收循环 - 参考slipif的实现方式 */ while (g_ppp_rx_thread_running) { @@ -72,7 +72,7 @@ static void ppp_lwip_receive_thread(void *arg) total_packets++; total_bytes += bytes_read; - PPP_DEBUG_INFO("PPP RX: Got %u bytes (total: %u packets, %u bytes)", + PPP_DEBUG_DEBUG("PPP RX: Got %u bytes (total: %u packets, %u bytes)", bytes_read, total_packets, total_bytes); /* 将接收到的数据添加到流缓冲区 - 加强边界检查 */ @@ -134,7 +134,7 @@ static void ppp_lwip_receive_thread(void *arg) } else if (ret != PPP_ERR_OK) { /* 检查是否是因为线程停止导致的错误 */ if (!g_ppp_rx_thread_running) { - PPP_DEBUG_INFO("PPP thread stopping, ignoring read error"); + PPP_DEBUG_DEBUG("PPP thread stopping, ignoring read error"); break; } PPP_DEBUG_ERROR("PPP serial read error: %d", ret); @@ -156,7 +156,7 @@ static void ppp_lwip_receive_thread(void *arg) // 统计信息输出 - 每2000次循环输出一次 if ((total_packets % 2000) == 0 && total_packets > 0) { - PPP_DEBUG_INFO("PPP lwIP RX: %u fragments, %u complete frames, %u total bytes", + PPP_DEBUG_DEBUG("PPP lwIP RX: %u fragments, %u complete frames, %u total bytes", total_packets, complete_frames, total_bytes); } @@ -229,7 +229,7 @@ ppp_error_t ppp_lwip_stop_receive_thread(void) } if (g_ppp_rx_thread_completed) { - PPP_DEBUG_INFO("PPP thread completed gracefully after %d ms", wait_count * 10); + PPP_DEBUG_DEBUG("PPP thread completed gracefully after %d ms", wait_count * 10); } else { PPP_DEBUG_WARN("PPP thread did not complete within timeout, forcing termination"); } diff --git a/code/sdk/zhihui/ppp/src/ppp_power_ctl.c b/code/sdk/zhihui/ppp/src/ppp_power_ctl.c index ff81172a4..b1f2538ff 100644 --- a/code/sdk/zhihui/ppp/src/ppp_power_ctl.c +++ b/code/sdk/zhihui/ppp/src/ppp_power_ctl.c @@ -117,23 +117,34 @@ void ppp_api_gpio_init(void) { case 0: uapi_gpio_register_isr_func(gpiopin, GPIO_INTERRUPT_FALLING_EDGE, ppp_ring_isr_callback); + PPP_DEBUG_PRINT("PPP: Register ring pin %d falling edge interrupt\n", gpiopin); break; case 1: uapi_gpio_register_isr_func(gpiopin, GPIO_INTERRUPT_RISING_EDGE, ppp_ring_isr_callback); + PPP_DEBUG_PRINT("PPP: Register ring pin %d rising edge interrupt\n", gpiopin); break; case 2: default: uapi_gpio_register_isr_func(gpiopin, GPIO_INTERRUPT_DEDGE, ppp_ring_isr_callback); + PPP_DEBUG_PRINT("PPP: Register ring pin %d both edge interrupt\n", gpiopin); break; } } } +void ppp_api_leiniao_serial_pin_to_gpio_input(void) +{ + uapi_pin_set_mode(SIO_UART_TX_PIN, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(SIO_UART_TX_PIN, GPIO_DIRECTION_INPUT); + uapi_pin_set_mode(SIO_UART_RX_PIN, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(SIO_UART_RX_PIN, GPIO_DIRECTION_INPUT); + PPP_DEBUG_PRINT("PPP: Leiniao serial pin to gpio input\n"); +} /** * @brief PPP模块设置电源引脚状态 */ -uint32_t ppp_api_cat1_power_on(uint32_t pwron) +uint32_t ppp_api_cat1_power_pin(uint32_t pwron) { pin_t en_pin = g_ppp_cat1_ctl_pins.pwr_pin; uint8_t en_value = g_ppp_cat1_ctl_pins.pwr_pin_en_value; @@ -168,7 +179,7 @@ uint32_t ppp_api_cat1_power_on(uint32_t pwron) /** * @brief PPP模块设置复位引脚状态 */ -uint32_t ppp_api_cat1_reset(uint32_t pwron) +uint32_t ppp_api_cat1_reset_pin(uint32_t pwron) { pin_t en_pin = g_ppp_cat1_ctl_pins.reset_pin; uint8_t en_value = g_ppp_cat1_ctl_pins.reset_pin_en_value; @@ -205,7 +216,7 @@ uint32_t ppp_api_cat1_reset(uint32_t pwron) /** * @brief PPP模块设置电池引脚状态 */ -uint32_t ppp_api_cat1_bat_on(uint32_t pwron) +uint32_t ppp_api_cat1_bat_pin(uint32_t pwron) { pin_t en_pin = g_ppp_cat1_ctl_pins.bat_pin; uint8_t en_value = g_ppp_cat1_ctl_pins.bat_pin_en_value; @@ -270,19 +281,19 @@ bool ppp_api_is_cat1_enabled(void) void ppp_power_on_cat1(void) { #if defined(BOARD_FD230) - ppp_api_cat1_power_on(1); - ppp_api_cat1_reset(0); + ppp_api_cat1_power_pin(1); + ppp_api_cat1_reset_pin(0); #elif (defined(BOARD_W9) || defined(BOARD_N9) ) - ppp_api_cat1_power_on(1); - ppp_api_cat1_bat_on(1); + ppp_api_cat1_power_pin(1); + ppp_api_cat1_bat_pin(1); osal_msleep(900); // 使用OSAL延时函数 - ppp_api_cat1_power_on(0); + ppp_api_cat1_power_pin(0); #elif defined(BOARD_LEINIAO) - ppp_api_cat1_reset(0); - ppp_api_cat1_power_on(1); - ppp_api_cat1_bat_on(1); + ppp_api_cat1_reset_pin(0); + ppp_api_cat1_power_pin(1); + ppp_api_cat1_bat_pin(1); osal_msleep(900); // 使用OSAL延时函数 - ppp_api_cat1_power_on(0); + ppp_api_cat1_power_pin(0); #endif g_ppp_cat1_power_status = true; @@ -295,21 +306,29 @@ void ppp_power_on_cat1(void) void ppp_power_off_cat1(void) { #if defined(BOARD_FD230) - ppp_api_cat1_reset(1); - ppp_api_cat1_power_on(0); + ppp_api_cat1_reset_pin(1); + ppp_api_cat1_power_pin(0); #elif (defined(BOARD_W9) || defined(BOARD_N9) ) - ppp_api_cat1_power_on(0); - ppp_api_cat1_bat_on(0); + ppp_api_cat1_power_pin(0); + ppp_api_cat1_bat_pin(0); #elif defined(BOARD_LEINIAO) - ppp_api_cat1_reset(0); - ppp_api_cat1_power_on(0); - ppp_api_cat1_bat_on(0); + ppp_api_cat1_reset_pin(0); + ppp_api_cat1_power_pin(0); + ppp_api_cat1_bat_pin(0); #endif g_ppp_cat1_power_status = false; PPP_DEBUG_PRINT("PPP: Cat1 power off sequence completed\n"); } + +void ppp_power_reset_cat1(void) +{ + ppp_api_cat1_reset_pin(1); + osal_msleep(50); + ppp_api_cat1_reset_pin(0); +} + /** * @brief PPP模块唤醒Cat1 */ @@ -446,7 +465,7 @@ void ppp_api_deinit(void) PPP_DEBUG_PRINT("PPP: deinit\n"); // 关闭电源 - ppp_api_cat1_power_on(0); + ppp_api_cat1_power_pin(0); g_ppp_cat1_power_status = false; } \ No newline at end of file diff --git a/code/sdk/zhihui/ppp/src/ppp_serial.c b/code/sdk/zhihui/ppp/src/ppp_serial.c index 6c3cc91b0..61123c92d 100644 --- a/code/sdk/zhihui/ppp/src/ppp_serial.c +++ b/code/sdk/zhihui/ppp/src/ppp_serial.c @@ -12,6 +12,10 @@ #include #include "arch_port.h" +/* PPP性能优化配置 */ +#define PPP_OPTIMIZED_UART_WRITE_TIMEOUT 200 /* UART写超时优化: 1000ms -> 200ms */ +#define PPP_OPTIMIZED_UART_READ_TIMEOUT 100 /* UART读超时优化: 200ms -> 100ms */ + /* 串口上下文结构 - 优化缓存机制 */ typedef struct { bool initialized; @@ -86,18 +90,18 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) } PPP_DEBUG_INFO("=== PPP Serial Initialization Start ==="); - PPP_DEBUG_INFO("Initializing PPP serial with unified buffer management"); - - /* 打印配置参数 */ - PPP_DEBUG_INFO("Configuration parameters:"); - PPP_DEBUG_INFO(" - UART Bus: %u", config->uart_bus); - PPP_DEBUG_INFO(" - IRQ Num: %u", config->irq_num); - PPP_DEBUG_INFO(" - Baudrate: %u", config->baudrate); - PPP_DEBUG_INFO(" - TX Pin: %u", config->tx_pin); - PPP_DEBUG_INFO(" - RX Pin: %u", config->rx_pin); - PPP_DEBUG_INFO(" - RX Buffer Size: %u bytes", config->rx_buffer_size); - PPP_DEBUG_INFO(" - TX Buffer Size: %u bytes", config->tx_buffer_size); - PPP_DEBUG_INFO(" - RX Callback: %s", config->rx_callback ? "Set" : "NULL"); + PPP_DEBUG_DEBUG("Initializing PPP serial with unified buffer management"); + + /* 配置参数 - 降级为DEBUG级别 */ + PPP_DEBUG_DEBUG("Configuration parameters:"); + PPP_DEBUG_DEBUG(" - UART Bus: %u", config->uart_bus); + PPP_DEBUG_DEBUG(" - IRQ Num: %u", config->irq_num); + PPP_DEBUG_DEBUG(" - Baudrate: %u", config->baudrate); + PPP_DEBUG_DEBUG(" - TX Pin: %u", config->tx_pin); + PPP_DEBUG_DEBUG(" - RX Pin: %u", config->rx_pin); + PPP_DEBUG_DEBUG(" - RX Buffer Size: %u bytes", config->rx_buffer_size); + PPP_DEBUG_DEBUG(" - TX Buffer Size: %u bytes", config->tx_buffer_size); + PPP_DEBUG_DEBUG(" - RX Callback: %s", config->rx_callback ? "Set" : "NULL"); /* 配置UART参数 */ g_serial_ctx.uart_bus = config->uart_bus; @@ -109,11 +113,11 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) g_serial_ctx.uart_attr.stop_bits = UART_STOP_BIT_1; g_serial_ctx.uart_attr.parity = UART_PARITY_NONE; - PPP_DEBUG_INFO("UART attributes configured:"); - PPP_DEBUG_INFO(" - Baud Rate: %u", g_serial_ctx.uart_attr.baud_rate); - PPP_DEBUG_INFO(" - Data Bits: %d", g_serial_ctx.uart_attr.data_bits); - PPP_DEBUG_INFO(" - Stop Bits: %d", g_serial_ctx.uart_attr.stop_bits); - PPP_DEBUG_INFO(" - Parity: %d", g_serial_ctx.uart_attr.parity); + PPP_DEBUG_DEBUG("UART attributes configured:"); + PPP_DEBUG_DEBUG(" - Baud Rate: %u", g_serial_ctx.uart_attr.baud_rate); + PPP_DEBUG_DEBUG(" - Data Bits: %d", g_serial_ctx.uart_attr.data_bits); + PPP_DEBUG_DEBUG(" - Stop Bits: %d", g_serial_ctx.uart_attr.stop_bits); + PPP_DEBUG_DEBUG(" - Parity: %d", g_serial_ctx.uart_attr.parity); /* 动态分配统一的接收缓冲区 */ g_serial_ctx.rx_buffer_size = config->rx_buffer_size; @@ -122,7 +126,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) PPP_DEBUG_ERROR("Failed to allocate RX buffer (%u bytes)", g_serial_ctx.rx_buffer_size); return PPP_ERR_MEMORY; } - PPP_DEBUG_INFO("RX buffer allocated: %u bytes at 0x%p", g_serial_ctx.rx_buffer_size, g_serial_ctx.rx_buffer); + PPP_DEBUG_DEBUG("RX buffer allocated: %u bytes at 0x%p", g_serial_ctx.rx_buffer_size, g_serial_ctx.rx_buffer); /* 动态分配发送缓冲区 */ g_serial_ctx.tx_buffer_size = config->tx_buffer_size; @@ -133,7 +137,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) g_serial_ctx.rx_buffer = NULL; return PPP_ERR_MEMORY; } - PPP_DEBUG_INFO("TX buffer allocated: %u bytes at 0x%p", g_serial_ctx.tx_buffer_size, g_serial_ctx.tx_buffer); + PPP_DEBUG_DEBUG("TX buffer allocated: %u bytes at 0x%p", g_serial_ctx.tx_buffer_size, g_serial_ctx.tx_buffer); /* 创建发送缓冲区互斥锁 */ if (osal_mutex_init(&g_serial_ctx.tx_mutex) != OSAL_SUCCESS) { @@ -145,18 +149,18 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) uapi_uart_deinit(g_serial_ctx.uart_bus); return PPP_ERR_MEMORY; } - PPP_DEBUG_INFO("TX mutex created successfully"); + PPP_DEBUG_DEBUG("TX mutex created successfully"); /* 配置UART使用我们分配的接收缓冲区 */ g_serial_ctx.buffer_config.rx_buffer = g_serial_ctx.rx_buffer; g_serial_ctx.buffer_config.rx_buffer_size = g_serial_ctx.rx_buffer_size; - PPP_DEBUG_INFO("UART buffer config:"); - PPP_DEBUG_INFO(" - RX Buffer Address: 0x%p", g_serial_ctx.buffer_config.rx_buffer); - PPP_DEBUG_INFO(" - RX Buffer Size: %u", g_serial_ctx.buffer_config.rx_buffer_size); - PPP_DEBUG_INFO("PPP TX buffer (software managed):"); - PPP_DEBUG_INFO(" - TX Buffer Address: 0x%p", g_serial_ctx.tx_buffer); - PPP_DEBUG_INFO(" - TX Buffer Size: %u", g_serial_ctx.tx_buffer_size); + PPP_DEBUG_DEBUG("UART buffer config:"); + PPP_DEBUG_DEBUG(" - RX Buffer Address: 0x%p", g_serial_ctx.buffer_config.rx_buffer); + PPP_DEBUG_DEBUG(" - RX Buffer Size: %u", g_serial_ctx.buffer_config.rx_buffer_size); + PPP_DEBUG_DEBUG("PPP TX buffer (software managed):"); + PPP_DEBUG_DEBUG(" - TX Buffer Address: 0x%p", g_serial_ctx.tx_buffer); + PPP_DEBUG_DEBUG(" - TX Buffer Size: %u", g_serial_ctx.tx_buffer_size); // errcode_t rett = uapi_uart_deinit(g_serial_ctx.uart_bus); // if (rett != ERRCODE_SUCC) { @@ -168,7 +172,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) // PPP_DEBUG_INFO("UART deinitialized successfully"); /* 初始化UART */ - PPP_DEBUG_INFO("Calling uapi_uart_init..."); + PPP_DEBUG_DEBUG("Calling uapi_uart_init..."); errcode_t ret = uapi_uart_init(g_serial_ctx.uart_bus, &g_serial_ctx.pin_config, &g_serial_ctx.uart_attr, @@ -188,7 +192,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) PPP_DEBUG_INFO("UART initialized successfully (error code = %d)", ret); /* 创建同步对象 */ - PPP_DEBUG_INFO("Creating synchronization objects..."); + PPP_DEBUG_DEBUG("Creating synchronization objects..."); if (osal_mutex_init(&g_serial_ctx.rx_mutex) != OSAL_SUCCESS) { PPP_DEBUG_ERROR("Failed to create RX mutex"); osal_kfree(g_serial_ctx.rx_buffer); @@ -199,7 +203,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) osal_mutex_destroy(&g_serial_ctx.tx_mutex); return PPP_ERR_MEMORY; } - PPP_DEBUG_INFO("RX mutex created successfully"); + PPP_DEBUG_DEBUG("RX mutex created successfully"); if (osal_sem_init(&g_serial_ctx.rx_semaphore, 0) != OSAL_SUCCESS) { PPP_DEBUG_ERROR("Failed to create RX semaphore"); @@ -212,7 +216,7 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) osal_mutex_destroy(&g_serial_ctx.tx_mutex); return PPP_ERR_MEMORY; } - PPP_DEBUG_INFO("RX semaphore created successfully"); + PPP_DEBUG_DEBUG("RX semaphore created successfully"); /* 初始化缓冲区状态 */ g_serial_ctx.rx_head = 0; @@ -238,11 +242,11 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) g_serial_ctx.consecutive_small_packets = 0; g_serial_ctx.idle_flush_threshold = 10; // 10ms空闲超时 - PPP_DEBUG_INFO("Buffer state initialized:"); - PPP_DEBUG_INFO(" - RX Head/Tail/Count: %u/%u/%u", g_serial_ctx.rx_head, g_serial_ctx.rx_tail, g_serial_ctx.rx_count); - PPP_DEBUG_INFO(" - TX Head/Tail/Count: %u/%u/%u", g_serial_ctx.tx_head, g_serial_ctx.tx_tail, g_serial_ctx.tx_count); - PPP_DEBUG_INFO(" - Current Mode: %d (AT)", g_serial_ctx.current_mode); - PPP_DEBUG_INFO(" - Initialized Flag: %s", g_serial_ctx.initialized ? "true" : "false"); + PPP_DEBUG_DEBUG("Buffer state initialized:"); + PPP_DEBUG_DEBUG(" - RX Head/Tail/Count: %u/%u/%u", g_serial_ctx.rx_head, g_serial_ctx.rx_tail, g_serial_ctx.rx_count); + PPP_DEBUG_DEBUG(" - TX Head/Tail/Count: %u/%u/%u", g_serial_ctx.tx_head, g_serial_ctx.tx_tail, g_serial_ctx.tx_count); + PPP_DEBUG_DEBUG(" - Current Mode: %d (AT)", g_serial_ctx.current_mode); + PPP_DEBUG_DEBUG(" - Initialized Flag: %s", g_serial_ctx.initialized ? "true" : "false"); PPP_DEBUG_INFO("PPP serial initialized successfully with unified buffer (%u bytes)", g_serial_ctx.rx_buffer_size); PPP_DEBUG_INFO("=== PPP Serial Initialization Complete ==="); @@ -265,8 +269,8 @@ ppp_error_t ppp_serial_switch_to_ppp_mode(void) } PPP_DEBUG_INFO("=== Switching to PPP Data Mode ==="); - PPP_DEBUG_INFO("Current mode: %d (AT) -> %d (PPP_DATA)", g_serial_ctx.current_mode, PPP_SERIAL_MODE_PPP_DATA); - PPP_DEBUG_INFO("UART Bus: %u", g_serial_ctx.uart_bus); + PPP_DEBUG_DEBUG("Current mode: %d (AT) -> %d (PPP_DATA)", g_serial_ctx.current_mode, PPP_SERIAL_MODE_PPP_DATA); + PPP_DEBUG_DEBUG("UART Bus: %u", g_serial_ctx.uart_bus); /* 清空接收缓冲区 */ osal_mutex_lock(&g_serial_ctx.rx_mutex); @@ -281,15 +285,15 @@ ppp_error_t ppp_serial_switch_to_ppp_mode(void) g_serial_ctx.tx_tail = 0; g_serial_ctx.tx_count = 0; osal_mutex_unlock(&g_serial_ctx.tx_mutex); - PPP_DEBUG_INFO("TX buffer cleared for mode switch"); + PPP_DEBUG_DEBUG("TX buffer cleared for mode switch"); /* PPP数据模式:使用优化的直接UART读取,增加超时时间获取完整数据 */ - PPP_DEBUG_INFO("PPP Data Mode: Using optimized direct UART read with longer timeout"); - PPP_DEBUG_INFO("This approach is more reliable than callback mechanism"); + PPP_DEBUG_DEBUG("PPP Data Mode: Using optimized direct UART read with longer timeout"); + PPP_DEBUG_DEBUG("This approach is more reliable than callback mechanism"); g_serial_ctx.current_mode = PPP_SERIAL_MODE_PPP_DATA; PPP_DEBUG_CRITICAL("Serial mode switched to PPP_DATA (%d)", g_serial_ctx.current_mode); - PPP_DEBUG_CRITICAL("PPP data mode active - UART will use direct read with 200ms timeout (balanced)"); + PPP_DEBUG_CRITICAL("PPP data mode active - UART will use direct read with %dms timeout (optimized for fast negotiation)", PPP_OPTIMIZED_UART_READ_TIMEOUT); PPP_DEBUG_INFO("=== PPP Data Mode Switch Complete ==="); return PPP_ERR_OK; } @@ -310,11 +314,11 @@ ppp_error_t ppp_serial_switch_to_at_mode(void) } PPP_DEBUG_INFO("=== Switching to AT Mode ==="); - PPP_DEBUG_INFO("Current mode: %d (PPP_DATA) -> %d (AT)", g_serial_ctx.current_mode, PPP_SERIAL_MODE_AT); - PPP_DEBUG_INFO("UART Bus: %u", g_serial_ctx.uart_bus); + PPP_DEBUG_DEBUG("Current mode: %d (PPP_DATA) -> %d (AT)", g_serial_ctx.current_mode, PPP_SERIAL_MODE_AT); + PPP_DEBUG_DEBUG("UART Bus: %u", g_serial_ctx.uart_bus); /* 清空接收缓冲区 */ - PPP_DEBUG_INFO("Clearing RX buffer..."); + PPP_DEBUG_DEBUG("Clearing RX buffer..."); osal_mutex_lock(&g_serial_ctx.rx_mutex); uint32_t old_rx_count = g_serial_ctx.rx_count; g_serial_ctx.rx_head = 0; @@ -324,7 +328,7 @@ ppp_error_t ppp_serial_switch_to_at_mode(void) PPP_DEBUG_INFO("RX buffer cleared (discarded %u bytes)", old_rx_count); /* 清空发送缓冲区 */ - PPP_DEBUG_INFO("Clearing TX buffer..."); + PPP_DEBUG_DEBUG("Clearing TX buffer..."); osal_mutex_lock(&g_serial_ctx.tx_mutex); uint32_t old_tx_count = g_serial_ctx.tx_count; g_serial_ctx.tx_head = 0; @@ -335,8 +339,8 @@ ppp_error_t ppp_serial_switch_to_at_mode(void) /* 从PPP数据模式切换回AT模式 */ if (g_serial_ctx.current_mode == PPP_SERIAL_MODE_PPP_DATA) { - PPP_DEBUG_INFO("Switching from PPP data mode to AT mode"); - PPP_DEBUG_INFO("No callback cleanup needed (using direct UART read)"); + PPP_DEBUG_DEBUG("Switching from PPP data mode to AT mode"); + PPP_DEBUG_DEBUG("No callback cleanup needed (using direct UART read)"); } g_serial_ctx.current_mode = PPP_SERIAL_MODE_AT; @@ -356,27 +360,27 @@ ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length) return PPP_ERR_INVALID_PARAM; } - PPP_DEBUG_INFO("=== PPP Serial Write Start ==="); + PPP_DEBUG_DEBUG("=== PPP Serial Write Start ==="); #ifdef PPP_LOW_POWER_MODE ppp_api_wakeup_cat1(true); #endif osal_msleep(1); - PPP_DEBUG_INFO("Write request: %u bytes in mode %d", length, g_serial_ctx.current_mode); - PPP_DEBUG_INFO("UART Bus: %u", g_serial_ctx.uart_bus); + PPP_DEBUG_DEBUG("Write request: %u bytes in mode %d", length, g_serial_ctx.current_mode); + PPP_DEBUG_DEBUG("UART Bus: %u", g_serial_ctx.uart_bus); ppp_error_t result = PPP_ERR_OK; int32_t write_result = 0; switch (g_serial_ctx.current_mode) { case PPP_SERIAL_MODE_AT: /* AT命令模式:直接使用UART发送 */ - PPP_DEBUG_INFO("Sending %u bytes via UART (AT mode)", length); + PPP_DEBUG_DEBUG("Sending %u bytes via UART (AT mode)", length); // PPP_DEBUG_HEXDUMP(data, length); - PPP_DEBUG_INFO("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=1000)...", + PPP_DEBUG_DEBUG("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=1000)...", g_serial_ctx.uart_bus, data, length); write_result = uapi_uart_write(g_serial_ctx.uart_bus, data, length, 1000); - PPP_DEBUG_INFO("uapi_uart_write returned: %d (expected: %u)", write_result, length); + PPP_DEBUG_DEBUG("uapi_uart_write returned: %d (expected: %u)", write_result, length); if (write_result != (int32_t)length) { PPP_DEBUG_ERROR("UART write failed in AT mode: returned %d, expected %u", write_result, length); @@ -404,10 +408,11 @@ ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length) // } // PPP_DEBUG_PRINT("\n"); - PPP_DEBUG_INFO("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=1000)...", - g_serial_ctx.uart_bus, data, length); + PPP_DEBUG_DEBUG("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=%d)...", + g_serial_ctx.uart_bus, data, length, PPP_OPTIMIZED_UART_WRITE_TIMEOUT); - write_result = uapi_uart_write(g_serial_ctx.uart_bus, data, length, 1000); + /* 优化UART写超时:使用配置的优化值以提高PPP协商速度 */ + write_result = uapi_uart_write(g_serial_ctx.uart_bus, data, length, PPP_OPTIMIZED_UART_WRITE_TIMEOUT); PPP_DEBUG_INFO("uapi_uart_write returned: %d (expected: %u)", write_result, length); if (write_result != (int32_t)length) { @@ -473,7 +478,8 @@ ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *byt { /* 使用适中的超时时间来平衡响应性和帧完整性 */ // PPP_DEBUG_DEBUG("PPP mode: Attempting UART read (timeout: 200ms)"); - int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 200); + /* 优化PPP数据模式读取超时:使用配置的优化值以提高协商响应速度 */ + int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, PPP_OPTIMIZED_UART_READ_TIMEOUT); if (read_result > 0) { *bytes_read = (uint32_t)read_result; g_serial_ctx.rx_bytes += *bytes_read; diff --git a/code/sdk/zhihui/utils/custom_utils.c b/code/sdk/zhihui/utils/custom_utils.c index 60581755b..f19980695 100644 --- a/code/sdk/zhihui/utils/custom_utils.c +++ b/code/sdk/zhihui/utils/custom_utils.c @@ -702,10 +702,7 @@ void startup_post_init_task(void) -#ifdef BOARD_LEINIAO - extern int ppp_env_init(void); - ppp_env_init(); -#else +#ifdef SUPPORT_CAT1_SERVICE if ( cm_poweron_cat1_on_bootup_flag() ) { PRINT("PowerOn Cat1 !\r\n"); @@ -714,6 +711,13 @@ if ( cm_poweron_cat1_on_bootup_flag() ) PRINT("PowerOff Cat1 !\r\n"); uapi_set4GCapability(false); } +#else + +#ifdef BOARD_LEINIAO + extern int ppp_env_init(void); + ppp_env_init(); +#endif + #endif #ifdef A5133_DEMO_SERVER