0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ID读卡器Python小程序开发

邹振豪 来源:jf_51178285 作者:jf_51178285 2025-01-10 16:05 次阅读

液显ID读卡器UDP协议开发Python小程序。代码如下:

# pip install netifaces
import subprocess
import struct
import threading
from PyQt5.QtGui import QFont
 
import os
import socket
import re
import datetime
import netifaces
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QDateTime
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget, QMessageBox, QCheckBox
 
from SockUdpReaderPyqt5UI import Ui_Frame
from WIFISetUp import Ui_wifiwin
from NetParaSetup import Ui_NetParaWin
from ISO15693RW import Ui_ISO15693RW
 
import sys
 
Bindip = ""
Bindprot = 0
listen = 0
changip = 0
LastBuf = bytes(9)  # 保存最后接收到的信息,用于比较是否重复接收的信息
CardNuff = bytearray()  # 保存C3主动读取IC卡扇区数据
 
 
class MyDialog(QThread):  # 对话框线程
    sig = pyqtSignal(object)
 
    def run(self):
        self.sig.emit('')
 
 
class SockListenThread(QThread):  # Socket端口侦听线程
    Sock_data = pyqtSignal(int, str, bytes)  # 创建一个信号,将接收到的数据交给槽函数处理
 
    def run(self):
        global LastBuf
        global CardNuff
 
        while listen == 1:
            try:
                data, addr = s.recvfrom(1024)
                RemortIPort = '%s:%s' % addr
                self.Sock_data.emit(0, RemortIPort, data)
            except:
                self.Sock_data.emit(1, 'Socket端口侦听线程正在重启...', bytes(0))
 
 
# 读写15693标签
# =======================================================================================================================
class ISO15693RW(QWidget, Ui_ISO15693RW):
    iso15693Signel = pyqtSignal(str, bytes)
 
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.pushButton_setrwblock.clicked.connect(self.pushButton_setrwblock_clicked)
        self.pushButton_readcard.clicked.connect(self.pushButton_readcard_clicked)
        self.pushButton_writecard.clicked.connect(self.pushButton_writecard_clicked)
        mainWindow.rw15693Signel.connect(self.getrw15693inf)
 
    def open(self):
        self.show()
 
    def closeEvent(self, event):
        mainWindow.setEnabled(True)
 
    def getrw15693inf(self, code, remoiport,dispinf): #接收到主窗口更新显示的信号
        if (remoiport==self.lineEdit_RemoIPort.text().strip()):
            if (code == 1):
                self.lineEdit_RWCardno.setText(dispinf)
            elif (code == 2):
                self.plainTextEdit_Data.setPlainText(dispinf)
            elif (code == 3):
                self.lineEdit_disp.setText(dispinf)
 
    def pushButton_setrwblock_clicked(self):  # 设置15693网络读写器 主动读卡块号,未选择块号则读取UID卡号上传
        self.lineEdit_disp.setText('')
        RemoIPort = self.lineEdit_RemoIPort.text().strip()
        if (IsIport(RemoIPort) == False):
            QMessageBox.critical(self, "警告", "远程设备IP端口输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIPort.setFocus()
            return
 
        afi = self.spinBox_AFI.value()
        masklen = self.spinBox_masklen.value()
        cardmask = self.lineEdit_Mask.text().strip()
        try:
            maskbuf = bytes.fromhex(cardmask)
            if (len(maskbuf) != 8):
                QMessageBox.critical(self, "警告", "掩码必须是16位16进制数!", QMessageBox.Yes)
                self.lineEdit_Mask.setFocus()
                return
        except:
            QMessageBox.critical(self, "警告", "掩码必须是16位16进制数!", QMessageBox.Yes)
            self.lineEdit_Mask.setFocus()
            return
 
        blocks = 255  # 块数取255,表示每次更新所有参数区
 
        sendbuf = bytes([eval('0x47')])  # 1字节指令码
        sendbuf = sendbuf + bytes.fromhex('0000')  # 2字节机号 0000表示任意机
        sendbuf = sendbuf + bytes([masklen])  # 1字节掩码长度
        sendbuf = sendbuf + bytes.fromhex(cardmask)  # 8字节掩码
        sendbuf = sendbuf + bytes([afi])  # 1字节AFI
        sendbuf = sendbuf + bytes([blocks % 256]) + bytes([blocks // 256])  # 2字节的块数
 
        seleblock = ''
        j = 0
        for i in range(64):
            self.chckbox = self.findChild(QCheckBox, "checkBox%d" % (i))
            if self.chckbox.isChecked():
                seleblock = '1' + seleblock
            else:
                seleblock = '0' + seleblock
            if (len(seleblock) == 8):
                sendbuf = sendbuf + bytes([int(seleblock, 2)])
                seleblock = ''
                j = j + 1
 
        for i in range(j, 32):
            sendbuf = sendbuf + bytes([0])
 
        sendbuf = sendbuf + bytes.fromhex('55AA6699')
        self.iso15693Signel.emit(RemoIPort, sendbuf)
 
    def pushButton_readcard_clicked(self):      #发指令驱动15693读写器读指定块号数据
        self.lineEdit_disp.setText('')
        self.plainTextEdit_Data.setPlainText('')
 
        RemoIPort = self.lineEdit_RemoIPort.text().strip()
        if (IsIport(RemoIPort) == False):
            QMessageBox.critical(self, "警告", "远程设备IP端口输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIPort.setFocus()
            return
 
        sendbuf = bytes([eval('0x30')])  # 1字节指令码
        sendbuf = sendbuf + bytes.fromhex('0000')  # 2字节机号 0000表示任意机
 
        if (self.radioButton_thiscard.isChecked()):  # 读写指定卡号的卡片
            RWCardNo = self.lineEdit_RWCardno.text().strip()
            try:
                rwcardbuf = bytes.fromhex(RWCardNo)
                if (len(rwcardbuf) != 8):
                    QMessageBox.critical(self, "警告", "读写卡号必须是16位16进制数!", QMessageBox.Yes)
                    self.lineEdit_RWCardno.setFocus()
                    return
                else:
                    sendbuf = sendbuf + bytes([64]) + rwcardbuf[::-1]  # 注意传入的卡号高位在前
            except:
                QMessageBox.critical(self, "警告", "读写卡号必须是16位16进制数!", QMessageBox.Yes)
                self.lineEdit_RWCardno.setFocus()
                return
        else:  # 读写感应区上任意卡
            sendbuf = sendbuf + bytes([0]) + bytes.fromhex('0000000000000000')
 
        afi = self.spinBox_AFI.value()
        sendbuf = sendbuf + bytes([afi])  # 指定AFI
 
        seleblock = ''
        blockflaglen = 0
        blockflag = bytes()
        for i in range(64):
            self.chckbox = self.findChild(QCheckBox, "checkBox%d" % (i))
            if self.chckbox.isChecked():
                seleblock = '1' + seleblock
                blockflaglen = i + 1
            else:
                seleblock = '0' + seleblock
 
            if (len(seleblock) == 8):
                blockflag = blockflag + bytes([int(seleblock, 2)])
                seleblock = ''
 
        sendbuf = sendbuf + bytes([blockflaglen % 256]) + bytes([blockflaglen // 256])  # 2字节的块数
 
        j = (blockflaglen + 7) // 8
        sendbuf = sendbuf + blockflag[0:j]
 
        sendbuf = sendbuf + bytes.fromhex('55AA6699')
        self.iso15693Signel.emit(RemoIPort, sendbuf)
 
    def pushButton_writecard_clicked(self):     #发指令驱动15693读写器写数据到指定块内
        self.lineEdit_disp.setText('')
        writestr=self.plainTextEdit_Data.toPlainText().strip()
        if (writestr==''):
            writestr='块号:00 数据:01020304n'
            writestr =writestr+ '块号:01 数据:05060708n'
            self.plainTextEdit_Data.setPlainText(writestr)
            QMessageBox.critical(self, "警告", "请按此格式输入要写入的数据!", QMessageBox.Yes)
 
        j=0
        k=4     #一般NXP每块都是 4 个字节
        datainfostr=""
        writearray = writestr.split('n')
        for i in range(0,len(writearray)):
            if (len(writearray[i])>0):
                blockinfostr=writearray[i].split(":")
                if (len(blockinfostr)>=2):
                    block='%02X' % (int(blockinfostr[1][0:2]))
                    writedata=blockinfostr[2].strip()
                    if (i==0 and  len(writedata)==16):
                        k=8 #本次写入的是每块有 8 个字节的卡片,如富士通的MB89R118
 
                    if (len(writedata)==k*2):
                        datainfostr=datainfostr+block+writedata
                        j=j+1
                    else:
                        QMessageBox.critical(self, "警告", "第 "+block+" 块的数据不正确!", QMessageBox.Yes)
                        return
 
                    if (k==4 and j==20):
                        QMessageBox.information(self, "警告", "每块4字节的卡片,一次最多写20块,多于20块请分次写入!", QMessageBox.Yes)
                        break
 
                    if (k==8 and j==10):
                        QMessageBox.information(self, "警告", "每块8字节的卡片,一次最多写10块,多于10块请分次写入!", QMessageBox.Yes)
                        break
 
        if (j==0):
            QMessageBox.critical(self, "警告", "请按样本输入正确的写卡数据!", QMessageBox.Yes)
            return
 
        RemoIPort = self.lineEdit_RemoIPort.text().strip()
        if (IsIport(RemoIPort) == False):
            QMessageBox.critical(self, "警告", "远程设备IP端口输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIPort.setFocus()
            return
 
        sendbuf = bytes([eval('0x31')])  # 1字节指令码
        sendbuf = sendbuf + bytes.fromhex('0000')  # 2字节机号 0000表示任意机
 
        if (self.radioButton_thiscard.isChecked()):  # 读写指定卡号的卡片
            RWCardNo = self.lineEdit_RWCardno.text().strip()
            try:
                rwcardbuf = bytes.fromhex(RWCardNo)
                if (len(rwcardbuf) != 8):
                    QMessageBox.critical(self, "警告", "读写卡号必须是16位16进制数!", QMessageBox.Yes)
                    self.lineEdit_RWCardno.setFocus()
                    return
                else:
                    sendbuf = sendbuf + bytes([64]) + rwcardbuf[::-1]  # 注意传入的卡号高位在前
            except:
                QMessageBox.critical(self, "警告", "读写卡号必须是16位16进制数!", QMessageBox.Yes)
                self.lineEdit_RWCardno.setFocus()
                return
        else:  # 读写感应区上任意卡
            sendbuf = sendbuf + bytes([0]) + bytes.fromhex('0000000000000000')
 
        afi = self.spinBox_AFI.value()
        sendbuf = sendbuf + bytes([afi])  # 指定AFI
        sendbuf = sendbuf + bytes([k])    # 每块字节数,15693卡每块的字节数,大多卡为每块4个字节,富士通15693卡有一些型号是8个字节
        sendbuf = sendbuf + bytes([j])    # 本次总计写块数,如果每块4字节 一次最多可写20块, 每块8字节一次最多写10块
        sendbuf = sendbuf + bytes.fromhex(datainfostr)  # 本次写入的每块数
        sendbuf = sendbuf + bytes.fromhex('55AA6699')   #  固定的后缀
        self.iso15693Signel.emit(RemoIPort, sendbuf)
 
# 设置读卡器网络参数=========================================================================================================
class NetParaSetwindow(QWidget, Ui_NetParaWin):
    netparaSignel = pyqtSignal(str, bytes)
 
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.pushButton_computerIP.clicked.connect(self.pushButton_computerIP_clicked)
        self.pushButton_broadcast.clicked.connect(self.pushButton_broadcast_clicked)
        self.pushButton_computerMAC.clicked.connect(self.pushButton_computerMAC_clicked)
        self.pushButton_gateway.clicked.connect(self.pushButton_gateway_clicked)
        self.pushButton_gatewayMAC.clicked.connect(self.pushButton_gatewayMAC_clicked)
        self.pushButton_SetupNew.clicked.connect(self.pushButton_SetupNew_clicked)
        self.pushButton_SetupOld.clicked.connect(self.pushButton_SetupOld_clicked)
        self.radioButton_RemoMACAuto.toggled.connect(self.radioButton_RemoMACAuto_changeEvent)
        self.radioButton_Gatwayauto.toggled.connect(self.radioButton_Gatwayauto_changeEvent)
        self.pushButton_SetTCP.clicked.connect(self.pushButton_SetTCP_clicked)
        self.pushButton_SetHttp.clicked.connect(self.pushButton_SetHttp_clicked)
 
    def open(self):
        self.show()
 
    def closeEvent(self, event):
        mainWindow.setEnabled(True)
 
    def pushButton_computerIP_clicked(self):
        self.lineEdit_RemoIP.setText(mainWindow.CBIP.currentText().strip())
        self.lineEdit_RemoMAC.setText(get_mac_address(mainWindow.CBIP.currentText().strip()))
 
    def pushButton_broadcast_clicked(self):
        self.lineEdit_RemoIP.setText("255.255.255.255")
        self.lineEdit_RemoMAC.setText("FF-FF-FF-FF-FF-FF")
        self.radioButton_RemoMACAuto.setChecked(True)
        return
 
    def pushButton_computerMAC_clicked(self):
        self.lineEdit_RemoMAC.setText(get_mac_address(self.lineEdit_RemoIP.text()))
 
    def pushButton_gateway_clicked(self):
        self.lineEdit_Gatwag.setText(get_default_gateway())
        self.lineEdit_GatwayMAC.setText(get_mac_address(self.lineEdit_Gatwag.text()))
 
    def pushButton_gatewayMAC_clicked(self):
        self.lineEdit_GatwayMAC.setText(get_mac_address(self.lineEdit_Gatwag.text()))
 
    def radioButton_RemoMACAuto_changeEvent(self):
        if (self.radioButton_RemoMACAuto.isChecked()):
            self.lineEdit_RemoMAC.setText("FF-FF-FF-FF-FF-FF")
 
    def radioButton_Gatwayauto_changeEvent(self):
        if (self.radioButton_Gatwayauto.isChecked()):
            self.lineEdit_GatwayMAC.setText("FF-FF-FF-FF-FF-FF")
 
    def pushButton_SetupOld_clicked(self):  # 固件日期为2015年以前设备的网络参数设置
        self.plainTextEdit_Disp.setPlainText(" ")
 
        DevNo = int(self.lineEdit_ReaderNnm.text())
        DEvIp = self.lineEdit_ReaderIP.text()
        DevMask = self.lineEdit_ReaderMask.text()
        ServeIp = self.lineEdit_RemoIP.text()
        SerialNum = self.lineEdit_Serial.text()
 
        sdata = bytes([eval('0xF0')])  # 1字节指令码
        try:
            FieldsList = DEvIp.split('.')
            HexStr = '%02X%02X%02X%02X' % (
                int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备IP
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备IP地址输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderIP.setFocus()
            return
 
        try:
            FieldsList = DevMask.split('.')
            HexStr = '%02X%02X%02X%02X' % (
                int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备子网掩码
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备子网掩码输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderMask.setFocus()
            return
 
        try:
            FieldsList = ServeIp.split('.')
            HexStr = '%02X%02X%02X%02X' % (
                int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备远程服务器IP
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备远程服务器IP输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIP.setFocus()
            return
 
        try:
            HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备机号输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderNnm.setFocus()
            return
 
        try:
            FieldsList = SerialNum.split('-')
            HexStr = FieldsList[0] + FieldsList[1] + FieldsList[2] + FieldsList[3]  # 4字节设备网出厂序号
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备出厂序号输入错误!", QMessageBox.Yes)
            self.lineEdit_Serial.setFocus()
            return
 
        sdata = sdata + bytes([self.comboBox_beep.currentIndex()])
        if (self.checkBox.isChecked()):
            RemoIPort = "255.255.255.255:39169"
        else:
            RemoIPort = self.lineEdit_RemoIPort.text().strip()
            if (IsIport(RemoIPort) == False):
                QMessageBox.critical(self, "警告", "远程设备IP端口输入错误!", QMessageBox.Yes)
                self.lineEdit_RemoIPort.setFocus()
                return
        self.netparaSignel.emit(RemoIPort, sdata)
 
    def pushButton_SetupNew_clicked(self):  # 固件日期为2015年以后设备的网络参数设置
        self.plainTextEdit_Disp.setPlainText(" ")
        if (self.radioButton_RemoMACAuto.isChecked()):
            self.lineEdit_RemoMAC.setText("FF-FF-FF-FF-FF-FF")
 
        if (self.radioButton_Gatwayauto.isChecked()):
            self.lineEdit_GatwayMAC.setText("FF-FF-FF-FF-FF-FF")
 
        DevNo = int(self.lineEdit_ReaderNnm.text())
        DEvIp = self.lineEdit_ReaderIP.text()
        DevMask = self.lineEdit_ReaderMask.text()
        DevPort = int(self.lineEdit_ReaderPort.text())
        DevGetway = self.lineEdit_Gatwag.text()
        GetwayMac = self.lineEdit_GatwayMAC.text()
        ServeIp = self.lineEdit_RemoIP.text()
        ServerMac = self.lineEdit_RemoMAC.text()
        SerialNum = self.lineEdit_Serial.text()
 
        sdata = bytes([eval('0xF9')])  # 1字节指令码
        try:
            FieldsList = DEvIp.split('.')
            HexStr = '%02X%02X%02X%02X' % (
                int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备IP
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备IP地址输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderIP.setFocus()
            return
 
        try:
            FieldsList = DevMask.split('.')
            HexStr = '%02X%02X%02X%02X' % (
                int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备子网掩码
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备子网掩码输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderMask.setFocus()
            return
 
        try:
            FieldsList = ServeIp.split('.')
            HexStr = '%02X%02X%02X%02X' % (
                int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备远程服务器IP
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备远程服务器IP输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIP.setFocus()
            return
 
        try:
            FieldsList = ServerMac.split('-')
            HexStr = FieldsList[0] + FieldsList[1] + FieldsList[2] + FieldsList[3] + FieldsList[4] + FieldsList[
                5]  # 6字节设备远程服务器MAC
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备远程服务器MAC输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoMAC.setFocus()
            return
 
        try:
            FieldsList = DevGetway.split('.')
            HexStr = '%02X%02X%02X%02X' % (
                int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备网关
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备网关IP输入错误!", QMessageBox.Yes)
            self.lineEdit_Gatwag.setFocus()
            return
 
        try:
            FieldsList = GetwayMac.split('-')
            HexStr = FieldsList[0] + FieldsList[1] + FieldsList[2] + FieldsList[3] + FieldsList[4] + FieldsList[
                5]  # 6字节设备网关MAC
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备网关MAC输入错误!", QMessageBox.Yes)
            self.lineEdit_GatwayMAC.setFocus()
            return
 
        try:
            HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备机号输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderNnm.setFocus()
            return
 
        try:
            HexStr = '%02X%02X' % (DevPort % 256, DevPort // 256)  # 2字节端口号
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备端口输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderPort.setFocus()
            return
 
        try:
            FieldsList = SerialNum.split('-')
            HexStr = FieldsList[0] + FieldsList[1] + FieldsList[2] + FieldsList[3]  # 4字节设备网出厂序号
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "设备出厂序号输入错误!", QMessageBox.Yes)
            self.lineEdit_Serial.setFocus()
            return
 
        searchcode = self.comboBox_beep.currentIndex()
        if (self.radioButton_RemoMACAuto.isChecked()):
            searchcode = searchcode + 2
        if (self.radioButton_Gatwayauto.isChecked()):
            searchcode = searchcode + 4
        if (self.checkBox_DHCP.isChecked()):
            searchcode = searchcode + 8
        if (self.comboBox_SendEn.currentIndex() == 1):
            searchcode = searchcode + 16
        searchcode = searchcode + self.comboBox_Sendinterval.currentIndex() * 32
        sdata = sdata + bytes([searchcode])
 
        sdata = sdata + bytes.fromhex('55AA6699')
 
        if (self.checkBox.isChecked()):
            RemoIPort = "255.255.255.255:39169"
        else:
            RemoIPort = self.lineEdit_RemoIPort.text().strip()
            if (IsIport(RemoIPort) == False):
                QMessageBox.critical(self, "警告", "远程设备IP端口输入错误!", QMessageBox.Yes)
                self.lineEdit_RemoIPort.setFocus()
                return
        self.netparaSignel.emit(RemoIPort, sdata)
 
    def pushButton_SetTCP_clicked(self):  # 设置TCP协议读卡器 远程服务器侦听端口
        self.plainTextEdit_Disp.setPlainText('')
 
        RemoIPort = self.lineEdit_RemoIPort.text().strip()
        if (IsIport(RemoIPort) == False):
            QMessageBox.critical(self, "警告", "远程设备IP端口输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIPort.setFocus()
            return
 
        sdata = bytes([eval('0x1D')])  # 1字节指令码
        sdata = sdata + bytes.fromhex("0000075C04")
 
        DevPort = int(self.lineEdit_ReaderPort.text())
        try:
            HexStr = '%02X%02X' % (DevPort % 256, DevPort // 256)  # 2字节端口号
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "读卡器通讯端口输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderPort.setFocus()
            return
 
        DevPort = int(self.lineEdit_TCPRemoPort.text())
        try:
            HexStr = '%02X%02X' % (DevPort % 256, DevPort // 256)  # 2字节端口号
            sdata = sdata + bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "服务器TCP通讯端口输入错误!", QMessageBox.Yes)
            self.lineEdit_TCPRemoPort.setFocus()
            return
        sdata = sdata + bytes([sdata[6] ^ sdata[7] ^ sdata[8] ^ sdata[9]])
        sdata = sdata + bytes.fromhex("55AA6699")
        self.netparaSignel.emit(RemoIPort, sdata)
 
    def pushButton_SetHttp_clicked(self):  # 设置HTTP协议读卡器数据传送方式、服务端侦听端口 及 访问文件
        self.plainTextEdit_Disp.setPlainText('')
 
        RemoIPort = self.lineEdit_RemoIPort.text().strip()
        if (IsIport(RemoIPort) == False):
            QMessageBox.critical(self, "警告", "远程设备IP端口输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIPort.setFocus()
            return
 
        filename = self.lineEdit_filename.text().strip()
        filenamebuf = bytes(filename, encoding='gbk')
        filelen = len(filenamebuf)
        if (filelen == 0 or filelen > 252):
            QMessageBox.critical(self, "警告", "访问文件不可以为空,文件长度也不可以>252!", QMessageBox.Yes)
            self.lineEdit_filename.setFocus()
            return
        if (filename[0:1] == '/'):
            QMessageBox.critical(self, "警告", "访问文件首字符不可以为: /", QMessageBox.Yes)
            self.lineEdit_filename.setFocus()
            return
        if (filename[0:4] == 'http'):
            QMessageBox.critical(self, "警告", "访问文件无需带域名!", QMessageBox.Yes)
            self.lineEdit_filename.setFocus()
            return
 
        DevPort = int(self.lineEdit_HttpRemoPort.text())
        try:
            HexStr = '%02X%02X' % (DevPort % 256, DevPort // 256)  # 2字节端口号
            PortBuf = bytes.fromhex(HexStr)
        except:
            QMessageBox.critical(self, "警告", "读卡器通讯端口输入错误!", QMessageBox.Yes)
            self.lineEdit_ReaderPort.setFocus()
            return
 
        sdata = bytes([eval('0x1D')])  # 1字节指令码
        sdata = sdata + bytes.fromhex("0000")  # 2字节机号 00表示任意机号
        sdata = sdata + bytes([filelen + 7])
        sdata = sdata + bytes([91])  # 设定HTTP协议的文件路径、上传方式  标识
        sdata = sdata + bytes([filelen + 4])
        sdata = sdata + bytes([self.comboBox_Sendmodel.currentIndex()])  # 提交方式
        sdata = sdata + bytes([255])
        sdata = sdata + PortBuf  # 服务器侦听端口
        sdata = sdata + filenamebuf  # 访问文件
 
        crc = sdata[6] ^ sdata[7] ^ sdata[8] ^ sdata[9]
        for num in range(0, len(filenamebuf)):
            crc = crc ^ filenamebuf[num]
 
        sdata = sdata + bytes([crc])
        sdata = sdata + bytes.fromhex("55AA6699")
 
        self.netparaSignel.emit(RemoIPort, sdata)
 
 
# 设置读卡器WIFI热点========================================================================================================
class WifiSetWindow(QWidget, Ui_wifiwin):
    WifiSignel = pyqtSignal(int, str, bytes)  # 创建一个信号,向主窗口请求发送对应的指令
 
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("WIFI热点参数设置")
        self.radioButton_DHCP.toggled.connect(self.radioButton_DHCP_changeEvent)
        self.pushButton_SetUp.clicked.connect(self.pushButton_SetUp_click)
        self.pushButton_Read.clicked.connect(self.pushButton_Read_click)
 
    def open(self):
        self.show()
 
    def closeEvent(self, event):
        mainWindow.setEnabled(True)
 
    def radioButton_DHCP_changeEvent(self):
        if (self.radioButton_DHCP.isChecked()):
            self.groupBox.setVisible(False)
        else:
            self.groupBox.setVisible(True)
 
    def pushButton_SetUp_click(self):  # 设置WIFI热点名称、密码、WIFIIP及数据传送方式
        self.plainTextEdit.setPlainText(" ")
        RemoIPort = self.lineEdit_RemoIPort.text().strip()
        if (IsIport(RemoIPort) == False):
            QMessageBox.critical(self, "警告", "设备有线IP端口输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIPort.setFocus()
            return
 
        wifiname = bytes(self.lineEdit_SSID.text().strip(), encoding='utf8')
        namelen = len(wifiname)
        if (namelen > 60):
            self.plainTextEdit.setPlainText("热点名称长度不可以大于60字节!")
            return
        wifipass = bytes(self.lineEdit_Password.text().strip(), encoding='utf8')
        passlen = len(wifipass)
        if (passlen > 64):
            self.plainTextEdit.setPlainText("WIFI密钥长度不可以大于64字节!")
            return
 
        comb = bytes([eval('0xF7')])  # F7是指令码
        comb = comb + bytes.fromhex('0000')  # 2字节机号
        comb = comb + bytes([namelen])  # 1字节热点名称长度
        if self.checkBox.isChecked():
            comb = comb + bytes([passlen])  # 1字节密码长度
        else:
            comb = comb + bytes([0])  # 1字节密码长度
        comb = comb + wifiname  # 热点名称
        for num in range(namelen, 60):  # 热点名称长度不足60,占位符
            comb = comb + bytes([0])
 
        comb = comb + wifipass  # WiFI密码
        for num in range(passlen, 64):  # WiFI密码长度不足64,占位符
            comb = comb + bytes([0])
 
        if (self.radioButton_DHCP.isChecked()):  # wifi的IP是DHCP自动分配
            comb = comb + bytes([0])
            comb = comb + bytes.fromhex('000000000000000000000000')
        else:  # wifi的IP是静态绑定
            wifiip = GetHexIPAdd(self.lineEdit_IP.text())
            if (wifiip == '00000000'):
                self.plainTextEdit.setPlainText("WIFI的IP地址输入错误!")
                self.lineEdit_IP.setFocus()
                return
 
            wifimask = GetHexIPAdd(self.lineEdit_mask.text())
            if (wifiip == '00000000'):
                self.plainTextEdit.setPlainText("WIFI的掩码地址输入错误!")
                self.lineEdit_mask.setFocus()
                return
 
            wifigetway = GetHexIPAdd(self.lineEdit_gateway.text())
            if (wifiip == '00000000'):
                self.plainTextEdit.setPlainText("WIFI的掩码地址输入错误!")
                self.lineEdit_gateway.setFocus()
                return
            comb = comb + bytes([1])
            comb = comb + bytes.fromhex(wifiip)
            comb = comb + bytes.fromhex(wifimask)
            comb = comb + bytes.fromhex(wifigetway)
 
        comb = comb + bytes([self.comboBox_Sendmode.currentIndex()])
        comb = comb + bytes.fromhex('55AA6699')  # 指令结束码,抗网络上的干扰信号
 
        self.WifiSignel.emit(1, RemoIPort, comb)  # 发送信号,主窗口接收到信号后,触发主窗口槽函数发送指令
 
    def pushButton_Read_click(self):  # 查询WIFI连接状态
        self.plainTextEdit.setPlainText(" ")
        RemoIPort = self.lineEdit_RemoIPort.text().strip()
        if (IsIport(RemoIPort) == False):
            QMessageBox.critical(self, "警告", "设备有线IP端口输入错误!", QMessageBox.Yes)
            self.lineEdit_RemoIPort.setFocus()
            return
 
        comb = bytes.fromhex("A40000")
        global LastBuf
        LastBuf = bytes(9)
        self.WifiSignel.emit(1, RemoIPort, comb)  # 发送信号,主窗口接收到信号后,触发主窗口槽函数发送指令
 
 
# 主窗口,侦听网络端口获取刷卡信息、向读卡器发送显示、响声、语音=====================================================================
class MainWindow(QtWidgets.QMainWindow, Ui_Frame):
    rw15693Signel = pyqtSignal(int, str,str)
 
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
 
        self.PBSearch.clicked.connect(self.PBSearch_click)
        self.PBClear.clicked.connect(self.PBClear_click)
        self.CBIP.currentIndexChanged.connect(self.CBIP_selectionchange)
        self.PBSendDispBeep.clicked.connect(self.PBSendDispBeep_click)
        self.PBEditpara.clicked.connect(self.PBEditpara_click)
        self.tableWidget.doubleClicked.connect(self.table_doubleClick)
        self.PBSwitchOn.clicked.connect(self.PBSwitchOn_click)
        self.PBSwitchOff.clicked.connect(self.PBSwitchOff_click)
        self.PBSendDispSpk.clicked.connect(self.PBSendDispSpk_click)
        self.PBSendDispTTS.clicked.connect(self.PBSendDispTTS_click)
        self.PBReadCard.clicked.connect(self.PBReadCard_click)
        self.PBWriteCard.clicked.connect(self.PBWriteCard_click)
        self.PBChangeKey.clicked.connect(self.PBChangeKey_click)
        self.PBSetRW.clicked.connect(self.PBSetRW_click)
        self.PBWifiSet.clicked.connect(self.PBWifiSet_click)
        self.PBGetmodel.clicked.connect(self.PBGetmodel_click)
        self.PB15693RW.clicked.connect(self.PB15693RW_click)
 
    def Getiso15693Signal(self, remortiport, sdata):
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        s.sendto(sdata, (Remoip, Reprot))  # 发送设置WIFI参数的指令
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def GetWiFiWindoSignal(self, sigcode, remortiport, sdata):
        if (sigcode == 1):  # 设置WIFI叁数的信号
            FieldsList = remortiport.split(':')
            Remoip = FieldsList[0]
            Reprot = int(FieldsList[1])
 
            s.sendto(sdata, (Remoip, Reprot))  # 发送设置WIFI参数的指令
 
            SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[
                                               0:22] + ' Data:'  # 为方便开发,打印出详细的指令
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.ListAddItem(SendInf)
 
    def GetNetParaSetSignal(self, remortiport, sdata):
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
 
        s.sendto(sdata, (Remoip, Reprot))  # 发送设置WIFI参数的指令
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def SockGetData(self, dispcode, RemortIPort, data):
        global LastBuf
        global CardNuff
 
        if (dispcode == 0):
            self.textEdit_7.setText(RemortIPort)
            DispStr = get_time() + 'FromIP:' + (RemortIPort + '                      ')[0:22] + ' Data:'
            for num in range(0, len(data)):
                DispStr = DispStr + '%02X ' % (data[num])
            self.ListAddItem(DispStr)
 
        if (len(data) > 8):
            if (data[0] == LastBuf[0] and data[1] == LastBuf[1] and data[2] == LastBuf[2] and data[3] ==
                    LastBuf[3] and data[4] == LastBuf[4] and data[5] == LastBuf[5] and data[6] == LastBuf[6] and
                    data[7] == LastBuf[7] and data[8] == LastBuf[8]):  # 比较是否是重发数据
                exit  # 是设备重发的数据,直接丢弃不做处理
            else:
                LastBuf = data[0:9]  # 将接收到的信息保存,用于下次接收数据时比对
 
                if (data[0] == eval('0xF2')):  # 接收到设备开机、搜索在线设备的返回信息,对信息解析
                    DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])
                    DevMask = '%d.%d.%d.%d' % (data[5], data[6], data[7], data[8])
                    DevPort = '%d' % (data[9] + data[10] * 256)
                    DevNo = '%05d' % (data[11] + data[12] * 256)
                    DevGetway = '%d.%d.%d.%d' % (data[13], data[14], data[15], data[16])
                    GetwayMac = ''
                    for num in range(17, 23):
                        GetwayMac = GetwayMac + '%02X' % (data[num])
                        if (num < 22):
                            GetwayMac = GetwayMac + '-'
                    ServeIp = '%d.%d.%d.%d' % (data[23], data[24], data[25], data[26])
                    ServerMac = ''
                    for num in range(27, 33):
                        ServerMac = ServerMac + '%02X' % (data[num])
                        if (num < 32):
                            ServerMac = ServerMac + '-'
 
                    Search = '%02X' % (data[33])
                    Beep = ('00000000' + bin(data[34])[2:])[-8:]
 
                    DevMac = '16-88-'
                    for num in range(35, 39):
                        DevMac = DevMac + '%02X' % (data[num])
                        if (num < 38):
                            DevMac = DevMac + '-'
                    SerialNum = ''
                    HCMac = ''
                    if (len(data) > 39):
                        for num in range(39, len(data)):
                            SerialNum = SerialNum + '%02X' % (data[num])
 
                            if (num < 45):
                                HCMac = '%02X' % (data[num]) + HCMac
                                if (num < 44):
                                    HCMac = '-' + HCMac
 
                    rowPosition = self.tableWidget.rowCount()
                    self.tableWidget.insertRow(rowPosition)
                    NewItem = QtWidgets.QTableWidgetItem(DevNo)
                    self.tableWidget.setItem(rowPosition, 0, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(DEvIp)
                    self.tableWidget.setItem(rowPosition, 1, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(DevMask)
                    self.tableWidget.setItem(rowPosition, 2, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(DevPort)
                    self.tableWidget.setItem(rowPosition, 3, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(DevGetway)
                    self.tableWidget.setItem(rowPosition, 4, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(GetwayMac)
                    self.tableWidget.setItem(rowPosition, 5, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(ServeIp)
                    self.tableWidget.setItem(rowPosition, 6, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(ServerMac)
                    self.tableWidget.setItem(rowPosition, 7, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(Search)
                    self.tableWidget.setItem(rowPosition, 8, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(Beep)
                    self.tableWidget.setItem(rowPosition, 9, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(DevMac[6:17])
                    self.tableWidget.setItem(rowPosition, 10, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(DevMac)
                    self.tableWidget.setItem(rowPosition, 11, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(SerialNum)
                    self.tableWidget.setItem(rowPosition, 12, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem(HCMac)
                    self.tableWidget.setItem(rowPosition, 13, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem('                     ')
                    self.tableWidget.setItem(rowPosition, 14, NewItem)
                    NewItem = QtWidgets.QTableWidgetItem('            ')
                    self.tableWidget.setItem(rowPosition, 15, NewItem)
                    self.tableWidget.resizeColumnsToContents()
 
                    self.textEdit_8.setText(DevNo)
                    dispinf = '数据解析:设备响应搜索指令、开机标识:F2,设备信息已在表格内显示,如需修改设备网络参数,先在表格内点击要修改的设备再点击 "修改选定设备的网络参数" 键!'
                    self.textEdit_9.setText(dispinf)
 
                elif (data[0] == eval('0xF3')):  # 接收到设备的心跳数据包,设备心跳间隔可根据协议自行设置
                    DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])
 
                elif (data[0] == eval('0xC1') or data[0] == eval('0xD1')):  # 接收到读取IC、ID卡信息的数据包,对信息解析
                    self.DisableSendAge(RemortIPort, data)
 
                    FunCode = '%02X' % (data[0])
                    DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])  # 设备IP
                    DevNo = '%05d' % (data[5] + data[6] * 256)  # 机号
                    FrameNo = '%d' % (data[7] + data[8] * 256)  # 数据包序号
                    SerialNum = ''  # 设备硬件序列号
                    for num in range(14, len(data)):
                        SerialNum = SerialNum + '%02X' % (data[num])
 
                    if (data[0] == eval('0xC1')):
                        Card16H = '%02X%02X%02X%02X' % (data[10], data[11], data[12], data[13])  # 原始16进制卡号
                        Cardno = data[10]
                        Cardno = Cardno + (data[11] * 256)
                        Cardno = Cardno + (data[12] * 65536)
                        Cardno = Cardno + (data[13] * 16777216)
                        CardnoStr = '%010d' % Cardno  # 转10进制卡号
                        dispinf = '数据解析:读IC卡号标识:'
                    else:
                        Card16H = '%02X%02X%02X%02X' % (data[9], data[10], data[11], data[12])  # 原始16进制卡号
                        Cardno = data[9]
                        Cardno = Cardno + (data[10] * 256)
                        Cardno = Cardno + (data[11] * 65536)
                        Cardno = Cardno + (data[12] * 16777216)
                        CardnoStr = '%010d' % Cardno  # 转10进制卡号
                        dispinf = '数据解析:读ID卡号标识:'
 
                    dispinf = dispinf + FunCode + ',设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H + " 转10进制卡号:" + CardnoStr + ",硬件序列号:" + SerialNum
                    self.textEdit_9.setText(dispinf)
                    self.textEdit_8.setPlainText(DevNo)
                    self.textEdit_3.setText(Card16H)
                    self.PBSendDispBeep_click()
 
                elif (data[0] == eval('0xC3')):  # 全扇区读写器收到读卡扇区内的数据(刷卡时主动读取并上传)
                    j = data[10] * 48
                    m = data[11] * 48
 
                    for num in range(0, m):  # 将读取到的扇区信息存入读卡缓冲
                        CardNuff.append(data[16 + num])
 
                    if (data[11] + data[10] >= data[
                        9]):  # 已完全收到所有包数据,一个数据包最多传4个扇区的数据,如果读写器设备读写扇区数大于4,数据要分2个包上传,扇区数大于8要分3个包,大与12要分4个包上传
                        FunCode = '%02X' % (data[0])
                        DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])
                        DevNo = '%05d' % (data[5] + data[6] * 256)  # 机号
                        FrameNo = '%d' % (data[7] + data[8] * 256)  # 数据包序号
                        Card16H = '%02X%02X%02X%02X' % (data[12], data[13], data[14], data[15])  # 原始16进制卡号
                        dispinf = '数据解析:读IC卡扇区标识:' + FunCode + ',设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H + ",读卡信息已在扇区数据栏显示!"
                        self.textEdit_9.setText(dispinf)
 
                        m = data[9] * 48
                        CardInfStr = ''
                        for num in range(0, m):
                            CardInfStr = CardInfStr + '%02X ' % (CardNuff[num])
                        self.textEdit_5.setPlainText(CardInfStr)
 
                        CardNuff = bytearray()  # 已接收完,清空接收缓冲
                        self.textEdit_3.setText(Card16H)
 
                elif (data[0] == eval('0xC5')):  # 指定区号、密码读卡返回信息
                    FunCode = '%02X' % (data[0])
                    DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])  # 设备IP
                    DevNo = '%05d' % (data[5] + data[6] * 256)  # 机号
                    SectNum = data[7]  # 扇区总数
                    Card16H = '%02X%02X%02X%02X' % (data[8], data[9], data[10], data[11])
                    Sectors = data[12]  # 扇区号
                    dispinf = '数据解析:读IC卡扇区标识:' + FunCode + ',设备IP:' + DEvIp + ',机号:' + DevNo + ",16进制卡号:" + Card16H
                    if (data[13] == 0):
                        CardInfStr = ''
                        for num in range(0, 48):
                            CardInfStr = CardInfStr + '%02X ' % (data[14 + num])
                        dispinf = dispinf + ",读取 " + str(Sectors) + " 扇区数据成功!"
                        self.textEdit_9.setText(dispinf)
                        self.textEdit_8.setText(DevNo)
                        self.textEdit_3.setText(Card16H)
                        self.textEdit_5.setPlainText(CardInfStr)
                    else:
                        if (data[13] == 12):
                            dispinf = dispinf + ",卡密码认证失败!本次读卡失败!"
                            self.textEdit_9.setText(dispinf)
                        else:
                            dispinf = dispinf + ",读卡失败,错误代码:%02X" % (data[13])
                            self.textEdit_9.setText(dispinf)
 
                elif (data[0] == eval('0xCD')):  # 响应写卡、更改卡密码后的返回信息
                    FunCode = '%02X' % (data[0])
                    DEvIp = '%d.%d.%d.%d' % (data[2], data[3], data[4], data[5])  # 设备IP
                    DevNo = '%05d' % (data[6] + data[7] * 256)  # 机号
                    SectNum = data[8]  # 扇区总数
                    Card16H = '%02X%02X%02X%02X' % (data[9], data[10], data[11], data[12])  # 原始16进制卡号
                    Sectors = data[13]  # 扇区号
                    dispinf = '数据解析:写IC卡扇区标识:' + FunCode + ',设备IP:' + DEvIp + ',机号:' + DevNo + ",16进制卡号:" + Card16H
                    if (data[1] == 0x3A):
                        if (data[14] == 0x00):
                            dispinf = dispinf + ',更改卡密码成功!'
                        elif (data[14] == 0x0C):
                            dispinf = dispinf + ',卡密码认证失败,更改卡密码失败!'
                        else:
                            dispinf = dispinf + ',更改卡密码失败,错误代码:%02X' % (data[14])
                    else:
                        if (data[1] == 0x3D):
                            if (data[14] == 0x00):
                                dispinf = dispinf + ',写卡成功!'
                            elif (data[14] == 0x0C):
                                dispinf = dispinf + ',卡密码认证失败,写卡失败!'
                            else:
                                dispinf = dispinf + ',写卡失败,错误代码:%02X' % (data[14])
                    self.textEdit_9.setText(dispinf)
 
                elif (data[0] == eval('0xCF') or data[0] == eval('0xDF')):  # 接收到IC、ID卡离开读卡器感应区的信息
                    # DisableSendAge(data, addr)
                    FunCode = '%02X' % (data[0])
                    DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])  # 设备IP
                    DevNo = '%05d' % (data[5] + data[6] * 256)  # 机号
                    FrameNo = ':%d' % (data[7] + data[8] * 256)  # 数据包序号
                    Card16H = '%02X%02X%02X%02X' % (data[11], data[12], data[13], data[14])  # 原始16进制卡号
                    Cardno = data[11]
                    Cardno = Cardno + (data[12] * 256)
                    Cardno = Cardno + (data[13] * 65536)
                    Cardno = Cardno + (data[14] * 16777216)
                    CardnoStr = '%010d' % Cardno  # 转10进制卡号
                    SerialNum = ''  # 设备硬件序列号
                    for num in range(15, len(data)):
                        SerialNum = SerialNum + '%02X' % (data[num])
                    if (data[0] == eval('0xCF')):
                        dispinf = '数据解析:IC卡离开标识:'
                    else:
                        dispinf = '数据解析:ID卡离开标识:'
                    dispinf = dispinf + FunCode + ',设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H + " 转10进制卡号:" + CardnoStr + ",硬件序列号:" + SerialNum
                    self.textEdit_9.setText(dispinf)
                    self.textEdit_8.setText(DevNo)
 
                elif (data[0] == eval('0xA4')):  # 返回WIFI连接状态
                    dispinf = 'WIFI的IP地址:%d.%d.%d.%d' % (data[7], data[8], data[9], data[10]) + "n"
                    dispinf = dispinf + 'WIFI子网掩码:%d.%d.%d.%d' % (data[11], data[12], data[13], data[14]) + "n"
                    dispinf = dispinf + '本地 MAC地址:%02X-%02X-%02X-%02X-%02X-%02X' % (
                    data[15], data[16], data[17], data[18], data[19], data[20]) + "n"
                    dispinf = dispinf + '  WIFI网关IP:%d.%d.%d.%d' % (data[21], data[22], data[23], data[24]) + "n"
                    dispinf = dispinf + '网关 MAC地址:%02X-%02X-%02X-%02X-%02X-%02X' % (
                    data[25], data[26], data[27], data[28], data[29], data[30]) + "n"
                    if (data[31] == 0):
                        dispinf = dispinf + 'WIFI网络状态:已连接wifi' + 'n'
                    elif (data[31] == 1):
                        dispinf = dispinf + 'WIFI网络状态:连接失败!' + 'n'
                    elif (data[31] == 2):
                        dispinf = dispinf + 'WIFI网络状态:已初始化!' + 'n'
                    else:
                        dispinf = dispinf + 'WIFI网络状态:未初始化!' + 'n'
                    dispinf = dispinf + '读卡器  名称:' + data[34:(34 + data[32])].decode('utf-8') + 'n'
                    dispinf = dispinf + 'WIFI热点名称:' + data[44:(44 + data[33])].decode('utf-8') + 'n'
 
                    self.wifiset.plainTextEdit.setPlainText(dispinf)
 
                elif (data[0] == eval('0xF6')):  # 返回设备版本型号、固件日期
                    DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])  # 设备IP
                    DevNo = '%05d' % (data[5] + data[6] * 256)  # 机号
                    namelen = data[7]
                    namebufbeg = 8
                    namebufend = namebufbeg + namelen
                    namestr = data[namebufbeg:namebufend].decode('gbk')
 
                    verlen = data[namebufend]
                    verbufbeg = namebufend + 1
                    verbufend = verbufbeg + verlen
                    verstr = '' + data[verbufbeg:verbufend].decode('gbk') + ''
 
                    SerialNum = ''
                    if (data[verbufend] == eval('0xFF')):
                        for num in range(verbufend + 1, len(data)):
                            SerialNum = SerialNum + '%02X' % (data[num])
 
                    rows = self.tableWidget.rowCount()
                    if (rows > 0):
                        for num in range(0, rows):
                            if (DEvIp == self.tableWidget.item(num, 1).text() and SerialNum == self.tableWidget.item(
                                    num, 12).text()):
                                self.tableWidget.item(num, 14).setText(namestr)
                                self.tableWidget.item(num, 15).setText(verstr)
                                break
                elif (data[0] == eval('0x47')):  # 设置15693读写器读卡块号成功
                    self.rw15693Signel.emit(3,RemortIPort, "设置15693读写器主动读卡块号成功!")
 
                elif (data[0] == eval('0xC7')):  # 15693卡刷卡信息
                    self.DisableSendAge(RemortIPort, data)
 
                    DEvIp = '%d.%d.%d.%d' % (data[1], data[2], data[3], data[4])  # 设备IP
                    DevNo = '%05d' % (data[5] + data[6] * 256)  # 机号
                    FrameNo = '%d' % (data[7] + data[8] * 256)  # 数据包序号
                    if (data[9] == eval('0x00')):
                        self.rw15693Signel.emit(3, RemortIPort, "卡不在感应区!")
                    else:
                        Card16H = '%02X%02X%02X%02X%02X%02X%02X%02X' % (
                        data[19], data[18], data[17], data[16], data[15], data[14], data[13], data[12])  # 原始16进制卡号
                        self.rw15693Signel.emit(1,RemortIPort, Card16H)
                        if (self.findChild(QWidget, "ISO15693标签读写器测试")):
                            self.ISO15693RW.lineEdit_RWCardno.setText(Card16H)
                        if (data[9] == eval('0x01')):  # 主动读取15693卡号
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(20, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:主动读取15693卡号,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(3, RemortIPort, "主动读取15693卡号成功!")
                        elif (data[9] == eval('0x02')):  # 主动读取15693卡号、块数据
                            DSFID = '%02X' % (data[11])
                            blockdata = ''
                            for j in range(1, data[21] + 1):
                                blockdata = blockdata + '块号:%02d' % (data[(j - 1) * (data[20] + 1) + 22]) + ' 数据:'
                                for i in range(1, data[20] + 1):
                                    blockdata = blockdata + '%02X' % (data[(j - 1) * (data[20] + 1) + 22 + i])
                                blockdata = blockdata + "n"
 
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(len(data) - 8, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:主动读取15693卡号及块数据,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H + ',DSFID:' + DSFID + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(2,RemortIPort, blockdata)
                            self.rw15693Signel.emit(3, RemortIPort, "主动读取15693卡号及块数据成功!")
                        elif (data[9] == eval('0x03')):  # 电脑发指令读卡成功,仅返回卡号
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(20, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:接收指令读取15693卡号,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(3, RemortIPort, "接收指令读取15693卡号成功!")
                        elif (data[9] == eval('0x04')):  # 电脑发指令读卡成功
                            DSFID = '%02X' % (data[11])
                            blockdata = ''
                            for j in range(1, data[21] + 1):
                                blockdata = blockdata + '块号:%02d' % (data[(j - 1) * (data[20] + 1) + 22]) + ' 数据:'
                                for i in range(1, data[20] + 1):
                                    blockdata = blockdata + '%02X' % (data[(j - 1) * (data[20] + 1) + 22 + i])
                                blockdata = blockdata + "n"
 
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(len(data) - 8, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:接收指令读取15693卡号及块数据,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H + ',DSFID:' + DSFID + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(2,RemortIPort, blockdata)
                            self.rw15693Signel.emit(3, RemortIPort, "接收指令读取15693卡号及块数据成功!")
                        elif (data[9] == eval('0x05')):  # 电脑发指令读卡成功,仅返回卡号
                            DSFID = '%02X' % (data[11])
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(20, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:电脑发指令重新读卡号成功,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H+ ',DSFID:' + DSFID + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(3, RemortIPort, "接收指令重新读卡号成功成功!")
                        elif (data[9] == eval('0x06')):  # 电脑发指令写卡成功
                            DSFID = '%02X' % (data[11])
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(20, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:电脑发指令写卡成功,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H+ ',DSFID:' + DSFID + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(3, RemortIPort, "电脑发指令写卡成功!")
                        elif (data[9] == eval('0x07')):  # 卡离开感应区
                            DSFID = '%02X' % (data[11])
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(20, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:卡离开感应区,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H+ ',DSFID:' + DSFID + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(3, RemortIPort, "卡离开感应区!")
                        elif (data[9] == eval('0x6A')):  # 电脑发指令写卡失败,返回卡号
                            DSFID = '%02X' % (data[11])
                            SerialNum = ''  # 设备硬件序列号
                            for num in range(20, len(data)):
                                SerialNum = SerialNum + '%02X' % (data[num])
                            dispinf = '数据解析:电脑发指令写卡失败,设备IP:' + DEvIp + ',机号:' + DevNo + ",数据包号:" + FrameNo + ",16进制卡号:" + Card16H+ ',DSFID:' + DSFID + ",硬件序列号:" + SerialNum
                            self.rw15693Signel.emit(3, RemortIPort, "电脑发指令写卡失败!")
                        self.textEdit_9.setText(dispinf)
 
        elif (len(data) > 0):
            if (data[0] == eval('0xF7')):
                if (len(data) == 8 and data[7] == 0):
                    self.wifiset.plainTextEdit.setPlainText("设置设备WIFI热点参数的指令已传送到设备,30秒后可以获取到设备WIFI连接状态!")
 
            elif (data[0] == eval('0x1D')):
                if (RemortIPort == self.netparawin.lineEdit_RemoIPort.text()):
                    self.netparawin.plainTextEdit_Disp.setPlainText('1D设置参数指令成功执行!')
 
        elif (dispcode == 1):
            self.ListAddItem(RemortIPort)
 
    def table_doubleClick(self):
        currentrow = self.tableWidget.currentRow()  # 获取当前鼠标点击了第几行
        if (currentrow >= 0):
            DevNo = self.tableWidget.item(currentrow, 0).text()
            DEvIp = self.tableWidget.item(currentrow, 1).text()
            DevPort = self.tableWidget.item(currentrow, 3).text()
            self.textEdit_7.setPlainText(DEvIp + ':' + DevPort)
            self.textEdit_8.setPlainText(DevNo)
 
    def PBEditpara_click(self):
        currentrow = self.tableWidget.currentRow()  # 获取当前鼠标点击了第几行
        if (currentrow >= 0):
            self.netparawin = NetParaSetwindow()  # 实例化 网络参数设置窗口
 
            screen = QDesktopWidget().screenGeometry()
            size = self.netparawin.geometry()
            newLeft = (screen.width() - size.width()) // 2
            newTop = (screen.height() - size.height()) // 2
            self.netparawin.move(newLeft, newTop)
 
            self.netparawin.setWindowFlags(QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowStaysOnTopHint)
 
            self.netparawin.lineEdit_ReaderNnm.setText(self.tableWidget.item(currentrow, 0).text())
            self.netparawin.lineEdit_ReaderIP.setText(self.tableWidget.item(currentrow, 1).text())
            self.netparawin.lineEdit_ReaderMask.setText(self.tableWidget.item(currentrow, 2).text())
            self.netparawin.lineEdit_ReaderPort.setText(self.tableWidget.item(currentrow, 3).text())
            self.netparawin.lineEdit_Gatwag.setText(self.tableWidget.item(currentrow, 4).text())
            self.netparawin.lineEdit_GatwayMAC.setText(self.tableWidget.item(currentrow, 5).text())
            self.netparawin.lineEdit_RemoIP.setText(self.tableWidget.item(currentrow, 6).text())
            self.netparawin.lineEdit_RemoMAC.setText(self.tableWidget.item(currentrow, 7).text())
            self.netparawin.lineEdit_Serial.setText(self.tableWidget.item(currentrow, 10).text())
            Search = eval('0x' + self.tableWidget.item(currentrow, 8).text().strip())
            if (Search == 0):
                self.netparawin.radioButton_gatwaybind.setChecked(True)
                self.netparawin.radioButton_RemoMACBind.setChecked(True)
            elif (Search == 1):
                self.netparawin.radioButton_gatwaybind.setChecked(True)
                self.netparawin.radioButton_RemoMACAuto.setChecked(True)
            elif (Search == 2):
                self.netparawin.radioButton_Gatwayauto.setChecked(True)
                self.netparawin.radioButton_RemoMACBind.setChecked(True)
            else:
                self.netparawin.radioButton_Gatwayauto.setChecked(True)
                self.netparawin.radioButton_RemoMACAuto.setChecked(True)
 
            paracod = self.tableWidget.item(currentrow, 9).text().strip()
            self.netparawin.comboBox_beep.setCurrentIndex(int(paracod[-1:8], 2))
            if (paracod[-2:7] == '1'):
                self.netparawin.checkBox_DHCP.setChecked(True)
            else:
                self.netparawin.checkBox_DHCP.setChecked(False)
            self.netparawin.comboBox_SendEn.setCurrentIndex(int(paracod[-3:6], 2))
            self.netparawin.comboBox_Sendinterval.setCurrentIndex(int(paracod[0:5], 2))
 
            self.netparawin.label_19.setStyleSheet('color:red;')
            self.netparawin.label_20.setStyleSheet('color:red;')
            self.netparawin.lineEdit_RemoIPort.setStyleSheet('color:blue;')
            self.netparawin.plainTextEdit_Disp.setStyleSheet('color:blue;')
            self.netparawin.lineEdit_RemoIPort.setText(self.textEdit_7.toPlainText().strip())
            self.netparawin.show()
            self.setEnabled(False)
 
            self.netparawin.netparaSignel.connect(self.GetNetParaSetSignal)  # 将设置网络参数窗口的 信号 绑定给 主窗口的 槽函数
        else:
            QMessageBox.critical(self, "警告", "     请选择一台在线设备!", QMessageBox.Yes)
 
    def ListAddItem(self, itemstr):
        if self.listWidget.count() > 10:
            self.listWidget.clear()
        self.listWidget.addItem(itemstr)
        self.listWidget.scrollToBottom()
        seleid = self.listWidget.count() - 1
        self.listWidget.item(seleid).setSelected(True)
 
    def PBSearch_click(self):
        global LastBuf
        LastBuf = bytes(9)
        self.tableWidget.setRowCount(0)  # 清空表格内现有记录
        self.textEdit_7.setPlainText('255.255.255.255:39169')
        sdata = bytes([eval('0xA6')])  # 搜索在线设备的指令码
        s.sendto(sdata, ('255.255.255.255', Bindprot))  # 发送搜索同网段内所有在线设备的广播指令
        self.ListAddItem(
            get_time() + 'SendTo:' + ("255.255.255.255:" + str(Bindprot) + "            ")[0:22] + " Data:A6")
 
        sdata = bytes([eval('0xA8')])  # 查询设备版本型号、固件更新日期
        s.sendto(sdata, ('255.255.255.255', Bindprot))  # 发送搜索同网段内所有在线设备的广播指令
        self.ListAddItem(
            get_time() + 'SendTo:' + ("255.255.255.255:" + str(Bindprot) + "            ")[0:22] + " Data:A8")
 
    def PBClear_click(self):
        self.listWidget.clear()
        self.textEdit_9.setText('')
 
    def CBIP_selectionchange(self):
        global listen
        global s
        if listen == 1:
            listen = 0
            s.close()
        if changip == 1:
            try:
                Bindip = self.CBIP.currentText()
                Bindprot = int(self.TEPort.toPlainText())
                s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
                s.bind((Bindip, Bindprot))
 
                self.subSockListenThread = SockListenThread()
                self.subSockListenThread.Sock_data.connect(self.SockGetData)
                self.subSockListenThread.start()
                listen = 1
 
                self.ListAddItem("Socket is bind to :" + Bindip + ":" + str(Bindprot))
            except:
                listen = 0
                self.ListAddItem("Socket is bind to :" + Bindip + ":" + str(Bindprot) + " failure!")
 
    def DisableSendAge(self, remortiport, data):  # 接收到读卡器上传的数据包立即回应,否则读卡器会继续上传三次
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        senddata = bytes(
            [105, data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8]])  # 接收到的数包前9字节,首字节改为 69H 来回应
        s.sendto(senddata, (Remoip, Reprot))
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(senddata)):
            SendInf = SendInf + '%02X ' % (senddata[num])
        self.ListAddItem(SendInf)
 
    def PBGetmodel_click(self):
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        comb = bytes([eval('0xA8')])  # A8是指令码
        s.sendto(comb, (Remoip, Reprot))  # 发送A8指令查询设备版本型号
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(comb)):
            SendInf = SendInf + '%02X ' % (comb[num])
        self.ListAddItem(SendInf)
 
    def PBSendDispBeep_click(self):
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
 
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
 
        dispinf = self.textEdit.toPlainText() + '                                    '  # 加空格是为了全屏显示
        DispStr = dispinf[0:34]
        disb = bytes(DispStr, encoding='gbk')  # 将要显示的文字转bytes
 
        comb = bytes([eval('0x5A')])  # 5A是指令码
        comb = comb + bytes.fromhex(HexStr)  # 2字节机号
        comb = comb + bytes([self.CBbeep.currentIndex()])  # 1字节蜂鸣代码
        comb = comb + bytes([self.spinBox.value()])  # 1字节显示时长
        sdata = comb + disb  # 34字节显示文字
 
        s.sendto(sdata, (Remoip, Reprot))  # 发送5A指令驱动读卡器显示文字+蜂鸣响声
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def PBSwitchOff_click(self):
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
        DelayTime = self.spinBox_2.value()
        DelHexStr = '%02X%02X' % (DelayTime % 256, DelayTime // 256)  # 2字节继电器延时
        switch = 'E%d' % (self.CBSwitch.currentIndex())  # 所选的继电器
 
        sdata = bytes([eval('0x78')])  # 78是指令码
        sdata = sdata + bytes.fromhex(HexStr)  # 2字节机号
        sdata = sdata + bytes.fromhex(switch)  # 1字节继电器代号
        sdata = sdata + bytes.fromhex(DelHexStr)  # 2字节延长时间
        s.sendto(sdata, (Remoip, Reprot))  # 发送78指令驱动读卡器关闭已开启的继电器
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def PBSwitchOn_click(self):
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
        DelayTime = self.spinBox_2.value()
        DelHexStr = '%02X%02X' % (DelayTime % 256, DelayTime // 256)  # 2字节继电器延时
        switch = 'F%d' % (self.CBSwitch.currentIndex())  # 所选的继电器
 
        sdata = bytes([eval('0x78')])  # 78是指令码
        sdata = sdata + bytes.fromhex(HexStr)  # 2字节机号
        sdata = sdata + bytes.fromhex(switch)  # 1字节继电器代号
        sdata = sdata + bytes.fromhex(DelHexStr)  # 2字节延长时间
        s.sendto(sdata, (Remoip, Reprot))  # 发送78指令驱动读卡器开启继电器
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def PBSendDispTTS_click(self):
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
 
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
 
        DelayTime = self.spinBox_2.value()
        DelHexStr = '%02X%02X' % (DelayTime % 256, DelayTime // 256)  # 2字节继电器延时
 
        voice = self.spinBox_3.value()  # 语音大小,最大声音值16
        if (voice > 16):
            voice = 16
 
        DispStr = self.textEdit.toPlainText() + '                                    '  # 加空格是为了全屏显示
        disb = bytes(DispStr, encoding='gbk')  # 将要显示的文字转bytes
 
        SpkStr = '[v' + str(
            voice) + ']' + self.textEdit_2.toPlainText()  # 要播报的TTS语音,[v10]表示音量,取值0-16,可放置字符串的任意地方,一次最多126个字节
        Spkb = bytes(SpkStr, encoding='gbk')  # 将要播报的TTS语音转bytes,
        Spkl = len(Spkb)  # TTS语音长度
 
        switch = 'F%d' % (self.CBSwitch.currentIndex())  # 所选的继电器
        sufb = bytes([eval('0x55'), eval('0xaa'), eval('0x66'), eval('0x99')])  # 固定的抗干扰后缀
 
        comb = bytes([eval('0x5C')])  # 5C是指令码
        comb = comb + bytes.fromhex(HexStr)  # 2字节机号
        comb = comb + bytes([self.CBbeep.currentIndex()])  # 1字节蜂鸣代码
        comb = comb + bytes.fromhex(switch)  # 1字节继电器代码
        comb = comb + bytes.fromhex(DelHexStr)  # 2字节继电器延时
        comb = comb + bytes([self.spinBox.value()])  # 1字节显示时长
        comb = comb + bytes([0, 34, Spkl])  # 1字节显示起始位+1字节显示长度+1语音长度
        sdata = comb + disb[0:34] + Spkb + sufb
 
        s.sendto(sdata, (Remoip, Reprot))  # 发送5C指令驱动读卡器显示文字+蜂鸣响声+开关继电器+播报TTS语音
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def PBSendDispSpk_click(self):
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
 
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
 
        DelayTime = self.spinBox_2.value()
        DelHexStr = '%02X%02X' % (DelayTime % 256, DelayTime // 256)  # 2字节延时
 
        DispStr = self.textEdit.toPlainText() + '                                    '  # 加空格是为了全屏显示
        disb = bytes(DispStr, encoding='gbk')  # 将要显示的文字转bytes
 
        Spkb = bytes([55, 41, 53])  # 固定组合语音代码,取值请查看通讯协议说明,一次最大取值21条
        Spkl = len(Spkb)  # 语音代码条数
 
        switch = 'F%d' % (self.CBSwitch.currentIndex())  # 所选的继电器
        sufb = bytes([eval('0x55'), eval('0xaa'), eval('0x66'), eval('0x99')])  # 固定的抗干扰后缀
 
        comb = bytes([eval('0x5B')])  # 5B是指令码
        comb = comb + bytes.fromhex(HexStr)  # 2字节机号
        comb = comb + bytes([self.CBbeep.currentIndex()])  # 1字节蜂鸣代码
        comb = comb + bytes.fromhex(switch)  # 1字节继电器代码
        comb = comb + bytes.fromhex(DelHexStr)  # 2字节继电器延时
        comb = comb + bytes([self.spinBox.value()])  # 1字节显示时长
        comb = comb + bytes([0, 36, Spkl])  # 1字节显示起始位+1字节显示长度+1语音长度
        sdata = comb + disb[0:36] + Spkb + sufb
 
        s.sendto(sdata, (Remoip, Reprot))  # 发送5B指令驱动读卡器显示文字+蜂鸣响声+开关继电器+播报固定组合语音
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def PBReadCard_click(self):
        keystr = self.textEdit_4.toPlainText().strip()  # 卡片认证密码
        if (is_valid_hex(keystr) == False or len(bytes.fromhex(keystr)) != 6):
            self.ListAddItem("卡密码输入错误!")
            self.textEdit_4.setFocus()
            return
 
        cardstr = self.textEdit_3.toPlainText().strip()
        if (is_valid_hex(cardstr) == False or len(bytes.fromhex(cardstr)) != 4):  # 16进制卡号
            self.ListAddItem("卡号输入错误!")
            self.textEdit_3.setFocus()
            return
 
        self.textEdit_5.setPlainText('')
        global LastBuf
        LastBuf = bytes(9)
 
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
        sector = self.CBPage.currentIndex()  # 读写扇区号
        auth = self.CBauth.currentIndex()  # 密码认证方式
 
        sdata = bytes([eval('0x3B')])  # 3B是指令码
        sdata = sdata + bytes.fromhex(HexStr)  # 2字节机号
        sdata = sdata + bytes([1])  # 1字节扇区个数
        sdata = sdata + bytes.fromhex(cardstr)  # 4字节16进制卡号 00000000 表示可操作任意卡
        sdata = sdata + bytes([sector])  # 1字节扇区号
        sdata = sdata + bytes([auth])  # 1字节密码认证方式
        sdata = sdata + bytes.fromhex(keystr)  # 6字节密码
 
        s.sendto(sdata, (Remoip, Reprot))  # 发送3B指令驱动读写器读卡
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def PBWriteCard_click(self):
        keystr = self.textEdit_4.toPlainText().strip()  # 卡片认证密码
        if (is_valid_hex(keystr) == False or len(bytes.fromhex(keystr)) != 6):
            self.ListAddItem("卡密码输入错误!")
            self.textEdit_4.setFocus()
            return
 
        cardstr = self.textEdit_3.toPlainText().strip()
        if (is_valid_hex(cardstr) == False or len(bytes.fromhex(cardstr)) != 4):  # 16进制卡号
            self.ListAddItem("卡号输入错误!")
            self.textEdit_3.setFocus()
            return
 
        Writestr = self.textEdit_5.toPlainText().strip()  # 48字节写卡数据
        if (is_valid_hex(Writestr) == False or len(bytes.fromhex(Writestr)) != 48):
            self.ListAddItem("写卡数据输入错误,请输入48个16进制写卡数据!")
            self.textEdit_5.setFocus()
            return
 
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
        sector = self.CBPage.currentIndex()  # 读写扇区号
        auth = self.CBauth.currentIndex()  # 密码认证方式
 
        sdata = bytes([eval('0x3D')])  # 3D是指令码
        sdata = sdata + bytes.fromhex(HexStr)  # 2字节机号
        sdata = sdata + bytes([1])  # 1字节扇区个数
        sdata = sdata + bytes.fromhex(cardstr)  # 4字节16进制卡号 00000000 表示可操作任意卡
        sdata = sdata + bytes([sector])  # 1字节扇区号
        sdata = sdata + bytes([auth])  # 1字节密码认证方式
        sdata = sdata + bytes.fromhex(keystr)  # 6字节卡密码
        sdata = sdata + bytes.fromhex(Writestr)  # 48字节写卡数据
        sdata = sdata + bytes.fromhex("55AA6699")  # 4字节防错
 
        s.sendto(sdata, (Remoip, Reprot))  # 发送3D指令驱动读写器写卡
 
        SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[0:22] + ' Data:'  # 为方便开发,打印出详细的指令
        for num in range(0, len(sdata)):
            SendInf = SendInf + '%02X ' % (sdata[num])
        self.ListAddItem(SendInf)
 
    def PBChangeKey_click(self):
        self.Dialog = MyDialog()
        self.Dialog.sig.connect(self.Changekey)
        self.Dialog.start()
 
    def Changekey(self, obj):
        res = QMessageBox.question(None, "警告", "     您确定要继续执行修改卡密码及控制位的操作吗?如确定修改请务必记住卡的新密码,否则卡片将报废!",
                                   QMessageBox.Yes | QMessageBox.No)
        if (QMessageBox.Yes == res):
            global LastBuf
            LastBuf = bytes(9)
            newkey = self.textEdit_6.toPlainText().strip()  # 16字节新卡密码
            if (is_valid_hex(newkey) == False or len(bytes.fromhex(newkey)) != 16):
                self.ListAddItem("卡新密钥输入错误!")
                self.textEdit_6.setFocus()
                return
 
            keystr = self.textEdit_4.toPlainText().strip()  # 卡片认证密码
            if (is_valid_hex(keystr) == False or len(bytes.fromhex(keystr)) != 6):
                self.ListAddItem("卡密码输入错误!")
                self.textEdit_4.setFocus()
                return
 
            cardstr = self.textEdit_3.toPlainText().strip()
            if (is_valid_hex(cardstr) == False or len(bytes.fromhex(cardstr)) != 4):  # 16进制卡号
                self.ListAddItem("卡号输入错误!")
                self.textEdit_3.setFocus()
                return
 
            remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
            FieldsList = remortiport.split(':')
            Remoip = FieldsList[0]
            Reprot = int(FieldsList[1])
            DevNo = int(self.textEdit_8.toPlainText())
            HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
            sector = self.CBPage.currentIndex()  # 读写扇区号
            auth = self.CBauth.currentIndex()  # 密码认证方式
            auth = auth + self.ChangeKey.currentIndex() * 2  # 密码修改方式
 
            sdata = bytes([eval('0x3A')])  # 3A是指令码
            sdata = sdata + bytes.fromhex(HexStr)  # 2字节机号
            sdata = sdata + bytes([1])  # 1字节扇区个数
            sdata = sdata + bytes.fromhex(cardstr)  # 4字节16进制卡号 00000000 表示可操作任意卡
            sdata = sdata + bytes([sector])  # 1字节扇区号
            sdata = sdata + bytes([auth])  # 1字节密码认证方式
            sdata = sdata + bytes.fromhex(keystr)  # 6字节卡密码
            sdata = sdata + bytes.fromhex(newkey)  # 16字节新密码
            sdata = sdata + bytes.fromhex("55AA6699")  # 4字节防错
 
            s.sendto(sdata, (Remoip, Reprot))  # 发送3A指令驱动读写器更改卡片密钥
            SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[
                                               0:22] + ' Data:'  # 为方便开发,打印出详细的指令
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.ListAddItem(SendInf)
 
    def PBSetRW_click(self):
        self.Dialog = MyDialog()
        self.Dialog.sig.connect(self.SetRW)
        self.Dialog.start()
 
    def SetRW(self, obj):
        remortiport = self.textEdit_7.toPlainText().strip()  # 需要驱动设备的 IP、端口
        FieldsList = remortiport.split(':')
        Remoip = FieldsList[0]
        Reprot = int(FieldsList[1])
        DevNo = int(self.textEdit_8.toPlainText())
        HexStr = '%02X%02X' % (DevNo % 256, DevNo // 256)  # 2字节机号
        sector = self.CBPage.currentIndex()  # 读写扇区号
        auth = self.CBauth.currentIndex()  # 密码认证方式
 
        res = QMessageBox.question(None, "提示", "     按 Yes 键把读写器设为主动读取第 " + str(
            self.CBPage.currentIndex()) + " 扇区数据,按 No 键将读写器设为只读卡号不读扇区数据。", QMessageBox.Yes | QMessageBox.No)
        if (QMessageBox.No == res):
            sdata = bytes([eval('0x4B')])  # 4B是指令码
            sdata = sdata + bytes.fromhex(HexStr)  # 2字节机号
            sdata = sdata + bytes([0])  # 读0个扇区数据
            sdata = sdata + bytes.fromhex("55AA6699")  # 4字节确认码
            s.sendto(sdata, (Remoip, Reprot))  # 发送4B指令将读写器设为只读卡号
            SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[
                                               0:22] + ' Data:'  # 为方便开发,打印出详细的指令
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.ListAddItem(SendInf)
        else:
            keystr = self.textEdit_4.toPlainText().strip()  # 卡片认证密码
            if (is_valid_hex(keystr) == False or len(bytes.fromhex(keystr)) != 6):
                self.ListAddItem("卡密码输入错误!")
                self.textEdit_4.setFocus()
                return
 
            sdata = bytes([eval('0x4B')])  # 4B是指令码
            sdata = sdata + bytes.fromhex("0000")  # 2字节机号
            sdata = sdata + bytes([1])  # 主动读取的扇区数,如果要开通几个扇区这里就填几
            if (auth == 0):
                sector = sector + 128
            sdata = sdata + bytes([sector]) + bytes.fromhex(
                keystr)  # 1字节的扇区号及密码认证类型 + 6字节卡认证密码 ,如果读多个扇区也按此结构加入,可以开通全部的16个扇区
            sdata = sdata + bytes.fromhex("55AA6699")  # 4字节确认码
            s.sendto(sdata, (Remoip, Reprot))  # 发送4B指令将读写器设为主动读取扇区
            SendInf = get_time() + 'SendTo:' + (remortiport + '                      ')[
                                               0:22] + ' Data:'  # 为方便开发,打印出详细的指令
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.ListAddItem(SendInf)
 
    def PBWifiSet_click(self):
        self.wifiset = WifiSetWindow()  # 实例化 wifi热点参数设置窗口
 
        screen = QDesktopWidget().screenGeometry()
        size = self.wifiset.geometry()
        # 获得窗口相关坐标
        newLeft = (screen.width() - size.width()) // 2
        newTop = (screen.height() - size.height()) // 2
        # 移动窗口使其居中
        self.wifiset.move(newLeft, newTop)
 
        self.wifiset.setWindowFlags(  # 使能最小化按钮 .WindowMinimizeButtonHint
            QtCore.Qt.WindowCloseButtonHint |  # 使能关闭按钮
            QtCore.Qt.WindowStaysOnTopHint)  # 窗体总在最前端
 
        self.wifiset.groupBox.setVisible(False)
        self.wifiset.comboBox_Sendmode.setCurrentIndex(1)
        self.wifiset.label_7.setStyleSheet('color: red;')
        self.wifiset.lineEdit_RemoIPort.setStyleSheet("color: red;")
        self.wifiset.show()
 
        self.setEnabled(False)
 
        self.wifiset.WifiSignel.connect(self.GetWiFiWindoSignal)  # 将wifi热点参数窗口的 信号 绑定给 主窗口的 槽函数
        self.wifiset.lineEdit_RemoIPort.setText(self.textEdit_7.toPlainText().strip())
 
    def PB15693RW_click(self):
        self.ISO15693RW = ISO15693RW()
 
        screen = QDesktopWidget().screenGeometry()
        size = self.ISO15693RW.geometry()
        # 获得窗口相关坐标
        newLeft = (screen.width() - size.width()) // 2
        newTop = (screen.height() - size.height()) // 2
        # 移动窗口使其居中
        self.ISO15693RW.move(newLeft, newTop)
 
        self.ISO15693RW.setWindowFlags(  # 使能最小化按钮 .WindowMinimizeButtonHint
            QtCore.Qt.WindowCloseButtonHint |  # 使能关闭按钮
            QtCore.Qt.WindowStaysOnTopHint)  # 窗体总在最前端
        self.ISO15693RW.lineEdit_RemoIPort.setText(self.textEdit_7.toPlainText().strip())
        self.ISO15693RW.lineEdit_Mask.setText('0000000000000000')
 
        self.ISO15693RW.label_19.setStyleSheet('color:red;')
        self.ISO15693RW.label_20.setStyleSheet('color:red;')
        self.ISO15693RW.lineEdit_RemoIPort.setStyleSheet('color:blue;')
        self.ISO15693RW.lineEdit_disp.setStyleSheet('color:blue;')
 
        self.ISO15693RW.show()
 
        self.setEnabled(False)
 
        self.ISO15693RW.iso15693Signel.connect(self.Getiso15693Signal)
 
 
# =======================================================================================================================
def get_time():
    current_time = datetime.datetime.now()
    current_time_str = current_time.strftime("%H:%M:%S.%f")[:-3]
    return current_time_str + ' '
 
 
def is_valid_hex(input_str):
    input_str = input_str.replace(" ", "")
    try:
        if (len(bytes.fromhex(input_str)) == len(input_str) / 2):
            return True
        else:
            return False
    except:
        return False
 
 
def GetHexIPAdd(inputstr):
    try:
        FieldsList = inputstr.split('.')
        HexIPAdd = '%02X%02X%02X%02X' % (
        int(FieldsList[0]), int(FieldsList[1]), int(FieldsList[2]), int(FieldsList[3]))  # 4字节设备IP
        if (len(HexIPAdd) != 8):
            HexIPAdd = "00000000"
    except:
        HexIPAdd = "00000000"
    return HexIPAdd
 
 
def IsIport(inputstr):
    try:
        remortiport = inputstr.strip()
        FieldsList = remortiport.split(':')
        Remoip = GetHexIPAdd(FieldsList[0])
        Reprot = int(FieldsList[1])
        if (Remoip == "00000000"):
            return False
        else:
            return True
    except:
        return False
 
 
def get_mac_address(ip_address):  # 不能返回本机MAC
    # 初始化 用正则表达式're'编译出匹配MAC地址的正则表达式对象
    patt_mac = re.compile('([a-f0-9]{2}[-:]){5}[a-f0-9]{2}', re.I)
    # ping
    os.popen('ping -n 1 -w 500 {} > nul'.format(ip_address))
    # 然后使用'arp'命令获取该IP地址对应的MAC地址 返回一个类文件对象 可以通过 read 方法获取命令的输出结果
    arp_file = os.popen('arp -a {}'.format(ip_address))
    # 使用正则表达式'self.patt_mac'在输出结果中查找符合 MAC 地址格式的字符串 并返回找到的第一个匹配项 即 IP 对应的 MAC 地址
    mac_addr = patt_mac.search(arp_file.read())
 
    # 根据正则表达式对象匹配MAC地址 如果匹配到了就返回MAC地址 否则返回None
    if mac_addr:
        mac_addr = mac_addr.group()
        return mac_addr
    else:
        return 'FF-FF-FF-FF-FF-FF'
 
 
def get_default_gateway():
    gateways = netifaces.gateways()
    return gateways['default'][netifaces.AF_INET][0]  # 获取IPv4的默认网关
 
 
# =======================================================================================================================
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = MainWindow()
 
    screen = QDesktopWidget().screenGeometry()
    size = mainWindow.geometry()
    # 获得窗口相关坐标
    newLeft = (screen.width() - size.width()) // 2
    newTop = (screen.height() - size.height()) // 2
    # 移动窗口使其居中
    mainWindow.move(newLeft, newTop)
 
    mainWindow.setWindowTitle("RFID网络读卡器测试工具 Ver:2024.04.01")
    mainWindow.show()
 
    mainWindow.TEPort.setPlainText("39169")
 
    mainWindow.textEdit.setPlainText("欢迎您使用我们的网络读卡器!")
    mainWindow.textEdit_2.setPlainText("欢迎您使用我们的网络读卡器!")
    mainWindow.textEdit_3.setPlainText("00000000")
    mainWindow.textEdit_4.setPlainText("FFFFFFFFFFFF")
    mainWindow.textEdit_5.setPlainText(
        "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")
    mainWindow.textEdit_6.setPlainText("FF FF FF FF FF FF FF 07 80 69 FF FF FF FF FF FF")
    mainWindow.textEdit_7.setPlainText('255.255.255.255:39169')
    mainWindow.textEdit_8.setPlainText('00000')
    mainWindow.spinBox.setValue(20)
    mainWindow.spinBox_2.setValue(200)
    mainWindow.spinBox_3.setValue(10)
    mainWindow.CBauth.setCurrentIndex(0)
 
    mainWindow.listWidget.setStyleSheet("color: blue;")
    mainWindow.textEdit_9.setStyleSheet("color: blue;")
    mainWindow.label_19.setStyleSheet("color: red;")
    mainWindow.PBSearch.setStyleSheet("color: red;")
 
    if sys.platform == 'linux' or sys.platform == 'mac':  # linux、mac系统获取电脑所有网卡IP
        ips = [ip.split('/')[0] for ip in os.popen("ip addr | grep 'inet '|awk '{print $2}'").readlines()]
        for i in ips:
            mainWindow.CBIP.addItem(i)
    else:
        addrs = socket.getaddrinfo(socket.gethostname(), None)  # Windows系统获取电脑所有网卡IP
        for item in addrs:
            if ':' not in item[4][0]:
                mainWindow.CBIP.addItem(item[4][0])
 
    if mainWindow.CBIP.count() > 0:
        Bindip = mainWindow.CBIP.currentText()
        Bindprot = int(mainWindow.TEPort.toPlainText())
 
        try:
            listen = 1
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            s.bind((Bindip, Bindprot))
 
            mainWindow.subSockListenThread = SockListenThread()
            mainWindow.subSockListenThread.Sock_data.connect(mainWindow.SockGetData)
            mainWindow.subSockListenThread.start()
 
            # t1=threading.Thread(target=run,args=("t1",))
            # t1.setDaemon(True)      #守护线程--也称“服务线程”,在没有用户线程可服务时会自动离开,确保关闭窗口后关闭处理线程
            # t1.start()
 
            mainWindow.ListAddItem("Socket is bind to :" + Bindip + ":" + str(Bindprot))
        except:
            listen = 0
            mainWindow.ListAddItem("Socket is bind to :" + Bindip + ":" + str(Bindprot) + " failure!")
 
        changip = 1
 
    sys.exit(app.exec_())

UDP通信代码如下:

#python通过缩进来表示代码块,不可以随意更改每行前面的空白,否则程序会运行错误!!!如果缩进不一致,就会报错: IndentationError
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#python -m pdb xxx.py 调试程度 n命令单步执行,s命令单步执行 会进入函数内部  b xx ,c
#import pdb    pdb.set_trace() 设断点
 
import sys
import os
import socket
import time
import pdb
 
#接收到数据包后向设备发确认信息,否则设备会重发三次--------------------------------------------
def DisableSendAge(data,addr):
   #105是指令码+接收到的信息前8个字节     
   sdata=bytes([105,data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8]])            
   s.sendto(sdata,addr)   
   message = 'SendData To %s:%s' % (addr, sdata)
   print(message+"n")         
 
#向读卡器发送显示及蜂鸣响声----------------------------------------------------------------
def SendDispBeep(DispStr,addr):
   DispStr=DispStr[0:34]
   disb=bytes(DispStr, encoding='gbk')  #将要显示的文字转bytes
   
   comb=bytes([eval('0x5A'),0,0,2,30])    #5A是指令码+2字节机号+1字节蜂鸣代码+1字节显示时长
   
   sdata=comb+disb
          
   s.sendto(sdata,addr)   
   message = 'SendData To %s:%s' % (addr, sdata)
   print(message+"n")       
   
#向读卡器发送显示+继电器+固定组合语音-------------------------------------------------------
def SendDispSpk(DispStr,addr): 
   DispStr=DispStr[0:34]
   disb=bytes(DispStr, encoding='gbk')  #将要显示的文字转bytes
 
   Spkb=bytes([55,41,53])               #固定组合语音代码,取值请查看通讯协议说明,一次最大取值21条
   Spkl=len(Spkb)                       #语音代码条数
 
   sufb=bytes([eval('0x55'),eval('0xaa'),eval('0x66'),eval('0x99')])  #固定的抗干扰后缀
   
   comb=bytes([eval('0x5B'),0,0,2,eval('0xF0'),30,0,20,0,36,Spkl])    #5B是指令码+2字节机号+1字节蜂鸣代码+1字节继电器代码+2字节继电器延时+1字节显示时长+1字节显示起始位+1字节显示长度+1语音长度
   
   sdata=comb+disb+Spkb+sufb
          
   s.sendto(sdata,addr)   
   message = 'SendData To %s:%s' % (addr, sdata)
   print(message+"n")       
 
#向读卡器发送显示+继电器+TTS语音-------------------------------------------------------
def SendDispTTS(DispStr,addr): 
   DispStr=DispStr[0:34]
   disb=bytes(DispStr, encoding='gbk')  #将要显示的文字转bytes
   
   SpkStr='[v10]感谢您的使用,再见!'       #要播报的TTS语音,[v10]表示音量,取值0-16,可放置字符串的任意地方,一次最多126个字节
   Spkb=bytes(SpkStr, encoding='gbk')   #将要播报的TTS语音转bytes,
   Spkl=len(Spkb)                       #TTS语音长度
   
   sufb=bytes([eval('0x55'),eval('0xaa'),eval('0x66'),eval('0x99')])  #固定的抗干扰后缀
   
   comb=bytes([eval('0x5C'),0,0,2,eval('0xF0'),20,0,20,0,36,Spkl])    #5C是指令码+2字节机号+1字节蜂鸣代码+1字节继电器代码+2字节继电器延时+1字节显示时长+1字节显示起始位+1字节显示长度+1语音长度
 
   sdata=comb+disb+Spkb+sufb
                
   s.sendto(sdata,addr)   
   message = 'SendData To %s:%s' % (addr, sdata)
   print(message+"n")      
   
#向读写器发送读扇区内数据的指令---------------------------------------------------------
def ReadCardInf(data,addr):   
   comb=bytes([eval('0x3B'),data[5],data[6],1,data[10],data[11],data[12],data[13],8,0,])    
   #指令码3B+2字节机号(data[5],data[6]存有机号)+1字节扇区个数+4个字节卡号(data存有卡号)+1字节扇区号+1字节密码认证方式    
   
   keys=bytes([eval('0xFF'),eval('0xFF'),eval('0xFF'),eval('0xFF'),eval('0xFF'),eval('0xFF')])        #6个字节的卡认证密码
   
   sdata=comb+keys
   
   s.sendto(sdata,addr)   
   message = 'SendData To %s:%s' % (addr, sdata)
   print(message+"n")
   
#向读写器发送写信息到指定扇区的指令---------------------------------------------------------
def WriteCard(data,addr):
   sdata=bytearray()
   sdata.append(eval('0x3D'))      #写卡指令码
   
   sdata.append(data[5])           #2个字节的机号,如都取0表示任意机号
   sdata.append(data[6])           #data[56]保存了上传时设备的机号
   
   sdata.append(1)                 #操作扇区的个数
   
   sdata.append(data[8])           #4个字节的卡号,data[891011]保存了已读取的卡号
   sdata.append(data[9])           #如果这4个字节全部取0表示任意卡
   sdata.append(data[10])
   sdata.append(data[11])
   
   sdata.append(8)                 #扇区号
   sdata.append(0)                 #取值0表示以A密码认证,取值1表示以B密码认证
   
   sdata.append(eval('0xFF'))      #6个字节的卡片认证密码
   sdata.append(eval('0xFF'))
   sdata.append(eval('0xFF'))
   sdata.append(eval('0xFF'))
   sdata.append(eval('0xFF'))
   sdata.append(eval('0xFF'))
   
   for num in range(0,48):         #48个字节的写卡信息
       sdata.append(data[14+num])  #data[14]保存了已读取的卡扇区信息,这里表示将已读取的数据再次写入,如要写新的数据将数据写入这段缓冲
   
   sdata.append(eval('0x55'))      #4个字节固定的抗干扰后缀
   sdata.append(eval('0xAA'))
   sdata.append(eval('0x66'))
   sdata.append(eval('0x99'))
   
   s.sendto(sdata,addr)   
   message = 'SendData To %s:%s' % (addr, sdata)
   print(message+"n")
   
#获取电脑时钟---------------------------------------------------------------------------
def get_time():
   st = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
   st=st[0:16]
   return st
 
#主程序---------------------------------------------------------------------------------
IpList=[]
if sys.platform == 'linux' or sys.platform=='mac':     # linux、mac系统获取电脑所有网卡IP
    ips = [ip.split('/')[0] for ip in os.popen("ip addr | grep 'inet '|awk '{print $2}'").readlines()]
    for i in ips:
        IpList.append(i)
        print('%d   '%(len(IpList)) + i)
else:
    addrs = socket.getaddrinfo(socket.gethostname(),None)   #windows获取电脑所有网卡IP
    for item in addrs:
        if ':' not in item[4][0]:
            IpList.append(item[4][0])
            print('%d   '%(len(IpList)) + item[4][0])
 
BUFSIZE = 1024
Bindip=IpList[1]  #如有多张网卡,可选择绑定不同的网卡
Bindprot=39169
 
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((Bindip, Bindprot))
print('n系统绑定IP:'+Bindip+':%d'% (Bindprot))
 
CardNuff=bytearray()
 
sdata=bytes([166])             #搜索在线设备的指令码
s.sendto(sdata,('255.255.255.255',Bindprot))   #发送搜索同网段内所有在线设备的广播指令
message = 'SendData To 255.255.255.255:39169  a6'
print(message+"n")
 
LastBuf=bytes([0,0,0,0,0,0,0,0,0])             #保存最后接收到的信息,用于比较是否重复接收的信息
 
while True:
    data, addr = s.recvfrom(BUFSIZE)
    message = 'Received from %s:%s' % (addr, data)
    print(message)
    
    if(len(data)>8):
        if(data[0]==LastBuf[0] and data[1]==LastBuf[1] and data[2]==LastBuf[2] and data[3]==LastBuf[3] and data[4]==LastBuf[4] and data[5]==LastBuf[5] and data[6]==LastBuf[6] and data[7]==LastBuf[7] and data[8]==LastBuf[8]):  #比较是否是重发数据
            DisableSendAge(data, addr)    #接收到重复上传的信息,不用解析处理
            print('n')
        else:
            LastBuf=data[0:9]             #将接收到的信息保存,用于下次接收数据时比对
            
            if(data[0]==eval('0xF2')):    #接收到设备开机、搜索在线设备的返回信息,对信息解析
                print('指令码 :%02x  设备开机 或 响应服务器的搜索' % (data[0]))           
                print('设备IP :%d.%d.%d.%d' % (data[1],data[2],data[3],data[4]))    
                print('掩  码 :%d.%d.%d.%d' % (data[5],data[6],data[7],data[8]))             
                print('通讯端口:%d' % (data[9]+data[10]*256))
                print('机  号 :%d' % (data[11]+data[12]*256))
                print('网  关 :%d.%d.%d.%d' % (data[13],data[14],data[15],data[16]))            
                MacStr=''
                for num in range(17,23):
                    MacStr=MacStr+'%02x' % (data[num])
                    if(num< 22):
                       MacStr=MacStr+'-'
                print('网关MAC:'+ MacStr)
                print('远程服务器IP:%d.%d.%d.%d' % (data[23],data[24],data[25],data[26])) 
                MacStr=''
                for num in range(27,33):
                    MacStr=MacStr+'%02x' % (data[num])
                    if(num< 32):
                       MacStr=MacStr+'-'
                print('服务器MAC:'+ MacStr)  
                print('网络标识:%02x' % (data[33])) 
                print('响声标识:%02x' % (data[34])) 
                MacStr='16-88-'
                for num in range(35,39):
                    MacStr=MacStr+'%02x' % (data[num])
                    if(num< 38):
                       MacStr=MacStr+'-'
                print('读卡器MAC:'+ MacStr)
                if(len(data) >39):
                    SerialNum=''
                    for num in range(39,len(data)):
                        SerialNum=SerialNum+'%02x' % (data[num])  
                    print('设备唯一序号:'+ SerialNum)   
                                           
                print('n') 
                
            elif(data[0]==eval('0xF3')):  #接收到设备的心跳数据包,设备心跳间隔可根据协议自行设置
                print('指令码 :%02x 设备心跳包' % (data[0]))
                print('设备IP :%d.%d.%d.%d' % (data[1],data[2],data[3],data[4]))             
                print('机  号 :%d' % (data[5]+data[6]*256))
                print('包序号 :%d' % (data[7]+data[8]*256))
                print('心跳类型:%02x' % (data[9]))
                print('长度   :%02x' % (data[10]))
                print('继电器状态:%02x' % (data[11]))
                print('外部输入状态:%02x' % (data[12]))
                print('随机动态码:%02x%02x%02x%02x' % (data[13],data[14],data[15],data[16]))
                SerialNum=''
                for num in range(17,len(data)):
                    SerialNum=SerialNum+'%02x' % (data[num])
                print('设备序列号:'+ SerialNum+'n')       
                
            elif(data[0]==eval('0xD1')):  #接收到读取ID卡信息的数据包,对信息解析
                print('指令码 :%02x 接收到ID卡刷卡' % (data[0]))           
                print('设备IP :%d.%d.%d.%d' % (data[1],data[2],data[3],data[4]))             
                print('机  号 :%d' % (data[5]+data[6]*256))
                print('包序号 :%d' % (data[7]+data[8]*256))
                print('16进制卡号:%02x%02x%02x%02x' % (data[9],data[10],data[11],data[12])) 
                Cardno=data[9]
                Cardno=Cardno+(data[10]*256)
                Cardno=Cardno+(data[11]*65536)
                Cardno=Cardno+(data[12]*16777216)
                CardnoStr='%010d' % Cardno
                print('10进制卡号:'+CardnoStr)
                SerialNum=''
                for num in range(14,len(data)):
                    SerialNum=SerialNum+'%02x' % (data[num])
                print('设备序列号:'+ SerialNum+'n')
                
                DisableSendAge(data, addr)    #向设备发送确认包,否则相同的信息设备会重复发送三次
                
                #在这里加入业务对数据库的查、增、删、改操作
                #将业务处理结果发送到设备
                
                DispStr='卡号:'+CardnoStr+'  '+get_time()+'                              '#满屏显示,补足后面空格
                
                SendDispBeep(DispStr,addr)     #向读卡器发送显示及蜂鸣响声  
                #SendDispSpk(DispStr,addr)     #向读卡器发送显示+继电器+固定组合语音       
                #SendDispTTS(DispStr,addr)     #向读卡器发送显示+继电器+TTS语音
                                        
            elif(data[0]==eval('0xC1')):       #接收到读取IC卡号的数据包,对信息解析
                print('指令码 :%02x 接收到IC卡刷卡' % (data[0]))           
                print('设备IP :%d.%d.%d.%d' % (data[1],data[2],data[3],data[4]))             
                print('机  号 :%d' % (data[5]+data[6]*256))
                print('包序号 :%d' % (data[7]+data[8]*256))
                print('16进制卡号:%02x%02x%02x%02x' % (data[10],data[11],data[12],data[13])) 
                Cardno=data[10]
                Cardno=Cardno+(data[11]*256)
                Cardno=Cardno+(data[12]*65536)
                Cardno=Cardno+(data[13]*16777216)
                CardnoStr='%010d' % Cardno
                print('10进制卡号:'+CardnoStr)
                SerialNum=''
                for num in range(14,len(data)):
                    SerialNum=SerialNum+'%02x' % (data[num])
                print('设备序列号:'+ SerialNum+'n')
                
                DisableSendAge(data, addr)             #向设备发送确认包,否则相同的信息设备会重复发送三次
                
                #在这里加入业务对数据库的查、增、删、改操作
                #将业务处理结果发送到设备
                
                DispStr='卡号:'+CardnoStr+'  '+get_time()+'                              '#满屏显示,补足后面空格
                
                #SendDispBeep(DispStr,addr)            #向读卡器发送显示及蜂鸣响声  
                #SendDispSpk(DispStr,addr)             #向读卡器发送显示+继电器+固定组合语音       
                SendDispTTS(DispStr,addr)              #向读卡器发送显示+继电器+TTS语音
                
                ReadCardInf(data,addr)                 #如果设备是读写器,可以继续 发送读取指定扇区信息的指令
 
            elif(data[0]==eval('0xC3')):               #全扇区读写器收到读卡扇区内的数据(刷卡时主动读取并上传)
                j=data[10]*48
                m=data[11]*48
                
                for num in range(0,m):                 #将读取到的扇区信息存入读卡缓冲                    
                    CardNuff.append(data[16+num])
                    
                if(data[11]+data[10]>=data[9]):        #已完全收到所有包数据,一个数据包最多传4个扇区的数据,如果读写器设备读写扇区数大于4,数据要分2个包上传,扇区数大于8要分3个包,大与12要分4个包上传
                    print('接收到的信息为IC卡扇区内数据')
                    print('指令码 :%02x ' % (data[0]))
                    print('设备IP :%d.%d.%d.%d' % (data[1],data[2],data[3],data[4]))
                    print('机  号 :%d' % (data[5]+data[6]*256))
                    print('包序号 :%d' % (data[7]+data[8]*256))
                    print('16进制卡号:%02x%02x%02x%02x' % (data[12],data[13],data[14],data[15])) 
                    Cardno=data[12]
                    Cardno=Cardno+(data[13]*256)
                    Cardno=Cardno+(data[14]*65536)
                    Cardno=Cardno+(data[15]*16777216)
                    CardnoStr='%010d' % Cardno
                    print('10进制卡号:'+CardnoStr)
                                        
                    m=data[9]*48
                    CardInfStr=''
                    for num in range(0,m):
                        CardInfStr=CardInfStr+'%02x ' % (CardNuff[num])                                       
                    print('卡片内数据:'+ CardInfStr)
                    
                    #在这里加入业务对数据库的查、增、删、改操作
                    
                    CardNuff=bytearray()                #已接收完,清空接收缓冲
                    
                print('n')    
 
            elif(data[0]==eval('0xC5')):               #指定区号、密码读卡返回信息
                print('接收到的信息为读取IC卡扇区内数据')
                print('指令码 :%02x ' % (data[0]))
                print('设备IP :%d.%d.%d.%d' % (data[1],data[2],data[3],data[4]))
                print('机  号 :%d' % (data[5]+data[6]*256))
                print('16进制卡号:%02x%02x%02x%02x' % (data[8],data[9],data[10],data[11])) 
                print('扇区数 :%02x ' % (data[7]))
                print('扇区号 :%02x ' % (data[12]))
                
                if(data[13]==0):
                    CardInfStr=''
                    for num in range(0,48):
                        CardInfStr=CardInfStr+'%02x ' % (data[14+num])                                       
                    print('卡片内数据:'+ CardInfStr+'n')
                    
                    WriteCard(data,addr)                 #如果写卡,可以继续 发送写信息到指定扇区的指令
                else:
                    if(data[13]==12):
                        print('卡密码认证失败n')
                    else:
                        print('读卡失败,错误代码:%02x ' % (data[13])+'n')
                        
            elif(data[0]==eval('0xCD')):               #响应写卡、更改卡密码后的返回信息
                print('指令码 :%02x ' % (data[0]))
                print('设备IP :%d.%d.%d.%d' % (data[2],data[3],data[4],data[5]))
                print('机  号 :%d' % (data[6]+data[7]*256))
                print('16进制卡号:%02x%02x%02x%02x' % (data[9],data[10],data[11],data[12])) 
                print('扇区数 :%02x ' % (data[8]))
                print('扇区号 :%02x ' % (data[13]))
                if(data[1]==0x3A):
                    if(data[14]==0x00):
                        print('更改卡密码成功!')
                    else:
                        print('更改卡密码失败,错误代码:%02x ' % (data[14]))
                else:
                    if(data[1]==0x3D):
                        if(data[14]==0x00):
                            print('写卡成功!')
                        else:
                            print('写卡失败,错误代码:%02x ' % (data[14]))
                            
                print('n')
                
    else:
        print('n')

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 读卡器
    +关注

    关注

    2

    文章

    419

    浏览量

    39397
  • python
    +关注

    关注

    56

    文章

    4800

    浏览量

    84820
收藏 人收藏

    评论

    相关推荐

    液显ID读卡器C#小程序开发

    液显WIFI无线读卡器ID-10F用C#语音开发HTTP协议读卡程序读卡器图片如下: 
    的头像 发表于 01-10 15:31 25次阅读
    液显<b class='flag-5'>ID</b><b class='flag-5'>读卡器</b>C#小<b class='flag-5'>程序</b><b class='flag-5'>开发</b>

    ID卡网络读卡器C#小程序开发

    (85.6x54x0.80±0.04mm)、异型卡等不同类型。按照应用场景,它通常包含个人的身份信息,如姓名、照片、身份证号码等,常见的包括身份证、员工工作证、学生证,以及用于考勤、门禁、一卡通等系统的卡片。 二、工作原理 ID卡的工作过程如下: ID卡阅读
    的头像 发表于 12-31 11:30 72次阅读
    <b class='flag-5'>ID</b>卡网络<b class='flag-5'>读卡器</b>C#小<b class='flag-5'>程序</b><b class='flag-5'>开发</b>

    ID读卡器TCP协议QT小程序开发

    ID卡网络读卡器TCP协议QT小程序开发。 TCP(传输控制协议,Transmission Control Protocol)是互联网中最核心、最基本的协议之一。以下是对TCP协议的详
    的头像 发表于 12-31 10:19 94次阅读
    <b class='flag-5'>ID</b><b class='flag-5'>读卡器</b>TCP协议QT小<b class='flag-5'>程序</b><b class='flag-5'>开发</b>

    开疆智能Modbus转Profinet网关连接Modbus读卡器YW-630MA配置案例

    简介: Modbus读卡器YW-630MA是基于RS485总线,遵循Modbus RTU协议的一款IC卡读卡器.。这款读卡器使为PLC而设计和研发的新一代读写,可以直接连接PLC,但
    的头像 发表于 12-23 09:41 121次阅读
    开疆智能Modbus转Profinet网关连接Modbus<b class='flag-5'>读卡器</b>YW-630MA配置案例

    充电桩非接触式读卡器 FSV-MD5422-01

    1、简介 FSV-MD5422-01 产品是一款基于 13.56MHZ 频率射频技术上开发出来的非接触式读卡器模块, 产品基于 TTL、RS232 串口两种设计接口,通信协议简单实用,方便产品
    的头像 发表于 10-29 10:27 230次阅读
    充电桩非接触式<b class='flag-5'>读卡器</b> FSV-MD5422-01

    TRF7970A NFC读卡器天线多路复用

    电子发烧友网站提供《TRF7970A NFC读卡器天线多路复用.pdf》资料免费下载
    发表于 10-26 11:15 0次下载
    TRF7970A NFC<b class='flag-5'>读卡器</b>天线多路复用

    AGV读卡器在AGV自动搬运小车上应用方案

    AGV小车上的AGV读卡器通过读取地面轨道的RFID电子标签信息,做出相应的动作(如改变速度、选择轨道、定位和停车等)。在AGV小车经过站点A处时,AGV读卡器读取A处的电子标签ID号,AGV小车
    的头像 发表于 10-12 17:33 265次阅读
    AGV<b class='flag-5'>读卡器</b>在AGV自动搬运小车上应用方案

    二代身份证识别仪身份证阅读读卡器

    扫描仪 工地实名制读卡器 二代证阅读 ID/IC读卡器 NFC读卡模块 多合一身份证读卡模块
    发表于 09-07 15:09

    X-CUBE-NFC4能否用于其他品牌的NFC读卡器

    X-CUBE-NFC4能否用于其他品牌的NFC读卡器,或者通过移植来驱动其他品牌的NFC读卡器
    发表于 05-22 06:27

    网络读卡器_产品手册

    电子发烧友网站提供《网络读卡器_产品手册.pdf》资料免费下载
    发表于 05-19 09:33 0次下载

    IO-Link RFID读卡器系统方案设计与挑战

    如图2这个IO-Link RFID传感的方案,使用了L6364和STM32G0通用电路来支持IO-Link的协议转换,使用ST25R3916来作为NFC的读卡器芯片。
    发表于 04-02 10:56 671次阅读
    IO-Link RFID<b class='flag-5'>读卡器</b>系统方案设计与挑战

    使用ST-link V2的过程中电脑插入读卡器设备后无法正常识别ST-link V2的原因?

    配合cubeIDE使用一切正常,电脑插入读卡器设备后无法正常识别ST-link V2,但在电脑的设备管理中还是可以找到ST-link,同时升级ST-link还可以正常操作,目前我只能拔掉读卡器设备后通过重启电脑来解决这个问题!
    发表于 03-11 06:30

    如何使用linux下gdb来调试python程序

    如何使用linux下gdb来调试python程序  在Linux下,可以使用GDB(GNU调试)来调试Python程序。GDB是一个强大的
    的头像 发表于 01-31 10:41 2667次阅读