From 8a14e745007c9912519bd142dd98a9ec626af404 Mon Sep 17 00:00:00 2001 From: ranchuan Date: Fri, 15 Sep 2023 10:53:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E5=90=88python=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 +- ReadMe.txt | 7 +- coder/coder_check.py | 42 ++ coder/coder_main.py | 471 ++++++++++++++++++ coder/coder_params.py | 121 +++++ coder/coder_test.py | 126 +++++ coder/prottcp.py | 519 ++++++++++++++++++++ coder_2ch/coder_check.py | 42 ++ coder_2ch/coder_main.py | 665 ++++++++++++++++++++++++++ coder_2ch/coder_params.py | 121 +++++ coder_2ch/coder_test.py | 126 +++++ coder_2ch/prottcp.py | 519 ++++++++++++++++++++ coder_dly/coder_pc.py | 306 ++++++++++++ mysql/mysql.py | 184 +++++++ mysql/quest.py | 97 ++++ ftp.py => updata/ftp.py | 0 icon.ico => updata/icon.ico | Bin memory_pic.py => updata/memory_pic.py | 0 updata/mysql.py | 179 +++++++ pic_2py.py => updata/pic_2py.py | 0 updata/prottcp.py | 536 +++++++++++++++++++++ updata/select_list.py | 52 ++ udp.py => updata/udp.py | 0 updata.py => updata/updata.py | 83 +++- updata/updata_uart.py | 554 +++++++++++++++++++++ 25 files changed, 4746 insertions(+), 9 deletions(-) create mode 100644 coder/coder_check.py create mode 100644 coder/coder_main.py create mode 100644 coder/coder_params.py create mode 100644 coder/coder_test.py create mode 100644 coder/prottcp.py create mode 100644 coder_2ch/coder_check.py create mode 100644 coder_2ch/coder_main.py create mode 100644 coder_2ch/coder_params.py create mode 100644 coder_2ch/coder_test.py create mode 100644 coder_2ch/prottcp.py create mode 100644 coder_dly/coder_pc.py create mode 100644 mysql/mysql.py create mode 100644 mysql/quest.py rename ftp.py => updata/ftp.py (100%) rename icon.ico => updata/icon.ico (100%) rename memory_pic.py => updata/memory_pic.py (100%) create mode 100644 updata/mysql.py rename pic_2py.py => updata/pic_2py.py (100%) create mode 100644 updata/prottcp.py create mode 100644 updata/select_list.py rename udp.py => updata/udp.py (100%) rename updata.py => updata/updata.py (89%) create mode 100644 updata/updata_uart.py diff --git a/.gitignore b/.gitignore index bdb7ab6..91f5bbd 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ dist/ file/ __pycache__/ *.pid -*.spec \ No newline at end of file +*.spec +download/ +*.csv +quest_info.txt \ No newline at end of file diff --git a/ReadMe.txt b/ReadMe.txt index 2a8494b..80c4055 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -35,4 +35,9 @@ 2023.7.28 添加升级方案按钮 .axf 结尾的为主板m4程序 - 改为20通道 \ No newline at end of file + 改为20通道 +2023.9.12 + 升级软件添加从服务器下载程序文件的功能 + 升级文件名不能有空格 +2023.9.15 + 整合python目录的代码 \ No newline at end of file diff --git a/coder/coder_check.py b/coder/coder_check.py new file mode 100644 index 0000000..516d326 --- /dev/null +++ b/coder/coder_check.py @@ -0,0 +1,42 @@ +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +import coder_params as cpars + + + + +class check_dlog(QObject): + + def __init__(self,father:QDialog,slave_num:int,txt:str) -> None: + QObject.__init__(self) + self.slave_num=slave_num + self.x_size=100*self.slave_num + if(self.x_size>1500): + self.x_size=1500 + self.w=QDialog(father) + self.w.resize(self.x_size+100,200) + self.w.setWindowTitle(txt) + self.w.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + self.code_list=QTableWidget(self.w) + self.code_list.setObjectName(u"code_list") + self.code_list.setGeometry(QRect(50, 50, self.x_size, 100)) + self.code_list.setColumnCount(self.slave_num) + self.code_list.insertRow(0) + channel_list=[] + for i in range(self.slave_num): + channel_list.append("通道{d}".format(d=i+1)) + self.code_list.setHorizontalHeaderLabels(channel_list) + self.code_list.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) + + def ack_list_init(self,ack_list:list): + length=len(ack_list) + for i in range(length): + self.code_list.setItem(0,i,QTableWidgetItem(cpars.code_errinfo(int(ack_list[i])))) + if(ack_list[i]!="0"): + self.code_list.item(0,i).setBackground(Qt.GlobalColor.red) + def show(self): + self.w.show() + def close(self): + self.w.destroy(True,True) + diff --git a/coder/coder_main.py b/coder/coder_main.py new file mode 100644 index 0000000..5c68a65 --- /dev/null +++ b/coder/coder_main.py @@ -0,0 +1,471 @@ +import os +import sys +import datetime +from datetime import datetime, timedelta +import prottcp as prot +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +import threading +import time +import serial +import serial.tools.list_ports +import coder_params as cpars +import coder_check as chk + + + + +# 批检仪赋码上位机 + + +STR_RED="\033[1;31m" +STR_BLUE="\033[1;34m" +STR_END="\033[0m" + + + +# 获取北京时间 +def get_date(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y%m%d") + return utc_time + +# 获取北京时间 +def get_time(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y-%m-%d %H:%M:%S") + return utc_time + + + + +class coder(QObject): + + def __init__(self) -> None: + QObject.__init__(self) + self.app = QApplication(sys.argv) + self.code_id=0 + self.run_times=0 + self.slave_num=10 + self.code_list_lock=[] + self.save_file="code_list.csv" + self.ser_is_open = False + self.ser=prot.protu() + self.widget = QWidget() + self.widget.resize(1500, 800) + self.widget.setWindowTitle("批检仪赋码工具") + self.com_but_init() + self.combsp_init() + self.com_init() + self.code_list_init() + self.dot_fat_init() + self.channel_init() + self.sig_list_init() + self.moterup_init() + self.infotext_init() + self.widget.destroyed.connect(self.quit) + + def quit(self): + self.close_serial() + print("app exit.") + # 程序退出 + sys.exit(1) + + # 初始化 + def init(self,detonator_fat:bytearray,chip_fat:bytearray,signature_code:bytearray,slave_num:int): + self.set_params(detonator_fat,chip_fat,signature_code,slave_num) + date=get_date().encode('utf-8') + self.date=date[-5:] + self.year=date[:4] + self.save_file=date.decode("utf-8")+".csv" + if(os.path.exists(self.save_file)): + with open(self.save_file) as f: + lines=f.readlines() + length=len(lines) + self.code_id=length + for i in lines: + self.code_list_add(i) + print("code id start as:",self.code_id) + self.code_list_to_bottom() + + # 设置雷管厂,芯片厂,特征码 + def set_params(self,detonator_fat:bytearray,chip_fat:bytearray,signature_code:bytearray,slave_num:int): + self.detonator_fat=detonator_fat + self.chip_fat=chip_fat + self.slave_num=slave_num + self.signature_code=signature_code + info="已更换编码参数,现在的编码参数为:"+"雷管厂:"+detonator_fat.decode("utf-8")+",芯片厂:"+chip_fat.decode("utf-8") + info+=",特征码:"+signature_code.decode("utf-8")+",通道数:"+str(slave_num) + self.set_infotext(info) + + # 选择波特率 + def combsp_init(self): + self.combsp = QComboBox(self.widget) + self.combsp.setObjectName(u"combsp") + self.combsp.setGeometry(QRect(465, 10, 85, 25)) + self.combsp.setEditable(True) + self.combsp.currentIndexChanged.connect(self.com_changed) + for i in cpars.uartbsp_list(): + self.combsp.addItem(i) + self.combsp_label = QLabel(self.widget) + self.combsp_label.setObjectName(u"label") + self.combsp_label.setGeometry(QRect(405, 16, 72, 15)) + self.combsp_label.setText("波特率:") + + # 选择雷管厂家 + def dot_fat_init(self): + self.dot_fat = QComboBox(self.widget) + self.dot_fat.setObjectName(u"dot_fat") + self.dot_fat.setGeometry(QRect(645, 10, 400, 25)) + self.dot_fat.setEditable(False) + self.dot_fat.currentIndexChanged.connect(self.params_changed) + for i in cpars.dot_fat_list(): + self.dot_fat.addItem(i) + self.dot_fat_label = QLabel(self.widget) + self.dot_fat_label.setObjectName(u"label") + self.dot_fat_label.setGeometry(QRect(570, 16, 72, 15)) + self.dot_fat_label.setText("雷管厂家:") + + # com口 + def com_init(self): + self.com = QComboBox(self.widget) + self.com.setObjectName(u"com") + self.com.setGeometry(QRect(95, 10, 300, 25)) + self.com.setEditable(True) + self.com.currentIndexChanged.connect(self.com_changed) + # self.com.addItem("utcp:7777") + ports_list = list(serial.tools.list_ports.comports()) + for comport in ports_list: + # print(comport.name,comport.description) + self.com.addItem(comport.name+":"+comport.description) + self.com_label = QLabel(self.widget) + self.com_label.setObjectName(u"label") + self.com_label.setGeometry(QRect(30, 16, 72, 15)) + self.com_label.setText("COM口:") + + # 特征码 + def sig_list_init(self): + self.sig_list = QComboBox(self.widget) + self.sig_list.setObjectName(u"sig_list") + self.sig_list.setGeometry(QRect(1285, 10, 85, 25)) + self.sig_list.setEditable(False) + self.sig_list.currentIndexChanged.connect(self.params_changed) + for i in cpars.code_signature_code_list(): + self.sig_list.addItem(i) + self.sig_list_label = QLabel(self.widget) + self.sig_list_label.setObjectName(u"label") + self.sig_list_label.setGeometry(QRect(1220, 16, 72, 15)) + self.sig_list_label.setText("特征码:") + + # 通道数 + def channel_init(self): + self.channel = QComboBox(self.widget) + self.channel.setObjectName(u"channel") + self.channel.setGeometry(QRect(1125, 10, 85, 25)) + self.channel.setEditable(True) + self.channel.currentIndexChanged.connect(self.params_changed) + for i in cpars.code_channel_list(): + self.channel.addItem(i) + self.channel_label = QLabel(self.widget) + self.channel_label.setObjectName(u"label") + self.channel_label.setGeometry(QRect(1055, 16, 72, 15)) + self.channel_label.setText("通道数:") + + # 提示信息 + def infotext_init(self): + self.infotext=QLabel(self.widget) + self.infotext.setGeometry(QRect(30, 765, 1200, 15)) + self.infotext.setText("请打开串口以开始赋码") + def set_infotext(self,text:str): + try: + self.infotext.setText(text) + except Exception as e: + pass + + # 初始化打开端口按钮 + def com_but_init(self): + self.com_but = QPushButton(self.widget) + self.com_but.setObjectName(u"com_but") + self.com_but.setGeometry(QRect(1250, 50, 93, 28)) + self.com_but.setText("打开端口") + self.com_but.clicked.connect(self.com_but_clicked) + + # 电机上升 + def moterup_init(self): + self.moterup=QPushButton(self.widget) + self.moterup.setObjectName(u"moteerup") + self.moterup.setGeometry(QRect(1250, 90, 93, 28)) + self.moterup.setText("电机上升") + self.moterup.clicked.connect(self.cmd_moter_up) + + # 注码结果列表 + def code_list_init(self): + self.code_list=QTableWidget(self.widget) + self.code_list.setObjectName(u"code_list") + self.code_list.setGeometry(QRect(30, 50, 1200, 700)) + self.code_list.setColumnCount(6) + self.code_list.setHorizontalHeaderLabels(list(["创建时间","通道号","注码结果","管壳码","UID","密码"])) + self.code_list.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) + + # 添加数据 + def code_list_add(self,code_line:str): + code_strs=code_line.split(",") + errcode=int(code_strs[2]) + code_strs[2]=cpars.code_errinfo(errcode) + RowCont=self.code_list.rowCount() + self.code_list.insertRow(RowCont) + for i in range(6): + self.code_list.setItem(RowCont,i,QTableWidgetItem(code_strs[i])) + if(errcode!=0): + self.code_list.item(RowCont,i).setBackground(Qt.GlobalColor.red) + # 滚动到底部 + def code_list_to_bottom(self): + self.code_list.scrollToBottom() + + def com_but_clicked(self): + print("com but clicked") + if(self.ser_is_open==False): + item=self.com.itemText(self.com.currentIndex()) + bsp=self.combsp.itemText(self.combsp.currentIndex()) + com=item.split(":")[0] + if(com!="utcp"): + item=com+":"+bsp + self.open_serial(item) + else: + self.close_serial() + def set_port_state(self,state:bool): + self.ser_is_open=state + if(state==True): + self.com_but.setText("关闭端口") + else: + self.com_but.setText("打开端口") + + # 无效化编码参数设置项 + def params_active(self,power:bool): + self.dot_fat.setEnabled(power) + self.sig_list.setEnabled(power) + self.channel.setEnabled(power) + + # 更换管壳码生成参数 + def params_changed(self,index:int): + try: + dot_fat=self.dot_fat.itemText(self.dot_fat.currentIndex()).split(":")[0].encode("utf-8") + chip_fat=b"AD" + sig_code=self.sig_list.itemText(self.sig_list.currentIndex()).encode("utf-8") + slave_num=self.channel.itemText(self.channel.currentIndex()) + self.set_params(dot_fat,chip_fat,sig_code,int(slave_num)) + except Exception as e: + pass + + # 更换端口时关闭之前的 + def com_changed(self,index:int): + print("com changed") + self.set_infotext("串口参数有变动,将自动关闭打开的串口") + self.close_serial() + # 打开通信接口 + def open_serial(self,com:str): + if(self.ser.init(com)==True): + self.ser.recv_signal.connect(self.recv_slot) + self.ser.start_recv() + self.set_port_state(True) + print("open serial.") + self.set_infotext("打开串口成功,开始监听请求赋码指令") + else: + self.set_infotext("打开串口失败,是否有其他程序占用了串口?") + print("open serial failed.") + def close_serial(self): + try: + self.ser.recv_signal.disconnect(self.recv_slot) + except Exception as a: + pass + self.ser.close() + self.set_infotext("串口已关闭") + self.set_port_state(False) + + def recv_slot(self,cmd:int,data:bytearray,err:str): + print("recv:","cmd:",hex(cmd),"data:",data.hex(' ')) + if(self.run_times<=0): + print("run times end.") + self.set_infotext("运行次数已结束,不再响应检测赋码指令") + return + self.run_times-=1 + ack=False + if(cmd==0x81): + self.set_infotext("已接收检测结果") + ack=self.decode_check(data) + if(ack==True): + self.cmd_code(self.slave_num) + else: + print("check failed.") + self.set_infotext("检测出现异常,未进行赋码,请排查异常后重试") + self.cmd_moter_up() + self.params_active(True) + elif(cmd==0x82): + self.set_infotext("已接收赋码结果") + ack=self.decode_code(data) + if(ack!=True): + print("code failed.") + self.set_infotext("赋码出现异常,本次赋码结果被丢弃,请排查异常后重试") + self.cmd_moter_up() + self.params_active(True) + elif(cmd==0x37): + print("key press.") + self.params_active(False) + self.set_infotext("已接收请求检测命令") + self.cmd_moter_down() + time.sleep(2) + self.cmd_check(self.slave_num) + + + def run(self,times:int): + self.run_times=times*4 + self.widget.show() + ret=self.app.exec() + self.close_serial() + sys.exit(ret) + + # 生成管壳码 + def calc_shell_code(self,id:int): + shell=bytearray() + shell+=self.detonator_fat + shell+=self.date + shell+=self.signature_code + shell+="{d:05d}".format(d=id).encode("utf-8") + return shell + + # 生成n通道的注码数据 + def creat_code_data(self,id:int,num:int): + d=bytearray() + d.append(num&0xff) + d+=self.year + for i in range(num): + d.append(i&0xff) + d+=self.calc_shell_code(id+i) + return d + # 发送检测命令 + def cmd_check(self,num:int): + d=bytearray() + d.append(num&0xff) + d.append(0) + self.ser.send(1,d) + print("check start.") + # 电机上升 + def cmd_moter_up(self): + d=bytearray() + d.append(0x02) + try: + self.ser.send(0x40,d) + except Exception as e: + self.set_infotext("发送命令失败,是否没有打开串口?") + print("moter up.") + # 电机下降 + def cmd_moter_down(self): + d=bytearray() + d.append(0x03) + self.ser.send(0x40,d) + print("moter down.") + + # 发送赋码指令 + def cmd_code(self,num:int): + self.ser.send(2,self.creat_code_data(self.code_id,num)) + print("code start.") + + # 解析检测结果 + def decode_check(self,data:bytearray): + num=data[0] + ack=True + acks_list=[] + for i in range(num): + ack_i=data[6*i+3] + str_start="" + if(ack_i!=0): + ack=False + str_start=STR_RED + print(str_start+"addr:",int(data[6*i+2]),"ack:",ack_i,STR_END) + acks_list.append(str(ack_i)) + try: + self.ch_dlog.close() + self.co_dlog.close() + except Exception as e: + pass + if(ack!=True): + self.ch_dlog=chk.check_dlog(self.widget,self.slave_num) + self.ch_dlog.ack_list_init(acks_list) + self.ch_dlog.show() + return ack + + # 解析注码结果 + def decode_code(self,data:bytearray): + num=data[0] + ack=True + code_list=[] + # 生成注码结果数据 + for i in range(num): + ack_i=data[39*i+2] + str_start="" + d=data[39*i+3:39*i+3+38] + shell_code=d[:13].decode("utf-8") + uid_code=d[13:13+16].decode("utf-8") + psw_code=d[13+16:13+16+8].decode("utf-8") + code_list.append(((i+1),ack_i,shell_code,uid_code,psw_code)) + + # 统计错误信息 + length=len(code_list) + if(len(self.code_list_lock)==0): + # 第一次失败,保存失败数据 + self.code_list_lock=code_list + else: + # 不是第一次失败,比对失败数据,把成功过的统计出来 + if (len(self.code_list_lock)>length): + self.code_list_lock=self.code_list_lock[:length] + for i in range(length): + # 长度不足的地方填充为本次的结果 + if(i>=len(self.code_list_lock)): + self.code_list_lock.append(code_list[i]) + if(self.code_list_lock[i][0]==code_list[i][0]): + if(code_list[i][1]==0): + self.code_list_lock[i]=code_list[i] + # 校验注码结果 + acks_list=[] + for i in self.code_list_lock: + str_start="" + ack_i=i[1] + if(ack_i!=0): + ack=False + str_start=STR_RED + print(str_start+"addr:",i[0],"ack:",ack_i,STR_END) + print("\t","shell_code:",i[2]) + print("\t","uid_code:",i[3]) + print("\t","psw_code:",i[4]) + acks_list.append(str(ack_i)) + if(ack==True): + s="" + time=get_time() + for i in self.code_list_lock: + s=time+","+str(i[0])+','+str(i[1])+','+i[2]+','+i[3]+','+i[4] + self.code_list_add(s) + with open(self.save_file,"+a") as f: + f.write(s+'\n') + self.code_list_to_bottom() + print("save to file:",self.save_file) + # 全部成功,清除错误记录 + self.code_list_lock.clear() + self.code_id+=self.slave_num + try: + self.co_dlog.close() + except Exception as e: + pass + if(ack!=True): + self.co_dlog=chk.check_dlog(self.widget,self.slave_num,"注码结果查看") + self.co_dlog.ack_list_init(acks_list) + self.co_dlog.show() + return ack + +if __name__ == "__main__": + c=coder() + c.init(b'00',b'AD',b'A',10) + c.run(5000) + diff --git a/coder/coder_params.py b/coder/coder_params.py new file mode 100644 index 0000000..b9d53dd --- /dev/null +++ b/coder/coder_params.py @@ -0,0 +1,121 @@ + + + + +# 雷管厂家列表 +detonator_fat_list="""00 测试用工厂代号 +01 北京京煤化工有限公司 +04 河北卫星化工股份有限公司 +07 山西焦煤集团化工有限责任公司汾矿分公司 +08 山西金恒化工集团股份有限公司 +09 山西壶化集团股份有限公司 +10 内蒙古生力资源集团红旗化工有限公司 +12 新时代民爆(辽宁)股份有限公司 +14 葫芦岛凌河化工集团有限责任公司 +15 辽宁华丰民用化工发展有限公司 +18 长春吉阳工业有限公司 +19 黑龙江青化民爆器材有限公司 +20 黑龙江盛安民用爆破器材有限责任公司鹤岗分公司 +21 徐州雷鸣民爆器材有限公司 +22 南京理工科技化工有限责任公司 +24 浙江物产光华民爆器材有限公司 +29 福建海峡科化股份有限公司烽林分公司 +30 福建省民爆化工股份有限公司永春分公司 +34 江西新余国泰特种化工有限责任公司 +36 山东圣世达化工有限责任公司 +37 山东泰山民爆器材有限公司 +38 前进民爆股份有限公司 +44 湖北卫东化工股份有限公司 +48 湖南神斧集团向红机械化工有限责任公司 +49 湘南爆破器材有限责任公司 +52 广东宏大韶化民爆有限公司 +53 广西金建华民用爆破器材有限公司 +56 四川省宜宾威力化工有限责任公司 +57 雅化集团绵阳实业有限公司 +58 重庆顺安天力达爆破器材有限公司 +59 贵州盘江民爆有限公司 +60 贵州久联民爆器材发展股份有限公司九八四四生产分公司 +61 云南燃一有限责任公司 +64 西安庆华民用爆破器材股份有限公司 +65 甘肃久联民爆器材有限公司白银雪松分公司 +68 新疆雪峰民用爆破器材有限责任公司""" + + +def dot_fat_list(): + str_lines=detonator_fat_list.split("\n") + fat_list=[] + for line in str_lines: + s=line.split("\t") + fat_list.append(s[0]+":"+s[1]) + return fat_list + + + + + + + +# 波特率列表 +def uartbsp_list(): + ulist=["115200","57600","9600"] + return ulist + + + + +# 根据注码异常代码获取描述 +code_errinfo_list=[ + "0:成功", + "1:检测器异常", + "2:电容异常", + "3:接触异常", + "4:桥丝异常", + "5:芯片异常", + "6:未找到相关任务", + "7:过流", + "8:短路", + "193:电压设置失败", + "194:三码验证失败", + "195:UID写入失败", + "196:密码写入失败", + "197:获取UID失败", + "198:UID比对失败", + "199:锁存失败", + "200:等待接入超时", + "201:已存在其他数据" +] + +def code_errinfo(errcode:int): + for i in code_errinfo_list: + s=i.split(":") + if(int(s[0])==errcode): + return s[1] + return "未定义的错误码" + + +# 通道数 +def code_channel_list(): + ulist=["10","20"] + return ulist + + + +# 特征号 +def code_signature_code_list(): + code_str="ACDEFGHIJKLMNOPQRSTUVWXYZabdefghijklmnpqrty0123456789" + sig_list=[] + for i in code_str: + sig_list.append(i) + return sig_list + + + +if __name__ == "__main__": + fats=dot_fat_list() + for line in fats: + print(line) + + + + + diff --git a/coder/coder_test.py b/coder/coder_test.py new file mode 100644 index 0000000..b6d5af5 --- /dev/null +++ b/coder/coder_test.py @@ -0,0 +1,126 @@ +import serial +import serial.tools.list_ports +import threading +import time +import socket + +# 把tcp封装为串口 +class utcp: + is_open=False + def __init__(self,port:int)->None: + self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.ser.bind(("",port)) + self.ser.settimeout(10) + self.ser.listen(128) + print("wait for mcu connect.") + self.client,self.client_addr=self.ser.accept() + print("client:",self.client_addr) + self.is_open=True + def read(self,len:int): + return self.client.recv(len) + def write(self,data:bytearray): + return self.client.send(data) + def close(self): + self.client.close() + self.ser.close() + self.is_open=False + +class port: + def __init__(self) -> None: + pass + def open(self,name:str,bsp:int): + if(name!="utcp"): + self.ser = serial.Serial(port=name, baudrate=bsp,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE,timeout=None) + else: + self.ser=utcp(9527) + def start_recv(self): + self.thread_ = threading.Thread(target=self.recv, args=()) + self.thread_.start() + def recv(self,num:int): + d=bytearray() + try: + while(num>len(d)): + d+=self.ser.read(num-len(d)) + except Exception as a: + print("port closed") + return 0 + print("recv code:",d.hex(" ")) + def send(self,data:bytearray): + self.ser.write(data) + # 测试上位机 + def ecode_test(self,times:int): + print("检测赋码系统耗时测试:") + tick=0 + while(tick0): + crc=0xffff + for i in range(len-offset): + crc=(crc^data[i+offset])&0xffff + for j in range(8): + if(crc&1)!=0: + crc=((crc>>1)^0xa001)&0xffff + else: + crc=(crc>>1)&0xffff + return crc&0xff,(crc>>8)&0xff + return 0,0 + + +def crc32(data:bytearray): + temp=0 + crc=0xffffffff + i=0 + if(len(data)%4!=0): + return 0 + while(iNone: + self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.ser.bind(("",port)) + self.ser.settimeout(10) + self.ser.listen(128) + print("wait for mcu connect.") + self.client,self.client_addr=self.ser.accept() + print("client:",self.client_addr) + self.is_open=True + def read(self,len:int): + # return self.ser.recv(len) + return self.client.recv(len) + def write(self,data:bytearray): + # return self.ser.send(data) + return self.client.send(data) + def close(self): + self.client.close() + self.ser.close() + self.is_open=False + + + + + + + + + + + + + + +# 生成一个任务的参数 +def scheme_task_to_byte(j:json): + data=bytearray() + data.append(j["TaskID"]) + data.append(j["TaskIndex"]) + data.append(j["RetryCount"]) + data.append(j["ErrJumpTo"]) + data.append((j["ParamCount"]&0x0f)|(j["ReturnCount"]<<4)) + for i in j["ParamVal"]: + data.append(i&0xff) + data.append(i>>8) + return data + +# 生成任务参数序列 +def scheme_tasks_to_byte(j:json): + data=bytearray() + for i in j["TaskArray"]: + data+=scheme_task_to_byte(i) + length=len(data) + if(length<(0x700-4)): + for i in range(0x700-4-length): + data.append(0xff) + return data + +# 生成任务id序列 +def scheme_taskids_to_byte(j:json): + t=bytearray() + t.append(j["PlanID"]&0xff) + t.append((j["PlanID"]>>8)&0xff) + t.append((j["PlanID"]>>16)&0xff) + t.append((j["PlanID"]>>24)&0xff) + for i in j["TaskArray"]: + t.append(i["TaskID"]) + length=len(t) + if(length<(0x100)): + for i in range(0x100-length): + t.append(0xff) + return t + +# 根据方案生成小板用的字节数据 +def scheme_to_byte(j:json): + t=bytearray() + t+=scheme_taskids_to_byte(j) + t+=scheme_tasks_to_byte(j) + crc=crc32(t) + t.append(crc&0xff) + t.append((crc>>8)&0xff) + t.append((crc>>16)&0xff) + t.append((crc>>24)&0xff) + return t + + +# int转数组 +def arr_from_int(num:int): + return bytearray([num&0xff,(num>>8)&0xff,(num>>16)&0xff,(num>>24)&0xff]) + + +# 提取方案中的范围数据, 先max后min +def scheme_get_task_range(j:json): + t=bytearray() + t+=arr_from_int(j["TaskID"]) + t+=arr_from_int(j["TaskIndex"]) + t+=arr_from_int(j["ReturnCount"]) + t+=arr_from_int(j["ExecuteErrCode"]) + index=0 + for i in j["TestStandard"]: + t+=arr_from_int(i["Max"]) + t+=arr_from_int(i["Min"]) + if (index None: + pass + + def get_rate(self): + return self.packet_now*100//self.packet_all + def get_data(self): + if(self.stat==0): + length=len(self.data) + # 1是写,0是读 + t=bytearray([1,length&0xff,(length>>8)&0xff,(length>>16)&0xff,(length>>24)&0xff]) + t+=self.name.encode() + self.stat=1 + return t + elif(self.stat==1): + packet_bytes=200 + if(len(self.data)0): + self.packet_now+=1 + t=bytearray() + t.append(2) + t.append(self.packet_now&0xff) + t.append((self.packet_now>>8)&0xff) + t.append(self.packet_all&0xff) + t.append((self.packet_all>>8)&0xff) + t+=self.data[self.sent_bytes:self.sent_bytes+packet_bytes] + self.sent_bytes+=packet_bytes + return t + else: + print("send done.") + return bytearray() + + # 设置要发送的文件 + def set_file(self,name:str): + self.data=bytearray() + with open(name,"rb") as f: + self.data=f.read() + self.name=f.name.split('/')[-1] + self.stat=0 + self.packet_all=(len(self.data)+199)//200 + self.sent_bytes=0 + self.packet_now=0 + self.packet_bytes=200 + + # 设置要发送的方案 + def set_json(self,name:str): + self.data=bytearray() + with open(name,"rb") as f: + json_obj=json.loads(f.read()) + d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + d+=scheme_to_host(json_obj) + # print("len=",len(d),d.hex(",")) + self.data=d + self.name=f.name.split('/')[-1] + self.stat=0 + self.packet_all=(len(self.data)+199)//200 + self.sent_bytes=0 + self.packet_now=0 + self.packet_bytes=200 + + + + + + + +class protu(QObject): + # 进度信号,ip,1~100 + rate_signal =pyqtSignal([int]) + # 结束信号,ip,成败,描述 + end_signal = pyqtSignal([bool,str]) + # 接收到数据信号 + recv_signal =pyqtSignal([int,bytearray,str]) + + hand=handle() + def __init__(self) -> None: + QObject.__init__(self) + self.cmd=0 + self.cmd_no=0 + self.str_err="" + self.is_big_data=False + self.num_to_recv=0 + self.recv_data=bytearray() + def init(self,com:str): + s=com.split(":") + try: + if(s[0]=="utcp"): + self.ser = utcp(int(s[1])) + else: + bsp=int(s[1]) + self.ser = serial.Serial(port=s[0], baudrate=bsp,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE,timeout=None) + except Exception as e: + print(str(e)) + return False + return True + + def encode(self,data:bytearray): + t=bytearray() + length=len(data)+3 + t.append(0x59) + t.append(0x6d) + t.append(length&0xff) + t.append(length>>8) + t.append(self.cmd) + t.append(self.cmd_no&0xff) + t.append(self.cmd_no>>8) + t+=data + a,b=crc16(t,2,length+4) + t.append(a) + t.append(b) + # print("encode:",t.hex(",")) + return t + def decode(self,data:bytearray): + self.str_err="ok" + if(len(data)<10): + print("recv data len too less.") + self.str_err="recv data len too less." + return bytearray() + if(data[0]!=0x59 or data[1]!=0x6d or data[2]!=0x43): + # print("frame head not 0x59 0x6d.") + self.str_err="frame head not 0x59 0x6d." + return bytearray() + length=data[3]|(data[4]<<8) + if(length==65535): + # 重新设置数据长度 + length=data[7]|(data[8]<<8)|(data[9]<<16)|(data[10]<<24); + self.is_big_data=True + else: + self.is_big_data=False + if(length+7!=len(data)): + print("recv data have lossed") + self.str_err="recv data have lossed" + return bytearray() + a,b=crc16(data,3,length+5) + if(a!=data[-2] or b!=data[-1]): + print("recv data check error.h_crc=%02x %02x,crc=%02x %02x",a,b,data[-2],data[-1]) + self.str_err="recv data check error." + self.cmd_no=data[6]|(data[7]<<8) + self.cmd=data[5] + if(self.is_big_data==False): + return bytearray(data[8:-2]) + else: + return bytearray(data[12:-2]) + # 不带校验的接收函数 + def recv_(self): + while(self.ser.is_open): + try: + data=self.ser.read(500) + except Exception as a: + # print("err:",str(a)) + print("port closed") + return + if(len(data)>0): + t=self.decode(data) + if(self.str_err=="ok"): + self.recv_data+=t + # print("recv",t.hex(",")) + # print(type(self.cmd),type(t),type(self.str_err)) + self.recv_signal.emit(self.cmd,t,self.str_err) + # self.send_file_next(self.cmd,t,self.str_err) + # print("sent signal---") + else: + print(data.decode("utf-8")) + # 带帧校验的接收函数 + def recv(self): + # self.recv_signal.connect(self.send_file_next) + data=bytearray() + while(self.ser.is_open): + d=bytes() + try: + d=self.ser.read(1) + except Exception as a: + # print("err:",str(a)) + print("port closed") + return + data+=d + if(len(data)==3): + if(data[0]==0x59 and data[1]==0x6d and data[2]==0x43): + self.num_to_recv=5 + else: + data=data[1:] + self.num_to_recv=0 + elif(len(data)==5): + length=data[3]|(data[4]<<8) + if(length<65535): + self.num_to_recv+=length+2 + self.is_big_data=False + else: + self.num_to_recv=12 + self.is_big_data=True + elif(len(data)==12): + if(self.is_big_data==True): + length=data[8]|(data[9]<<8)|(data[10]<<16)|(data[11]<<24) + self.num_to_recv=5+length+2 + if(self.num_to_recv>0 and self.num_to_recv==len(data)): + t=self.decode(data) + + self.recv_data+=t + # print("recv",t.hex(",")) + self.recv_signal.emit(self.cmd,t,self.str_err) + # self.send_file_next(self.cmd,t,self.str_err) + # print("sent signal---") + data.clear() + # else: + # print("len(data)={d1},num_ro_recv={d2}".format(d1=len(data),d2=self.num_to_recv)) + def send(self,cmd:int,data:bytearray): + self.cmd=cmd + self.cmd_no+=1 + self.ser.write(self.encode(data)) + def send_str(self,txt:str): + self.ser.write(txt.encode("utf-8")) + def start_recv(self): + self.thread_ = threading.Thread(target=self.recv, args=()) + self.thread_.start() + def wait(self): + self.thread_.join() + def close(self): + try: + if(self.ser.is_open): + self.ser.close() + except Exception as e: + print(str(e)) + def send_file_next(self,cmd:int,data:bytearray,err:str): + print("send_file_next") + data=self.hand.get_data() + if(len(data)>0): + self.send(cmd,data) + else: + self.close() + def send_file(self,cmd:int,name:str): + self.start_recv() + self.hand.set_file(name) + # self.send_file_next(cmd,bytearray([0]),"ok") + self.recv_signal.emit(cmd,bytearray([0]),"ok") + self.wait() + + + + + + + + + + + +# 0x30 开始检测 +# 0x31 检测上报 +# 0x32 读写方案 +# 0x33 连接维护 +# 0x34 自检数据 +# 0x35 自检上报 +# 0x36 升级脚本 +# 0xed 主板升级 +# 0xee 小板升级 +# 0x40 电机矫正 +# 0x41 小板电阻矫正 +# 0x42 小板电阻测量 +# 0x43 小板硬件版本 + +# with open("file/judge.lua","rb") as f: +# send_file("COM5",0x36,f.name.split('/')[-1],f.read()) +# with open("file/JQ_JCXB_V54.bin","rb") as f: +# send_file("COM5",0xee,f.name.split('/')[-1],f.read()) +# with open("file/checker_ye_cfg.json","rb") as f: +# json_obj=json.loads(f.read()) + # d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + # d=scheme_to_host(json_obj) + # print("len=",len(d),d.hex(",")) + # send_file("COM5",0x32,f.name.split('/')[-1],f.read()) + + + +def int2str(num:int): + s=str(num//100) + s=s+str(num%100//10) + s=s+str(num%10) + return s + + +if __name__ == "__main__": + u=protu() + # u.init("utcp:7777") + # u.send_file(0xee,"file/JQ_JCXB_V54.bin") + # u.send_file(0xed,"../Objects/checker_gen1_app_20230602.bin") + + # 设置电阻 矫正值 + u.cmd=0x41 + data=bytearray([1,0,0x00,2,0,0x00,3,0,0x00,4,0,0x00,5,0,0x00,6,0,0x00,7,0,0x00,8,0,0x00,9,0,0x00,10,0,0x00,11,0,0x00,12,0,0x00,13,0,0x00,14,0,0x00,15,0,0x00,16,0,0x00,17,0,0x00,18,0,0x00,19,0,0x00,20,0,0x00]) + # 测量电阻 + # u.cmd=0x42 + # data=bytearray([0]) + # 设置硬件版本号 + # u.cmd=0x43 + # data=bytearray([1,50,0x00,2,51,0x00,3,52,0x00,4,53,0x00,5,54,0x00,6,55,0x00,7,56,0x00,8,57,0x00,9,58,0x00,10,59,0x00,11,60,0x00,12,61,0x00,13,62,0x00,14,63,0x00,15,64,0x00,16,65,0x00,17,66,0x00,18,67,0x00,19,68,0x00,20,69,0x00]) + # 设置电机校正值 + # u.cmd=0x40 + # data=bytearray([0x01,100,0]) + # data=bytearray([0x02]) # 上升 + # data=bytearray([0x03]) # 下降 + + print(u.encode(data).hex(' ')) + # with open("file/EX_Coder_Test_2023-07-6.json","rb") as f: + # json_obj=json.loads(f.read()) + # d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + # d+=scheme_to_host(json_obj) + + # print(int2str(20)) + # s="{d:03d}".format(d=2) + # print(s) + + # with open("file/7-15.json","rb") as f: + # u.cmd=0x22 + # p=u.encode(f.read()) + # print(p.hex(' ')) + + +# 开始检测 +# 59 6d 03 00 30 00 00 60 0f +# 结束应答 +# 59 6D 03 00 31 00 00 31 CF + + diff --git a/coder_2ch/coder_check.py b/coder_2ch/coder_check.py new file mode 100644 index 0000000..516d326 --- /dev/null +++ b/coder_2ch/coder_check.py @@ -0,0 +1,42 @@ +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +import coder_params as cpars + + + + +class check_dlog(QObject): + + def __init__(self,father:QDialog,slave_num:int,txt:str) -> None: + QObject.__init__(self) + self.slave_num=slave_num + self.x_size=100*self.slave_num + if(self.x_size>1500): + self.x_size=1500 + self.w=QDialog(father) + self.w.resize(self.x_size+100,200) + self.w.setWindowTitle(txt) + self.w.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + self.code_list=QTableWidget(self.w) + self.code_list.setObjectName(u"code_list") + self.code_list.setGeometry(QRect(50, 50, self.x_size, 100)) + self.code_list.setColumnCount(self.slave_num) + self.code_list.insertRow(0) + channel_list=[] + for i in range(self.slave_num): + channel_list.append("通道{d}".format(d=i+1)) + self.code_list.setHorizontalHeaderLabels(channel_list) + self.code_list.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) + + def ack_list_init(self,ack_list:list): + length=len(ack_list) + for i in range(length): + self.code_list.setItem(0,i,QTableWidgetItem(cpars.code_errinfo(int(ack_list[i])))) + if(ack_list[i]!="0"): + self.code_list.item(0,i).setBackground(Qt.GlobalColor.red) + def show(self): + self.w.show() + def close(self): + self.w.destroy(True,True) + diff --git a/coder_2ch/coder_main.py b/coder_2ch/coder_main.py new file mode 100644 index 0000000..ff542cf --- /dev/null +++ b/coder_2ch/coder_main.py @@ -0,0 +1,665 @@ +import os +import sys +import datetime +from datetime import datetime, timedelta +import prottcp as prot +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +import threading +import time +import serial +import serial.tools.list_ports +import coder_params as cpars +import coder_check as chk + + + + +# 批检仪赋码上位机 + + +STR_RED="\033[1;31m" +STR_BLUE="\033[1;34m" +STR_END="\033[0m" + + + +# 获取北京时间 +def get_date(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y%m%d") + return utc_time + +# 获取北京时间 +def get_time(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y-%m-%d %H:%M:%S") + return utc_time + + + + +class coder(QObject): + + def __init__(self) -> None: + QObject.__init__(self) + self.app = QApplication(sys.argv) + self.code_id=0 + self.run_times=0 + self.slave_num=10 + self.code_list_lock=[] + self.save_file="code_list.csv" + self.ser_is_open = False + self.recv_handler=None + self.autoinc_id=False + self.autotest_is_open=0 + self.ser=prot.protu() + self.widget = QWidget() + self.widget.resize(1500, 800) + self.widget.setWindowTitle("批检仪赋码工具") + self.com_but_init() + self.combsp_init() + self.com_init() + self.code_list_init() + self.dot_fat_init() + self.channel_init() + self.sig_list_init() + self.moterup_init() + self.infotext_init() + self.recv_handler_table_init() + self.device_type_init() + self.autoinc_init() + self.check_but_init() + self.posend_but_init() + self.autotest_but_init() + self.stop_but_init() + self.widget.destroyed.connect(self.quit) + + def quit(self): + self.close_serial() + print("app exit.") + # 程序退出 + sys.exit(1) + + # 初始化 + def init(self,detonator_fat:bytearray,chip_fat:bytearray,signature_code:bytearray,slave_num:int): + self.set_params(detonator_fat,chip_fat,signature_code,slave_num) + date=get_date().encode('utf-8') + self.date=date[-5:] + self.year=date[:4] + self.save_file=date.decode("utf-8")+".csv" + if(os.path.exists(self.save_file)): + with open(self.save_file) as f: + lines=f.readlines() + length=len(lines) + self.code_id=length + for i in lines: + self.code_list_add(i) + print("code id start as:",self.code_id) + self.code_list_to_bottom() + + # 设置雷管厂,芯片厂,特征码 + def set_params(self,detonator_fat:bytearray,chip_fat:bytearray,signature_code:bytearray,slave_num:int): + self.detonator_fat=detonator_fat + self.chip_fat=chip_fat + self.slave_num=slave_num + self.signature_code=signature_code + info="已更换编码参数,现在的编码参数为:"+"雷管厂:"+detonator_fat.decode("utf-8")+",芯片厂:"+chip_fat.decode("utf-8") + info+=",特征码:"+signature_code.decode("utf-8")+",通道数:"+str(slave_num) + self.set_infotext(info) + + # 选择波特率 + def combsp_init(self): + self.combsp = QComboBox(self.widget) + self.combsp.setObjectName(u"combsp") + self.combsp.setGeometry(QRect(465, 10, 85, 25)) + self.combsp.setEditable(True) + self.combsp.currentIndexChanged.connect(self.com_changed) + for i in cpars.uartbsp_list(): + self.combsp.addItem(i) + self.combsp_label = QLabel(self.widget) + self.combsp_label.setObjectName(u"label") + self.combsp_label.setGeometry(QRect(405, 16, 72, 15)) + self.combsp_label.setText("波特率:") + + # 选择雷管厂家 + def dot_fat_init(self): + self.dot_fat = QComboBox(self.widget) + self.dot_fat.setObjectName(u"dot_fat") + self.dot_fat.setGeometry(QRect(645, 10, 400, 25)) + self.dot_fat.setEditable(False) + self.dot_fat.currentIndexChanged.connect(self.params_changed) + for i in cpars.dot_fat_list(): + self.dot_fat.addItem(i) + self.dot_fat_label = QLabel(self.widget) + self.dot_fat_label.setObjectName(u"label") + self.dot_fat_label.setGeometry(QRect(570, 16, 72, 15)) + self.dot_fat_label.setText("雷管厂家:") + + # com口 + def com_init(self): + self.com = QComboBox(self.widget) + self.com.setObjectName(u"com") + self.com.setGeometry(QRect(95, 10, 300, 25)) + self.com.setEditable(True) + self.com.currentIndexChanged.connect(self.com_changed) + # self.com.addItem("utcp:7777") + ports_list = list(serial.tools.list_ports.comports()) + for comport in ports_list: + # print(comport.name,comport.description) + self.com.addItem(comport.name+":"+comport.description) + self.com_label = QLabel(self.widget) + self.com_label.setObjectName(u"label") + self.com_label.setGeometry(QRect(30, 16, 72, 15)) + self.com_label.setText("COM口:") + + # 特征码 + def sig_list_init(self): + self.sig_list = QComboBox(self.widget) + self.sig_list.setObjectName(u"sig_list") + self.sig_list.setGeometry(QRect(1285, 10, 85, 25)) + self.sig_list.setEditable(False) + self.sig_list.currentIndexChanged.connect(self.params_changed) + for i in cpars.code_signature_code_list(): + self.sig_list.addItem(i) + self.sig_list_label = QLabel(self.widget) + self.sig_list_label.setObjectName(u"label") + self.sig_list_label.setGeometry(QRect(1220, 16, 72, 15)) + self.sig_list_label.setText("特征码:") + + # 通道数 + def channel_init(self): + self.channel = QComboBox(self.widget) + self.channel.setObjectName(u"channel") + self.channel.setGeometry(QRect(1125, 10, 85, 25)) + self.channel.setEditable(True) + self.channel.currentIndexChanged.connect(self.params_changed) + for i in cpars.code_channel_list(): + self.channel.addItem(i) + self.channel_label = QLabel(self.widget) + self.channel_label.setObjectName(u"label") + self.channel_label.setGeometry(QRect(1055, 16, 72, 15)) + self.channel_label.setText("通道数:") + + # 提示信息 + def infotext_init(self): + self.infotext=QLabel(self.widget) + self.infotext.setGeometry(QRect(30, 765, 1200, 15)) + self.infotext.setText("请打开串口以开始赋码") + def set_infotext(self,text:str): + try: + self.infotext.setText(text) + except Exception as e: + pass + + # 初始化打开端口按钮 + def com_but_init(self): + self.com_but = QPushButton(self.widget) + self.com_but.setObjectName(u"com_but") + self.com_but.setGeometry(QRect(1250, 50, 93, 28)) + self.com_but.setText("打开端口") + self.com_but.clicked.connect(self.com_but_clicked) + + # 电机上升 + def moterup_init(self): + self.moterup=QPushButton(self.widget) + self.moterup.setObjectName(u"moteerup") + self.moterup.setGeometry(QRect(1250, 90, 93, 28)) + self.moterup.setText("电机上升") + self.moterup.clicked.connect(self.cmd_moter_up) + + # 自动增加id号 + def autoinc_init(self): + self.autoinc=QPushButton(self.widget) + self.autoinc.setObjectName(u"autoinc") + self.autoinc.setGeometry(QRect(1250, 130, 93, 28)) + self.autoinc.clicked.connect(self.autoinc_clicked) + self.autoinc_clicked() + + # 开始检测 + def check_but_init(self): + self.check_but=QPushButton(self.widget) + self.check_but.setObjectName(u"check_but") + self.check_but.setGeometry(QRect(1250, 170, 93, 28)) + self.check_but.clicked.connect(self.check_but_clicked) + self.check_but.setText("开始检测") + + # 到位感应 + def posend_but_init(self): + self.posend_but=QPushButton(self.widget) + self.posend_but.setObjectName(u"posend_but") + self.posend_but.setGeometry(QRect(1250, 210, 93, 28)) + self.posend_but.clicked.connect(self.posend_but_clicked) + self.posend_but.setText("到位感应") + + # 自动测试 + def autotest_but_init(self): + self.autotest_but=QPushButton(self.widget) + self.autotest_but.setObjectName(u"autotest_but") + self.autotest_but.setGeometry(QRect(1250, 250, 93, 28)) + self.autotest_but.clicked.connect(self.autotest_but_clicked) + self.autotest_but.setText("开自动测试") + + # 自动测试 + def stop_but_init(self): + self.stop_but=QPushButton(self.widget) + self.stop_but.setObjectName(u"stop_but") + self.stop_but.setGeometry(QRect(1250, 290, 93, 28)) + self.stop_but.clicked.connect(self.stop_but_clicked) + self.stop_state=True + self.stop_but_clicked() + + # 初始化设备类型选择框 + def device_type_init(self): + self.device_type_list = QComboBox(self.widget) + self.device_type_list.setObjectName(u"device_type_list") + self.device_type_list.setGeometry(QRect(1370, 50, 93, 28)) + self.device_type_list.setEditable(False) + self.device_type_list.currentIndexChanged.connect(self.device_type_changed) + for i in self.recv_handler_table.items(): + self.device_type_list.addItem(i[0]) + # self.device_type_list_label = QLabel(self.widget) + # self.device_type_list_label.setObjectName(u"label") + # self.device_type_list_label.setGeometry(QRect(1220, 16, 72, 15)) + # self.device_type_list_label.setText("特征码:") + self.device_type_changed(0) + + # 注码结果列表 + def code_list_init(self): + self.code_list=QTableWidget(self.widget) + self.code_list.setObjectName(u"code_list") + self.code_list.setGeometry(QRect(30, 50, 1200, 700)) + self.code_list.setColumnCount(6) + self.code_list.setHorizontalHeaderLabels(list(["创建时间","通道号","注码结果","管壳码","UID","密码"])) + self.code_list.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) + + # 添加数据 + def code_list_add(self,code_line:str): + code_strs=code_line.split(",") + errcode=int(code_strs[2]) + code_strs[2]=cpars.code_errinfo(errcode) + RowCont=self.code_list.rowCount() + self.code_list.insertRow(RowCont) + for i in range(6): + self.code_list.setItem(RowCont,i,QTableWidgetItem(code_strs[i])) + if(errcode!=0): + self.code_list.item(RowCont,i).setBackground(Qt.GlobalColor.red) + # 滚动到底部 + def code_list_to_bottom(self): + self.code_list.scrollToBottom() + + def com_but_clicked(self): + print("com but clicked") + if(self.ser_is_open==False): + item=self.com.itemText(self.com.currentIndex()) + bsp=self.combsp.itemText(self.combsp.currentIndex()) + com=item.split(":")[0] + if(com!="utcp"): + item=com+":"+bsp + self.open_serial(item) + else: + self.close_serial() + def set_port_state(self,state:bool): + self.ser_is_open=state + if(state==True): + self.com_but.setText("关闭端口") + else: + self.com_but.setText("打开端口") + + # 修改id自增状态 + def autoinc_clicked(self): + if(self.autoinc_id==True): + self.autoinc_id=False + self.autoinc.setText("打开ID自增") + self.set_infotext("已关闭ID自增") + else: + self.autoinc_id=True + self.autoinc.setText("关闭ID自增") + self.set_infotext("已打开ID自增") + + def check_but_clicked(self): + print("send start check cmd.") + self.cmd_user(0x90,bytearray([2])) + + def posend_but_clicked(self): + print("send in place cmd.") + self.cmd_user(0x90,bytearray([3])) + + def stop_but_clicked(self): + print("send stop cmd.") + if(self.stop_state==False): + # 发送急停命令 + self.cmd_user(0x90,bytearray([0])) + self.stop_but.setText("运行") + self.stop_state=True + else: + # 发送启动命令 + self.cmd_user(0x90,bytearray([1])) + self.stop_but.setText("急停") + self.stop_state=False + + def autotest_but_clicked(self): + if(self.autotest_is_open==0): + self.autotest_but.setText("启动中...") + self.autotest_is_open=2 + self.autotest_but.setEnabled(False) + self.start_autotest() + elif(self.autotest_is_open==1): + self.autotest_but.setText("关闭中...") + self.autotest_is_open=3 + self.autotest_but.setEnabled(False) + + # 无效化编码参数设置项 + def params_active(self,power:bool): + self.dot_fat.setEnabled(power) + self.sig_list.setEnabled(power) + self.channel.setEnabled(power) + self.device_type_list.setEnabled(power) + + # 更换管壳码生成参数 + def params_changed(self,index:int): + try: + dot_fat=self.dot_fat.itemText(self.dot_fat.currentIndex()).split(":")[0].encode("utf-8") + chip_fat=b"AD" + sig_code=self.sig_list.itemText(self.sig_list.currentIndex()).encode("utf-8") + slave_num=self.channel.itemText(self.channel.currentIndex()) + self.set_params(dot_fat,chip_fat,sig_code,int(slave_num)) + except Exception as e: + pass + + # 设备类型发生了改变 + def device_type_changed(self,index:int): + device_type=self.device_type_list.itemText(index) + self.recv_handler=self.recv_handler_table[device_type] + self.set_infotext("设备已切换为:"+device_type) + + # 更换端口时关闭之前的 + def com_changed(self,index:int): + print("com changed") + self.set_infotext("串口参数有变动,将自动关闭打开的串口") + self.close_serial() + # 打开通信接口 + def open_serial(self,com:str): + if(self.ser.init(com)==True): + self.ser.recv_signal.connect(self.recv_slot) + self.ser.start_recv() + self.set_port_state(True) + print("open serial.") + self.set_infotext("打开串口成功,开始监听请求赋码指令") + else: + self.set_infotext("打开串口失败,是否有其他程序占用了串口?") + print("open serial failed.") + def close_serial(self): + try: + self.ser.recv_signal.disconnect(self.recv_slot) + except Exception as a: + pass + self.ser.close() + self.set_infotext("串口已关闭") + self.set_port_state(False) + + def recv_slot(self,cmd:int,data:bytearray,err:str): + # print("recv:","cmd:",hex(cmd),"data:",data.hex(' ')) + if(self.run_times<=0): + print("run times end.") + self.set_infotext("运行次数已结束,不再响应检测赋码指令") + return + self.run_times-=1 + if (self.recv_handler!=None): + self.recv_handler(cmd,data,err) + + # 2通道赋码设备的处理函数 + def recv_deal_coder2ch(self,cmd:int,data:bytearray,err:str): + ack=False + if(cmd==0x8b): + self.params_active(False) + self.set_infotext("已接收请求赋码命令") + self.cmd_code(self.slave_num) + elif(cmd==0x82): + self.set_infotext("已接收赋码结果") + ack=self.decode_code(data) + if(ack!=True): + print("code failed.") + self.set_infotext("赋码出现异常,本次赋码结果被丢弃,请排查异常后重试") + self.params_active(True) + elif(cmd==0x8c): + s="设备信息:{d1},{d2}".format(d1=int(data[0]),d2=data[1:].decode("utf-8")) + print(s) + self.set_infotext(s) + elif(cmd==0x8a): + self.cmd_user(0x8a,bytearray([0])) + elif(cmd==0x91): + # 输入通道状态 + print("input:channel({d1})={d2}".format(d1=int(data[0]),d2=int(data[1]))) + elif(cmd==0x92): + # 输出通道状态 + print("output:channel({d1})={d2}".format(d1=int(data[0]),d2=int(data[1]))) + + + # 批检仪的处理函数 + def recv_deal_checker(self,cmd:int,data:bytearray,err:str): + ack=False + if(cmd==0x81): + self.set_infotext("已接收检测结果") + ack=self.decode_check(data) + if(ack==True): + self.cmd_code(self.slave_num) + else: + print("check failed.") + self.set_infotext("检测出现异常,未进行赋码,请排查异常后重试") + self.cmd_moter_up() + self.params_active(True) + elif(cmd==0x82): + self.set_infotext("已接收赋码结果") + ack=self.decode_code(data) + if(ack!=True): + print("code failed.") + self.set_infotext("赋码出现异常,本次赋码结果被丢弃,请排查异常后重试") + self.cmd_moter_up() + self.params_active(True) + elif(cmd==0x37): + print("key press.") + self.params_active(False) + self.set_infotext("已接收请求检测命令") + self.cmd_moter_down() + time.sleep(2) + self.cmd_check(self.slave_num) + + # 初始化处理函数列表 + def recv_handler_table_init(self): + self.recv_handler_table={"批检仪":self.recv_deal_checker, + "赋码控制器":self.recv_deal_coder2ch} + + def run(self,times:int): + self.run_times=times*4 + self.widget.show() + ret=self.app.exec() + self.close_serial() + sys.exit(ret) + + # 生成管壳码 + def calc_shell_code(self,id:int): + shell=bytearray() + shell+=self.detonator_fat + shell+=self.date + shell+=self.signature_code + shell+="{d:05d}".format(d=id).encode("utf-8") + return shell + + # 生成n通道的注码数据 + def creat_code_data(self,id:int,num:int): + d=bytearray() + d.append(num&0xff) + d+=self.year + for i in range(num): + d.append(i&0xff) + d+=self.calc_shell_code(id+i) + return d + # 发送检测命令 + def cmd_check(self,num:int): + d=bytearray() + d.append(num&0xff) + d.append(0) + self.ser.send(1,d) + print("check start.") + # 电机上升 + def cmd_moter_up(self): + d=bytearray() + d.append(0x02) + try: + self.ser.send(0x40,d) + except Exception as e: + self.set_infotext("发送命令失败,是否没有打开串口?") + print("moter up.") + # 电机下降 + def cmd_moter_down(self): + d=bytearray() + d.append(0x03) + self.ser.send(0x40,d) + print("moter down.") + + # 发送赋码指令 + def cmd_code(self,num:int): + self.ser.send(2,self.creat_code_data(self.code_id,num)) + print("code start.") + + # 发送任意命令 + def cmd_user(self,cmd:int,data:bytearray): + try: + self.ser.send(cmd,data) + except Exception as e: + self.set_infotext("发送命令失败,是否没有打开串口?") + + # 解析检测结果 + def decode_check(self,data:bytearray): + num=data[0] + ack=True + acks_list=[] + for i in range(num): + ack_i=data[6*i+3] + str_start="" + if(ack_i!=0): + ack=False + str_start=STR_RED + print(str_start+"addr:",int(data[6*i+2]),"ack:",ack_i,STR_END) + acks_list.append(str(ack_i)) + try: + self.ch_dlog.close() + self.co_dlog.close() + except Exception as e: + pass + if(ack!=True): + self.ch_dlog=chk.check_dlog(self.widget,self.slave_num) + self.ch_dlog.ack_list_init(acks_list) + self.ch_dlog.show() + return ack + + # 解析注码结果 + def decode_code(self,data:bytearray): + num=data[0] + ack=True + code_list=[] + # 生成注码结果数据 + for i in range(num): + ack_i=data[39*i+2] + str_start="" + d=data[39*i+3:39*i+3+38] + shell_code=d[:13].decode("utf-8") + uid_code=d[13:13+16].decode("utf-8") + psw_code=d[13+16:13+16+8].decode("utf-8") + code_list.append(((i+1),ack_i,shell_code,uid_code,psw_code)) + + # 统计错误信息 + length=len(code_list) + if(len(self.code_list_lock)==0): + # 第一次失败,保存失败数据 + self.code_list_lock=code_list + else: + # 不是第一次失败,比对失败数据,把成功过的统计出来 + if (len(self.code_list_lock)>length): + self.code_list_lock=self.code_list_lock[:length] + for i in range(length): + # 长度不足的地方填充为本次的结果 + if(i>=len(self.code_list_lock)): + self.code_list_lock.append(code_list[i]) + if(self.code_list_lock[i][0]==code_list[i][0]): + if(code_list[i][1]==0): + self.code_list_lock[i]=code_list[i] + else: + if(self.code_list_lock[i][1]!=0): + self.code_list_lock[i]=code_list[i] + # 校验注码结果 + acks_list=[] + for i in self.code_list_lock: + str_start="" + ack_i=i[1] + if(ack_i!=0): + ack=False + str_start=STR_RED + print(str_start+"addr:",i[0],"ack:",ack_i,STR_END) + print("\t","shell_code:",i[2]) + print("\t","uid_code:",i[3]) + print("\t","psw_code:",i[4]) + acks_list.append(str(ack_i)) + if(ack==True): + s="" + time=get_time() + for i in self.code_list_lock: + s=time+","+str(i[0])+','+str(i[1])+','+i[2]+','+i[3]+','+i[4] + self.code_list_add(s) + with open(self.save_file,"+a") as f: + f.write(s+'\n') + self.code_list_to_bottom() + print("save to file:",self.save_file) + # 全部成功,清除错误记录 + self.code_list_lock.clear() + if(self.autoinc_id==True): + self.code_id+=self.slave_num + try: + self.co_dlog.close() + except Exception as e: + pass + if(ack!=True): + self.co_dlog=chk.check_dlog(self.widget,self.slave_num,"注码结果查看") + self.co_dlog.ack_list_init(acks_list) + self.co_dlog.show() + return ack + + def start_autotest(self): + self.thread_ = threading.Thread(target=self.autotest, args=()) + self.thread_.start() + + def autotest(self): + self.autotest_but.setText("关自动测试") + self.autotest_is_open=1 + self.autotest_but.setEnabled(True) + while(self.autotest_is_open==1): + if(self.ser_is_open!=True): + print("ser was closed,stop autotest.") + break + self.check_but_clicked() + time.sleep(3) + self.posend_but_clicked() + time.sleep(13) + self.autotest_but.setText("开自动测试") + self.autotest_is_open=0 + self.autotest_but.setEnabled(True) + + + + + + + + + + + +if __name__ == "__main__": + c=coder() + c.init(b'00',b'AD',b'A',int(cpars.code_channel_list()[0])) + c.run(10000) + diff --git a/coder_2ch/coder_params.py b/coder_2ch/coder_params.py new file mode 100644 index 0000000..4ca815a --- /dev/null +++ b/coder_2ch/coder_params.py @@ -0,0 +1,121 @@ + + + + +# 雷管厂家列表 +detonator_fat_list="""00 测试用工厂代号 +01 北京京煤化工有限公司 +04 河北卫星化工股份有限公司 +07 山西焦煤集团化工有限责任公司汾矿分公司 +08 山西金恒化工集团股份有限公司 +09 山西壶化集团股份有限公司 +10 内蒙古生力资源集团红旗化工有限公司 +12 新时代民爆(辽宁)股份有限公司 +14 葫芦岛凌河化工集团有限责任公司 +15 辽宁华丰民用化工发展有限公司 +18 长春吉阳工业有限公司 +19 黑龙江青化民爆器材有限公司 +20 黑龙江盛安民用爆破器材有限责任公司鹤岗分公司 +21 徐州雷鸣民爆器材有限公司 +22 南京理工科技化工有限责任公司 +24 浙江物产光华民爆器材有限公司 +29 福建海峡科化股份有限公司烽林分公司 +30 福建省民爆化工股份有限公司永春分公司 +34 江西新余国泰特种化工有限责任公司 +36 山东圣世达化工有限责任公司 +37 山东泰山民爆器材有限公司 +38 前进民爆股份有限公司 +44 湖北卫东化工股份有限公司 +48 湖南神斧集团向红机械化工有限责任公司 +49 湘南爆破器材有限责任公司 +52 广东宏大韶化民爆有限公司 +53 广西金建华民用爆破器材有限公司 +56 四川省宜宾威力化工有限责任公司 +57 雅化集团绵阳实业有限公司 +58 重庆顺安天力达爆破器材有限公司 +59 贵州盘江民爆有限公司 +60 贵州久联民爆器材发展股份有限公司九八四四生产分公司 +61 云南燃一有限责任公司 +64 西安庆华民用爆破器材股份有限公司 +65 甘肃久联民爆器材有限公司白银雪松分公司 +68 新疆雪峰民用爆破器材有限责任公司""" + + +def dot_fat_list(): + str_lines=detonator_fat_list.split("\n") + fat_list=[] + for line in str_lines: + s=line.split("\t") + fat_list.append(s[0]+":"+s[1]) + return fat_list + + + + + + + +# 波特率列表 +def uartbsp_list(): + ulist=["115200","57600","9600"] + return ulist + + + + +# 根据注码异常代码获取描述 +code_errinfo_list=[ + "0:成功", + "1:检测器异常", + "2:电容异常", + "3:接触异常", + "4:桥丝异常", + "5:芯片异常", + "6:未找到相关任务", + "7:过流", + "8:短路", + "193:电压设置失败", + "194:三码验证失败", + "195:UID写入失败", + "196:密码写入失败", + "197:获取UID失败", + "198:UID比对失败", + "199:锁存失败", + "200:等待接入超时", + "201:已存在其他数据" +] + +def code_errinfo(errcode:int): + for i in code_errinfo_list: + s=i.split(":") + if(int(s[0])==errcode): + return s[1] + return "未定义的错误码" + + +# 通道数 +def code_channel_list(): + ulist=["1","10","20"] + return ulist + + + +# 特征号 +def code_signature_code_list(): + code_str="ACDEFGHIJKLMNOPQRSTUVWXYZabdefghijklmnpqrty0123456789" + sig_list=[] + for i in code_str: + sig_list.append(i) + return sig_list + + + +if __name__ == "__main__": + fats=dot_fat_list() + for line in fats: + print(line) + + + + + diff --git a/coder_2ch/coder_test.py b/coder_2ch/coder_test.py new file mode 100644 index 0000000..b6d5af5 --- /dev/null +++ b/coder_2ch/coder_test.py @@ -0,0 +1,126 @@ +import serial +import serial.tools.list_ports +import threading +import time +import socket + +# 把tcp封装为串口 +class utcp: + is_open=False + def __init__(self,port:int)->None: + self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.ser.bind(("",port)) + self.ser.settimeout(10) + self.ser.listen(128) + print("wait for mcu connect.") + self.client,self.client_addr=self.ser.accept() + print("client:",self.client_addr) + self.is_open=True + def read(self,len:int): + return self.client.recv(len) + def write(self,data:bytearray): + return self.client.send(data) + def close(self): + self.client.close() + self.ser.close() + self.is_open=False + +class port: + def __init__(self) -> None: + pass + def open(self,name:str,bsp:int): + if(name!="utcp"): + self.ser = serial.Serial(port=name, baudrate=bsp,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE,timeout=None) + else: + self.ser=utcp(9527) + def start_recv(self): + self.thread_ = threading.Thread(target=self.recv, args=()) + self.thread_.start() + def recv(self,num:int): + d=bytearray() + try: + while(num>len(d)): + d+=self.ser.read(num-len(d)) + except Exception as a: + print("port closed") + return 0 + print("recv code:",d.hex(" ")) + def send(self,data:bytearray): + self.ser.write(data) + # 测试上位机 + def ecode_test(self,times:int): + print("检测赋码系统耗时测试:") + tick=0 + while(tick0): + crc=0xffff + for i in range(len-offset): + crc=(crc^data[i+offset])&0xffff + for j in range(8): + if(crc&1)!=0: + crc=((crc>>1)^0xa001)&0xffff + else: + crc=(crc>>1)&0xffff + return crc&0xff,(crc>>8)&0xff + return 0,0 + + +def crc32(data:bytearray): + temp=0 + crc=0xffffffff + i=0 + if(len(data)%4!=0): + return 0 + while(iNone: + self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.ser.bind(("",port)) + self.ser.settimeout(10) + self.ser.listen(128) + print("wait for mcu connect.") + self.client,self.client_addr=self.ser.accept() + print("client:",self.client_addr) + self.is_open=True + def read(self,len:int): + # return self.ser.recv(len) + return self.client.recv(len) + def write(self,data:bytearray): + # return self.ser.send(data) + return self.client.send(data) + def close(self): + self.client.close() + self.ser.close() + self.is_open=False + + + + + + + + + + + + + + +# 生成一个任务的参数 +def scheme_task_to_byte(j:json): + data=bytearray() + data.append(j["TaskID"]) + data.append(j["TaskIndex"]) + data.append(j["RetryCount"]) + data.append(j["ErrJumpTo"]) + data.append((j["ParamCount"]&0x0f)|(j["ReturnCount"]<<4)) + for i in j["ParamVal"]: + data.append(i&0xff) + data.append(i>>8) + return data + +# 生成任务参数序列 +def scheme_tasks_to_byte(j:json): + data=bytearray() + for i in j["TaskArray"]: + data+=scheme_task_to_byte(i) + length=len(data) + if(length<(0x700-4)): + for i in range(0x700-4-length): + data.append(0xff) + return data + +# 生成任务id序列 +def scheme_taskids_to_byte(j:json): + t=bytearray() + t.append(j["PlanID"]&0xff) + t.append((j["PlanID"]>>8)&0xff) + t.append((j["PlanID"]>>16)&0xff) + t.append((j["PlanID"]>>24)&0xff) + for i in j["TaskArray"]: + t.append(i["TaskID"]) + length=len(t) + if(length<(0x100)): + for i in range(0x100-length): + t.append(0xff) + return t + +# 根据方案生成小板用的字节数据 +def scheme_to_byte(j:json): + t=bytearray() + t+=scheme_taskids_to_byte(j) + t+=scheme_tasks_to_byte(j) + crc=crc32(t) + t.append(crc&0xff) + t.append((crc>>8)&0xff) + t.append((crc>>16)&0xff) + t.append((crc>>24)&0xff) + return t + + +# int转数组 +def arr_from_int(num:int): + return bytearray([num&0xff,(num>>8)&0xff,(num>>16)&0xff,(num>>24)&0xff]) + + +# 提取方案中的范围数据, 先max后min +def scheme_get_task_range(j:json): + t=bytearray() + t+=arr_from_int(j["TaskID"]) + t+=arr_from_int(j["TaskIndex"]) + t+=arr_from_int(j["ReturnCount"]) + t+=arr_from_int(j["ExecuteErrCode"]) + index=0 + for i in j["TestStandard"]: + t+=arr_from_int(i["Max"]) + t+=arr_from_int(i["Min"]) + if (index None: + pass + + def get_rate(self): + return self.packet_now*100//self.packet_all + def get_data(self): + if(self.stat==0): + length=len(self.data) + # 1是写,0是读 + t=bytearray([1,length&0xff,(length>>8)&0xff,(length>>16)&0xff,(length>>24)&0xff]) + t+=self.name.encode() + self.stat=1 + return t + elif(self.stat==1): + packet_bytes=200 + if(len(self.data)0): + self.packet_now+=1 + t=bytearray() + t.append(2) + t.append(self.packet_now&0xff) + t.append((self.packet_now>>8)&0xff) + t.append(self.packet_all&0xff) + t.append((self.packet_all>>8)&0xff) + t+=self.data[self.sent_bytes:self.sent_bytes+packet_bytes] + self.sent_bytes+=packet_bytes + return t + else: + print("send done.") + return bytearray() + + # 设置要发送的文件 + def set_file(self,name:str): + self.data=bytearray() + with open(name,"rb") as f: + self.data=f.read() + self.name=f.name.split('/')[-1] + self.stat=0 + self.packet_all=(len(self.data)+199)//200 + self.sent_bytes=0 + self.packet_now=0 + self.packet_bytes=200 + + # 设置要发送的方案 + def set_json(self,name:str): + self.data=bytearray() + with open(name,"rb") as f: + json_obj=json.loads(f.read()) + d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + d+=scheme_to_host(json_obj) + # print("len=",len(d),d.hex(",")) + self.data=d + self.name=f.name.split('/')[-1] + self.stat=0 + self.packet_all=(len(self.data)+199)//200 + self.sent_bytes=0 + self.packet_now=0 + self.packet_bytes=200 + + + + + + + +class protu(QObject): + # 进度信号,ip,1~100 + rate_signal =pyqtSignal([int]) + # 结束信号,ip,成败,描述 + end_signal = pyqtSignal([bool,str]) + # 接收到数据信号 + recv_signal =pyqtSignal([int,bytearray,str]) + + hand=handle() + def __init__(self) -> None: + QObject.__init__(self) + self.cmd=0 + self.cmd_no=0 + self.str_err="" + self.is_big_data=False + self.num_to_recv=0 + self.recv_data=bytearray() + def init(self,com:str): + s=com.split(":") + try: + if(s[0]=="utcp"): + self.ser = utcp(int(s[1])) + else: + bsp=int(s[1]) + self.ser = serial.Serial(port=s[0], baudrate=bsp,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE,timeout=None) + except Exception as e: + print(str(e)) + return False + return True + + def encode(self,data:bytearray): + t=bytearray() + length=len(data)+3 + t.append(0x59) + t.append(0x6d) + t.append(length&0xff) + t.append(length>>8) + t.append(self.cmd) + t.append(self.cmd_no&0xff) + t.append(self.cmd_no>>8) + t+=data + a,b=crc16(t,2,length+4) + t.append(a) + t.append(b) + # print("encode:",t.hex(",")) + return t + def decode(self,data:bytearray): + self.str_err="ok" + if(len(data)<10): + print("recv data len too less.") + self.str_err="recv data len too less." + return bytearray() + if(data[0]!=0x59 or data[1]!=0x6d or data[2]!=0x43): + # print("frame head not 0x59 0x6d.") + self.str_err="frame head not 0x59 0x6d." + return bytearray() + length=data[3]|(data[4]<<8) + if(length==65535): + # 重新设置数据长度 + length=data[7]|(data[8]<<8)|(data[9]<<16)|(data[10]<<24); + self.is_big_data=True + else: + self.is_big_data=False + if(length+7!=len(data)): + print("recv data have lossed") + self.str_err="recv data have lossed" + return bytearray() + a,b=crc16(data,3,length+5) + if(a!=data[-2] or b!=data[-1]): + print("recv data check error.h_crc=%02x %02x,crc=%02x %02x",a,b,data[-2],data[-1]) + self.str_err="recv data check error." + self.cmd_no=data[6]|(data[7]<<8) + self.cmd=data[5] + if(self.is_big_data==False): + return bytearray(data[8:-2]) + else: + return bytearray(data[12:-2]) + # 不带校验的接收函数 + def recv_(self): + while(self.ser.is_open): + try: + data=self.ser.read(500) + except Exception as a: + # print("err:",str(a)) + print("port closed") + return + if(len(data)>0): + t=self.decode(data) + if(self.str_err=="ok"): + self.recv_data+=t + # print("recv",t.hex(",")) + # print(type(self.cmd),type(t),type(self.str_err)) + self.recv_signal.emit(self.cmd,t,self.str_err) + # self.send_file_next(self.cmd,t,self.str_err) + # print("sent signal---") + else: + print(data.decode("utf-8")) + # 带帧校验的接收函数 + def recv(self): + # self.recv_signal.connect(self.send_file_next) + data=bytearray() + while(self.ser.is_open): + d=bytes() + try: + d=self.ser.read(1) + except Exception as a: + # print("err:",str(a)) + print("port closed") + return + data+=d + if(len(data)==3): + if(data[0]==0x59 and data[1]==0x6d and data[2]==0x43): + self.num_to_recv=5 + else: + data=data[1:] + self.num_to_recv=0 + elif(len(data)==5): + length=data[3]|(data[4]<<8) + if(length<65535): + self.num_to_recv+=length+2 + self.is_big_data=False + else: + self.num_to_recv=12 + self.is_big_data=True + elif(len(data)==12): + if(self.is_big_data==True): + length=data[8]|(data[9]<<8)|(data[10]<<16)|(data[11]<<24) + self.num_to_recv=5+length+2 + if(self.num_to_recv>0 and self.num_to_recv==len(data)): + t=self.decode(data) + + self.recv_data+=t + # print("recv",t.hex(",")) + self.recv_signal.emit(self.cmd,t,self.str_err) + # self.send_file_next(self.cmd,t,self.str_err) + # print("sent signal---") + data.clear() + # else: + # print("len(data)={d1},num_ro_recv={d2}".format(d1=len(data),d2=self.num_to_recv)) + def send(self,cmd:int,data:bytearray): + self.cmd=cmd + self.cmd_no+=1 + self.ser.write(self.encode(data)) + def send_str(self,txt:str): + self.ser.write(txt.encode("utf-8")) + def start_recv(self): + self.thread_ = threading.Thread(target=self.recv, args=()) + self.thread_.start() + def wait(self): + self.thread_.join() + def close(self): + try: + if(self.ser.is_open): + self.ser.close() + except Exception as e: + print(str(e)) + def send_file_next(self,cmd:int,data:bytearray,err:str): + print("send_file_next") + data=self.hand.get_data() + if(len(data)>0): + self.send(cmd,data) + else: + self.close() + def send_file(self,cmd:int,name:str): + self.start_recv() + self.hand.set_file(name) + # self.send_file_next(cmd,bytearray([0]),"ok") + self.recv_signal.emit(cmd,bytearray([0]),"ok") + self.wait() + + + + + + + + + + + +# 0x30 开始检测 +# 0x31 检测上报 +# 0x32 读写方案 +# 0x33 连接维护 +# 0x34 自检数据 +# 0x35 自检上报 +# 0x36 升级脚本 +# 0xed 主板升级 +# 0xee 小板升级 +# 0x40 电机矫正 +# 0x41 小板电阻矫正 +# 0x42 小板电阻测量 +# 0x43 小板硬件版本 + +# with open("file/judge.lua","rb") as f: +# send_file("COM5",0x36,f.name.split('/')[-1],f.read()) +# with open("file/JQ_JCXB_V54.bin","rb") as f: +# send_file("COM5",0xee,f.name.split('/')[-1],f.read()) +# with open("file/checker_ye_cfg.json","rb") as f: +# json_obj=json.loads(f.read()) + # d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + # d=scheme_to_host(json_obj) + # print("len=",len(d),d.hex(",")) + # send_file("COM5",0x32,f.name.split('/')[-1],f.read()) + + + +def int2str(num:int): + s=str(num//100) + s=s+str(num%100//10) + s=s+str(num%10) + return s + + +if __name__ == "__main__": + u=protu() + # u.init("utcp:7777") + # u.send_file(0xee,"file/JQ_JCXB_V54.bin") + # u.send_file(0xed,"../Objects/checker_gen1_app_20230602.bin") + + # 设置电阻 矫正值 + u.cmd=0x41 + data=bytearray([1,0,0x00,2,0,0x00,3,0,0x00,4,0,0x00,5,0,0x00,6,0,0x00,7,0,0x00,8,0,0x00,9,0,0x00,10,0,0x00,11,0,0x00,12,0,0x00,13,0,0x00,14,0,0x00,15,0,0x00,16,0,0x00,17,0,0x00,18,0,0x00,19,0,0x00,20,0,0x00]) + # 测量电阻 + # u.cmd=0x42 + # data=bytearray([0]) + # 设置硬件版本号 + # u.cmd=0x43 + # data=bytearray([1,50,0x00,2,51,0x00,3,52,0x00,4,53,0x00,5,54,0x00,6,55,0x00,7,56,0x00,8,57,0x00,9,58,0x00,10,59,0x00,11,60,0x00,12,61,0x00,13,62,0x00,14,63,0x00,15,64,0x00,16,65,0x00,17,66,0x00,18,67,0x00,19,68,0x00,20,69,0x00]) + # 设置电机校正值 + # u.cmd=0x40 + # data=bytearray([0x01,100,0]) + # data=bytearray([0x02]) # 上升 + # data=bytearray([0x03]) # 下降 + + print(u.encode(data).hex(' ')) + # with open("file/EX_Coder_Test_2023-07-6.json","rb") as f: + # json_obj=json.loads(f.read()) + # d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + # d+=scheme_to_host(json_obj) + + # print(int2str(20)) + # s="{d:03d}".format(d=2) + # print(s) + + # with open("file/7-15.json","rb") as f: + # u.cmd=0x22 + # p=u.encode(f.read()) + # print(p.hex(' ')) + + +# 开始检测 +# 59 6d 03 00 30 00 00 60 0f +# 结束应答 +# 59 6D 03 00 31 00 00 31 CF + + diff --git a/coder_dly/coder_pc.py b/coder_dly/coder_pc.py new file mode 100644 index 0000000..132e8c5 --- /dev/null +++ b/coder_dly/coder_pc.py @@ -0,0 +1,306 @@ + +import serial +import serial.tools.list_ports +import threading +import time +import socket + + + + + +def crc8(data:bytearray,seed:int=0xff): + poly=0x0135 + crc=seed + length=len(data) + for i in range(length): + d=data[i] + for j in range(8): + bit=(crc^d)&0x01 + crc>>= 1 + if(bit>0): + crc^=poly + crc=crc&0xff + d>>=1 + return crc + + + + + + + + + + + + + +# 把tcp封装为串口 +class utcp: + is_open=False + def __init__(self,port:int)->None: + self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.ser.bind(("",port)) + self.ser.settimeout(10) + self.ser.listen(128) + print("wait for mcu connect.") + self.client,self.client_addr=self.ser.accept() + print("client:",self.client_addr) + self.is_open=True + def read(self,len:int): + return self.client.recv(len) + def write(self,data:bytearray): + return self.client.send(data) + def close(self): + self.client.close() + self.ser.close() + self.is_open=False + + + +class port: + def __init__(self) -> None: + pass + def open(self,name:str,bsp:int): + if(name!="utcp"): + self.ser = serial.Serial(port=name, baudrate=bsp,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE,timeout=None) + else: + self.ser=utcp(9527) + def start_recv(self): + self.thread_ = threading.Thread(target=self.recv, args=()) + self.thread_.start() + def recv(self): + d=bytearray() + while(True): + try: + d+=self.ser.read(1) + except Exception as a: + # print("err:",str(a)) + print("port closed") + return 0,bytearray() + if(d[0]!=0x23): + d=d[1:] + if((len(d)>=4) and (len(d)>=((d[2]<<8)|d[3]))): + print("recv code:",d.hex(" ")) + return self.decode(d) + def send(self,type:int,data:bytearray): + print("send:",self.encode(type,data).hex(" ")) + self.ser.write(self.encode(type,data)) + def encode(self,type:int,data:bytearray): + table=b"0123456789" + d=bytearray() + d.append(0x23) + d.append(table[type]) + length=len(data)+7 + d.append((length>>8)&0xff) + d.append(length&0xff) + d+=data + d.append(crc8(d)) + d.append(0x0d) + d.append(0x0a) + return d + # 解码 返回指令类型,内容 + def decode(self,data:bytearray): + d=data[0:-3] + if(crc8(d)==data[-3]): + return d[1]-0x30,d[4:] + else: + print("crc failed.") + return 0,bytearray() + def calc_shell_code(self,id:int): + shell=bytearray() + # shell+=b"58" + shell+=b"61" + shell+=b"30815A" + shell+="{d:05d}".format(d=id).encode("utf-8") + return shell + # 打包pc到密码终端注码指令 + def pack_code_cmd(self,id_start:int,data_other:bytearray=bytearray()): + d=bytearray() + # d+=b"AD" + d+=b"A0" + d.append(0) + d.append(10) + for i in range(10): + d.append(0) + d.append(i+1) + d.append(0) + d.append(13) + leng=len(data_other) + d.append((leng>>8)&0xff) + d.append((leng&0xff)) + shell_code=self.calc_shell_code(id_start+i) + print("shell_code:",shell_code.decode("utf-8")) + d+=shell_code + d+=data_other + return d + # 打包pc到密码终端注码指令,生成uid + def pack_code2_cmd(self,id_start:int,data_other:bytearray=bytearray()): + d=bytearray() + fact_chip=b"A0" + year=b"23" + d+=fact_chip + d.append(0) + d.append(10) + for i in range(10): + d.append(0) + d.append(i+1) + d.append(0) + d.append(13) + shell_code=self.calc_shell_code(id_start+i) + uid_code=fact_chip+year+shell_code[0:2]+shell_code[3:] + leng=len(uid_code) + d.append((leng>>8)&0xff) + d.append((leng&0xff)) + leng=len(data_other) + d.append((leng>>8)&0xff) + d.append((leng&0xff)) + d+=shell_code + d+=uid_code + d+=data_other + return d + # 根据管壳码生成uid和密码 + def pack_psw_cmd(self,data:bytearray,year:bytearray=b"23"): + d=bytearray() + fact_chip=data[0:2] + num=(data[2]<<8)|data[3] + data=data[4:] + d+=fact_chip + d.append((num>>8)&0xff) + d.append(num&0xff) + for i in range(num): + index=(data[0]<<8)|data[1] + shell_len=(data[2]<<8)|data[3] + other_len=(data[4]<<8)|data[5] + shell_code=data[6:6+shell_len] + other=data[6+shell_len:6+shell_len+other_len] + # print("shell code:",shell_code.decode("utf-8")) + # print("other:",other.decode("utf-8")) + # 一位年份扩展为两位年份,需考虑计划年份与生产时年份不同的情况 + # uid为16位,包含芯片厂家代码和两位年份 + uid_code=fact_chip+year+shell_code[0:2]+shell_code[3:] + uid_len=len(uid_code) + # 默认生成的密码 + psw_code=b"12345678" + psw_len=len(psw_code) + d.append((index>>8)&0xff) + d.append(index&0xff) + d.append((shell_len>>8)&0xff) + d.append(shell_len&0xff) + d.append((uid_len>>8)&0xff) + d.append(uid_len&0xff) + d.append((psw_len>>8)&0xff) + d.append(psw_len&0xff) + d.append((other_len>>8)&0xff) + d.append(other_len&0xff) + d+=shell_code + d+=uid_code + d+=psw_code + d+=other + data=data[6+shell_len+other_len:] + return d + # 根据管壳码密码注码,生成注码结果 + def code_write(self,data:bytearray): + d=bytearray() + fact_chip=data[0:2] + num=(data[2]<<8)|data[3] + data=data[4:] + d+=fact_chip + d.append((num>>8)&0xff) + d.append(num&0xff) + for i in range(num): + index=(data[0]<<8)|data[1] + shell_len=(data[2]<<8)|data[3] + uid_len=(data[4]<<8)|data[5] + psw_len=(data[6]<<8)|data[7] + other_len=(data[8]<<8)|data[9] + shell_code=data[10:10+shell_len] + uid_code=data[10+shell_len:10+shell_len+uid_len] + psw_code=data[10+shell_len+uid_len:10+shell_len+uid_len+psw_len] + other=data[10+shell_len+uid_len+psw_len:10+shell_len+uid_len+psw_len+other_len] + ack=bytearray([0]) + ack_len=len(ack) + + print("shell_code:",shell_code.decode("utf-8")) + print("uid_code:",uid_code.decode("utf-8")) + print("psw_code:",psw_code.decode("utf-8")) + print("other:",other.decode("utf-8")) + + d.append((index>>8)&0xff) + d.append(index&0xff) + d.append((shell_len>>8)&0xff) + d.append(shell_len&0xff) + d.append((uid_len>>8)&0xff) + d.append(uid_len&0xff) + d.append((other_len>>8)&0xff) + d.append(other_len&0xff) + # d.append((ack_len>>8)&0xff) + d.append(ack_len&0xff) + d+=shell_code + d+=uid_code + d+=other + d+=ack + data=data[10+shell_len+uid_len+psw_len+other_len:] + return d + # 解析注码结果 + def code_wirte_end(self,data:bytearray): + fact_chip=data[0:2] + num=(data[2]<<8)|data[3] + data=data[4:] + print("fact_chip:",fact_chip) + print("num:",num) + for i in range(num): + index=(data[0]<<8)|data[1] + shell_len=(data[2]<<8)|data[3] + uid_len=(data[4]<<8)|data[5] + other_len=(data[6]<<8)|data[7] + ack_len=(data[8]<<8)|data[9] + shell_code=data[10:10+shell_len] + uid_code=data[10+shell_len:10+shell_len+uid_len] + other=data[10+shell_len+uid_len:10+shell_len+uid_len+other_len] + ack=data[10+shell_len+uid_len+other_len:10+shell_len+uid_len+other_len+ack_len] + + +if __name__ == "__main__": + p=port() + # p.open("com11",115200) + # print("生成透传任意指令") + # d_send=p.encode(5,b"123456789aaaddddggd") + # print(d_send.hex(" ")) + d_send=p.encode(6,b"987654321ssddffghhf") + print(d_send.hex(" ")) + # print("解析透传任意指令") + # typ,d_recv=p.decode(d_send) + # print(typ,d_recv.hex(" ")) + + print("生成管壳码注码命令") + d_send=p.encode(1,p.pack_code_cmd(987,b"asdfgk")) + print(d_send.hex(" ")) + # print("生成管壳码UID注码命令") + # d_send=p.encode(7,p.pack_code2_cmd(0,b"asdfgk")) + # print(d_send.hex(" ")) + # print("解析管壳码注码命令,生成UID密码注码命令") + # typ,d_recv=p.decode(d_send) + # d_send=p.encode(2,p.pack_psw_cmd(d_recv)) + # print(d_send.hex(" ")) + # while (True): + # typ,d_recv=p.recv() + # start = time.perf_counter() + # print("解析uid密码注码命令,生成注码结果") + # # d_send=p.encode(3,p.code_write(d_recv)) + # # print(d_send.hex(" ")) + # # time.sleep(0.1) + # if(typ==2): + # print("返回透传数据") + # p.send(6,b"sssss") + # print("发送注码成功") + # p.send(3,p.code_write(d_recv)) + # end = time.perf_counter() + # print("赋码耗时:",end-start) + # elif(typ==5): + # print("返回透传数据") + # p.send(6,b"hello world.") + # end = time.perf_counter() + # print("透传耗时:",end-start) diff --git a/mysql/mysql.py b/mysql/mysql.py new file mode 100644 index 0000000..eab10cf --- /dev/null +++ b/mysql/mysql.py @@ -0,0 +1,184 @@ +import pymysql as mysql +import datetime +from datetime import datetime, timedelta +import hashlib +import os +import sys +import quest + +def connect(): + try: + db=mysql.connect(host='124.70.178.159',user='admin',passwd='Rc5345750.',port=3306) + print("connect mysql success.") + return db + except Exception as e: + print("can not connect service.") + return None + + +# 获取北京时间 +def get_date(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y%m%d") + return utc_time + +# 获取北京时间 +def get_time(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y-%m-%d %H:%M:%S") + return utc_time + + +# 获取数据md5 +def md5(data:bytearray): + m=hashlib.md5(data).hexdigest() + # print(m) + return m + + +# 获得主板sn号 +def get_computer_sn(): + sn = os.popen("wmic bios get serialnumber").readlines() + return sn[2].strip() + + +class sql: + def __init__(self) -> None: + self.download_path="download/" + + + # 初始化返回True成功 + def init(self,table_name:str): + self.db=connect() + self.table_name=table_name + if(self.db!=None): + self.cur=self.db.cursor() + self.cur.execute("use andy_data") + self.cur.execute("select version()") + a=self.cur.fetchone() + print(a) + self.create_table(self.table_name) + return True + return False + + # 创建表 + def create_table(self,table_name:str): + cmd="""CREATE TABLE IF NOT EXISTS `{d1}`( + `id` INT UNSIGNED AUTO_INCREMENT, + `time` VARCHAR(30) NOT NULL, + `name` VARCHAR(256) NOT NULL, + `md5` VARCHAR(33) NOT NULL, + `data` MEDIUMBLOB NOT NULL, + `info` VARCHAR(512), + PRIMARY KEY ( `id` ) + )ENGINE=InnoDB DEFAULT CHARSET=utf8;""".format(d1=table_name) + + self.cur.execute(cmd) + + # 插入数据 + def insert(self,file_name:str,info:str=""): + s=file_name.split('.') + if(len(s)<2): + print("file name without type suffix,will not insert.") + return + with open(file_name,"rb") as f: + d=f.read() + md=md5(d) + lis=self.show() + if(len(lis)>0): + if(lis[-1][3]==md): + print("the same file was saved,will not insert.") + return + try: + cmd="INSERT INTO {d1} (time,name,md5,data,info) VALUES (%s,%s,%s,%s,%s);".format(d1=self.table_name) + self.db.begin() + self.cur.execute(cmd,([get_time(),file_name,md,d,info])) + self.db.commit() + print("insert file success.") + except Exception as e: + self.db.rollback() + print(str(e)) + + # 查看数据 + def show(self): + cmd= "select id,time,name,md5,info from {d1};".format(d1=self.table_name) + self.cur.execute(cmd) + a=self.cur.fetchall() + # for i in a: + # print(i[0],i[1],i[2],i[3]) + return a + + def show_tables(self): + cmd= "show tables" + self.cur.execute(cmd) + a=self.cur.fetchall() + for i in a: + print(i) + return a + + # 下载指定文件,返回文件路径 + def download(self,id:int): + if not os.path.exists(self.download_path): + os.makedirs(self.download_path) + ack,name=self.exists(id) + if(ack==True): + print("the same file is exists,will not download.") + return name + cmd="select name,data from {d1} WHERE id={d2};".format(d1=self.table_name,d2=id) + self.cur.execute(cmd) + a=self.cur.fetchall() + for i in a: + ss=i[0].replace('\\','/') + ss=ss.split('/')[-1].split('.') + name=self.download_path+ss[0]+' -'+str(id)+'.'+ss[1] + with open(name,'+bw') as f: + f.write(i[1]) + return name + print("can not find the file with id:",id) + return "" + + # 获取md5 + def get_md5(self,id:int): + cmd="select md5 from {d1} WHERE id={d2};".format(d1=self.table_name,d2=id) + self.cur.execute(cmd) + a=self.cur.fetchall()[0] + return a[0] + + # 扫描文件 + def scan_files(self): + path = self.download_path + if not os.path.exists(path): + os.makedirs(path) + list=os.listdir(path) + return list + # 判断文件是否存在 + def exists(self,id:int): + for i in self.scan_files(): + s=i.split('.')[-2].split('-')[-1] + if(int(s)==id): + with open(self.download_path+i,"rb") as f: + md=md5(f.read()) + if(md==self.get_md5(id)): + return True,i + return False,"" + + +if __name__ == "__main__": + + if(len(sys.argv)>=3): + sql_path=sys.argv[1] + sql_file=sys.argv[2] + s=sql() + if(s.init(sql_path)==True): + q=quest.quest_text("请输入本次提交的描述信息") + ack,text=q.show() + if(ack==True): + s.insert(sql_file,text) + else: + print("user cancelled.") + + + + diff --git a/mysql/quest.py b/mysql/quest.py new file mode 100644 index 0000000..e5ea70e --- /dev/null +++ b/mysql/quest.py @@ -0,0 +1,97 @@ +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +import sys +import os + + + + +# 定义询问字符文件 +QUEST_FILE = "quest_info.txt" + + +def load_info(): + if os.path.exists(QUEST_FILE): + with open(QUEST_FILE,"r") as f: + return f.read() + return "" +def save_info(text:str): + with open(QUEST_FILE,'+w') as f: + print("save:",text) + f.write(text) + +class quest_text(QObject): + def __init__(self,title:str): + QObject.__init__(self) + self.app = QApplication(sys.argv) + self.w=QDialog() + self.w.resize(800,400) + self.w.setWindowTitle(title) + self.w.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + self.w.setWindowModality(Qt.WindowModality.ApplicationModal) + self.text=load_info() + self.text_edit = QTextEdit(self.w) + self.text_edit.setObjectName(u"text") + self.text_edit.setGeometry(QRect(20, 20, 760, 320)) + self.text_edit.setFrameShape(QFrame.Shape.Box) + self.text_edit.setMidLineWidth(1) + self.text_edit.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.text_edit.setPlainText(self.text) + self.text_edit.moveCursor(QTextCursor.MoveOperation.End, QTextCursor.MoveMode.MoveAnchor) + self.ok_but_init() + self.cancel_but_init() + + def ok_but_init(self): + self.ok_but=QPushButton(self.w) + self.ok_but.setObjectName(u"ok_but") + self.ok_but.setGeometry(QRect(700, 350, 93, 28)) + self.ok_but.clicked.connect(self.ok_but_clicked) + self.ok_but.setText("确认") + self.ok_but.setCheckable(True) + self.ok_but.setChecked(True) + self.ok_state=False + + def cancel_but_init(self): + self.cancel_but=QPushButton(self.w) + self.cancel_but.setObjectName(u"cancel_but") + self.cancel_but.setGeometry(QRect(600, 350, 93, 28)) + self.cancel_but.clicked.connect(self.cancel_but_clicked) + self.cancel_but.setText("取消") + self.ok_but.setCheckable(True) + self.ok_state=False + + def ok_but_clicked(self): + self.text=self.text_edit.toPlainText() + self.ok_state=True + self.w.done(QDialog.DialogCode.Accepted) + self.w.close() + + def cancel_but_clicked(self): + self.text=self.text_edit.toPlainText() + self.ok_state=False + self.w.done(QDialog.DialogCode.Accepted) + self.w.close() + + def item_clicked(self,item:QListWidgetItem ): + self.select_item=item.text() + self.w.done(QDialog.DialogCode.Accepted) + self.w.close() + def show(self): + # if(self.w.exec()==QDialog.DialogCode.Accepted): + # return self.ok_state,self.text + self.w.show() + a=self.app.exec() + # sys.exit() + save_info(self.text) + return self.ok_state,self.text + + + + + + +if __name__=="__main__": + q=quest_text("输入本次提交的描述") + ack,text=q.show() + print("ack=",ack,"text=",text) diff --git a/ftp.py b/updata/ftp.py similarity index 100% rename from ftp.py rename to updata/ftp.py diff --git a/icon.ico b/updata/icon.ico similarity index 100% rename from icon.ico rename to updata/icon.ico diff --git a/memory_pic.py b/updata/memory_pic.py similarity index 100% rename from memory_pic.py rename to updata/memory_pic.py diff --git a/updata/mysql.py b/updata/mysql.py new file mode 100644 index 0000000..d2d663a --- /dev/null +++ b/updata/mysql.py @@ -0,0 +1,179 @@ +import pymysql as mysql +import datetime +from datetime import datetime, timedelta +import hashlib +import os + +def connect(): + try: + db=mysql.connect(host='124.70.178.159',user='admin',passwd='Rc5345750.',port=3306) + print("connect mysql success.") + return db + except Exception as e: + print("can not connect service.") + return None + + +# 获取北京时间 +def get_date(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y%m%d") + return utc_time + +# 获取北京时间 +def get_time(): + now_time = datetime.utcnow() + utc_time = now_time + timedelta(hours=8) # UTC只是比北京时间提前了8个小时 + utc_time = utc_time.strftime("%Y-%m-%d %H:%M:%S") + return utc_time + + +# 获取数据md5 +def md5(data:bytearray): + m=hashlib.md5(data).hexdigest() + # print(m) + return m + + +# 获得主板sn号 +def get_computer_sn(): + sn = os.popen("wmic bios get serialnumber").readlines() + return sn[2].strip() + + +class sql: + def __init__(self) -> None: + self.download_path="download/" + if not os.path.exists(self.download_path): + os.makedirs(self.download_path) + + + # 初始化返回True成功 + def init(self,table_name:str): + self.db=connect() + self.table_name=table_name + if(self.db!=None): + self.cur=self.db.cursor() + self.cur.execute("use andy_data") + self.cur.execute("select version()") + a=self.cur.fetchone() + print(a) + # self.create_table(self.table_name) + return True + return False + + # 创建表 + def create_table(self,table_name:str): + cmd="""CREATE TABLE IF NOT EXISTS `{d1}`( + `id` INT UNSIGNED AUTO_INCREMENT, + `time` VARCHAR(30) NOT NULL, + `name` VARCHAR(256) NOT NULL, + `md5` VARCHAR(33) NOT NULL, + `data` MEDIUMBLOB NOT NULL, + `info` VARCHAR(512), + PRIMARY KEY ( `id` ) + )ENGINE=InnoDB DEFAULT CHARSET=utf8;""".format(d1=table_name) + + self.cur.execute(cmd) + + # 插入数据 + def insert(self,file_name:str): + s=file_name.split('.') + if(len(s)<2): + print("file name without type suffix,will not insert.") + return + with open(file_name,"rb") as f: + d=f.read() + md=md5(d) + lis=self.show() + if(len(lis)>0): + if(lis[-1][3]==md): + print("the same file was saved,will not insert.") + return + try: + cmd="INSERT INTO {d1} (time,name,md5,data) VALUES (%s,%s,%s,%s);".format(d1=self.table_name) + self.db.begin() + self.cur.execute(cmd,([get_time(),file_name,md,d])) + self.db.commit() + print("insert file success.") + except Exception as e: + self.db.rollback() + print(str(e)) + + # 查看数据 + def items(self): + cmd= "select id,time,name,md5,info from {d1};".format(d1=self.table_name) + self.cur.execute(cmd) + a=self.cur.fetchall() + # for i in a: + # print(i[0],i[1],i[2],i[3]) + return a + + def show_tables(self): + cmd= "show tables" + self.cur.execute(cmd) + a=self.cur.fetchall() + # for i in a: + # print(i) + return a + + # 下载指定文件,返回文件路径 + def download(self,id:int): + ack,name=self.exists(id) + if(ack==True): + print("the same file is exists,will not download.") + return name + cmd="select name,data from {d1} WHERE id={d2};".format(d1=self.table_name,d2=id) + self.cur.execute(cmd) + a=self.cur.fetchall() + for i in a: + ss=i[0].replace('\\','/') + ss=ss.split('/')[-1].split('.') + name_prefix='.'.join(ss[:-1]) + name=self.download_path+name_prefix+'--'+str(id)+'.'+ss[-1] + with open(name,'+bw') as f: + f.write(i[1]) + return name + print("can not find the file with id:",id) + return "" + + # 获取md5 + def get_md5(self,id:int): + cmd="select md5 from {d1} WHERE id={d2};".format(d1=self.table_name,d2=id) + self.cur.execute(cmd) + a=self.cur.fetchall()[0] + return a[0] + + # 扫描文件 + def scan_files(self): + path = self.download_path + if not os.path.exists(path): + os.makedirs(path) + list=os.listdir(path) + return list + # 判断文件是否存在 + def exists(self,id:int): + for i in self.scan_files(): + s=i.split('.')[-2].split('-')[-1] + if(int(s)==id): + name=self.download_path+i + with open(name,"rb") as f: + md=md5(f.read()) + if(md==self.get_md5(id)): + return True,name + return False,"" + + +if __name__ == "__main__": + s=sql() + if(s.init("test_data")==True): + # s.insert("file\\check_result.csv") + # s.show() + # file=s.download(1) + # print("save file:",file) + s.show_tables() + + + + diff --git a/pic_2py.py b/updata/pic_2py.py similarity index 100% rename from pic_2py.py rename to updata/pic_2py.py diff --git a/updata/prottcp.py b/updata/prottcp.py new file mode 100644 index 0000000..22d3755 --- /dev/null +++ b/updata/prottcp.py @@ -0,0 +1,536 @@ +import serial +import serial.tools.list_ports +import threading +import time +import json +import socket +from PyQt5.QtCore import * + + + + + + + + + + + +def crc16(data:bytearray,offset:int,len:int): + if(len>0): + crc=0xffff + for i in range(len-offset): + crc=(crc^data[i+offset])&0xffff + for j in range(8): + if(crc&1)!=0: + crc=((crc>>1)^0xa001)&0xffff + else: + crc=(crc>>1)&0xffff + return crc&0xff,(crc>>8)&0xff + return 0,0 + + +def crc32(data:bytearray): + temp=0 + crc=0xffffffff + i=0 + if(len(data)%4!=0): + return 0 + while(iNone: + self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.ser.bind(("",port)) + self.ser.settimeout(10) + self.ser.listen(128) + print("wait for mcu connect.") + self.client,self.client_addr=self.ser.accept() + print("client:",self.client_addr) + self.is_open=True + def read(self,len:int): + # return self.ser.recv(len) + return self.client.recv(len) + def write(self,data:bytearray): + # return self.ser.send(data) + return self.client.send(data) + def close(self): + self.client.close() + self.ser.close() + self.is_open=False + + + + + + + + + + + + + + +# 生成一个任务的参数 +def scheme_task_to_byte(j:json): + data=bytearray() + data.append(j["TaskID"]) + data.append(j["TaskIndex"]) + data.append(j["RetryCount"]) + data.append(j["ErrJumpTo"]) + data.append((j["ParamCount"]&0x0f)|(j["ReturnCount"]<<4)) + for i in j["ParamVal"]: + data.append(i&0xff) + data.append(i>>8) + return data + +# 生成任务参数序列 +def scheme_tasks_to_byte(j:json): + data=bytearray() + for i in j["TaskArray"]: + data+=scheme_task_to_byte(i) + length=len(data) + if(length<(0x700-4)): + for i in range(0x700-4-length): + data.append(0xff) + return data + +# 生成任务id序列 +def scheme_taskids_to_byte(j:json): + t=bytearray() + t.append(j["PlanID"]&0xff) + t.append((j["PlanID"]>>8)&0xff) + t.append((j["PlanID"]>>16)&0xff) + t.append((j["PlanID"]>>24)&0xff) + for i in j["TaskArray"]: + t.append(i["TaskID"]) + length=len(t) + if(length<(0x100)): + for i in range(0x100-length): + t.append(0xff) + return t + +# 根据方案生成小板用的字节数据 +def scheme_to_byte(j:json): + t=bytearray() + t+=scheme_taskids_to_byte(j) + t+=scheme_tasks_to_byte(j) + crc=crc32(t) + t.append(crc&0xff) + t.append((crc>>8)&0xff) + t.append((crc>>16)&0xff) + t.append((crc>>24)&0xff) + return t + + +# int转数组 +def arr_from_int(num:int): + return bytearray([num&0xff,(num>>8)&0xff,(num>>16)&0xff,(num>>24)&0xff]) + + +# 提取方案中的范围数据, 先max后min +def scheme_get_task_range(j:json): + t=bytearray() + t+=arr_from_int(j["TaskID"]) + t+=arr_from_int(j["TaskIndex"]) + t+=arr_from_int(j["ReturnCount"]) + t+=arr_from_int(j["ExecuteErrCode"]) + index=0 + for i in j["TestStandard"]: + t+=arr_from_int(i["Max"]) + t+=arr_from_int(i["Min"]) + if (index None: + pass + + def get_rate(self): + return self.packet_now*100//self.packet_all + def get_data(self): + if(self.stat==0): + length=len(self.data) + # 1是写,0是读 + t=bytearray([1,length&0xff,(length>>8)&0xff,(length>>16)&0xff,(length>>24)&0xff]) + t+=self.name.encode() + self.stat=1 + return t + elif(self.stat==1): + packet_bytes=200 + if(len(self.data)0): + self.packet_now+=1 + t=bytearray() + t.append(2) + t.append(self.packet_now&0xff) + t.append((self.packet_now>>8)&0xff) + t.append(self.packet_all&0xff) + t.append((self.packet_all>>8)&0xff) + t+=self.data[self.sent_bytes:self.sent_bytes+packet_bytes] + self.sent_bytes+=packet_bytes + return t + else: + print("send done.") + return bytearray() + + # 设置要发送的文件 + def set_file(self,name:str): + self.data=bytearray() + with open(name,"rb") as f: + self.data=f.read() + self.name=f.name.split('/')[-1] + self.stat=0 + self.packet_all=(len(self.data)+199)//200 + self.sent_bytes=0 + self.packet_now=0 + self.packet_bytes=200 + + # 设置要发送的方案 + def set_json(self,name:str): + self.data=bytearray() + with open(name,"rb") as f: + json_obj=json.loads(f.read()) + d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + d+=scheme_to_host(json_obj) + # print("len=",len(d),d.hex(",")) + self.data=d + self.name=f.name.split('/')[-1] + self.stat=0 + self.packet_all=(len(self.data)+199)//200 + self.sent_bytes=0 + self.packet_now=0 + self.packet_bytes=200 + + + + + + + +class protu(QObject): + # 进度信号,ip,1~100 + rate_signal =pyqtSignal([int]) + # 结束信号,ip,成败,描述 + end_signal = pyqtSignal([bool,str]) + # 接收到数据信号 + recv_signal =pyqtSignal([int,bytearray,str]) + # 接收到字符串信号 + recv_str_signal =pyqtSignal([int,str,str]) + + hand=handle() + def __init__(self) -> None: + QObject.__init__(self) + self.cmd=0 + self.cmd_no=0 + self.str_err="" + self.is_big_data=False + self.num_to_recv=0 + self.recv_data=bytearray() + def init(self,com:str): + s=com.split(":") + try: + if(s[0]=="utcp"): + self.ser = utcp(int(s[1])) + else: + bsp=int(s[1]) + self.ser = serial.Serial(port=s[0], baudrate=bsp,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE,timeout=None) + except Exception as e: + print(str(e)) + return False + return True + + def encode(self,data:bytearray): + t=bytearray() + length=len(data)+3 + t.append(0x59) + t.append(0x6d) + t.append(length&0xff) + t.append(length>>8) + t.append(self.cmd) + t.append(self.cmd_no&0xff) + t.append(self.cmd_no>>8) + t+=data + a,b=crc16(t,2,length+4) + t.append(a) + t.append(b) + # print("encode:",t.hex(",")) + return t + def decode(self,data:bytearray): + self.str_err="ok" + if(len(data)<10): + print("recv data len too less.") + self.str_err="recv data len too less." + return bytearray() + if(data[0]!=0x59 or data[1]!=0x6d or data[2]!=0x43): + # print("frame head not 0x59 0x6d.") + self.str_err="frame head not 0x59 0x6d." + return bytearray() + length=data[3]|(data[4]<<8) + if(length==65535): + # 重新设置数据长度 + length=data[7]|(data[8]<<8)|(data[9]<<16)|(data[10]<<24); + self.is_big_data=True + else: + self.is_big_data=False + if(length+7!=len(data)): + print("recv data have lossed") + self.str_err="recv data have lossed" + return bytearray() + a,b=crc16(data,3,length+5) + if(a!=data[-2] or b!=data[-1]): + print("recv data check error.h_crc=%02x %02x,crc=%02x %02x",a,b,data[-2],data[-1]) + self.str_err="recv data check error." + self.cmd_no=data[6]|(data[7]<<8) + self.cmd=data[5] + if(self.is_big_data==False): + return bytearray(data[8:-2]) + else: + return bytearray(data[12:-2]) + # 不带校验的接收函数 + def recv_(self): + while(self.ser.is_open): + try: + data=self.ser.read(500) + except Exception as a: + # print("err:",str(a)) + print("port closed") + return + if(len(data)>0): + t=self.decode(data) + if(self.str_err=="ok"): + self.recv_data+=t + # print("recv",t.hex(",")) + # print(type(self.cmd),type(t),type(self.str_err)) + self.recv_signal.emit(self.cmd,t,self.str_err) + # self.send_file_next(self.cmd,t,self.str_err) + # print("sent signal---") + else: + print(data.decode("utf-8")) + # 带帧校验的接收函数 + def recv(self): + # self.recv_signal.connect(self.send_file_next) + data=bytearray() + data_str=bytearray() + while(self.ser.is_open): + d=bytes() + try: + d=self.ser.read(1) + except Exception as a: + # print("err:",str(a)) + print("port closed") + return + data+=d + data_str+=d + if(len(data)==3): + if(data[0]==0x59 and data[1]==0x6d and data[2]==0x43): + self.num_to_recv=5 + else: + data=data[1:] + self.num_to_recv=0 + elif(len(data)==5): + length=data[3]|(data[4]<<8) + if(length<65535): + self.num_to_recv+=length+2 + self.is_big_data=False + else: + self.num_to_recv=12 + self.is_big_data=True + elif(len(data)==12): + if(self.is_big_data==True): + length=data[8]|(data[9]<<8)|(data[10]<<16)|(data[11]<<24) + self.num_to_recv=5+length+2 + if(self.num_to_recv>0 and self.num_to_recv==len(data)): + t=self.decode(data) + + self.recv_data+=t + # print("recv",t.hex(",")) + self.recv_signal.emit(self.cmd,t,self.str_err) + # self.send_file_next(self.cmd,t,self.str_err) + # print("sent signal---") + data.clear() + data_str.clear() + elif(len(data_str)>=2): + if((data_str[-2]==0x0d) and (data_str[-1]==0x0a)): + data_str=data_str[:-2] + recv_str="" + try: + recv_str=data_str.decode("utf-8") + self.recv_str_signal.emit(0,recv_str,"ok") + data_str.clear() + except Exception as e: + print(str(e)) + # print(recv_str) + # else: + # print("len(data)={d1},num_ro_recv={d2}".format(d1=len(data),d2=self.num_to_recv)) + def send(self,cmd:int,data:bytearray): + self.cmd=cmd + self.cmd_no+=1 + # print("send:",data.hex(",")) + self.ser.write(self.encode(data)) + def send_str(self,txt:str): + self.ser.write(txt.encode("utf-8")) + def start_recv(self): + self.thread_ = threading.Thread(target=self.recv, args=()) + self.thread_.start() + def wait(self): + self.thread_.join() + def close(self): + try: + if(self.ser.is_open): + self.ser.close() + except Exception as e: + print(str(e)) + def send_file_next(self,cmd:int,data:bytearray,err:str): + print("send_file_next") + data=self.hand.get_data() + if(len(data)>0): + self.send(cmd,data) + else: + self.close() + def send_file(self,cmd:int,name:str): + self.start_recv() + self.hand.set_file(name) + # self.send_file_next(cmd,bytearray([0]),"ok") + self.recv_signal.emit(cmd,bytearray([0]),"ok") + self.wait() + + + + + + + + + + + +# 0x30 开始检测 +# 0x31 检测上报 +# 0x32 读写方案 +# 0x33 连接维护 +# 0x34 自检数据 +# 0x35 自检上报 +# 0x36 升级脚本 +# 0xed 主板升级 +# 0xee 小板升级 +# 0x40 电机矫正 +# 0x41 小板电阻矫正 +# 0x42 小板电阻测量 +# 0x43 小板硬件版本 + +# with open("file/judge.lua","rb") as f: +# send_file("COM5",0x36,f.name.split('/')[-1],f.read()) +# with open("file/JQ_JCXB_V54.bin","rb") as f: +# send_file("COM5",0xee,f.name.split('/')[-1],f.read()) +# with open("file/checker_ye_cfg.json","rb") as f: +# json_obj=json.loads(f.read()) + # d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + # d=scheme_to_host(json_obj) + # print("len=",len(d),d.hex(",")) + # send_file("COM5",0x32,f.name.split('/')[-1],f.read()) + + + +def int2str(num:int): + s=str(num//100) + s=s+str(num%100//10) + s=s+str(num%10) + return s + + +if __name__ == "__main__": + u=protu() + # u.init("utcp:7777") + # u.send_file(0xee,"file/JQ_JCXB_V54.bin") + # u.send_file(0xed,"../Objects/checker_gen1_app_20230602.bin") + + # 设置电阻 矫正值 + u.cmd=0x41 + data=bytearray([1,0,0x00,2,0,0x00,3,0,0x00,4,0,0x00,5,0,0x00,6,0,0x00,7,0,0x00,8,0,0x00,9,0,0x00,10,0,0x00,11,0,0x00,12,0,0x00,13,0,0x00,14,0,0x00,15,0,0x00,16,0,0x00,17,0,0x00,18,0,0x00,19,0,0x00,20,0,0x00]) + # 测量电阻 + # u.cmd=0x42 + # data=bytearray([0]) + # 设置硬件版本号 + # u.cmd=0x43 + # data=bytearray([1,50,0x00,2,51,0x00,3,52,0x00,4,53,0x00,5,54,0x00,6,55,0x00,7,56,0x00,8,57,0x00,9,58,0x00,10,59,0x00,11,60,0x00,12,61,0x00,13,62,0x00,14,63,0x00,15,64,0x00,16,65,0x00,17,66,0x00,18,67,0x00,19,68,0x00,20,69,0x00]) + # 设置电机校正值 + # u.cmd=0x40 + # data=bytearray([0x01,100,0]) + # data=bytearray([0x02]) # 上升 + # data=bytearray([0x03]) # 下降 + + print(u.encode(data).hex(' ')) + # with open("file/EX_Coder_Test_2023-07-6.json","rb") as f: + # json_obj=json.loads(f.read()) + # d=scheme_to_byte(json_obj) + # print("len=",len(d),d.hex(",")) + # d+=scheme_to_host(json_obj) + + # print(int2str(20)) + # s="{d:03d}".format(d=2) + # print(s) + + # with open("file/7-15.json","rb") as f: + # u.cmd=0x22 + # p=u.encode(f.read()) + # print(p.hex(' ')) + + +# 开始检测 +# 59 6d 03 00 30 00 00 60 0f +# 结束应答 +# 59 6D 03 00 31 00 00 31 CF + + diff --git a/updata/select_list.py b/updata/select_list.py new file mode 100644 index 0000000..708ad99 --- /dev/null +++ b/updata/select_list.py @@ -0,0 +1,52 @@ +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * + + + + + + + + + + +class select_list(QObject): + def __init__(self,father:QDialog,title:str,str_list:list): + QObject.__init__(self) + self.w=QDialog(father) + self.w.resize(800,400) + self.w.setWindowTitle(title) + self.w.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + self.w.setWindowModality(Qt.WindowModality.ApplicationModal) + + self.file_list = QListWidget(self.w) + self.file_list.setObjectName(u"str_list") + self.file_list.setGeometry(QRect(20, 20, 760, 360)) + self.file_list.setFrameShape(QFrame.Shape.Box) + self.file_list.setMidLineWidth(1) + self.file_list.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.file_list.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) + self.file_list.itemDoubleClicked.connect(self.item_clicked) + self.item_append(str_list) + + def item_append(self,items:list): + for i in items: + # print("add item",i[0]) + self.file_list.addItem(i[0]) + def item_clicked(self,item:QListWidgetItem ): + self.select_item=item.text() + self.w.done(QDialog.DialogCode.Accepted) + self.w.close() + def show(self): + # self.w.show() + if(self.w.exec()==QDialog.DialogCode.Accepted): + # print(self.select_item) + return self.select_item + return "" + + + + + + diff --git a/udp.py b/updata/udp.py similarity index 100% rename from udp.py rename to updata/udp.py diff --git a/updata.py b/updata/updata.py similarity index 89% rename from updata.py rename to updata/updata.py index cd1eda8..c19eb18 100644 --- a/updata.py +++ b/updata/updata.py @@ -14,6 +14,8 @@ import encodings.idna import base64 import memory_pic import ctypes +import mysql +import select_list ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid") STR_RED="\033[1;31m" @@ -90,8 +92,6 @@ class data_box(QObject): - - class updata_dlg(QObject): # 进度信号,ip,1~100 rate_signal =pyqtSignal([str,int]) @@ -106,6 +106,7 @@ class updata_dlg(QObject): self.widget.resize(703, 409) self.widget.setWindowTitle("批检仪程序升级") self.widget.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint) + self.addrs="" self.but_y=60 self.but_y_step=40 self.file_list_init() @@ -117,8 +118,10 @@ class updata_dlg(QObject): self.hand_but_init() self.addfile_but_init() self.scheme_but_init() + self.download_but_init() self.ip_prefix_init() self.ip_hand_init() + self.channel_init() self.widget.destroyed.connect(self.quit) self.scan_file() self.scan_slave() @@ -246,11 +249,20 @@ class updata_dlg(QObject): self.scheme_but.setToolTip("请先将要升级的方案文件发送到主板中,然后点击此按钮开始升级方案到MCU。") # self.addfile_but.setToolTipDuration(1) + # 初始化下载文件按钮 + def download_but_init(self): + self.download_but = QPushButton(self.widget) + self.download_but.setObjectName(u"download_but") + self.download_but.setGeometry(QRect(590, self.but_y, 93, 28)) + self.but_y+=self.but_y_step + self.download_but.setText("下载文件") + self.download_but.clicked.connect(self.download_but_clicked) + # ip前缀 def ip_prefix_init(self): self.ip_prefix = QLineEdit(self.widget) self.ip_prefix.setObjectName(u"ip_prefix") - self.ip_prefix.setGeometry(QRect(130, 10, 113, 21)) + self.ip_prefix.setGeometry(QRect(110, 10, 113, 21)) self.ip_prefix.setText("192.168.80") self.ip_prefix_label = QLabel(self.widget) self.ip_prefix_label.setObjectName(u"label") @@ -265,18 +277,33 @@ class updata_dlg(QObject): def ip_hand_init(self): self.ip_hand = QLineEdit(self.widget) self.ip_hand.setObjectName(u"ip_hand") - self.ip_hand.setGeometry(QRect(430, 10, 120, 21)) + self.ip_hand.setGeometry(QRect(360, 10, 120, 21)) ip=self.ip_prefix.text() self.ip_hand.setText(ip+".81") self.ip_hand_label = QLabel(self.widget) self.ip_hand_label.setObjectName(u"ip_hand_label") - self.ip_hand_label.setGeometry(QRect(300, 10, 120, 21)) + self.ip_hand_label.setGeometry(QRect(230, 10, 120, 21)) self.ip_hand_label.setText("手动添加IP地址:") self.ip_hand_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.ip_hand_label.setToolTip("如果扫描不到设备,可以尝试手动添加设备的IP地址,然后升级。") self.ip_hand.setToolTip("如果扫描不到设备,可以尝试手动添加设备的IP地址,然后升级。") # self.ip_hand_label.setToolTipDuration(1) + # 选择通道数 + def channel_init(self): + self.channel = QComboBox(self.widget) + self.channel.setObjectName(u"channel") + self.channel.setGeometry(QRect(560, 10, 100, 25)) + self.channel.setEditable(True) + self.channel.addItem("10通道") + self.channel.addItem("20通道") + self.channel.currentIndexChanged.connect(self.channel_changed) + self.channel_changed(0) + # self.channel_label = QLabel(self.widget) + # self.channel_label.setObjectName(u"label") + # self.channel_label.setGeometry(QRect(410, 16, 72, 15)) + # self.channel_label.setText("波特率:") + # 显示消息框 def show_msg(self,msg:str): m=QMessageBox(self.widget) @@ -366,6 +393,14 @@ class updata_dlg(QObject): ip=self.ip_hand.text() self.slave_list.addItem(ip+",local_id_0") + def channel_changed(self,index:int): + s=self.channel.itemText(index) + print("channel_changed,str=",s) + if(s=="10通道"): + self.addrs="1,2,3,4,5,6,7,8,9,10 " + elif(s=="20通道"): + self.addrs="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 " + print("addrs:",self.addrs) # 发送文件按钮按下 def save_but_clicked(self): print("save_but_clicked.") @@ -456,6 +491,39 @@ class updata_dlg(QObject): shutil.copy(i,path+i.split("/")[-1]) self.scan_file() + def download_but_clicked(self): + sql=mysql.sql() + if(sql.init("")): + str_list=sql.show_tables() + sel=select_list.select_list(self.widget,"选择文件目录",str_list) + path=sel.show() + # print("path:",path) + if(len(path)<=0): + print("not select any item,break.") + return + sql.table_name=path + items=sql.items() + str_list=[] + for i in items: + item_name=i[2].replace("\\","/") + item_name=item_name.split("/")[-1] + if(i[4]!=None): + s=str(i[0])+"|"+i[1]+"|"+item_name+"|"+i[4] + else: + s=str(i[0])+"|"+i[1]+"|"+item_name + # print(s) + str_list.append((s,)) + sel=select_list.select_list(self.widget,"选择文件",str_list) + item=sel.show() + # print("item:",item) + if(len(item)<=0): + print("not select any item,break.") + return + item=item.split("|") + file_name=sql.download(int(item[0])) + dst="file/"+file_name.split("/")[-1] + shutil.copy(file_name,dst) + self.scan_file() # 开始运行 def run(self): @@ -523,7 +591,8 @@ class updata_dlg(QObject): u.dst_ip_list=ip_list u.rate_signal.connect(self.rate_slot) u.end_signal.connect(self.end_slot) - updata_cmd="mcu updata 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 " + print("addrs:",self.addrs) + updata_cmd="mcu updata "+self.addrs+' ' updata_cmd+="/home/root/config/"+file cmd_list=[] cmd_list.append((updata_cmd,1,900)) @@ -536,7 +605,7 @@ class updata_dlg(QObject): u.dst_ip_list=ip_list u.rate_signal.connect(self.rate_slot) u.end_signal.connect(self.end_slot) - updata_cmd="mcu scheme 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 " + updata_cmd="mcu scheme "+self.addrs+' ' cmd_list=[] cmd_list.append((updata_cmd,1,9)) t = threading.Thread(target=u.bordcast, args=(cmd_list,)) diff --git a/updata/updata_uart.py b/updata/updata_uart.py new file mode 100644 index 0000000..9dc4613 --- /dev/null +++ b/updata/updata_uart.py @@ -0,0 +1,554 @@ + + +import sys +import os +import shutil +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +import threading +import time +import portalocker +import serial +import serial.tools.list_ports +import prottcp +import mysql +import select_list + + +STR_RED="\033[1;31m" +STR_BLUE="\033[1;34m" +STR_END="\033[0m" + + + + + +class progress_box(QObject): + + + def __init__(self) -> None: + QObject.__init__(self) + + def init(self,father:QDialog,text:str,x:int): + # print("text=",text) + self.lable = QLabel(father) + self.lable.setObjectName(u"label") + self.lable.setGeometry(QRect(40, x, 120, 15)) + self.lable.setText(text) + self.p=QProgressBar(father) + self.p.setValue(0) + self.p.setGeometry(QRect(40,x+20,450,20)) + def set_rate(self,rate:int): + # print(text) + self.p.setValue(rate) + + + +class data_box(QObject): + def __init__(self) -> None: + QObject.__init__(self) + self.select_item="" + + def init(self,father:QDialog,title:str,text:str,x:int): + # print("text=",text) + self.lable = QLabel(father) + self.lable.setObjectName(u"label") + self.lable.setGeometry(QRect(40, x, 120, 20)) + self.lable.setText(title) + self.text = QLabel(father) + self.text.setObjectName(u"text") + self.text.setGeometry(QRect(40,x+20,450,30)) + self.text.setText(text) + + + + + +class updata_dlg(QObject): + # 进度信号,ip,1~100 + rate_signal =pyqtSignal([int]) + # 结束信号,ip,成败,描述 + end_signal = pyqtSignal([bool,str]) + + failed_signal = pyqtSignal() + + def __init__(self): + QObject.__init__(self) + self.app = QApplication(sys.argv) + self.widget = QWidget() + self.widget.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + self.widget.resize(703, 409) + self.widget.setWindowTitle("赋码仪程序升级") + self.file_list_init() + self.com_but_init() + self.save_but_init() + self.updatas_but_init() + # self.cmd_but_init() + self.sstate_but_init() + self.scheme_but_init() + self.com_init() + self.combsp_init() + self.download_but_init() + self.widget.destroyed.connect(self.quit) + self.failed_signal.connect(self.updata_failed) + self.cmd=0 + self.port_is_open=False + + def quit(self): + self.close_port() + # 程序退出 + qApp.exit(1) + # 初始化文件列表 + def file_list_init(self): + self.file_list = QListWidget(self.widget) + self.file_list.setObjectName(u"file_list") + self.file_list.setGeometry(QRect(25, 60, 531, 310)) + self.file_list.setFrameShape(QFrame.Shape.Box) + self.file_list.setMidLineWidth(1) + self.file_list.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.file_list.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) + self.file_list.itemDoubleClicked.connect(self.item_clicked) + + + + # 初始化打开端口按钮 + def com_but_init(self): + self.com_but = QPushButton(self.widget) + self.com_but.setObjectName(u"com_but") + self.com_but.setGeometry(QRect(590, 10, 93, 28)) + self.com_but.setText("打开端口") + self.com_but.clicked.connect(self.com_but_clicked) + + + # 初始化发送文件按钮 + def save_but_init(self): + self.save_but = QPushButton(self.widget) + self.save_but.setObjectName(u"save_but") + self.save_but.setGeometry(QRect(590, 60, 93, 28)) + self.save_but.setText("发送文件") + self.save_but.clicked.connect(self.save_but_clicked) + + # 初始化发送命令按钮 + def cmd_but_init(self): + self.cmd_but = QPushButton(self.widget) + self.cmd_but.setObjectName(u"save_but") + self.cmd_but.setGeometry(QRect(590, 100, 93, 28)) + self.cmd_but.setText("升级MCU") + self.cmd_but.clicked.connect(self.cmd_but_clicked) + + # 初始化升级小板按钮 + def updatas_but_init(self): + self.updatas_but = QPushButton(self.widget) + self.updatas_but.setObjectName(u"updatas_but") + self.updatas_but.setGeometry(QRect(590, 100, 93, 28)) + self.updatas_but.setText("升级小板") + self.updatas_but.clicked.connect(self.updatas_but_clicked) + + # 初始化在线状态按钮 + def sstate_but_init(self): + self.sstate_but = QPushButton(self.widget) + self.sstate_but.setObjectName(u"sstate_but") + self.sstate_but.setGeometry(QRect(590, 140, 93, 28)) + self.sstate_but.setText("主板参数") + self.sstate_but.clicked.connect(self.sstate_but_clicked) + + # 初始化方案状态按钮 + def scheme_but_init(self): + self.scheme_but = QPushButton(self.widget) + self.scheme_but.setObjectName(u"scheme_but") + self.scheme_but.setGeometry(QRect(590, 180, 93, 28)) + self.scheme_but.setText("方案参数") + self.scheme_but.clicked.connect(self.scheme_but_clicked) + + # 初始化下载文件按钮 + def download_but_init(self): + self.download_but = QPushButton(self.widget) + self.download_but.setObjectName(u"download_but") + self.download_but.setGeometry(QRect(590, 220, 93, 28)) + self.download_but.setText("下载文件") + self.download_but.clicked.connect(self.download_but_clicked) + + + # com口 + def com_init(self): + self.com = QComboBox(self.widget) + self.com.setObjectName(u"com") + self.com.setGeometry(QRect(85, 10, 300, 25)) + self.com.setEditable(True) + self.com.currentIndexChanged.connect(self.com_changed) + self.com.addItem("utcp:7777") + ports_list = list(serial.tools.list_ports.comports()) + for comport in ports_list: + # print(comport.name,comport.description) + self.com.addItem(comport.name+":"+comport.description) + self.com_label = QLabel(self.widget) + self.com_label.setObjectName(u"label") + self.com_label.setGeometry(QRect(30, 16, 72, 15)) + self.com_label.setText("COM口:") + + # 选择波特率 + def combsp_init(self): + self.combsp = QComboBox(self.widget) + self.combsp.setObjectName(u"combsp") + self.combsp.setGeometry(QRect(470, 10, 80, 25)) + self.combsp.setEditable(True) + self.combsp.addItem("115200") + self.combsp.addItem("57600") + self.combsp.addItem("38400") + self.combsp.addItem("9600") + self.combsp_label = QLabel(self.widget) + self.combsp_label.setObjectName(u"label") + self.combsp_label.setGeometry(QRect(410, 16, 72, 15)) + self.combsp_label.setText("波特率:") + + # 显示消息框 + def show_msg(self,msg:str): + m=QMessageBox(self.widget) + m.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + m.setText(msg) + m.setWindowTitle("提示") + m.show() + + # 找到已选择的文件 + def get_selected_file_by_type(self,type:str): + file_list=[] + items=self.file_list.selectedItems() + for i in items: + if(i.text()[-len(type):]==type): + file_list.append(i.text()) + if(len(file_list)!=1): + self.show_msg("请选择一个并且只选择一个 "+type+" 文件") + return "" + return file_list[0] + + # 获取已选择的文件列表 + def get_selected_fils(self): + file_list=[] + items=self.file_list.selectedItems() + if(len(items)==0): + self.show_msg("请选择至少一个文件") + return [] + have_elf=False + have_bin=False + have_lua=False + for i in items: + if(i.text()[-4:]==".elf"): + if(have_elf==True): + self.show_msg("只可选择一个 .elf 文件") + return [] + have_elf=True + if(i.text()[-4:]==".bin"): + if(have_bin==True): + self.show_msg("只可选择一个 .bin 文件") + return [] + have_bin=True + if(i.text()[-4:]==".lua"): + if(have_lua==True): + self.show_msg("只可选择一个 .lua 文件") + return [] + have_lua=True + file_list.append(i.text()) + return file_list + + + + def item_clicked(self,item:QListWidgetItem ): + print("item clicked.") + print("slected item is",item.text()) + + def com_but_clicked(self): + print("com but clicked") + if(self.port_is_open==False): + self.open_port() + else: + self.close_port() + + def com_changed(self,index:int): + print("com changed") + self.close_port() + def get_cmd(self,file:str): + l=[(".bin",0xee),(".pkt",0xed),(".json",0x32)] + for i in l: + if(file.endswith(i[0])): + return i[1] + return 0 + + # 发送文件按钮按下 + def save_but_clicked(self): + print("save_but_clicked.") + path = self.getpath()+"file\\" + file_list=self.get_selected_fils() + if(len(file_list)==0): + return + self.cmd=self.get_cmd(file_list[0]) + print("cmd=",self.cmd) + w=QDialog(self.widget) + w.resize(703-150, 1*40+20) + w.setWindowTitle("上传文件") + w.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + self.handle_=prottcp.handle() + if(file_list[0].endswith(".json")): + self.handle_.set_json("file/"+file_list[0]) + else: + self.handle_.set_file("file/"+file_list[0]) + d=self.handle_.get_data() + try: + self.port.send(self.cmd,d) + except Exception as e: + print("com not open") + self.show_msg("端口未打开") + del self.handle_ + w.close() + return + self.creat_progress(w) + w.show() + # self.failed_signal.connect(w.close) + # w.destroyed.connect(self.close_port) + def updata_failed(self): + self.show_msg("打开端口失败") + + # 创建进度条 + def creat_progress(self,father:QDialog): + self.probar_list=[] + for i in range(1): + p=progress_box() + p.init(father,"发送文件",+i*40) + self.rate_signal.connect(p.set_rate) + self.probar_list.append(p) + + # 发送命令按钮按下 + def cmd_but_clicked(self): + print("cmd_but clicked.") + file=self.get_selected_file_by_type(".bin") + if(len(file)==0): + return + print("file:",file) + w=QDialog(self.widget) + w.resize(703-150, 1*40+20) + w.setWindowTitle("升级mcu") + self.updata_mcu(file) + self.creat_progress(w) + w.show() + + + def sstate_but_clicked(self): + print("sstate_but clicked.") + try: + self.port.send_str("sysinfo") + except Exception as e: + print("com not open") + print(str(e)) + + def scheme_but_clicked(self): + print("scheme_but clicked.") + try: + self.port.send_str("scheme") + except Exception as e: + print("com not open") + print(str(e)) + + def updatas_but_clicked(self): + print("updatas_but clicked.") + try: + self.port.send_str("updatas 1,2,3,4,5,6,7,8,9,10") + self.show_msg("已发送升级指令,请留意小板升级情况") + except Exception as e: + self.show_msg("命令发送失败") + print("com not open") + print(str(e)) + + def download_but_clicked(self): + sql=mysql.sql() + if(sql.init("")): + str_list=sql.show_tables() + sel=select_list.select_list(self.widget,"选择文件目录",str_list) + path=sel.show() + # print("path:",path) + if(len(path)<=0): + print("not select any item,break.") + return + sql.table_name=path + items=sql.items() + str_list=[] + for i in items: + item_name=i[2].replace("\\","/") + item_name=item_name.split("/")[-1] + if(i[4]!=None): + s=str(i[0])+"|"+i[1]+"|"+item_name+"|"+i[4] + else: + s=str(i[0])+"|"+i[1]+"|"+item_name + # print(s) + str_list.append((s,)) + sel=select_list.select_list(self.widget,"选择文件",str_list) + item=sel.show() + # print("item:",item) + if(len(item)<=0): + print("not select any item,break.") + return + item=item.split("|") + file_name=sql.download(int(item[0])) + dst="file/"+file_name.split("/")[-1] + shutil.copy(file_name,dst) + self.scan_file() + + # 开始运行 + def run(self): + self.widget.show() + sys.exit(self.app.exec()) + + def set_port_state(self,state:bool): + self.port_is_open=state + if(state==True): + self.com_but.setText("关闭端口") + else: + self.com_but.setText("打开端口") + + # 扫描文件 + def scan_file(self): + self.file_list.clear() + self.file_list.addItems(self.find_type([".bin",".json",".pkt"])) + + + # 扫描指定类型的文件 + def find_type(self,types:list): + path = self.getpath()+"file\\" + if not os.path.exists(path): + os.makedirs(path) + list=os.listdir(path) + file_list=[] + for t in types: + for i in list: + if(len(t)>0): + if(i[-len(t):]==t): + file_list.append(i) + else: + file_list.append(i) + return file_list + + # 获得文件绝对路径 + def getpath(self): + path=os.path.abspath(sys.argv[0]) + list_str=path.split("\\") + return path.replace(list_str[-1],"") + + # 调用此函数打开通信 + def open_port(self): + t = threading.Thread(target=self.com_thread, args=()) + t.start() + def com_thread(self): + self.port=prottcp.protu() + item=self.com.itemText(self.com.currentIndex()) + bsp=self.combsp.itemText(self.combsp.currentIndex()) + com=item.split(":")[0] + if(com!="utcp"): + item=com+":"+bsp + print("item text:",item) + if(self.port.init(item)==False): + print("init port failed.") + self.failed_signal.emit() + self.set_port_state(False) + return + else: + print("init port success.") + self.set_port_state(True) + self.port.recv_signal.connect(self.recv_slot) + self.port.recv_str_signal.connect(self.recv_str_slot) + self.port.start_recv() + self.port.wait() + def close_port(self): + print("close port") + self.set_port_state(False) + try: + self.port.close() + self.port.recv_signal.disconnect(self.recv_slot) + self.port.recv_str_signal.disconnect(self.recv_str_slot) + except Exception as e: + pass + def recv_str_slot(self,cmd:int,txt:str,err:str): + print("|-|",txt) + def recv_slot(self,cmd:int,data:bytearray,err:str): + # print("recv:",cmd,data) + if(self.cmd!=cmd): + return + try: + data=self.handle_.get_data() + if(len(data)>0): + self.port.send(cmd,data) + rate=self.handle_.get_rate() + self.rate_signal.emit(rate) + else: + del self.handle_ + except Exception as e: + print(str(e)) + # 开始升级mcu + def updata_mcu(self,file): + pass + + # 小板通信测试 + def comm_test(self): + pass + + + + def end_slot(self,ip,ack,err): + # print(ip,ack,err) + if(ack==False): + self.show_msg(ip+":"+err) + + def rate_slot(self,rate): + # print("rate signal:",ip,rate) + self.rate_signal.emit(rate) + + def data_slot(self,ip,text): + pass + + # 创建数据显示 + def creat_databoxs(self,father:QDialog,data_list:list): + self.datab_list=[] + for i in range(len(data_list)): + p=data_box() + p.init(father,data_list[i][0],data_list[i][1],+i*50) + self.datab_list.append(p) + + + + + + +class locker(): + def _get_lock(self): + file_name = os.path.basename(__file__) + # linux等平台依然使用标准的/var/run,其他nt等平台使用当前目录 + if os.name == "posix": + lock_file_name = f"/var/run/{file_name}.pid" + else: + lock_file_name = f"{file_name}.pid" + self.fd = open(lock_file_name, "w") + try: + portalocker.lock(self.fd, portalocker.LOCK_EX | portalocker.LOCK_NB) + # 将当前进程号写入文件 + # 如果获取不到锁上一步就已经异常了,所以不用担心覆盖 + self.fd.writelines(str(os.getpid())) + # 写入的数据太少,默认会先被放在缓冲区,我们强制同步写入到文件 + self.fd.flush() + except: + print(f"{file_name} have another instance running.") + exit(1) + + def __init__(self): + self._get_lock() + + # 和fcntl有点区别,portalocker释放锁直接有unlock()方法 + # 还是一样,其实并不需要在最后自己主动释放锁 + def __del__(self): + portalocker.unlock(self.fd) + + +if __name__ == "__main__": + lock=locker() + dlg=updata_dlg() + dlg.scan_file() + dlg.run() + +