CCID多线程界面-python

具体功能:
读取一个带有SN号信息的.elsx表,可以根据CCID通讯的终端设备,匹配特定SN号段的相关信息,后根据与终端自定的协议发送.elsx表中设备SN号段中所有配置信息,方便多个设备终端录入配置信息

总结:
俩个点:
1. TK界面 列表框 和 文本标签,可以设置一个tk.StringVar()类,然后 可以在另一个线程中调用类的set()方法,即可改变tk标签上的显示的内容

    varlistb = tk.StringVar()
    listb = tk.Listbox(root, listvariable=varlistb, height=20, width=50, yscrollcommand=sb.set)  # 创建两个列表组件
    var = tk.StringVar()  # 将label标签的内容设置为字符类型,用var来接收hit_me函数的传出内容用以显示在标签上
    l = tk.Label(root, textvariable=var, font=('Arial', 12), width=40, height=5)
2. 打包成.exe文件时, 使用 pyinstaller -F 时,运行显示 win系统找不到PySmartCard文件,所以打包的时候需要自己拼装相应的文件
#命令语法:pyinstaller -F 文件名(带后缀py)
#常用参数说明:
#–icon=图标路径
#-F 打包成一个exe文件
#-w 使用窗口,无控制台
#-c 使用控制台,无窗口
#-D 创建一个目录,里面包含exe以及其他一些依赖性文件

使用 pyinstaller -F -D xxxx.py,运行后再运行.exe,缺失什么文件,可以直接拷贝至.exe文件夹中即可

缺陷:
线程之前切换时,没有使用互斥锁,后期可以优化一下
源代码:

import xlrd
import tkinter as tk
import time
from PySmartCard.CpuCard import PcscReader
import threading
import os
#根据函数生成索引表
def Get_QR_ListData(table, i):
    return table.row_values(i)

#得到各行数据
def Creat_QR_Data(suoyingList, Hang_data):
    i = 0
    Message = ''
    for StrMessage in suoyingList:
        if str(Hang_data[i]) != '':
            Message += StrMessage + '=' + str(Hang_data[i]) + '&'
        i = i + 1
    return (Message.encode('GBK'))

#根据第几行生成对应的二维码
def Create_Photo(table,Meessage):
    global packDATA
    #print(Creat_QR_Data(Get_QR_ListData(table, 0), Get_QR_ListData(table, i)))
    num = table.nrows
    recv_list = []
    for i in range(1, num):
        if Meessage == 'SN':
            continue
        if Meessage in Get_QR_ListData(table, i):
            adu = Creat_QR_Data(Get_QR_ListData(table, 0), Get_QR_ListData(table, i))
            packDATA = adu

#指令数据处理
def CCID_Data(adu):
    global ucMode
    if len(adu) > 1000:
        print("数据长度不能大于1000字节")
        exit()
    #指令头
    AT_Hear = 'F0 2F 51 '
    #数据地址
    AT_Hear_Adder = 16
    Pack_div_len = 252
    #包数据
    Pack_list = ['a1', 'a2', 'a3', 'a4']

    Pack_list.append(hex(int(len(adu) / Pack_div_len)).replace('0x', ''))
    Pack_list.append(hex(len(adu) % Pack_div_len).replace('0x', ''))
    #有效数据
    for i in adu:
        Pack_list.append(hex(i).replace('0x', ''))

    for i in range(0, int(len(Pack_list)/Pack_div_len) + 1):
        MessPackData = ''
        if i != int(len(Pack_list)/Pack_div_len):
            for MessBuf in Pack_list[i*Pack_div_len:(i+1)*Pack_div_len]:
                if len(MessBuf) == 1:
                    MessPackData += '0'
                MessPackData += str(MessBuf)
        else:
            for MessBuf in Pack_list[i*Pack_div_len:]:
                if len(MessBuf) == 1:
                    MessPackData += '0'
                MessPackData += str(MessBuf)
        Message = AT_Hear + str(hex(AT_Hear_Adder + i).replace('0x', '')) \
                  + hex(int(len(MessPackData)/2)).replace('0x', '') + MessPackData
        recv_list = []
        sendApdu(pcsc, Message, recv_list, 2)
        if recv_list[1] != '9000':
            var.set('CCID下载失败')  # 为label设置值
    var.set('参数下载成功')
    time.sleep(2)
    ucMode = 0

def g():
    global packDATA
    CCID_Data(packDATA)

def showLog(data, issend):
    '''打印日志函数'''
    current = time.strftime('%Y_%m_%d %H:%M:%S', time.localtime())
    if issend:  # 发送到卡片的数据
        send = '-->'
    else:  # 卡片返回的数据
        send = '<--'
    print("{} {} {}".format(current, send, data))

def sendApdu(reader, apdu, recv_list, readerType=None):
    '''给卡片发送指令的函数'''
    # 清空
    recv_list[:] = []
    # 去掉多余的空格
    apdu = apdu.replace(' ', '')
    #showLog(apdu, True)
    respone = reader.send_apdu(apdu, readerType)
    #showLog(respone, False)
    # recv_list第1个元素是返回数据
    recv_list.append(respone[:-4])
    # recv_list第2个元素是sw
    recv_list.append(respone[-4:])

def SendCCidMeessage():
    '''获取所有的读卡器列表'''
    readerName = pcsc.get_pcsc_readerlist()
    ##print(readerName)#字符串类型的读卡器名称,按;隔开
    # 按;切割字符串,得到所有的读卡器名称
    #print('当前连接的读卡器有:')
    readerNameList = readerName.split(';')
    for i in range(len(readerNameList) - 1):
        #print("{} {} :{}".format('reader', i, readerNameList[i]))
        pass
    '''连接指定的读卡器'''
    #print('*' * 40)
    # 要连接的读卡器
    useReaderName = "TianYu ANYPAY 0"

    # 得到的是字符串类型的复位信息
    ATR = pcsc.connect_device(useReaderName)
    if ATR:
        #print("ConnectDevice Success...")
        #print("ATR: ", ATR)
        return 1
    else:
        #print("ConnectDevice Failed!")
        #print("设备连接失败,请检查设备")
        return 0

#线程操作
def autoCaozuo():
    global pcsc, SN, root, ucMode, table
    while 1:
        if ucMode == 0:
            # '''实例化PCSC读卡器'''
            pcsc = PcscReader()
            #print(pcsc)
            if SendCCidMeessage() != 1:
                #print('设备请先进入维护模式')
                varlistb.set('')
                var.set('请先连接终端')  # 为label设置值
                ucMode = 7
            else:
                ucMode = 1
        elif ucMode == 1:
            pcsc = PcscReader()
            SendCCidMeessage()
            # 通过索引顺序获取

            if '商户信息配置表.xlsx' not in os.listdir(os.getcwd()):
                var.set('缺少商户信息配置表.xlsx')
                time.sleep(3)
                ucMode = 0
            else:
                data = xlrd.open_workbook('商户信息配置表.xlsx')
                table = data.sheet_by_index(0)
                # '''读SN号'''#
                recv_list = []
                SN = ''
                sendApdu(pcsc, 'FE 01 01 06 00', recv_list, 2)
                if recv_list[1] == '9000':
                    LenSn = int(recv_list[0][2:4]) * 2
                    SN = str(recv_list[0][4:4 + LenSn])
                # 找SN列的
                i = 0
                # 遍历0行 找SN列数的
                for Mesage in table.row_values(0):
                    if 'SN' == Mesage:
                        break
                    i += 1
                # SN列中对应的SN号
                a = 0
                for Message in table.col_values(i):
                    a += 1
                    if SN == Message:
                        #print('SN号段匹配成功!')
                        var.set('')
                        Message_list = []
                        j = 0
                        # print('设备SN号: ' + SN)
                        for title in table.row_values(0):
                            Message_list.append(title + ':' + table.row_values(a-1)[j])
                            j += 1
                        varlistb.set(Message_list)
                        Create_Photo(table, SN)
                        ucMode = 2
                        break
                    else:
                        if a == table.nrows:
                            ucMode = 0
                            var.set('未找到该设备对应的信息')  # 为label设置值
                            break
        elif ucMode == 7:
            ucMode = 0
        else:
            time.sleep(1)
            pass

def auto_destroy():
    global ucMode
    while 1:
        time.sleep(1)
        if ucMode == 2:
            g()
        elif ucMode == 7:
            ucMode = 0
        else:
            time.sleep(1)
            pass

def CheckActive():
    while 1:
        if True != a.isAlive() or True != b.isAlive():
            a.join(1)
            b.join(1)
            var.set('工具异常,请检查运行环境')
            time.sleep(5)
            root.destroy()
            exit(0)


if __name__ == '__main__':
    pcsc = []
    SN = ''
    ucMode = 0
    xixi = 1
    root = []
    packDATA = ''
    root = tk.Tk()  # 创建窗口对象的背景色
    sb = tk.Scrollbar(root)  # 垂直滚动条组件
    sb.pack(side=tk.RIGHT, fill=tk.Y)  # 设置垂直滚动条显示的位置
    varlistb = tk.StringVar()
    listb = tk.Listbox(root, listvariable=varlistb, height=20, width=50, yscrollcommand=sb.set)  # 创建两个列表组件
    listb.pack()  # 将小部件放置到主窗口中
    var = tk.StringVar()  # 将label标签的内容设置为字符类型,用var来接收hit_me函数的传出内容用以显示在标签上
    l = tk.Label(root, textvariable=var, font=('Arial', 12), width=40, height=5)
    l.pack()
    threadLock = threading.Lock()
    a = threading.Thread(target=autoCaozuo)
    b = threading.Thread(target=auto_destroy)
    c = threading.Thread(target=CheckActive)
    a.start()
    b.start()
    c.start()
    root.mainloop()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值