Browse Source

EMV 模拟器

樊春春 2 years ago
commit
397f113181
61 changed files with 2359 additions and 0 deletions
  1. 114 0
      .gitignore
  2. BIN
      assets/background.jpeg
  3. BIN
      assets/bitbug_favicon.ico
  4. BIN
      assets/ic_launch.png
  5. BIN
      assets/icon/三级上电.jpeg
  6. BIN
      assets/icon/下载.jpg
  7. BIN
      assets/icon/下载2.jpg
  8. BIN
      assets/icon/下载3.jpeg
  9. BIN
      assets/icon/参数设置.jpg
  10. BIN
      assets/icon/实时曲线.png
  11. BIN
      assets/icon/密码.jpg
  12. BIN
      assets/icon/心跳.jpeg
  13. BIN
      assets/icon/数据保存.jpg
  14. BIN
      assets/icon/文件.jpg
  15. BIN
      assets/icon/断路器.jpeg
  16. BIN
      assets/icon/用户管理.jpg
  17. BIN
      assets/icon/继电器开关.jpg
  18. BIN
      assets/icon/设置2.jpg
  19. BIN
      assets/icon/读取参数.png
  20. BIN
      assets/icon/配置参数.jpeg
  21. BIN
      assets/icon/铁电.jpg
  22. 153 0
      build_pyd.py
  23. BIN
      config/ControlCANx86/ControlCAN.dll
  24. BIN
      config/ControlCANx86/kerneldlls/CAN232.dll
  25. BIN
      config/ControlCANx86/kerneldlls/CANETE.dll
  26. BIN
      config/ControlCANx86/kerneldlls/CANET_TCP.dll
  27. BIN
      config/ControlCANx86/kerneldlls/PC104C2.dll
  28. BIN
      config/ControlCANx86/kerneldlls/PC104CAN.dll
  29. BIN
      config/ControlCANx86/kerneldlls/PCI5121.dll
  30. BIN
      config/ControlCANx86/kerneldlls/gisadll.dll
  31. BIN
      config/ControlCANx86/kerneldlls/gpcidll.dll
  32. BIN
      config/ControlCANx86/kerneldlls/isa5420.dll
  33. 20 0
      config/ControlCANx86/kerneldlls/kerneldll.ini
  34. BIN
      config/ControlCANx86/kerneldlls/usbcan.dll
  35. 0 0
      controller/__init__.py
  36. 340 0
      controller/emv_ctl.py
  37. 32 0
      controller/emv_status_ctl.py
  38. 35 0
      emv_upper.py
  39. 13 0
      requirements.txt
  40. 0 0
      ui/__init__.py
  41. 322 0
      ui/home.py
  42. 0 0
      ui/own/__init__.py
  43. 21 0
      ui/own/frame_theme.py
  44. 257 0
      ui/own/led.py
  45. 87 0
      ui/own/palette_theme.py
  46. 90 0
      ui/own/switch_button.py
  47. 57 0
      ui/statusbar.py
  48. 0 0
      utils/__init__.py
  49. 209 0
      utils/can.py
  50. 61 0
      utils/com.py
  51. 32 0
      utils/delay.py
  52. 148 0
      utils/globalvar.py
  53. 28 0
      utils/log_signal.py
  54. 66 0
      utils/qt.py
  55. 27 0
      utils/resource.py
  56. 95 0
      utils/utils.py
  57. 0 0
      widget/__init__.py
  58. 74 0
      widget/emv_home.py
  59. 21 0
      widget/emv_status_bar.py
  60. 0 0
      worker/__init__.py
  61. 57 0
      worker/emv_work.py

+ 114 - 0
.gitignore

@@ -0,0 +1,114 @@
+# Mac
+.DS_Store
+*/.DS_Store
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# vscode 
+.vscode
+.vscode/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
+*.csv
+**/Thumbs.db

BIN
assets/background.jpeg


BIN
assets/bitbug_favicon.ico


BIN
assets/ic_launch.png


BIN
assets/icon/三级上电.jpeg


BIN
assets/icon/下载.jpg


BIN
assets/icon/下载2.jpg


BIN
assets/icon/下载3.jpeg


BIN
assets/icon/参数设置.jpg


BIN
assets/icon/实时曲线.png


BIN
assets/icon/密码.jpg


BIN
assets/icon/心跳.jpeg


BIN
assets/icon/数据保存.jpg


BIN
assets/icon/文件.jpg


BIN
assets/icon/断路器.jpeg


BIN
assets/icon/用户管理.jpg


BIN
assets/icon/继电器开关.jpg


BIN
assets/icon/设置2.jpg


BIN
assets/icon/读取参数.png


BIN
assets/icon/配置参数.jpeg


BIN
assets/icon/铁电.jpg


+ 153 - 0
build_pyd.py

@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :setup.py
+@时间    :2022/02/21 17:00:46
+@作者    :None
+@版本    :1.0
+@说明    :源码编译文件
+'''
+
+
+import sys
+import os
+import shutil
+import time
+from distutils.core import setup
+from Cython.Build import cythonize
+
+# import zipextimporter
+
+start_time = time.time()
+curr_dir = os.path.abspath('.')
+parent_path = sys.argv[1] if len(sys.argv) > 1 else ""
+setup_file = __file__.replace('/', '')
+build_dir = "build"
+build_tmp_dir = build_dir + "/temp"
+
+s = "# cython: language_level=3"
+
+"""
+获取py文件的路径
+:param base_path: 根路径
+:param parent_path: 父路径
+:param excepts: 排除文件
+:return: py文件的迭代器
+"""
+
+
+def get_py(base_path=os.path.abspath('.'), parent_path='', name='', excepts=(), copyOther=False, delC=False):
+
+    full_path = os.path.join(base_path, parent_path, name)
+    for filename in os.listdir(full_path):
+        full_filename = os.path.join(full_path, filename)
+        if os.path.isdir(full_filename) and filename != build_dir and not filename.startswith('.'):
+            for f in get_py(base_path, os.path.join(parent_path, name), filename, excepts, copyOther, delC):
+                yield f
+        elif os.path.isfile(full_filename):
+            ext = os.path.splitext(filename)[1]
+            if ext == ".c":
+                if delC and os.stat(full_filename).st_mtime > start_time:
+                    os.remove(full_filename)
+            elif full_filename not in excepts and os.path.splitext(filename)[1] not in ('.pyc', '.pyx'):
+                if os.path.splitext(filename)[1] in ('.py', '.pyx') and not filename.startswith('__'):
+                    path = os.path.join(parent_path, name, filename)
+                    yield path
+        else:
+            pass
+
+
+def pack_pyd():
+    # 获取py列表
+    module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,)))
+    try:
+        setup(
+            ext_modules=cythonize(module_list, language_level="3"),
+            script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir],
+        )
+    except Exception as ex:
+        print("error! ", str(ex))
+    else:
+        module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,), copyOther=True))
+
+    module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,), delC=True))
+    if os.path.exists(build_tmp_dir):
+        shutil.rmtree(build_tmp_dir)
+
+    print("complate! time:", time.time() - start_time, 's')
+
+
+"""
+删除编译过程中生成的.c文件
+:param path:
+:param excepts:
+:return:
+"""
+
+
+def delete_c(path='.', excepts=(setup_file,)):
+
+    dirs = os.listdir(path)
+    for dir in dirs:
+        new_dir = os.path.join(path, dir)
+        if os.path.isfile(new_dir):
+            ext = os.path.splitext(new_dir)[1]
+            if ext == '.c':
+                os.remove(new_dir)
+        elif os.path.isdir(new_dir):
+            delete_c(new_dir)
+
+
+if __name__ == '__main__':
+    try:
+        pack_pyd()
+    except Exception as e:
+        print(str(e))
+    finally:
+        delete_c()
+
+# #!/usr/bin/env python
+# # -*- coding:utf-8 -*-
+# # @time: 2021/5/26 14:17
+# # @File: create_pyd_file.py
+# import os
+# import shutil
+# import time
+# import sys
+
+
+# def func(path):
+#     folder_path = os.path.dirname(path)
+#     file_path = os.path.split(path)[1]
+#     os.chdir(folder_path)
+#     with open('setup.py', 'w') as f:
+#         f.write('from setuptools import setup\n')
+#         f.write('from Cython.Build import cythonize\n')
+#         f.write('setup(\n')
+#         f.write("name='test',\n")
+#         f.write("ext_modules=cythonize('%s')\n" % file_path)
+#         f.write(")\n")
+#     os.system('python setup.py build_ext --inplace')
+#     filename = file_path.split('.py')[0]
+#     time.sleep(2)
+#     # 这里的cp37-win_amd64需要注意一下,这个是依据python解释器类型以及windows版本生成的,建议是单个生成一个pyd文件然后相应修改一下
+#     os.rename('%s\\%s.cp38-win_64.pyd' % (folder_path, filename), '%s\\%s.pyd' % (folder_path, filename))
+#     # 这个是删除py源文件,测试的时候可以先注释掉查看效果
+#     os.remove('%s.c' % filename)
+#     build_folder_path = os.path.join(folder_path, 'build')
+#     # 删除掉生成的build文件夹
+#     shutil.rmtree(build_folder_path)
+#     os.remove('setup.py')
+#     os.remove(file_path)
+
+
+# def get_all_file(path):
+#     for root, dirs, files in os.walk(path):
+#         for name in files:
+#             if name.endswith(".py"):
+#                 file_path = os.path.join(root, name)
+#                 func(file_path)
+
+
+# paths = sys.argv[1]
+# get_all_file(paths)

BIN
config/ControlCANx86/ControlCAN.dll


BIN
config/ControlCANx86/kerneldlls/CAN232.dll


BIN
config/ControlCANx86/kerneldlls/CANETE.dll


BIN
config/ControlCANx86/kerneldlls/CANET_TCP.dll


BIN
config/ControlCANx86/kerneldlls/PC104C2.dll


BIN
config/ControlCANx86/kerneldlls/PC104CAN.dll


BIN
config/ControlCANx86/kerneldlls/PCI5121.dll


BIN
config/ControlCANx86/kerneldlls/gisadll.dll


BIN
config/ControlCANx86/kerneldlls/gpcidll.dll


BIN
config/ControlCANx86/kerneldlls/isa5420.dll


+ 20 - 0
config/ControlCANx86/kerneldlls/kerneldll.ini

@@ -0,0 +1,20 @@
+[KERNELDLL]
+COUNT=18
+1=PCI5121.dll
+2=PCI9810B.dll
+3=USBCAN.dll
+4=USBCAN.dll
+5=PCI9820B.dll
+6=CAN232.dll
+7=PCI5121.dll
+8=CANLite.dll
+9=ISA9620B.dll
+10=ISA5420.dll
+11=PC104CAN.dll
+12=CANETE.dll
+13=DNP9810B.dll
+14=PCI9840B.dll
+15=PC104C2.dll
+16=PCI9820I.dll
+17=CANET_TCP.dll
+18=pec9920.dll

BIN
config/ControlCANx86/kerneldlls/usbcan.dll


+ 0 - 0
controller/__init__.py


+ 340 - 0
controller/emv_ctl.py

@@ -0,0 +1,340 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :bms_pcs_ctl.py
+@时间    :2022/02/21 16:56:26
+@作者    :None
+@版本    :1.0
+@说明    :主页面 CTL
+'''
+
+from sys import argv
+from utils.globalvar import SD, EmvState
+from utils.qt import QApplication, QThread
+from controller.emv_status_ctl import EmvStatusControll
+from widget.emv_home import Win_Emv_Home
+from worker.emv_work import EmvCanReceived, EmvComWork
+from utils.utils import calculate_crc_8, a_bit
+import serial.tools.list_ports
+
+
+class EmvControll:
+    def __init__(self):
+        self._app = QApplication(argv)
+        self._view = Win_Emv_Home()
+        self._model = EmvState()
+        self.init()
+
+    def init(self):
+        self.port_check()
+        self.emv_status = EmvStatusControll()
+        self._view.setStatusBar(self.emv_status._view.statusbar)
+        self._view.interface_signal.connect(self.interface_chose)
+        self._view.cb_bms.currentIndexChanged.connect(self._bms_id)
+        self._view.connect_signal.connect(self.emv_connect)
+        self._view.disconnect_signal.connect(self.emv_disconnect)
+        self._view.emv_on_signal.connect(self.emv_on)
+        self._view.emv_off_signal.connect(self.emv_off)
+
+    def _bms_id(self):
+        SD.EMV_ID = int(self._view.cb_bms.currentText())
+
+    def emv_on(self):
+        if SD.CAN_ON_OFF:
+            data = [0, 0, 0, 0, 0, 0, 0, 0xAA]
+            if self._view.cb_cls.currentIndex() == 0:
+                data[1] = 0xff
+                data[2] = 0x01
+            elif self._view.cb_cls.currentIndex() <= 8:
+                data[1] = 1 << self._view.cb_cls.currentIndex() - 1
+            else:
+                data[2] = 1 << (self._view.cb_cls.currentIndex() - 9)
+
+            self._model.emv_1_state = a_bit(data[1], 1)
+            self._model.emv_2_state = a_bit(data[1], 2)
+            self._model.emv_3_state = a_bit(data[1], 3)
+            self._model.emv_4_state = a_bit(data[1], 4)
+            self._model.emv_5_state = a_bit(data[1], 5)
+            self._model.emv_6_state = a_bit(data[1], 6)
+            self._model.emv_7_state = a_bit(data[1], 7)
+            self._model.emv_8_state = a_bit(data[1], 8)
+            self._model.emv_9_state = a_bit(data[2], 1)
+
+            if self._view.cb_interface.currentIndex() == 0:
+                data[0] = calculate_crc_8(0x18CF0000 | SD.EMV_ID, data[1:])
+                SD.CAN_CONTROL.send(0x18CF0000 | SD.EMV_ID, data, extern_flag=True)
+            elif self._view.cb_interface.currentIndex() == 1:
+                SD.COM_CONTROL.send_16h(0x01, 0x0064, 0x0003, 3, [data[1], data[2], data[7]])
+                self._emv_ce_signal(data, 1)
+            else:
+                return
+
+    def emv_off(self):
+        if SD.CAN_ON_OFF:
+            data = [0, 0xFF, 1, 0, 0, 0, 0, 0xFF]
+            if self._view.cb_cls.currentIndex() == 0:
+                data[1] = 0
+                data[2] = 0
+            elif self._view.cb_cls.currentIndex() <= 8:
+                data[1] = (~ (1 << self._view.cb_cls.currentIndex() - 1)) & 0xFF
+            else:
+                data[2] = 0
+
+            self._model.emv_1_state = a_bit(data[1], 1)
+            self._model.emv_2_state = a_bit(data[1], 2)
+            self._model.emv_3_state = a_bit(data[1], 3)
+            self._model.emv_4_state = a_bit(data[1], 4)
+            self._model.emv_5_state = a_bit(data[1], 5)
+            self._model.emv_6_state = a_bit(data[1], 6)
+            self._model.emv_7_state = a_bit(data[1], 7)
+            self._model.emv_8_state = a_bit(data[1], 8)
+            self._model.emv_9_state = a_bit(data[2], 1)
+
+            if self._view.cb_interface.currentIndex() == 0:
+                data[0] = calculate_crc_8(0x18CF0000 | SD.EMV_ID, data[1:])
+                SD.CAN_CONTROL.send(0x18CF0000 | SD.EMV_ID, data, extern_flag=True)
+            elif self._view.cb_interface.currentIndex() == 1:
+                SD.COM_CONTROL.send_16h(0x01, 0x0064, 0x0003, 3, [data[1], data[2], data[7]])
+                self._emv_ce_signal(data, 1)
+            else:
+                return
+
+    def port_check(self):
+        com_port = {}
+        port_list = list(serial.tools.list_ports.comports())
+        self._view.cb_com_interface_port.clear()
+
+        for port in port_list:
+            com_port["%s" % port_list[0]] = "%s" % port[1]
+            self._view.cb_com_interface_port.addItem(port[0])
+
+    def emv_connect(self):
+        if self._view.cb_interface.currentIndex() == 0:
+            self.emv_can_connect()
+        elif self._view.cb_interface.currentIndex() == 1:
+            self.emv_com_connect()
+        else:
+            return
+
+    def emv_com_connect(self):
+        self._port = self._view.cb_com_interface_port.currentText()
+        self._baudrate = int(self._view.cb_com_interface_baudrate.currentText())
+        self._bytesize = int(self._view.cb_com_interface_word_length.currentText())
+        self._stopbits = int(self._view.cb_com_interface_stop.currentText())
+
+        if self._view.cb_com_interface_parity.currentIndex() == 0:
+            self._parity = 'N'
+        elif self._view.cb_com_interface_parity.currentIndex() == 1:
+            self._parity = 'E'
+        elif self._view.cb_com_interface_parity.currentIndex() == 2:
+            self._parity = 'O'
+        else:
+            self._parity = 'M'
+
+        SD.COM_CONTROL.set_com(self._port, self._baudrate, self._bytesize, self._parity, self._stopbits)
+        SD.CAN_ON_OFF = SD.COM_CONTROL.open_device()
+
+        if SD.CAN_ON_OFF:
+            self.emv_com_connected()
+            self._view.groupbox_com_interface.setDisabled(True)
+            self._view.groupbox_interface.setDisabled(True)
+        else:
+            self._view.no_com_device()
+
+    def emv_com_connected(self):
+        # Com线程类
+        self.emv_com_thread = QThread()
+        self.emv_com_work = EmvComWork()
+        self.emv_com_work.moveToThread(self.emv_com_thread)
+        self.emv_com_thread.finished.connect(self.emv_com_work.deleteLater)
+        self.emv_com_thread.started.connect(self.emv_com_work.work)
+
+        self.emv_com_work.show_com_signal.connect(self.emv_com_signal)
+
+        # 启动线程
+        self.emv_com_thread.start()
+        self.emv_status.emv_connect()
+
+    def emv_com_signal(self, v1, v2, v3):
+        self._view.led_emv_total.set_status(1)
+        ver = "v" + str(v1) + "." + str(v2) + "." + str(v3)
+        self._view.edt_emv_version.setText(ver)
+
+    def emv_can_connect(self):
+        self._can_index_var = self._view.cb_can_interface_index.currentText()
+        self._can_chanel_var = self._view.cb_can_interface_channel.currentText()
+        self._can_baudrate_var = self._view.cb_can_interface_baudrate.currentText()
+
+        can_index = int(self._can_index_var)
+        can_channel = int(self._can_chanel_var)
+        can_baudrate = self._can_baudrate_var
+
+        SD.CAN_CONTROL.set_can_board(can_index, can_channel, can_baudrate)
+        try:
+            if SD.CAN_CONTROL.open_device():
+                SD.CAN_ON_OFF = SD.CAN_CONTROL.init_can(0x00000000, 0xFFFFFFFF)
+
+            if SD.CAN_ON_OFF:
+                self.emv_can_connected()
+                self._view.groupbox_can_interface.setDisabled(True)
+                self._view.groupbox_interface.setDisabled(True)
+            else:
+                self._view.can_connect_error()
+        except AttributeError:
+            self._view.no_can_device()
+
+    def emv_disconnect(self):
+        if self._view.cb_interface.currentIndex() == 0:
+            self.emv_can_disconnect()
+        elif self._view.cb_interface.currentIndex() == 1:
+            self.emv_com_disconnect()
+        else:
+            return
+
+    def emv_com_disconnect(self):
+        if SD.CAN_ON_OFF:
+            SD.CAN_ON_OFF = False
+
+        if self.emv_com_thread.isRunning():
+            self.emv_com_thread.quit()
+            self.emv_com_thread.wait()
+
+        if self.emv_com_thread.isFinished():
+            del self.emv_com_work
+            del self.emv_com_thread
+
+        self._view.groupbox_com_interface.setDisabled(False)
+        self._view.groupbox_interface.setDisabled(False)
+        self.emv_data_recovery()
+        self.emv_status.emv_disconnect()
+
+    def emv_can_disconnect(self):
+        if SD.CAN_ON_OFF:
+            SD.CAN_ON_OFF = False
+            SD.CAN_CONTROL.clear_buffer()
+            SD.CAN_CONTROL.close_can()
+
+        if self.emv_can_received_thread.isRunning():
+            self.emv_can_received_thread.quit()
+            self.emv_can_received_thread.wait()
+
+        if self.emv_can_received_thread.isFinished():
+            del self.emv_can_received
+            del self.emv_can_received_thread
+
+        self._view.groupbox_can_interface.setDisabled(False)
+        self._view.groupbox_interface.setDisabled(False)
+        self.emv_status.emv_disconnect()
+        self.emv_data_recovery()
+
+    def emv_can_connected(self):
+        # CAN数据接收类
+        self.emv_can_received_thread = QThread()
+        self.emv_can_received = EmvCanReceived()
+        self.emv_can_received.moveToThread(self.emv_can_received_thread)
+        self.emv_can_received_thread.finished.connect(self.emv_can_received.deleteLater)
+        self.emv_can_received_thread.started.connect(self.emv_can_received.received)
+
+        self.emv_can_received.show_emv_ce_signal.connect(self._emv_ce_signal)
+        self.emv_can_received.show_emv_cf_signal.connect(self._emv_cf_signal)
+        # 启动线程
+        self.emv_can_received_thread.start()
+        self.emv_status.emv_connect()
+
+    def _emv_ce_signal(self, data, con_type):
+        if (data[0] == 0xaa and con_type == 0) or (data[7] == 0xaa and con_type == 1):
+            if self._view.cb_cls.currentIndex() == 0:
+                self._view.led_emv_1.set_status(self._model.emv_1_state)
+                self._view.led_emv_2.set_status(self._model.emv_2_state)
+                self._view.led_emv_3.set_status(self._model.emv_3_state)
+                self._view.led_emv_4.set_status(self._model.emv_4_state)
+                self._view.led_emv_5.set_status(self._model.emv_5_state)
+                self._view.led_emv_6.set_status(self._model.emv_6_state)
+                self._view.led_emv_7.set_status(self._model.emv_7_state)
+                self._view.led_emv_8.set_status(self._model.emv_8_state)
+                self._view.led_emv_9.set_status(self._model.emv_9_state)
+            elif self._view.cb_cls.currentIndex() == 1:
+                self._view.led_emv_1.set_status(self._model.emv_1_state)
+            elif self._view.cb_cls.currentIndex() == 2:
+                self._view.led_emv_2.set_status(self._model.emv_2_state)
+            elif self._view.cb_cls.currentIndex() == 3:
+                self._view.led_emv_3.set_status(self._model.emv_3_state)
+            elif self._view.cb_cls.currentIndex() == 4:
+                self._view.led_emv_4.set_status(self._model.emv_4_state)
+            elif self._view.cb_cls.currentIndex() == 5:
+                self._view.led_emv_5.set_status(self._model.emv_5_state)
+            elif self._view.cb_cls.currentIndex() == 6:
+                self._view.led_emv_6.set_status(self._model.emv_6_state)
+            elif self._view.cb_cls.currentIndex() == 7:
+                self._view.led_emv_7.set_status(self._model.emv_7_state)
+            elif self._view.cb_cls.currentIndex() == 8:
+                self._view.led_emv_8.set_status(self._model.emv_8_state)
+            elif self._view.cb_cls.currentIndex() == 9:
+                self._view.led_emv_9.set_status(self._model.emv_9_state)
+            else:
+                return
+        elif (data[0] == 0xff and con_type == 0) or (data[7] == 0xff and con_type == 1):
+            if self._view.cb_cls.currentIndex() == 0:
+                self._view.led_emv_1.set_status(self._model.emv_1_state)
+                self._view.led_emv_2.set_status(self._model.emv_2_state)
+                self._view.led_emv_3.set_status(self._model.emv_3_state)
+                self._view.led_emv_4.set_status(self._model.emv_4_state)
+                self._view.led_emv_5.set_status(self._model.emv_5_state)
+                self._view.led_emv_6.set_status(self._model.emv_6_state)
+                self._view.led_emv_7.set_status(self._model.emv_7_state)
+                self._view.led_emv_8.set_status(self._model.emv_8_state)
+                self._view.led_emv_9.set_status(self._model.emv_9_state)
+            elif self._view.cb_cls.currentIndex() == 1:
+                self._view.led_emv_1.set_status(self._model.emv_1_state)
+            elif self._view.cb_cls.currentIndex() == 2:
+                self._view.led_emv_2.set_status(self._model.emv_2_state)
+            elif self._view.cb_cls.currentIndex() == 3:
+                self._view.led_emv_3.set_status(self._model.emv_3_state)
+            elif self._view.cb_cls.currentIndex() == 4:
+                self._view.led_emv_4.set_status(self._model.emv_4_state)
+            elif self._view.cb_cls.currentIndex() == 5:
+                self._view.led_emv_5.set_status(self._model.emv_5_state)
+            elif self._view.cb_cls.currentIndex() == 6:
+                self._view.led_emv_6.set_status(self._model.emv_6_state)
+            elif self._view.cb_cls.currentIndex() == 7:
+                self._view.led_emv_7.set_status(self._model.emv_7_state)
+            elif self._view.cb_cls.currentIndex() == 8:
+                self._view.led_emv_8.set_status(self._model.emv_8_state)
+            elif self._view.cb_cls.currentIndex() == 9:
+                self._view.led_emv_9.set_status(self._model.emv_9_state)
+            else:
+                return
+        else:
+            return
+
+    def _emv_cf_signal(self, data):
+        self._view.led_emv_total.set_status(1)
+        emv_ver = "v" + str(a_bit(data[0], 1)) + "." + str(a_bit(data[0], 2)) + "." + str(a_bit(data[0], 3))
+        self._view.edt_emv_version.setText(emv_ver)
+
+    def run(self):
+        self._view.show()
+        return self._app.exec_()
+
+    def interface_chose(self, current_interface):
+        if current_interface == 1:
+            self._view.groupbox_can_interface.hide()
+            self._view.groupbox_com_interface.show()
+        else:
+            self._view.groupbox_com_interface.hide()
+            self._view.groupbox_can_interface.show()
+
+    def emv_data_recovery(self):
+        self._view.cb_bms.setCurrentIndex(0)
+        self._view.led_emv_total.set_status(0)
+        self._view.led_emv_1.set_status(0)
+        self._view.led_emv_2.set_status(0)
+        self._view.led_emv_3.set_status(0)
+        self._view.led_emv_4.set_status(0)
+        self._view.led_emv_5.set_status(0)
+        self._view.led_emv_6.set_status(0)
+        self._view.led_emv_7.set_status(0)
+        self._view.led_emv_8.set_status(0)
+        self._view.led_emv_9.set_status(0)
+        self._view.led_emv_10.set_status(0)
+        SD.EMV_ID = 1

+ 32 - 0
controller/emv_status_ctl.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :bms_status_ctl.py
+@时间    :2022/02/21 16:57:56
+@作者    :None
+@版本    :1.0
+@说明    : 状态栏 CTL
+'''
+
+
+from widget.emv_status_bar import Win_Emv_Status_Bar
+from utils.globalvar import SD
+
+
+class EmvStatusControll:
+    def __init__(self):
+        self._view = Win_Emv_Status_Bar()
+
+    def emv_connect(self):
+        self._view.label_emv_connect.setText("已连接")
+        self._view.label_emv_send.setText("发送参数中")
+        self._view.label_emv_received.setText("接收数据中")
+
+    def emv_disconnect(self):
+        if SD.CAN_ON_OFF is False:
+            self._view.label_emv_send.setText("发送未启动")
+            self._view.label_emv_received.setText("接收未启动")
+            self._view.label_emv_connect.setText("未连接")
+
+    def run(self):
+        self._view.show()

+ 35 - 0
emv_upper.py

@@ -0,0 +1,35 @@
+"""
+@文件    :EmvUpper.py
+@时间    :2021/12/08 16:32:57
+@作者    :None
+@版本    :1.0
+@说明    :EmvUpper程序主入口
+"""
+
+
+from sys import exit
+from controller.emv_ctl import EmvControll
+from utils.globalvar import SD
+from utils.qt import QApplication, QCoreApplication, Qt, QStyleFactory
+
+
+def emv_start():
+
+    # 适配分辨率
+    if hasattr(Qt, 'AA_EnableHighDpiScaling'):
+        QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
+
+    if hasattr(Qt, 'AA_UseHighDpiPixmaps'):
+        QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
+        SD.HIGH_DPI = 0
+    else:
+        SD.HIGH_DPI = 1
+    main_connrtoller = EmvControll()
+
+    QApplication.setStyle(QStyleFactory.create("windows"))
+
+    exit(main_connrtoller.run())
+
+
+if __name__ == "__main__":
+    emv_start()

+ 13 - 0
requirements.txt

@@ -0,0 +1,13 @@
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile requirements.txt
+#
+
+
+PyQt5
+PyQtChart
+PySide
+requests
+pyserial

+ 0 - 0
ui/__init__.py


+ 322 - 0
ui/home.py

@@ -0,0 +1,322 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :home.py
+@时间    :2022/01/22 09:53:31
+@作者    :None
+@版本    :1.0
+@说明    :主页面
+'''
+
+
+from ui.own.frame_theme import MyFrame
+from ui.own.switch_button import SwitchButton
+from ui.own.led import Led
+from ui.own.palette_theme import set_my_palette
+from utils.qt import Qt, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QGroupBox, QPushButton, QSizePolicy, QComboBox, QSize, QCoreApplication, QMetaObject
+
+
+class UiEmvHomePage(object):
+    def setupUi(self, main):
+        main.resize(500, 400)
+        main.setMinimumSize(500, 400)
+        main.setMaximumSize(500, 400)
+
+        set_my_palette(main)
+
+        self.central_widget = QWidget(main)
+        self.main_layout = QHBoxLayout(self.central_widget)
+        self.main_layout.setContentsMargins(0, 0, 0, 0)
+        self.main_layout.setSpacing(0)
+
+        # 主窗口左侧布局
+        self.left_widget = QWidget(self.central_widget)
+        # 主窗口左侧采用垂直布局
+        self.left_layout = QVBoxLayout(self.left_widget)
+        self.left_layout.setContentsMargins(0, 0, 0, 0)
+        self.left_layout.setSpacing(0)
+
+        # 数据接口
+        self.interface_widget = MyFrame(self.left_widget)
+        self.interface_hlayout = QHBoxLayout(self.interface_widget)
+        self.interface_hlayout.setContentsMargins(0, 0, 0, 0)
+        self.interface_hlayout.setSpacing(0)
+        self.groupbox_interface = QGroupBox(self.interface_widget)
+        self.interface_vlayout = QVBoxLayout(self.groupbox_interface)
+        self.cb_interface = QComboBox(self.groupbox_interface)
+        self.cb_interface.addItems(["CAN通讯", "串口通讯"])
+        self.interface_vlayout.addWidget(self.cb_interface)
+        self.interface_hlayout.addWidget(self.groupbox_interface)
+        self.left_layout.addWidget(self.interface_widget)
+
+        # CAN通讯配置
+        self.can_interface_widget = MyFrame(self.left_widget)
+        self.can_interface_hlayout = QHBoxLayout(self.can_interface_widget)
+        self.can_interface_hlayout.setContentsMargins(0, 0, 0, 0)
+        self.can_interface_hlayout.setSpacing(0)
+        self.groupbox_can_interface = QGroupBox(self.can_interface_widget)
+        self.can_interface_glayout = QGridLayout(self.groupbox_can_interface)
+
+        self.lb_can_interface_channel = QLabel(self.groupbox_can_interface)
+        self.lb_can_interface_channel.setText("设备索引号:")
+        self.can_interface_glayout.addWidget(self.lb_can_interface_channel, 0, 0)
+        self.cb_can_interface_channel = QComboBox(self.groupbox_can_interface)
+        self.cb_can_interface_channel.addItems([str(i) for i in range(9)])
+        self.can_interface_glayout.addWidget(self.cb_can_interface_channel, 0, 1)
+
+        self.lb_can_interface_index = QLabel(self.groupbox_can_interface)
+        self.lb_can_interface_index.setText("设备通道号:")
+        self.can_interface_glayout.addWidget(self.lb_can_interface_index, 1, 0)
+        self.cb_can_interface_index = QComboBox(self.groupbox_can_interface)
+        self.cb_can_interface_index.addItems(["0", "1"])
+        self.can_interface_glayout.addWidget(self.cb_can_interface_index, 1, 1)
+
+        self.lb_can_interface_baudrate = QLabel(self.groupbox_can_interface)
+        self.lb_can_interface_baudrate.setText("CAN波特率:")
+        self.can_interface_glayout.addWidget(self.lb_can_interface_baudrate, 2, 0)
+        self.cb_can_interface_baudrate = QComboBox(self.groupbox_can_interface)
+        self.cb_can_interface_baudrate.addItems(["125Kbps", "250Kbps", "500Kbps"])
+        self.cb_can_interface_baudrate.setCurrentText("250Kbps")
+        self.can_interface_glayout.addWidget(self.cb_can_interface_baudrate, 2, 1)
+
+        self.can_interface_hlayout.addWidget(self.groupbox_can_interface)
+        self.left_layout.addWidget(self.can_interface_widget)
+
+        # 串口通讯配置
+        self.com_interface_widget = MyFrame(self.left_widget)
+        self.com_interface_hlayout = QHBoxLayout(self.com_interface_widget)
+        self.com_interface_hlayout.setContentsMargins(0, 0, 0, 0)
+        self.com_interface_hlayout.setSpacing(0)
+        self.groupbox_com_interface = QGroupBox(self.interface_widget)
+        self.com_interface_glayout = QGridLayout(self.groupbox_com_interface)
+
+        self.lb_com_interface_port = QLabel(self.groupbox_com_interface)
+        self.lb_com_interface_port.setText("端口号:")
+        self.com_interface_glayout.addWidget(self.lb_com_interface_port, 0, 0)
+        self.cb_com_interface_port = QComboBox(self.groupbox_com_interface)
+        self.cb_com_interface_port.addItems([str(i + 1) for i in range(9)])
+        self.com_interface_glayout.addWidget(self.cb_com_interface_port, 0, 1)
+
+        self.lb_com_interface_baudrate = QLabel(self.groupbox_com_interface)
+        self.lb_com_interface_baudrate.setText("波特率:")
+        self.com_interface_glayout.addWidget(self.lb_com_interface_baudrate, 1, 0)
+        self.cb_com_interface_baudrate = QComboBox(self.groupbox_com_interface)
+        self.cb_com_interface_baudrate.addItems(["9600", "115200"])
+        self.com_interface_glayout.addWidget(self.cb_com_interface_baudrate, 1, 1)
+
+        self.lb_com_interface_parity = QLabel(self.groupbox_com_interface)
+        self.lb_com_interface_parity.setText("校验位:")
+        self.com_interface_glayout.addWidget(self.lb_com_interface_parity, 2, 0)
+        self.cb_com_interface_parity = QComboBox(self.groupbox_com_interface)
+        self.cb_com_interface_parity.addItems(["无校验", "偶校验", "奇校验"])
+        self.com_interface_glayout.addWidget(self.cb_com_interface_parity, 2, 1)
+
+        self.lb_com_interface_word_length = QLabel(self.groupbox_com_interface)
+        self.lb_com_interface_word_length.setText("数据位:")
+        self.com_interface_glayout.addWidget(self.lb_com_interface_word_length, 3, 0)
+        self.cb_com_interface_word_length = QComboBox(self.groupbox_com_interface)
+        self.cb_com_interface_word_length.addItems(["8", "9"])
+        self.com_interface_glayout.addWidget(self.cb_com_interface_word_length, 3, 1)
+
+        self.lb_com_interface_stop = QLabel(self.groupbox_com_interface)
+        self.lb_com_interface_stop.setText("停止位:")
+        self.com_interface_glayout.addWidget(self.lb_com_interface_stop, 4, 0)
+        self.cb_com_interface_stop = QComboBox(self.groupbox_com_interface)
+        self.cb_com_interface_stop.addItems(["1", "1.5", "2"])
+        self.com_interface_glayout.addWidget(self.cb_com_interface_stop, 4, 1)
+        self.groupbox_com_interface.hide()
+        self.com_interface_hlayout.addWidget(self.groupbox_com_interface)
+        self.left_layout.addWidget(self.com_interface_widget)
+
+        # BMS连接开关
+        self.emv_connect_widget = MyFrame(self.left_widget)
+        self.emv_connect_layout = QHBoxLayout(self.emv_connect_widget)
+        self.emv_connect_layout.setContentsMargins(0, 0, 0, 0)
+        self.emv_connect_layout.setSpacing(0)
+        self.groupbox_emv_connect = QGroupBox(self.emv_connect_widget)
+        self.bms_connect_hlayout = QHBoxLayout(self.groupbox_emv_connect)
+        self.emv_switch = SwitchButton(self.groupbox_emv_connect)
+        size_policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
+        size_policy.setHorizontalStretch(0)
+        size_policy.setVerticalStretch(0)
+        size_policy.setHeightForWidth(self.emv_switch.sizePolicy().hasHeightForWidth())
+        self.emv_switch.setSizePolicy(size_policy)
+        self.emv_switch.setMinimumSize(QSize(70, 30))
+        self.bms_connect_hlayout.addWidget(self.emv_switch)
+        self.emv_connect_layout.addWidget(self.groupbox_emv_connect)
+        self.left_layout.addWidget(self.emv_connect_widget)
+
+        # 其他信息
+        self.bms_widget = MyFrame(self.left_widget)
+        self.bms_layout = QHBoxLayout(self.bms_widget)
+        self.bms_layout.setContentsMargins(0, 0, 0, 0)
+        self.bms_layout.setSpacing(0)
+        self.groupbox_bms = QGroupBox(self.bms_widget)
+        self.bms_hlayout = QGridLayout(self.groupbox_bms)
+        self.lb_bms = QLabel(self.groupbox_bms)
+        self.lb_bms.setText("簇编号:")
+        self.bms_hlayout.addWidget(self.lb_bms, 0, 0)
+        self.cb_bms = QComboBox(self.groupbox_bms)
+        self.cb_bms.addItems(["1", "2", "3", "4", "5", "6", "7", "8", "9"])
+        self.bms_hlayout.addWidget(self.cb_bms, 0, 1)
+        size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
+        size_policy.setHorizontalStretch(0)
+        size_policy.setVerticalStretch(0)
+        size_policy.setHeightForWidth(self.groupbox_bms.sizePolicy().hasHeightForWidth())
+        self.groupbox_bms.setSizePolicy(size_policy)
+        self.bms_layout.addWidget(self.groupbox_bms)
+        self.left_layout.addWidget(self.bms_widget)
+
+        # 其他信息
+        self.other_widget = MyFrame(self.left_widget)
+        self.other_layout = QHBoxLayout(self.other_widget)
+        self.other_layout.setContentsMargins(0, 0, 0, 0)
+        self.other_layout.setSpacing(0)
+        self.groupbox_other = QGroupBox(self.other_widget)
+        size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
+        size_policy.setHorizontalStretch(0)
+        size_policy.setVerticalStretch(0)
+        size_policy.setHeightForWidth(self.groupbox_other.sizePolicy().hasHeightForWidth())
+        self.groupbox_other.setSizePolicy(size_policy)
+        self.other_layout.addWidget(self.groupbox_other)
+        self.left_layout.addWidget(self.other_widget)
+
+        self.main_layout.addWidget(self.left_widget, stretch=1)
+
+        self.right_widget = QWidget(self.central_widget)
+        # 主窗口右侧采用垂直布局
+        self.right_layout = QVBoxLayout(self.right_widget)
+        self.right_layout.setContentsMargins(0, 0, 0, 0)
+        self.right_layout.setSpacing(0)
+
+        # 数据接口
+        self.relay_widget = MyFrame(self.right_widget)
+        self.relay_vlayout = QVBoxLayout(self.relay_widget)
+        self.relay_vlayout.setContentsMargins(0, 0, 0, 0)
+        self.relay_vlayout.setSpacing(0)
+        self.groupbox_relay = QGroupBox(self.relay_widget)
+        self.groupbox_relay.setTitle("电磁阀控制指令")
+        self.relay_glayout = QGridLayout(self.groupbox_relay)
+
+        self.emv_version = QLabel(self.groupbox_relay)
+        self.emv_version.setText("电磁阀软件版本号:")
+        self.relay_glayout.addWidget(self.emv_version, 0, 0, 1, 1, Qt.AlignCenter)
+
+        self.edt_emv_version = QLabel(self.groupbox_relay)
+        self.edt_emv_version.setText("")
+        self.relay_glayout.addWidget(self.edt_emv_version, 0, 1, 1, 1, Qt.AlignCenter)
+
+        self.lb_cls = QLabel(self.groupbox_relay)
+        self.lb_cls.setText("电磁阀:")
+        self.relay_glayout.addWidget(self.lb_cls, 1, 0, 1, 1, Qt.AlignCenter)
+        self.cb_cls = QComboBox(self.groupbox_relay)
+        self.cb_cls.addItems(["总", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
+        self.relay_glayout.addWidget(self.cb_cls, 1, 1, 1, 1)
+        self.btn_emv_on = QPushButton(self.groupbox_relay)
+        self.btn_emv_on.setText("闭合")
+        self.relay_glayout.addWidget(self.btn_emv_on, 2, 0, 1, 1, Qt.AlignCenter)
+        self.btn_emv_off = QPushButton(self.groupbox_relay)
+        self.btn_emv_off.setText("断开")
+        self.relay_glayout.addWidget(self.btn_emv_off, 2, 1, 1, 1, Qt.AlignCenter)
+
+        self.relay_vlayout.addWidget(self.groupbox_relay)
+        self.right_layout.addWidget(self.relay_widget)
+
+        # 数据接口
+        self.emv_data_widget = MyFrame(self.right_widget)
+        self.emv_data_hlayout = QHBoxLayout(self.emv_data_widget)
+        self.emv_data_hlayout.setContentsMargins(0, 0, 0, 0)
+        self.emv_data_hlayout.setSpacing(0)
+        self.groupbox_emv_data = QGroupBox(self.emv_data_widget)
+        self.groupbox_emv_data.setTitle("电磁阀状态")
+        self.emv_data_glayout = QGridLayout(self.groupbox_emv_data)
+
+        # 总
+        self.led_emv_total = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_total, 0, 0, 1, 1, Qt.AlignCenter)
+        self.lb_emv_total = QLabel(self.groupbox_emv_data)
+        self.lb_emv_total.setText("总")
+        self.emv_data_glayout.addWidget(self.lb_emv_total, 1, 0, 1, 1, Qt.AlignCenter)
+
+        # 1
+        self.led_emv_1 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_1, 0, 1, 1, 1, Qt.AlignCenter)
+        self.lb_emv_1 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_1.setText("#1")
+        self.emv_data_glayout.addWidget(self.lb_emv_1, 1, 1, 1, 1, Qt.AlignCenter)
+
+        # 2
+        self.led_emv_2 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_2, 0, 2, 1, 1, Qt.AlignCenter)
+        self.lb_emv_2 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_2.setText("#2")
+        self.emv_data_glayout.addWidget(self.lb_emv_2, 1, 2, 1, 1, Qt.AlignCenter)
+
+        # 3
+        self.led_emv_3 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_3, 0, 3, 1, 1, Qt.AlignCenter)
+        self.lb_emv_3 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_3.setText("#3")
+        self.emv_data_glayout.addWidget(self.lb_emv_3, 1, 3, 1, 1, Qt.AlignCenter)
+
+        # 4
+        self.led_emv_4 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_4, 0, 4, 1, 1, Qt.AlignCenter)
+        self.lb_emv_4 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_4.setText("#4")
+        self.emv_data_glayout.addWidget(self.lb_emv_4, 1, 4, 1, 1, Qt.AlignCenter)
+
+        # 5
+        self.led_emv_5 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_5, 0, 5, 1, 1, Qt.AlignCenter)
+        self.lb_emv_5 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_5.setText("#5")
+        self.emv_data_glayout.addWidget(self.lb_emv_5, 1, 5, 1, 1, Qt.AlignCenter)
+
+        # 6
+        self.led_emv_6 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_6, 2, 1, 1, 1, Qt.AlignCenter)
+        self.lb_emv_6 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_6.setText("#6")
+        self.emv_data_glayout.addWidget(self.lb_emv_6, 3, 1, 1, 1, Qt.AlignCenter)
+
+        # 7
+        self.led_emv_7 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_7, 2, 2, 1, 1, Qt.AlignCenter)
+        self.lb_emv_7 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_7.setText("#7")
+        self.emv_data_glayout.addWidget(self.lb_emv_7, 3, 2, 1, 1, Qt.AlignCenter)
+
+        # 8
+        self.led_emv_8 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_8, 2, 3, 1, 1, Qt.AlignCenter)
+        self.lb_emv_8 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_8.setText("#8")
+        self.emv_data_glayout.addWidget(self.lb_emv_8, 3, 3, 1, 1, Qt.AlignCenter)
+
+        # 9
+        self.led_emv_9 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_9, 2, 4, 1, 1, Qt.AlignCenter)
+        self.lb_emv_9 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_9.setText("#9")
+        self.emv_data_glayout.addWidget(self.lb_emv_9, 3, 4, 1, 1, Qt.AlignCenter)
+
+        # 10
+        self.led_emv_10 = Led(self.groupbox_emv_data)
+        self.emv_data_glayout.addWidget(self.led_emv_10, 2, 5, 1, 1, Qt.AlignCenter)
+        self.lb_emv_10 = QLabel(self.groupbox_emv_data)
+        self.lb_emv_10.setText("#10")
+        self.emv_data_glayout.addWidget(self.lb_emv_10, 3, 5, 1, 1, Qt.AlignCenter)
+
+        self.emv_data_hlayout.addWidget(self.groupbox_emv_data)
+        self.right_layout.addWidget(self.emv_data_widget)
+        self.main_layout.addWidget(self.right_widget, stretch=2)
+
+        main.setCentralWidget(self.central_widget)
+
+        self.retranslateUi(main)
+        QMetaObject.connectSlotsByName(main)
+
+    def retranslateUi(self, MainWindow):
+        _translate = QCoreApplication.translate
+        MainWindow.setWindowTitle(_translate("MainWindow", "电磁阀控制器"))

+ 0 - 0
ui/own/__init__.py


+ 21 - 0
ui/own/frame_theme.py

@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :frame_theme.py
+@时间    :2022/01/22 10:04:48
+@作者    :None
+@版本    :1.0
+@说明    :Frame控件主题
+'''
+
+
+from utils.qt import QFrame
+
+
+class MyFrame(QFrame):
+    def __init__(self, parent=None):
+        super(MyFrame, self).__init__(parent)
+        self.setFrameStyle(QFrame.Panel | QFrame.Raised)
+        # 设置外线宽度
+        self.setLineWidth(3)
+        self.setMidLineWidth(3)

+ 257 - 0
ui/own/led.py

@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :led.py
+@时间    :2022/01/14 09:31:20
+@作者    :None
+@版本    :2.0
+@说明    :LED灯
+'''
+
+
+# from numpy import array, uint8
+from utils.qt import QApplication, QColor, QSize, QPushButton
+
+
+class Led(QPushButton):
+    black = QColor(0x00, 0x00, 0x00)
+    white = QColor(0xff, 0xff, 0xff)
+    blue = QColor(0x73, 0xce, 0xf4)
+    green = QColor(0xad, 0xff, 0x2f)
+    orange = QColor(0xff, 0xa5, 0x00)
+    purple = QColor(0xaf, 0x00, 0xff)
+    red = QColor(0xf4, 0x37, 0x53)
+    yellow = QColor(0xff, 0xff, 0x00)
+
+    capsule = 1
+    circle = 2
+    rectangle = 3
+
+    def __init__(self, parent, first_color=green, second_color=red, third_color=yellow, off_color=black, shape=circle):
+        super().__init__()
+
+        self._qss = 'QPushButton {{ \
+                                   border: 3px solid lightgray; \
+                                   border-radius: {}px; \
+                                   background-color: \
+                                       QLinearGradient( \
+                                           y1: 0, y2: 1, \
+                                           stop: 0 white, \
+                                           stop: 0.2 #{}, \
+                                           stop: 0.8 #{}, \
+                                           stop: 1 #{} \
+                                       ); \
+                                 }}'
+        self._first_qss = ''
+        self._second_qss = ''
+        self._third_qss = ''
+        self._off_qss = ''
+
+        self._status = 0
+        self._end_radius = 0
+
+        # Properties that will trigger changes on qss.
+        self.__first_color = None
+        self.__second_color = None
+        self.__third_color = None
+        self.__off_color = None
+        self.__shape = None
+        self.__height = 0
+
+        self._first_color = first_color
+        self._second_color = second_color
+        self._third_color = third_color
+        self._off_color = off_color
+        self._shape = shape
+        self._height = self.sizeHint().height()
+
+    # =================================================== Reimplemented Methods
+    def sizeHint(self):
+        res_h = QApplication.desktop().screenGeometry().height()
+        # res_w = QApplication.desktop().screenGeometry().width()
+
+        # res_w, res_h = pyautogui.size()  # Available resolution geometry
+        if self._shape == Led.capsule:
+            base_w = 50
+            base_h = 30
+        elif self._shape == Led.circle:
+            base_w = 30
+            base_h = 30
+        elif self._shape == Led.rectangle:
+            base_w = 40
+            base_h = 30
+
+        width = int(base_w * res_h / 1080)
+        height = int(base_h * res_h / 1080)
+        return QSize(width, height)
+
+    def resizeEvent(self, event):
+        self._height = self.size().height()
+        QPushButton.resizeEvent(self, event)
+
+    def setFixedSize(self, width, height):
+        self._height = height
+        if self._shape == Led.circle:
+            QPushButton.setFixedSize(self, height, height)
+        else:
+            QPushButton.setFixedSize(self, width, height)
+
+    # ============================================================== Properties
+    # 一级故障
+    @property
+    def _first_color(self):
+        return self.__first_color
+
+    @_first_color.setter
+    def _first_color(self, color):
+        self.__first_color = color
+        self._update_first_qss()
+
+    @_first_color.deleter
+    def _first_color(self):
+        del self.__first_color
+
+    # 二级故障
+    @property
+    def _second_color(self):
+        return self.__second_color
+
+    @_second_color.setter
+    def _second_color(self, color):
+        self.__second_color = color
+        self._update_second_qss()
+
+    @_second_color.deleter
+    def _second_color(self):
+        del self.__second_color
+
+    # 三级故障
+    @property
+    def _third_color(self):
+        return self.__third_color
+
+    @_third_color.setter
+    def _third_color(self, color):
+        self.__third_color = color
+        self._update_third_qss()
+
+    @_third_color.deleter
+    def _third_color(self):
+        del self.__third_color
+
+    # 无故障
+    @property
+    def _off_color(self):
+        return self.__off_color
+
+    @_off_color.setter
+    def _off_color(self, color):
+        self.__off_color = color
+        self._update_off_qss()
+
+    @_off_color.deleter
+    def _off_color(self):
+        del self.__off_color
+
+    @property
+    def _shape(self):
+        return self.__shape
+
+    @_shape.setter
+    def _shape(self, shape):
+        self.__shape = shape
+        self._update_end_radius()
+        self._update_first_qss()
+        self._update_second_qss()
+        self._update_third_qss()
+        self._update_off_qss()
+        self.set_status(self._status)
+
+    @_shape.deleter
+    def _shape(self):
+        del self.__shape
+
+    @property
+    def _height(self):
+        return self.__height
+
+    @_height.setter
+    def _height(self, height):
+        self.__height = height
+        self._update_end_radius()
+        self._update_first_qss()
+        self._update_second_qss()
+        self._update_third_qss()
+        self._update_off_qss()
+        self.set_status(self._status)
+
+    @_height.deleter
+    def _height(self):
+        del self.__height
+
+    # ================================================================= Methods
+    def _update_first_qss(self):
+        color, grad = self._get_gradient(self.__first_color)
+        self._first_qss = self._qss.format(self._end_radius, grad, color, color)
+
+    def _update_second_qss(self):
+        color, grad = self._get_gradient(self.__second_color)
+        self._second_qss = self._qss.format(self._end_radius, grad, color, color)
+
+    def _update_third_qss(self):
+        color, grad = self._get_gradient(self.__third_color)
+        self._third_qss = self._qss.format(self._end_radius, grad, color, color)
+
+    def _update_off_qss(self):
+        color, grad = self._get_gradient(self.__off_color)
+        self._off_qss = self._qss.format(self._end_radius, grad, color, color)
+
+    def _get_gradient(self, color):
+        grad = QColor(int((self.white.red() - color.red()) / 2) + color.red(), int((self.white.green() - color.green()) / 2) + color.green(), int((self.white.blue() - color.blue()) / 2) + color.blue())
+        grad = '{:02X}{:02X}{:02X}'.format(grad.red(), grad.green(), grad.blue())
+        color = '{:02X}{:02X}{:02X}'.format(color.red(), color.green(), color.blue())
+        return color, grad
+
+    def _update_end_radius(self):
+        if self.__shape == Led.rectangle:
+            self._end_radius = int(self.__height / 10)
+        else:
+            self._end_radius = int(self.__height / 2)
+
+    def _toggle_first(self):
+        self.setStyleSheet(self._first_qss)
+
+    def _toggle_second(self):
+        self.setStyleSheet(self._second_qss)
+
+    def _toggle_third(self):
+        self.setStyleSheet(self._third_qss)
+
+    def _toggle_off(self):
+        self.setStyleSheet(self._off_qss)
+
+    def set_first_color(self, color):
+        self._first_color = color
+
+    def set_second_color(self, color):
+        self._second_color = color
+
+    def set_third_color(self, color):
+        self._third_color = color
+
+    def set_off_color(self, color):
+        self._off_color = color
+
+    def set_shape(self, shape):
+        self._shape = shape
+
+    def set_status(self, status):
+        self._status = status
+        if self._status == 0:
+            self._toggle_off()
+        elif self._status == 1:
+            self._toggle_first()
+        elif self._status == 2:
+            self._toggle_second()
+        else:
+            self._toggle_third()

+ 87 - 0
ui/own/palette_theme.py

@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :palette_theme.py
+@时间    :2022/01/15 19:42:22
+@作者    :None
+@版本    :1.0
+@说明    :主题
+'''
+
+import os
+from utils.globalvar import SD
+from utils.resource import resource_path
+from utils.qt import QPalette, QFont, QBrush, QPixmap, QColor, QIcon
+
+THEME = 0
+
+
+def set_my_palette(self):
+
+    icon = QIcon()
+    icon.addPixmap(QPixmap(resource_path(os.path.join("assets", "ic_launch.png"))), QIcon.Normal, QIcon.Off)
+    self.setWindowIcon(icon)
+
+    self.setAutoFillBackground(True)
+    palette = QPalette()
+
+    if THEME:
+        # 背景图片
+        palette.setBrush(QPalette.Window, QBrush(QPixmap(resource_path(os.path.join("assets", "background.jpeg")))))
+        # 背景字体
+        palette.setColor(QPalette.WindowText, QColor(255, 255, 255))
+        palette.setColor(QPalette.ButtonText, QColor(255, 255, 255))
+        palette.setColor(QPalette.Button, QColor("#1A1A1A"))
+        palette.setColor(QPalette.Base, QColor("#1A1A1A"))
+        palette.setColor(QPalette.Text, QColor(255, 255, 255))
+        palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 255))
+
+    self.setPalette(palette)
+    # 定义字体样式
+    font = QFont('Microsoft YaHei')
+    if SD.HIGH_DPI == 1:
+        font.setPixelSize(17)
+    self.setFont(font)
+
+
+def set_sure_background(self):
+    palette = self.palette()
+    palette.setColor(QPalette.Button, QColor("#99CC99"))
+    self.setPalette(palette)
+    self.setAutoFillBackground(True)
+    self.setFlat(True)
+
+
+def set_edt_bg(self, color):
+    palette = self.palette()
+    palette.setColor(QPalette.Base, color)
+    self.setPalette(palette)
+    self.setAutoFillBackground(True)
+
+
+def set_edt_bg_white(self):
+    palette = self.palette()
+    palette.setColor(QPalette.Base, QColor("#FFFFFF"))
+    self.setPalette(palette)
+    self.setAutoFillBackground(True)
+
+
+def set_tab_bg(self):
+    palette = QPalette()
+    palette.setColor(QPalette.Active, QPalette.Button, QColor(0, 0, 255))
+    self.setPalette(palette)
+    self.setAutoFillBackground(True)
+
+
+def set_table_header_bg(self):
+    palette = QPalette()
+    palette.setColor(QPalette.Button, QColor("#FFA500"))
+    self.setPalette(palette)
+    self.setAutoFillBackground(True)
+
+
+def set_table_line_bg(self):
+    palette = QPalette()
+    palette.setColor(QPalette.Active, QPalette.ColorRole, QColor("#FFA500"))
+    self.setPalette(palette)
+    self.setAutoFillBackground(True)

+ 90 - 0
ui/own/switch_button.py

@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :switch_button.py
+@时间    :2022/01/22 10:05:50
+@作者    :None
+@版本    :1.0
+@说明    :连接开关
+'''
+
+
+from utils.qt import QWidget, Signal, Qt, QRect, QPainter, QFont, QColor, QBrush, QPen
+
+
+class SwitchButton(QWidget):
+
+    """自定义Switch按钮"""
+    # 信号
+    checkedChanged = Signal(bool)
+
+    def __init__(self, parent=None):
+        super(SwitchButton, self).__init__(parent)
+
+        # 设置无边框和背景透明
+        self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
+        self.setAttribute(Qt.WA_TranslucentBackground)
+
+        self.resize(70, 30)
+        self.state = False  # 按钮状态:True表示开,False表示关
+
+    def mousePressEvent(self, event):
+        """鼠标点击事件:用于切换按钮状态"""
+        super(SwitchButton, self).mousePressEvent(event)
+
+        # self.state = False if self.state else True
+        self.state = not self.state
+        # 发射信号
+        self.checkedChanged.emit(self.state)
+
+        self.update()
+
+    def paintEvent(self, event):
+        """绘制按钮"""
+        super(SwitchButton, self).paintEvent(event)
+
+        # 创建绘制器并设置抗锯齿和图片流畅转换
+        painter = QPainter(self)
+        painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
+
+        # 定义字体样式
+        font = QFont('Microsoft YaHei')
+        font.setPixelSize(14)
+        painter.setFont(font)
+
+        # 开关为开的状态
+        if self.state:
+            # 绘制背景
+            painter.setPen(Qt.NoPen)
+            # brush = QBrush(QColor('#969696'))
+            brush = QBrush(QColor('#006400'))
+            painter.setBrush(brush)
+            painter.drawRoundedRect(0, 0, self.width(), self.height(), self.height() // 2, self.height() // 2)
+
+            # 绘制圆圈
+            painter.setPen(Qt.NoPen)
+            brush.setColor(QColor('#ffffff'))
+            painter.setBrush(brush)
+            painter.drawRoundedRect(43, 3, 24, 24, 12, 12)
+
+            # 绘制文本
+            painter.setPen(QPen(QColor('#ffffff')))
+            painter.setBrush(Qt.NoBrush)
+            painter.drawText(QRect(18, 4, 50, 20), Qt.AlignLeft, '开')
+        # 开关为关的状态
+        else:
+            # 绘制背景
+            painter.setPen(Qt.NoPen)
+            brush = QBrush(QColor('#FFFFFF'))
+            painter.setBrush(brush)
+            painter.drawRoundedRect(0, 0, self.width(), self.height(), self.height() // 2, self.height() // 2)
+
+            # 绘制圆圈
+            pen = QPen(QColor('#999999'))
+            pen.setWidth(1)
+            painter.setPen(pen)
+            painter.drawRoundedRect(3, 3, 24, 24, 12, 12)
+
+            # 绘制文本
+            painter.setBrush(Qt.NoBrush)
+            painter.drawText(QRect(38, 4, 50, 20), Qt.AlignLeft, '关')

+ 57 - 0
ui/statusbar.py

@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :statusbar.py
+@时间    :2022/01/22 09:55:34
+@作者    :None
+@版本    :1.0
+@说明    :状态栏页面
+'''
+
+
+from utils.qt import QStatusBar, QLabel, QFrame, QMetaObject, QCoreApplication
+
+
+class UiStatusBar(object):
+    def setupUi(self, emv_status):
+        self.statusbar = QStatusBar()
+        # pcs连接状态
+        self.label_emv_connect = QLabel()
+        self.label_emv_connect.setFrameStyle(QFrame.Panel | QFrame.Raised)
+        self.label_emv_connect.setLineWidth(3)
+        self.label_emv_connect.setMidLineWidth(3)
+
+        # pcs发送状态
+        self.label_emv_send = QLabel()
+        self.label_emv_send.setFrameStyle(QFrame.Panel | QFrame.Raised)
+        self.label_emv_send.setLineWidth(3)
+        self.label_emv_send.setMidLineWidth(3)
+
+        # pcs发送状态
+        self.label_emv_received = QLabel()
+        self.label_emv_received.setFrameStyle(QFrame.Panel | QFrame.Raised)
+        self.label_emv_received.setLineWidth(3)
+        self.label_emv_received.setMidLineWidth(3)
+
+        # pcs软件版本号
+        self.label_emv_version = QLabel()
+        self.label_emv_version.setFrameStyle(QFrame.Panel | QFrame.Raised)
+        self.label_emv_version.setLineWidth(3)
+        self.label_emv_version.setMidLineWidth(3)
+
+        # 往状态栏中添加组件(stretch应该是拉伸组件宽度)
+        self.statusbar.addWidget(self.label_emv_connect, stretch=0)
+        self.statusbar.addWidget(self.label_emv_send, stretch=0)
+        self.statusbar.addWidget(self.label_emv_received, stretch=0)
+        self.statusbar.addPermanentWidget(self.label_emv_version, stretch=0)
+
+        self.statusbar.setSizeGripEnabled(False)
+
+        self.retranslateUi(emv_status)
+        QMetaObject.connectSlotsByName(emv_status)
+
+    def retranslateUi(self, emv_status):
+        _translate = QCoreApplication.translate
+        self.label_emv_connect.setText(_translate("emv_status", "未连接"))
+        self.label_emv_send.setText(_translate("emv_status", "发送未启动"))
+        self.label_emv_received.setText(_translate("emv_status", "接收未启动"))

+ 0 - 0
utils/__init__.py


+ 209 - 0
utils/can.py

@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :canConnect.py
+@时间    :2021/12/09 13:47:58
+@作者    :None
+@版本    :1.0
+@说明    :CAN连接驱动
+'''
+
+
+from ctypes.util import find_library
+from sys import platform
+import ctypes
+from ctypes import c_ubyte, c_uint
+from utils.log_signal import LogSignal
+from utils.resource import resource_path, resource_path_extend
+
+PYINSTALLER = 1
+if PYINSTALLER:
+    if platform == "win64":
+        _CanDLLName = resource_path("config\\ControlCANx64\\ControlCAN.dll")
+        ZLGCAN = ctypes.windll.LoadLibrary(_CanDLLName)
+    elif platform == "win32":
+        _CanDLLName = resource_path("config\\ControlCANx86\\ControlCAN.dll")
+        ZLGCAN = ctypes.windll.LoadLibrary(_CanDLLName)
+    elif platform == "linux":
+        _CanDLLName = resource_path("config/linux/libusbcan.so")
+        ZLGCAN = ctypes.cdll.LoadLibrary(_CanDLLName)
+    else:
+        ZLGCAN = ctypes.cdll.LoadLibrary(find_library("libPCBUSB.dylib"))
+else:
+    if platform == "win64":
+        resource_path_extend("config")
+        ZLGCAN = ctypes.windll.LoadLibrary("ControlCAN.dll")
+    elif platform == "win32":
+        resource_path_extend("config")
+        ZLGCAN = ctypes.windll.LoadLibrary("ControlCAN.dll")
+    else:
+        ZLGCAN = ""
+
+ubyte_array = c_ubyte * 8
+ubyte_3array = c_ubyte * 3
+
+# can type
+CANTYPE = {
+    'USBCAN-I': 3,
+    'USBCAN-II': 4,
+}
+
+# can mode
+NORMAL_MODE = 0
+LISTEN_MODE = 1
+
+# filter type
+SINGLE_FILTER = 0
+DOUBLE_FILTER = 1
+
+# status
+STATUS_OK = 1
+
+# sendtype
+SEND_NORMAL = 0
+SEND_SINGLE = 1
+SELF_SEND_RECV = 2
+SELF_SEND_RECV_SINGLE = 3
+
+
+class VCI_INIT_CONFIG(ctypes.Structure):
+    _fields_ = [("AccCode", c_uint),  # 验收码。SJA1000的帧过滤验收码。对经过屏蔽码过滤为“有关位”进行匹配,全部匹配成功后,此帧可以被接收。
+                # 屏蔽码。SJA1000的帧过滤屏蔽码。对接收的CAN帧ID进行过滤,对应位为0的是“有关位”,对应位为1的是“无关位”。屏蔽码推荐设置为0xFFFFFFFF,即全部接收。
+                ("AccMask", c_uint),
+                # 保留
+                ("Reserved", c_uint),
+                # 滤波方式
+                ("Filter", c_ubyte),
+                # 波特率定时器 0
+                ("Timing0", c_ubyte),
+                # 波特率定时器 1
+                ("Timing1", c_ubyte),
+                # 模式。=0表示正常模式(相当于正常节点),=1表示只听模式(只接收,不影响总线),=2表示自发自收模式(环回模式)。
+                ("Mode", c_ubyte)
+                ]
+
+
+# VCI_CAN_OBJ结构体是CAN帧结构体,即1个结构体表示一个帧的数据结构。在发送函数VCI_Transmit和接收函数VCI_Receive中,被用来传送CAN信息帧。
+class VCI_CAN_OBJ(ctypes.Structure):
+    _fields_ = [("ID", c_uint),  # 帧ID。32位变量,数据格式为靠右对齐
+                # 设备接收到某一帧的时间标识。时间标示从CAN卡上电开始计时,计时单位为0.1ms。
+                ("TimeStamp", c_uint),
+                # 是否使用时间标识,为1时TimeStamp有效,TimeFlag和TimeStamp只在此帧为接收帧时有意义。
+                ("TimeFlag", c_ubyte),
+                # 发送帧类型。=0时为正常发送(发送失败会自动重发,重发时间为4秒,4秒内没有发出则取消);=1时为单次发送(只发送一次,发送失败不会自动重发,总线只产生一帧数据);其它值无效。
+                ("SendType", c_ubyte),
+                # 是否是远程帧。=0时为为数据帧,=1时为远程帧(数据段空)。
+                ("RemoteFlag", c_ubyte),
+                # 是否是扩展帧。=0时为标准帧(11位ID),=1时为扩展帧(29位ID)。
+                ("ExternFlag", c_ubyte),
+                # 数据长度 DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节
+                ("DataLen", c_ubyte),
+                ("Data", c_ubyte * 8),
+                # CAN帧的数据。由于CAN规定了最大是8个字节,所以这里预留了8个字节的空间,受DataLen约束。如DataLen定义为3,即Data[0]、Data[1]、Data[2]是有效的
+                ("Reserved", c_ubyte * 3)  # 系统保留
+                ]
+
+
+class PVCI_ERR_INFO(ctypes.Structure):
+    _fields_ = [("ErrorCode", c_uint),
+                ("PassiveErrData", c_ubyte * 3),
+                ("ArLostErrData", c_ubyte)
+                ]
+
+
+baudRateConfig = {
+    '5Kbps': {'time0': 0xBF, 'time1': 0xFF},
+    '10Kbps': {'time0': 0x31, 'time1': 0x1C},
+    '20Kbps': {'time0': 0x18, 'time1': 0x1C},
+    '40Kbps': {'time0': 0x87, 'time1': 0xFF},
+    '50Kbps': {'time0': 0x09, 'time1': 0x1C},
+    '80Kbps': {'time0': 0x83, 'time1': 0xFF},
+    '100Kbps': {'time0': 0x04, 'time1': 0x1C},
+    '125Kbps': {'time0': 0x03, 'time1': 0x1C},
+    '200Kbps': {'time0': 0x81, 'time1': 0xFA},
+    '250Kbps': {'time0': 0x01, 'time1': 0x1C},
+    '400Kbps': {'time0': 0x80, 'time1': 0xFA},
+    '500Kbps': {'time0': 0x00, 'time1': 0x1C},
+    '666Kbps': {'time0': 0x80, 'time1': 0xB6},
+    '800Kbps': {'time0': 0x00, 'time1': 0x16},
+    '1000Kbps': {'time0': 0x00, 'time1': 0x14},
+}
+
+
+class MessageDeal:
+    def __init__(self):
+        self.canType = CANTYPE['USBCAN-II']
+
+    def set_can_board(self, canIndex, canChannel, canBaudrate):
+        self.canIndex = canIndex
+        self.canChannel = canChannel
+        self.canBaudrate = canBaudrate
+
+    def open_device(self):
+        ret = ZLGCAN.VCI_OpenDevice(self.canType, self.canChannel, self.canChannel)
+        if ret != STATUS_OK:
+            # LogSignal.print_log_signal().log_emit('打开CAN卡失败: {}'.format(str(self.canChannel)) if SD.SYSTEM_LANGUAGE == 0 else 'CAN Device Error: {}'.format(str(self.canChannel)))
+            return False
+        return True
+
+    def init_can(self, accCode, accMask):
+        # 初始化通道
+        _vci_initconfig = VCI_INIT_CONFIG(accCode, accMask, 0, DOUBLE_FILTER,
+                                          baudRateConfig[self.canBaudrate]['time0'],
+                                          baudRateConfig[self.canBaudrate]['time1'],
+                                          NORMAL_MODE)
+        ret = ZLGCAN.VCI_InitCAN(self.canType, self.canIndex, self.canChannel, ctypes.byref(_vci_initconfig))
+        if ret != STATUS_OK:
+            # LogSignal.print_log_signal().log_emit('初始化CAN卡失败: {}'.format(str(self.canChannel)) if SD.SYSTEM_LANGUAGE == 0 else 'CAN Open Error: {}'.format(str(self.canChannel)))
+            return False
+
+        ret = ZLGCAN.VCI_StartCAN(self.canType, self.canIndex, self.canChannel)
+        if ret != STATUS_OK:
+            # LogSignal.print_log_signal().log_emit('启动CAN卡失败: {}'.format(str(self.canChannel))if SD.SYSTEM_LANGUAGE == 0 else 'CAN Start Error: {}'.format(str(self.canChannel)))
+            return False
+        return True
+
+    def get_undeal_number(self):
+        return ZLGCAN.VCI_GetReceiveNum(self.canType, self.canIndex, self.canChannel)
+
+    def receive(self, number=1):
+        objs = (VCI_CAN_OBJ * number)()
+        ret = ZLGCAN.VCI_Receive(self.canType, self.canIndex, self.canChannel, ctypes.byref(objs), number, 10)
+        if ret == 0xFFFFFFFF:
+            return None
+        else:
+            return objs[:ret]
+
+    def send(self, ID, data, remote_flag=False, extern_flag=False, data_len=8):
+        vci_can_obj = VCI_CAN_OBJ()
+        vci_can_obj.ID = ID
+        vci_can_obj.SendType = SEND_NORMAL
+        if remote_flag:
+            vci_can_obj.RemoteFlag = 1
+        else:
+            vci_can_obj.RemoteFlag = 0
+        if extern_flag:
+            vci_can_obj.ExternFlag = 1
+        else:
+            vci_can_obj.ExternFlag = 0
+        vci_can_obj.DataLen = data_len
+        if len(data) < 8:
+            data += (8 - len(data)) * [0]
+        vci_can_obj.Data = (c_ubyte * 8)(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7])
+        ret = ZLGCAN.VCI_Transmit(self.canType, self.canIndex, self.canChannel, ctypes.byref(vci_can_obj), 1)
+        if ret != STATUS_OK:
+            LogSignal.print_log_signal().log_emit("CAN Send Error!")
+            return False
+        else:
+            return True
+
+    def read_err_info(self):
+        errInfo = PVCI_ERR_INFO(0, ubyte_3array(0, 0, 0), 0)
+        ZLGCAN.VCI_ReadErrInfo(self.canType, self.canIndex, self.canChannel, ctypes.byref(errInfo))
+        LogSignal.print_log_signal().log_emit(errInfo.ErrorCode, errInfo.PassiveErrData[0], errInfo.PassiveErrData[1], errInfo.PassiveErrData[2], errInfo.ArLostErrData)
+
+    def clear_buffer(self):
+        return ZLGCAN.VCI_ClearBuffer(self.canType, self.canIndex, self.canChannel)
+
+    def close_can(self):
+        return ZLGCAN.VCI_CloseDevice(self.canType, self.canIndex)

+ 61 - 0
utils/com.py

@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :com.py
+@时间    :2022/11/14 17:28:23
+@作者    :None
+@版本    :1.0
+@说明    :modbus 485驱动
+'''
+
+import serial.tools.list_ports
+import serial
+from serial.serialutil import SerialException
+from utils.utils import calculate_crc_16
+
+
+class ComMaster:
+    def __init__(self):
+        super(ComMaster, self).__init__()
+        self.master = None
+
+    def set_com(self, port, baudrate, bytesize, parity, stopbits):
+        self.port = port
+        self.baudrate = baudrate
+        self.bytesize = bytesize
+        self.parity = parity
+        self.stopbits = stopbits
+
+    def open_device(self):
+        try:
+            self.com_manager = serial.Serial(port=self.port, baudrate=self.baudrate, bytesize=self.bytesize, parity=self.parity, stopbits=self.stopbits, xonxoff=0)
+            # if (self.com_manager is open):
+            return True
+        except SerialException:
+            return False
+
+    def send_16h(self, slave, addr, num, number_write, data):
+        buf = [slave, 0x16, (addr >> 8) & 0xFF, addr & 0xFF, (num >> 8) & 0xFF, num & 0xFF, number_write] + data
+        crc = calculate_crc_16(buf, len(buf))
+        buf = buf + [crc & 0xFF, (crc >> 8) & 0xFF]
+        self.com_manager.write(buf)
+
+    def send(self, addr=0, command=0, param1=0, param0=0, data3=0, data2=0, data1=0, data0=0):
+        buf = [addr, command, param1, param0, data3, data2, data1, data0]
+        self.com_manager.write(buf)
+
+    def reveive_env_version(self):
+        sub_seq = list()
+        try:
+            data_count = self.com_manager.inWaiting()
+            if data_count == 5:
+                result = self.com_manager.read(data_count).hex()
+                ptr = 0
+                while ptr < len(result):
+                    sub_seq += [int('0x' + result[ptr:ptr + 2], 16)]
+                    ptr += 2
+            else:
+                return [0]
+        except Exception as e:
+            print(str(e))
+        return sub_seq

+ 32 - 0
utils/delay.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :delay.py
+@时间    :2022/02/17 15:37:43
+@作者    :None
+@版本    :1.0
+@说明    :精确到ms延迟函数
+'''
+
+
+import sys
+import ctypes
+from time import sleep
+
+
+def m_delay(ms):
+    if sys.platform == "darwin" or sys.platform == "linux":
+        sleep(ms / 1000)
+    elif sys.platform == "win32" or sys.platform == "win64":
+        stop_value = ctypes.c_longlong(0)
+        start_value = ctypes.c_longlong(0)
+        freq = ctypes.c_longlong(0)
+        n = 0
+        ctypes.windll.kernel32.QueryPerformanceFrequency(ctypes.byref(freq))
+        count = ms * freq.value / 1000
+        ctypes.windll.kernel32.QueryPerformanceCounter(ctypes.byref(start_value))
+        while n < count:
+            ctypes.windll.kernel32.QueryPerformanceCounter(ctypes.byref(stop_value))
+            n = stop_value.value - start_value.value
+    else:
+        sleep(ms / 1000)

+ 148 - 0
utils/globalvar.py

@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :globalvar.py
+@时间    :2022/01/22 10:11:23
+@作者    :None
+@版本    :1.0
+@说明    :全局变量
+'''
+
+from utils.can import MessageDeal
+from utils.com import ComMaster
+
+
+class SD:
+    # 一二级BMS Can开关,Can开关开启后开始接收数据
+    CAN_ON_OFF = False
+
+    # 加载CAN连接驱动
+    CAN_CONTROL = MessageDeal()
+
+    # 加载串口连接驱动
+    COM_CONTROL = ComMaster()
+
+    EMV_ID = 1
+
+    HIGH_DPI = 0
+
+
+class EmvState:
+    def __init__(self):
+        self.__emv_total = 0
+        self.__emv_1 = 0
+        self.__emv_2 = 0
+        self.__emv_3 = 0
+        self.__emv_4 = 0
+        self.__emv_5 = 0
+        self.__emv_6 = 0
+        self.__emv_7 = 0
+        self.__emv_8 = 0
+        self.__emv_9 = 0
+
+    @property
+    def emv_total_state(self):
+        return self.__emv_total
+
+    @emv_total_state.setter
+    def emv_total_state(self, value):
+        self.__emv_total = value
+
+    @property
+    def emv_1_state(self):
+        return self.__emv_1
+
+    @emv_1_state.setter
+    def emv_1_state(self, value):
+        if isinstance(value, int):
+            self.__emv_1 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @property
+    def emv_2_state(self):
+        return self.__emv_2
+
+    @emv_2_state.setter
+    def emv_2_state(self, value):
+        if isinstance(value, int):
+            self.__emv_2 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @property
+    def emv_3_state(self):
+        return self.__emv_3
+
+    @emv_3_state.setter
+    def emv_3_state(self, value):
+        if isinstance(value, int):
+            self.__emv_3 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @property
+    def emv_4_state(self):
+        return self.__emv_4
+
+    @emv_4_state.setter
+    def emv_4_state(self, value):
+        if isinstance(value, int):
+            self.__emv_4 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @property
+    def emv_5_state(self):
+        return self.__emv_5
+
+    @emv_5_state.setter
+    def emv_5_state(self, value):
+        if isinstance(value, int):
+            self.__emv_5 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @ property
+    def emv_6_state(self):
+        return self.__emv_6
+
+    @emv_6_state.setter
+    def emv_6_state(self, value):
+        if isinstance(value, int):
+            self.__emv_6 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @ property
+    def emv_7_state(self):
+        return self.__emv_7
+
+    @emv_7_state.setter
+    def emv_7_state(self, value):
+        if isinstance(value, int):
+            self.__emv_7 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @ property
+    def emv_8_state(self):
+        return self.__emv_8
+
+    @emv_8_state.setter
+    def emv_8_state(self, value):
+        if isinstance(value, int):
+            self.__emv_8 = value
+        else:
+            raise ValueError("'int' type need")
+
+    @ property
+    def emv_9_state(self):
+        return self.__emv_9
+
+    @emv_9_state.setter
+    def emv_9_state(self, value):
+        if isinstance(value, int):
+            self.__emv_9 = value
+        else:
+            raise ValueError("'int' type need")

+ 28 - 0
utils/log_signal.py

@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :log_signal.py
+@时间    :2022/02/17 15:37:11
+@作者    :None
+@版本    :1.0
+@说明    : 日志打印实例/单例模式
+'''
+
+from utils.qt import Signal, QObject
+
+
+class LogSignal(QObject):
+    instance = None
+    signal = Signal(str)
+
+    @classmethod
+    def print_log_signal(cls):
+        if cls.instance:
+            return cls.instance
+        else:
+            obj = cls()
+            cls.instance = obj
+            return cls.instance
+
+    def log_emit(self, data):
+        self.signal.emit(data)

+ 66 - 0
utils/qt.py

@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :qt.py
+@时间    :2022/02/21 16:48:46
+@作者    :None
+@版本    :1.0
+@说明    : pyqt和pyside2兼容包
+'''
+
+
+QT_CHOSE = 1
+if QT_CHOSE:
+    # PySide2
+    from PySide2 import (  # noqa F401
+        QtGui, QtWidgets, QtCore
+    )
+    from PySide2.QtWidgets import (  # noqa F401
+        QMainWindow, QDesktopWidget, QStyleFactory, QWidget, QFrame,
+        QApplication, QSizePolicy, QHBoxLayout, QVBoxLayout, QGridLayout,
+        QLabel, QPushButton, QLineEdit, QProgressBar, QComboBox, QLCDNumber,
+        QMessageBox, QFileDialog, QPlainTextEdit, QStatusBar, QGroupBox, QTabBar,
+        QTabWidget, QTableWidget, QAbstractItemView, QCheckBox, QHeaderView,
+        QStyle, QStyleOptionButton, QTableWidgetItem, QSpacerItem
+    )
+    from PySide2.QtGui import (  # noqa F401
+        QGuiApplication, QPalette, QPainter, QColor, QPen,
+        QLinearGradient, QFont, QBrush, QPixmap, QIcon, QRegExpValidator, QKeySequence
+    )
+    from PySide2.QtCore import (  # noqa F401
+        QObject, QCoreApplication, QStandardPaths, QMetaObject, Qt,
+        QPoint, QRect, QRectF, QPointF, QDateTime, QTimer, QSize,
+        QThread, QMutex, QSemaphore, QRegExp, QModelIndex, Signal, Slot
+    )
+    from PySide2.QtCharts import QtCharts
+    QChartView = QtCharts.QChartView
+    QChart = QtCharts.QChart
+    QLineSeries = QtCharts.QLineSeries
+    QCategoryAxis = QtCharts.QCategoryAxis
+    QValueAxis = QtCharts.QValueAxis
+    QLegendMarker = QtCharts.QLegendMarker
+else:
+    # PyQt5
+    from PyQt5 import (  # noqa F401
+        QtGui, QtWidgets, QtCore, QtChart
+    )
+    from PyQt5.QtWidgets import (  # noqa F401
+        QMainWindow, QDesktopWidget, QStyleFactory, QWidget, QFrame,
+        QApplication, QSizePolicy, QHBoxLayout, QVBoxLayout, QGridLayout,
+        QLabel, QPushButton, QLineEdit, QProgressBar, QComboBox, QLCDNumber,
+        QMessageBox, QFileDialog, QPlainTextEdit, QStatusBar, QGroupBox, QTabBar,
+        QTabWidget, QTableWidget, QAbstractItemView, QCheckBox, QHeaderView,
+        QStyle, QStyleOptionButton, QTableWidgetItem, QSpacerItem
+    )
+    from PyQt5.QtGui import (  # noqa F401
+        QGuiApplication, QPalette, QPainter, QColor, QPen,
+        QLinearGradient, QFont, QBrush, QPixmap, QIcon, QRegExpValidator, QKeySequence
+    )
+    from PyQt5.QtCore import (  # noqa F401
+        QObject, QCoreApplication, QStandardPaths, QMetaObject, Qt, QRect, QRectF,
+        QPoint, QPointF, QDateTime, QTimer, QSize,
+        QThread, QMutex, QSemaphore, QRegExp, QModelIndex, pyqtSignal as Signal, pyqtSlot as Slot
+    )
+    from PyQt5.QtChart import (  # noqa F401
+        QChartView, QLineSeries, QChart, QCategoryAxis, QValueAxis, QLegendMarker
+    )

+ 27 - 0
utils/resource.py

@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :resourcePath.py
+@时间    :2021/12/09 13:49:58
+@作者    :None
+@版本    :1.0
+@说明    :资源文件路径配置
+'''
+
+
+from os import path
+import sys
+from sys import path as spath
+
+
+def resource_path(relative_path):
+    try:
+        base_path = sys._MEIPASS
+    except Exception:
+        base_path = path.abspath(".")
+    return path.join(base_path, relative_path)
+
+
+def resource_path_extend(relative_path):
+    spath.append(path.abspath(relative_path))
+    print(sys.path)

+ 95 - 0
utils/utils.py

@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :hexBit.py
+@时间    :2021/12/09 13:48:58
+@作者    :None
+@版本    :1.0
+@说明    :获取位的值
+'''
+
+
+def a_bit(data, i):
+    if i == 1:
+        return data & 0x01
+    if i == 2:
+        return (data & 0x02) >> 1
+    if i == 3:
+        return (data & 0x04) >> 2
+    if i == 4:
+        return (data & 0x08) >> 3
+    if i == 5:
+        return (data & 0x10) >> 4
+    if i == 6:
+        return (data & 0x20) >> 5
+    if i == 7:
+        return (data & 0x40) >> 6
+    if i == 8:
+        return (data & 0x80) >> 7
+
+
+def hex_bcd(data):
+    s = data // 16
+    g = data % 16
+    c = s * 10 + g
+    return str(c)
+
+
+def bcd_hex(data):
+    int_data = int(data)
+    s = int_data // 10
+    g = int_data % 10
+    c = s * 16 + g
+    return c
+
+
+def swap_bytes(word_val):
+    msb = (word_val >> 8) & 0xFF
+    lsb = word_val & 0xFF
+    return (lsb << 8) + msb
+
+
+def calculate_crc_8(id, data):
+    crc8table = (
+        0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81,
+        0xa6, 0xbb, 0xcd, 0xd0, 0xf7, 0xea, 0xb9, 0xa4, 0x83, 0x9e, 0x25, 0x38, 0x1f, 0x02,
+        0x51, 0x4c, 0x6b, 0x76, 0x87, 0x9a, 0xbd, 0xa0, 0xf3, 0xee, 0xc9, 0xd4, 0x6f, 0x72,
+        0x55, 0x48, 0x1b, 0x06, 0x21, 0x3c, 0x4a, 0x57, 0x70, 0x6d, 0x3e, 0x23, 0x04, 0x19,
+        0xa2, 0xbf, 0x98, 0x85, 0xd6, 0xcb, 0xec, 0xf1, 0x13, 0x0e, 0x29, 0x34, 0x67, 0x7a,
+        0x5d, 0x40, 0xfb, 0xe6, 0xc1, 0xdc, 0x8f, 0x92, 0xb5, 0xa8, 0xde, 0xc3, 0xe4, 0xf9,
+        0xaa, 0xb7, 0x90, 0x8d, 0x36, 0x2b, 0x0c, 0x11, 0x42, 0x5f, 0x78, 0x65, 0x94, 0x89,
+        0xae, 0xb3, 0xe0, 0xfd, 0xda, 0xc7, 0x7c, 0x61, 0x46, 0x5b, 0x08, 0x15, 0x32, 0x2f,
+        0x59, 0x44, 0x63, 0x7e, 0x2d, 0x30, 0x17, 0x0a, 0xb1, 0xac, 0x8b, 0x96, 0xc5, 0xd8,
+        0xff, 0xe2, 0x26, 0x3b, 0x1c, 0x01, 0x52, 0x4f, 0x68, 0x75, 0xce, 0xd3, 0xf4, 0xe9,
+        0xba, 0xa7, 0x80, 0x9d, 0xeb, 0xf6, 0xd1, 0xcc, 0x9f, 0x82, 0xa5, 0xb8, 0x03, 0x1e,
+        0x39, 0x24, 0x77, 0x6a, 0x4d, 0x50, 0xa1, 0xbc, 0x9b, 0x86, 0xd5, 0xc8, 0xef, 0xf2,
+        0x49, 0x54, 0x73, 0x6e, 0x3d, 0x20, 0x07, 0x1a, 0x6c, 0x71, 0x56, 0x4b, 0x18, 0x05,
+        0x22, 0x3f, 0x84, 0x99, 0xbe, 0xa3, 0xf0, 0xed, 0xca, 0xd7, 0x35, 0x28, 0x0f, 0x12,
+        0x41, 0x5c, 0x7b, 0x66, 0xdd, 0xc0, 0xe7, 0xfa, 0xa9, 0xb4, 0x93, 0x8e, 0xf8, 0xe5,
+        0xc2, 0xdf, 0x8c, 0x91, 0xb6, 0xab, 0x10, 0x0d, 0x2a, 0x37, 0x64, 0x79, 0x5e, 0x43,
+        0xb2, 0xaf, 0x88, 0x95, 0xc6, 0xdb, 0xfc, 0xe1, 0x5a, 0x47, 0x60, 0x7d, 0x2e, 0x33,
+        0x14, 0x09, 0x7f, 0x62, 0x45, 0x58, 0x0b, 0x16, 0x31, 0x2c, 0x97, 0x8a, 0xad, 0xb0,
+        0xe3, 0xfe, 0xd9, 0xc4
+    )
+    xor_out = 0xff
+    crc_value = 0xff
+    crc_value = crc8table[crc_value ^ (id & 0xff)]
+    crc_value = crc8table[crc_value ^ ((id >> 8) & 0xFF)]
+
+    for count in range(len(data)):
+        crc_value = crc8table[crc_value ^ data[count]]
+
+    crc_value = crc_value ^ xor_out
+    return crc_value
+
+
+def calculate_crc_16(data, num):
+    crc = 0xFFFF
+    i = 0
+    while (num):
+        crc = crc ^ data[i]
+        i += 1
+        for j in range(8):
+            crc = ((crc >> 1) ^ 0xA001) if (crc & 0x0001) else (crc >> 1)
+        num -= 1
+    return crc

+ 0 - 0
widget/__init__.py


+ 74 - 0
widget/emv_home.py

@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :emv_home.py
+@时间    :2022/11/17 13:33:56
+@作者    :None
+@版本    :1.0
+@说明    :主页面逻辑
+'''
+
+
+from ui.home import UiEmvHomePage
+from utils.qt import QMainWindow, Qt, QStyle, QMessageBox, QGuiApplication, Signal
+
+
+class Win_Emv_Home(UiEmvHomePage, QMainWindow):
+
+    interface_signal = Signal(int)
+    connect_signal = Signal()
+    disconnect_signal = Signal()
+    emv_on_signal = Signal()
+    emv_off_signal = Signal()
+
+    def __init__(self, parent=None):
+        super(Win_Emv_Home, self).__init__(parent)
+        self.setupUi(self)
+
+        self.cb_interface.currentIndexChanged.connect(self._interface_chose)
+        self.emv_switch.checkedChanged.connect(self._get_state)
+        self.btn_emv_on.clicked.connect(self._emv_on)
+        self.btn_emv_off.clicked.connect(self._emv_off)
+
+    # 居中显示
+    def center(self):
+        # 新方法
+        self.setGeometry(
+            QStyle.alignedRect(
+                Qt.LeftToRight,
+                Qt.AlignCenter,
+                self.size(),
+                QGuiApplication.primaryScreen().availableGeometry(),
+            ),
+        )
+
+    def _interface_chose(self):
+        self.interface_signal.emit(self.cb_interface.currentIndex())
+
+    # EMV 连接
+    def _get_state(self, checked):
+        if checked:
+            self.connect_signal.emit()
+        else:
+            self.disconnect_signal.emit()
+
+    def _emv_on(self):
+        self.emv_on_signal.emit()
+
+    def _emv_off(self):
+        self.emv_off_signal.emit()
+
+    def can_connect_error(self):
+        QMessageBox.critical(self, "失败!", "CAN 连接失败!")
+        self.emv_switch.state = False
+        return
+
+    def no_can_device(self):
+        QMessageBox.critical(self, "失败!", "无CAN 设备!")
+        self.emv_switch.state = False
+        return
+
+    def no_com_device(self):
+        QMessageBox.critical(self, "失败!", "无法连接此串口设备!")
+        self.emv_switch.state = False
+        return

+ 21 - 0
widget/emv_status_bar.py

@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :bmu_data.py
+@时间    :2022/01/03 01:57:32
+@作者    :None
+@版本    :1.0
+@说明    :一级主页
+'''
+
+
+from ui.own.frame_theme import MyFrame
+from ui.statusbar import UiStatusBar
+
+
+class Win_Emv_Status_Bar(UiStatusBar, MyFrame):
+    def __init__(self, parent=None):
+        super(Win_Emv_Status_Bar, self).__init__(parent)
+        self.setupUi(self)
+
+        self.label_emv_version.setText("Version:v1.0.0")

+ 0 - 0
worker/__init__.py


+ 57 - 0
worker/emv_work.py

@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@文件    :emv_work.py
+@时间    :2022/11/16 13:32:02
+@作者    :None
+@版本    :1.0
+@说明    :
+'''
+
+
+from utils.globalvar import SD
+from utils.qt import QObject, Signal
+from utils.delay import m_delay
+
+
+class EmvCanReceived(QObject):
+
+    show_emv_ce_signal = Signal(object, int)
+    show_emv_cf_signal = Signal(object)
+
+    def __init__(self):
+        super(EmvCanReceived, self).__init__()
+
+    # 接收数据
+    def received(self):
+        while SD.CAN_ON_OFF:
+            restNum = SD.CAN_CONTROL.get_undeal_number()
+            if restNum <= 0:
+                continue
+            revRet = SD.CAN_CONTROL.receive(restNum)
+            for i in revRet:
+                if int(i.RemoteFlag) != 0:
+                    continue
+
+                if i.ID == 0x1800CF00 | SD.EMV_ID:
+                    self.show_emv_cf_signal.emit(i.Data)
+                elif i.ID == 0x1800CE00 | SD.EMV_ID:
+                    self.show_emv_ce_signal.emit(i.Data, 0)
+                else:
+                    continue
+
+
+class EmvComWork(QObject):
+
+    show_com_signal = Signal(int, int, int)
+
+    def __init__(self):
+        super(EmvComWork, self).__init__()
+
+    # 接收数据
+    def work(self):
+        while SD.CAN_ON_OFF:
+            ver = SD.COM_CONTROL.reveive_env_version()
+            if ver[0] == 1:
+                self.show_com_signal.emit(ver[1], ver[2], ver[3])
+            m_delay(10)