在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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(num39):
                    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

    瀏覽量

    84821
收藏 人收藏

    評論

    相關推薦

    液顯ID讀卡器C#小程序開發

    液顯WIFI無線讀卡器ID-10F用C#語音開發HTTP協議讀卡程序讀卡器圖片如下:?
    的頭像 發表于 01-10 15:31 ?32次閱讀
    液顯<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 ?231次閱讀
    充電樁非接觸式<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 ?266次閱讀
    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次閱讀
    主站蜘蛛池模板: 色网站免费看| 嫩草影院在线入口| 中国一级特黄真人毛片免费看| 嫩草网| 69国产| 四虎在线精品| 免费网站日本永久免费观看| 经典三级四虎在线观看| 丁香在线视频| 天天干天天色综合| 国产精品福利午夜在线观看| 国产精品任我爽爆在线播放6080| 亚洲一区欧美二区| 一二三四日本视频社区| 四虎最新免费网址| 美女18毛片| bt天堂资源种子在线| 欧美黑粗特黄午夜大片| 欧美最猛黑人xxxx黑人猛交黄| 男生脱美女内裤内衣动态图| 中国毛茸茸bbxx| 日本黄色免费电影| 国产成人精品1024在线| 天堂网www| 日本人六九视频69jzz免费| 日本视频一区二区三区| 天天摸日日添狠狠添婷婷| 欧美刺激午夜性久久久久久久| 沟沟人体一区二区| 男女啪视频大全1000| hdhdhd69日本xxx| 亚洲国产精品综合久久2007| 模特精品视频一区| 午夜一级毛片看看| 免费在线观看的网站| 亚洲天堂.com| 久草视频资源在线| 天天插夜夜| 亚洲一区二区三区免费看| 四虎影视最新| freesexvideo性欧美2|