--- /dev/null
+# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+# 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_V21"
+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()))
+
+ 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/"
+
+