mirror of
https://gitee.com/bianbu-linux/factorytest
synced 2025-04-22 21:27:25 -04:00
Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
|
bb8f6f2c92 | ||
|
bd7463643a |
12 changed files with 786 additions and 243 deletions
28
LICENSE
Normal file
28
LICENSE
Normal file
|
@ -0,0 +1,28 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2024, SpacemiT
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,7 +1,9 @@
|
|||
from typing import Union
|
||||
import os
|
||||
import json
|
||||
from cricket.singleton import SingletonMeta, singleton
|
||||
|
||||
@singleton
|
||||
class SimpleLang(object):
|
||||
def __init__(self, file = None):
|
||||
file = file if file else 'languages.json'
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
"wifi": "WiFi",
|
||||
"wifi_mac": "WiFi Mac",
|
||||
|
||||
"cpu_temp": "CPU温度"
|
||||
"cpu_temp": "CPU温度",
|
||||
"wifi_signal_init":"正在检测WiFi信号强度",
|
||||
"peripheral_test":"外设性能测试"
|
||||
},
|
||||
"en": {
|
||||
"title": "Factory Test",
|
||||
|
@ -77,6 +79,8 @@
|
|||
"wifi": "WiFi",
|
||||
"wifi_mac": "WiFi Mac",
|
||||
|
||||
"cpu_temp": "CPU_Temp"
|
||||
"cpu_temp": "CPU_Temp",
|
||||
"wifi_signal_init":"Checking WiFi signal strength",
|
||||
"peripheral_test":"Peripheral performance testing"
|
||||
}
|
||||
}
|
32
cricket/cricket/loggermanager.py
Normal file
32
cricket/cricket/loggermanager.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
|
||||
import logging
|
||||
import os
|
||||
import inspect
|
||||
import logging.handlers
|
||||
import sys
|
||||
|
||||
class LoggerManager:
|
||||
def __init__(self, name='LoggerManager', console_level=logging.INFO):
|
||||
self.logger = logging.getLogger(name)
|
||||
self.logger.setLevel(logging.DEBUG) # Set the root log level to DEBUG to capture all logs
|
||||
|
||||
# Create formatter
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s [%(filename)s:%(lineno)d]')
|
||||
|
||||
# Create and configure the console processor
|
||||
self.console_handler = logging.StreamHandler(sys.stdout)
|
||||
self.console_handler.setLevel(console_level)
|
||||
self.console_handler.setFormatter(formatter)
|
||||
|
||||
# Add a processor to the logger
|
||||
self.logger.addHandler(self.console_handler)
|
||||
|
||||
# Creating a file processor
|
||||
self.file_handler = logging.FileHandler("/root/factorytest.log")
|
||||
self.file_handler.setLevel(logging.INFO)
|
||||
self.file_handler.setFormatter(formatter)
|
||||
|
||||
self.logger.addHandler(self.file_handler)
|
||||
|
||||
def get_logger(self):
|
||||
return self.logger
|
58
cricket/cricket/macro.py
Normal file
58
cricket/cricket/macro.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
|
||||
from cricket.model import TestMethod, TestCase, TestModule
|
||||
|
||||
PASS_COLOR = '#28C025'
|
||||
FAIL_COLOR = '#E32C2E'
|
||||
|
||||
PASSSTR = "PASS"
|
||||
FAILSTR = "FAIL"
|
||||
INITSTR = "NA"
|
||||
|
||||
READ_ERROR = 'read error'
|
||||
|
||||
# Display constants for test status
|
||||
STATUS = {
|
||||
TestMethod.STATUS_PASS: {
|
||||
'description': u'通过',
|
||||
'symbol': u'\u25cf',
|
||||
'tag': 'pass',
|
||||
'color': PASS_COLOR
|
||||
},
|
||||
TestMethod.STATUS_SKIP: {
|
||||
'description': u'Skipped',
|
||||
'symbol': u'S',
|
||||
'tag': 'skip',
|
||||
'color': '#259EBF'
|
||||
},
|
||||
TestMethod.STATUS_FAIL: {
|
||||
'description': u'失败',
|
||||
'symbol': u'F',
|
||||
'tag': 'fail',
|
||||
'color': FAIL_COLOR
|
||||
},
|
||||
TestMethod.STATUS_EXPECTED_FAIL: {
|
||||
'description': u'Expected\n failure',
|
||||
'symbol': u'X',
|
||||
'tag': 'expected',
|
||||
'color': '#3C25BF'
|
||||
},
|
||||
TestMethod.STATUS_UNEXPECTED_SUCCESS: {
|
||||
'description': u'Unexpected\n success',
|
||||
'symbol': u'U',
|
||||
'tag': 'unexpected',
|
||||
'color': '#C82788'
|
||||
},
|
||||
TestMethod.STATUS_ERROR: {
|
||||
'description': 'Error',
|
||||
'symbol': u'E',
|
||||
'tag': 'error',
|
||||
'color': '#E4742C'
|
||||
},
|
||||
}
|
||||
|
||||
STATUS_DEFAULT = {
|
||||
'description': 'Not\nexecuted',
|
||||
'symbol': u'',
|
||||
'tag': None,
|
||||
'color': '#BFBFBF',
|
||||
}
|
271
cricket/cricket/peripheraltestview.py
Normal file
271
cricket/cricket/peripheraltestview.py
Normal file
|
@ -0,0 +1,271 @@
|
|||
from PyQt5.QtCore import Qt, QTimer, QUrl, QObject, QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QColor, QPixmap, QImage, QPalette
|
||||
from PyQt5.QtWidgets import (QWidget, QDialog, QFrame, QHBoxLayout, QVBoxLayout, QLabel,
|
||||
QPushButton,QLineEdit, QCheckBox,QComboBox, QSizePolicy, QSpacerItem, QTextEdit)
|
||||
|
||||
import subprocess
|
||||
import re
|
||||
import os
|
||||
from typing import Tuple, List
|
||||
from cricket.lang import SimpleLang
|
||||
from cricket.loggermanager import LoggerManager
|
||||
from cricket.macro import *
|
||||
import time
|
||||
|
||||
|
||||
class PeripheralTestWindow(QDialog):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._parent = parent
|
||||
self.sl = SimpleLang()
|
||||
|
||||
self.info_msg_index = 0
|
||||
|
||||
self.log_manager = LoggerManager(name='PeripheralLogger')
|
||||
self.custom_logger = self.log_manager.get_logger()
|
||||
|
||||
self.name_dict = {'EMMC':"EMMC", "SSD":"SSD", 'TF':'TF Card', 'FlashDrive':'U盘'}
|
||||
|
||||
self.th_dict = {'EMMC':50.0*0.25, 'SSD':380*0.25, 'TF':40.0*0.20, 'FlashDrive':50.0*0.25} # key corresponds to name
|
||||
self.size_dict = {'EMMC':'1GB'}
|
||||
|
||||
self.test_sequence = []
|
||||
self.current_test_index = 0
|
||||
|
||||
self.initUI()
|
||||
self.test_sequence.append({"type":"storage", "name": "EMMC", "control":self.emmc_control, "output_file":'/dev/mmcblk2', "seek":0})
|
||||
self.test_sequence.append({"type":"storage", "name": "SSD", "control":self.ssd_control, "output_file":'/dev/nvme0n1', "seek":0})
|
||||
self.test_sequence.append({"type":"storage", "name": "TF", "control":self.tf_card_control, "output_file":'/dev/mmcblk0', "seek":10240})
|
||||
self.test_sequence.append({"type":"storage", "name": "FlashDrive", "control":self.flash_drive_control, "output_file":'/dev/sda', "seek":0})
|
||||
|
||||
def initUI(self):
|
||||
font_size = 32
|
||||
self.setGeometry(200,200, 800, 800)
|
||||
self.setStyleSheet(f"font-size: {font_size}px;")
|
||||
self.setWindowTitle('Peripheral Test')
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
# frame, [check_box, commbox, speed_show, result_show]
|
||||
# EMMC
|
||||
emmc_frame, self.emmc_control = self.gen_storage_device_testing_ui(self.name_dict['EMMC'], font_size=font_size)
|
||||
layout.addWidget(emmc_frame)
|
||||
|
||||
# SSD
|
||||
ssd_frame, self.ssd_control = self.gen_storage_device_testing_ui(self.name_dict['SSD'], font_size=font_size)
|
||||
layout.addWidget(ssd_frame)
|
||||
|
||||
# TF Card
|
||||
tf_card_frame, self.tf_card_control = self.gen_storage_device_testing_ui(self.name_dict['TF'], font_size=font_size)
|
||||
layout.addWidget(tf_card_frame)
|
||||
|
||||
# U盘
|
||||
flash_drive_frame, self.flash_drive_control = self.gen_storage_device_testing_ui(self.name_dict['FlashDrive'], font_size=font_size)
|
||||
layout.addWidget(flash_drive_frame)
|
||||
|
||||
# Create a text edit box that displays the run information
|
||||
self.text_edit = QTextEdit(self)
|
||||
self.text_edit.setReadOnly(True)
|
||||
self.text_edit.setFixedHeight(100)
|
||||
self.text_edit.setStyleSheet("font-size: 18px;")
|
||||
layout.addWidget(self.text_edit)
|
||||
|
||||
# call button
|
||||
self.test_button = QPushButton('一键测试', self)
|
||||
self.test_button.setStyleSheet(f"font-size: {font_size}px;")
|
||||
self.test_button.clicked.connect(self.test_all)
|
||||
layout.addWidget(self.test_button)
|
||||
|
||||
|
||||
def gen_storage_device_testing_ui(self, storage_name, font_size=32) -> Tuple[QFrame, List[QWidget]]:
|
||||
storage_frame = QFrame(self)
|
||||
# storage_frame.setAutoFillBackground(True)
|
||||
storage_frame.setPalette(QPalette(QColor('darkgray')))
|
||||
storage_layout = QHBoxLayout(storage_frame)
|
||||
|
||||
spacer = QSpacerItem(40, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
||||
storage_layout.addSpacerItem(spacer)
|
||||
|
||||
# check
|
||||
check_box_frame = QWidget(storage_frame)
|
||||
check_box_layout = QHBoxLayout(check_box_frame)
|
||||
storage_check_box = QCheckBox(storage_frame)
|
||||
storage_check_box.setStyleSheet("""
|
||||
QCheckBox::indicator {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
""")
|
||||
storage_check_box.setChecked(True)
|
||||
check_box_layout.addWidget(storage_check_box)
|
||||
|
||||
storage_name_label = QLabel(storage_name, check_box_frame)
|
||||
storage_name_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||
check_box_layout.addWidget(storage_name_label)
|
||||
|
||||
storage_layout.addWidget(check_box_frame)
|
||||
|
||||
spacer = QSpacerItem(60, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
||||
storage_layout.addSpacerItem(spacer)
|
||||
|
||||
# write size
|
||||
write_size_frame = QWidget(storage_frame)
|
||||
write_size_frame_layout = QHBoxLayout(write_size_frame)
|
||||
write_text_label = QLabel('写入大小:', write_size_frame)
|
||||
write_text_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
write_text_label.setStyleSheet(f"font-size: {font_size}px;")
|
||||
write_size_frame_layout.addWidget(write_text_label)
|
||||
|
||||
storage_comm_box = QComboBox(write_size_frame)
|
||||
storage_comm_box.addItems(['1GB', '2GB', '3GB', '4GB'])
|
||||
storage_comm_box.setStyleSheet(f"font-size: {font_size}px;")
|
||||
storage_comm_box.currentText()
|
||||
write_size_frame_layout.addWidget(storage_comm_box)
|
||||
storage_layout.addWidget(write_size_frame)
|
||||
|
||||
spacer = QSpacerItem(60, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
||||
storage_layout.addSpacerItem(spacer)
|
||||
|
||||
# speed result
|
||||
speed_frame = QWidget(storage_frame)
|
||||
speed_frame_layout = QHBoxLayout(speed_frame)
|
||||
speed_text_label = QLabel('速度:', speed_frame)
|
||||
speed_text_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
speed_text_label.setStyleSheet(f"font-size: {font_size}px;")
|
||||
speed_frame_layout.addWidget(speed_text_label)
|
||||
|
||||
storage_speed_show = QLabel(' ', speed_frame)
|
||||
storage_speed_show.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||
storage_speed_show.setStyleSheet(f"font-size: {font_size}px;")
|
||||
speed_frame_layout.addWidget(storage_speed_show)
|
||||
storage_layout.addWidget(speed_frame)
|
||||
|
||||
spacer = QSpacerItem(32, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
||||
storage_layout.addSpacerItem(spacer)
|
||||
# speed result judgment
|
||||
judgment_frame = QWidget(storage_frame)
|
||||
judgment_frame_layout = QHBoxLayout(judgment_frame)
|
||||
judgment_text_label = QLabel('结果:', judgment_frame)
|
||||
judgment_text_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
judgment_text_label.setStyleSheet(f"font-size: {font_size}px;")
|
||||
judgment_frame_layout.addWidget(judgment_text_label)
|
||||
|
||||
judgment_show = QLabel('未测', judgment_frame)
|
||||
judgment_show.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||
judgment_show.setStyleSheet(f"font-size: {font_size}px;")
|
||||
judgment_frame_layout.addWidget(judgment_show)
|
||||
storage_layout.addWidget(judgment_frame)
|
||||
|
||||
return storage_frame, [storage_check_box, storage_comm_box, storage_speed_show, judgment_show]
|
||||
|
||||
|
||||
def test_all(self):
|
||||
self.test_button.setEnabled(False)
|
||||
self.text_edit.append(f"{self.info_msg_index} : 开始测试所有被勾选项目................")
|
||||
self.info_msg_index += 1
|
||||
self.run_next_test()
|
||||
|
||||
def run_next_test(self):
|
||||
if self.current_test_index < len(self.test_sequence):
|
||||
test_info = self.test_sequence[self.current_test_index]
|
||||
|
||||
if test_info["type"] == "storage":
|
||||
of = test_info["output_file"]
|
||||
if test_info["name"] == "FlashDrive":
|
||||
of = self.find_sda_to_sdf_devices()
|
||||
self.test_storage_wrapper(test_info["control"], test_info["name"], output_file=of, seek=test_info["seek"])
|
||||
elif test_info["type"] == "network":
|
||||
pass
|
||||
else:
|
||||
self.test_button.setEnabled(True)
|
||||
self.text_edit.append(f"{self.info_msg_index} : 所有测试项目已完成")
|
||||
self.info_msg_index += 1
|
||||
self.current_test_index = 0
|
||||
|
||||
# storage function
|
||||
def test_storage_wrapper(self, storage_control, test_name, output_file='/dev/mmcblk2', seek=0):
|
||||
if storage_control[0].isChecked():
|
||||
self.text_edit.append(f"{self.info_msg_index} : 开始测试{self.name_dict[test_name]}写入速度................")
|
||||
self.info_msg_index += 1
|
||||
size = storage_control[1].currentText()
|
||||
size = int(size[0]) * 1024
|
||||
|
||||
self.thread_storage = StorageTestThread(output_file=output_file, size=size, seek=seek)
|
||||
self.thread_storage.task_finished.connect(
|
||||
lambda msg, storage_control=storage_control, test_name=test_name:self.test_storage_postprocessing(msg, storage_control, test_name))
|
||||
self.thread_storage.start()
|
||||
else:
|
||||
self.current_test_index += 1
|
||||
self.run_next_test()
|
||||
|
||||
def test_storage_postprocessing(self, msg, storage_control, test_name):
|
||||
ret = msg[0]
|
||||
speed = msg[1]
|
||||
time_cst = msg[2]
|
||||
if type(ret) == str:
|
||||
storage_control[2].setText(ret)
|
||||
else:
|
||||
storage_control[2].setText(f"{speed} MB/S")
|
||||
th = self.th_dict[test_name]
|
||||
if speed>=th:
|
||||
storage_control[3].setText(f"通过")
|
||||
storage_control[3].setStyleSheet(f"color: {PASS_COLOR};")
|
||||
else:
|
||||
storage_control[3].setText(f"失败")
|
||||
storage_control[3].setStyleSheet(f"color: {FAIL_COLOR};")
|
||||
self.text_edit.append(f"{self.info_msg_index} : {self.name_dict[test_name]}写入速度测试完成, 耗时为{time_cst}s, 返回:{ret}")
|
||||
self.info_msg_index += 1
|
||||
|
||||
test_info = self.test_sequence[self.current_test_index]
|
||||
if test_info["type"] == "storage":
|
||||
self.thread_storage.quit()
|
||||
self.thread_storage.wait()
|
||||
del self.thread_storage
|
||||
elif test_info["type"] == "network":
|
||||
pass
|
||||
|
||||
# Move to the next test item
|
||||
self.current_test_index += 1
|
||||
self.run_next_test()
|
||||
|
||||
def find_sda_to_sdf_devices(self):
|
||||
try:
|
||||
file_list = ['/dev/'+sub for sub in ['sda', 'sdb', 'sdc', 'sdd', 'sde', 'sdf']]
|
||||
for device in file_list:
|
||||
if os.path.exists(device):
|
||||
return device
|
||||
return '/dev/noexist'
|
||||
except Exception as e:
|
||||
return '/dev/noexist'
|
||||
|
||||
class StorageTestThread(QThread):
|
||||
# Defines a signal that notifies the main thread when a thread task has completed
|
||||
task_finished = pyqtSignal(list)
|
||||
|
||||
def __init__(self, output_file='', size='', seek=''):
|
||||
super().__init__()
|
||||
|
||||
self.output_file = output_file
|
||||
self.size = size
|
||||
self.seek = seek
|
||||
self.speed = None
|
||||
self.ret = None
|
||||
|
||||
def run(self):
|
||||
t_start = time.time()
|
||||
self.ret = self.test_storage_write_speed(output_file=self.output_file, count=self.size, seek=self.seek)
|
||||
t_period = time.time() - t_start
|
||||
speed = float(self.size)/t_period
|
||||
self.speed = round(speed, 1)
|
||||
self.task_finished.emit([self.ret, self.speed, round(t_period, 1)])
|
||||
|
||||
def test_storage_write_speed(self, output_file, bs="1M", count=1024, seek=0):
|
||||
try:
|
||||
if not os.path.exists(output_file):
|
||||
return "设备不存在"
|
||||
|
||||
command = ["dd", f"if=/dev/zero", f"of={output_file}", f"bs={bs}", f"count={count}", "oflag=direct", f"seek={seek}"]
|
||||
result = subprocess.run(command, stderr=subprocess.PIPE, text=True)
|
||||
return 0
|
||||
except Exception as e:
|
||||
return f"dd命令执行异常{e}"
|
|
@ -40,76 +40,30 @@ from importlib import import_module
|
|||
from cricket.model import TestMethod, TestCase, TestModule
|
||||
from cricket.executor import Executor
|
||||
from cricket.lang import SimpleLang
|
||||
|
||||
PASS_COLOR = '#28C025'
|
||||
FAIL_COLOR = '#E32C2E'
|
||||
|
||||
# Display constants for test status
|
||||
STATUS = {
|
||||
TestMethod.STATUS_PASS: {
|
||||
'description': u'通过',
|
||||
'symbol': u'\u25cf',
|
||||
'tag': 'pass',
|
||||
'color': '#28C025',
|
||||
},
|
||||
TestMethod.STATUS_SKIP: {
|
||||
'description': u'Skipped',
|
||||
'symbol': u'S',
|
||||
'tag': 'skip',
|
||||
'color': '#259EBF'
|
||||
},
|
||||
TestMethod.STATUS_FAIL: {
|
||||
'description': u'失败',
|
||||
'symbol': u'F',
|
||||
'tag': 'fail',
|
||||
'color': '#E32C2E'
|
||||
},
|
||||
TestMethod.STATUS_EXPECTED_FAIL: {
|
||||
'description': u'Expected\n failure',
|
||||
'symbol': u'X',
|
||||
'tag': 'expected',
|
||||
'color': '#3C25BF'
|
||||
},
|
||||
TestMethod.STATUS_UNEXPECTED_SUCCESS: {
|
||||
'description': u'Unexpected\n success',
|
||||
'symbol': u'U',
|
||||
'tag': 'unexpected',
|
||||
'color': '#C82788'
|
||||
},
|
||||
TestMethod.STATUS_ERROR: {
|
||||
'description': 'Error',
|
||||
'symbol': u'E',
|
||||
'tag': 'error',
|
||||
'color': '#E4742C'
|
||||
},
|
||||
}
|
||||
|
||||
STATUS_DEFAULT = {
|
||||
'description': 'Not\nexecuted',
|
||||
'symbol': u'',
|
||||
'tag': None,
|
||||
'color': '#BFBFBF',
|
||||
}
|
||||
from cricket.macro import *
|
||||
from cricket.statusview import StatusView
|
||||
from cricket.peripheraltestview import PeripheralTestWindow
|
||||
from cricket.wifimacview import WifiMacView
|
||||
|
||||
|
||||
class MainWindow(QMainWindow, SimpleLang):
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, root):
|
||||
super().__init__()
|
||||
|
||||
self.sl = SimpleLang()
|
||||
self._project = None
|
||||
self.test_table = {}
|
||||
self.test_list = {}
|
||||
self.run_status = {}
|
||||
self.executor = {}
|
||||
|
||||
|
||||
self.usb_list = []
|
||||
|
||||
|
||||
self.set_brightness()
|
||||
|
||||
|
||||
self.wifi_mac_Ok = False
|
||||
|
||||
self.root = root
|
||||
self.setWindowTitle(self.get_text('title'))
|
||||
self.setWindowTitle(self.sl.get_text('title'))
|
||||
# self.showFullScreen()
|
||||
|
||||
self.font_size = 14
|
||||
|
@ -117,6 +71,8 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
# Set up the main content for the window.
|
||||
self._setup_main_content()
|
||||
|
||||
self.peripheral_test_view = PeripheralTestWindow(self)
|
||||
|
||||
# Set up listeners for runner events.
|
||||
Executor.bind('test_status_update', self.on_executorStatusUpdate)
|
||||
Executor.bind('test_start', self.on_executorTestStart)
|
||||
|
@ -127,7 +83,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
######################################################
|
||||
# Internal GUI layout methods.
|
||||
######################################################
|
||||
|
||||
|
||||
def _setup_main_content(self):
|
||||
'''
|
||||
The button toolbar runs as a horizontal area at the top of the GUI.
|
||||
|
@ -146,30 +102,30 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
toolbar = QFrame(self.content)
|
||||
layout = QGridLayout(toolbar)
|
||||
|
||||
self.run_all_button = QPushButton(self.get_text('run_all_button'), toolbar)
|
||||
self.run_all_button = QPushButton(self.sl.get_text('run_all_button'), toolbar)
|
||||
self.run_all_button.clicked.connect(self.cmd_run_all)
|
||||
self.run_all_button.setFocus()
|
||||
layout.addWidget(self.run_all_button, 0, 0)
|
||||
|
||||
self.run_selected_button = QPushButton(self.get_text('run_selected_button'),
|
||||
self.run_selected_button = QPushButton(self.sl.get_text('run_selected_button'),
|
||||
toolbar)
|
||||
self.run_selected_button.setDisabled(True)
|
||||
self.run_selected_button.clicked.connect(self.cmd_run_selected)
|
||||
layout.addWidget(self.run_selected_button, 0, 1)
|
||||
|
||||
self.stop_button = QPushButton(self.get_text('stop_button'), toolbar)
|
||||
self.stop_button = QPushButton(self.sl.get_text('stop_button'), toolbar)
|
||||
self.stop_button.setDisabled(True)
|
||||
self.stop_button.clicked.connect(self.cmd_stop)
|
||||
layout.addWidget(self.stop_button, 0 , 2)
|
||||
|
||||
self.reboot_button = QPushButton(self.get_text('reboot_button'), toolbar)
|
||||
self.reboot_button = QPushButton(self.sl.get_text('reboot_button'), toolbar)
|
||||
self.reboot_button.clicked.connect(self.cmd_reboot)
|
||||
layout.addWidget(self.reboot_button, 0, 3)
|
||||
|
||||
self.poweroff_button = QPushButton(self.get_text('poweroff_button'), toolbar)
|
||||
self.poweroff_button = QPushButton(self.sl.get_text('poweroff_button'), toolbar)
|
||||
self.poweroff_button.clicked.connect(self.cmd_poweroff)
|
||||
layout.addWidget(self.poweroff_button, 0, 4)
|
||||
|
||||
|
||||
self.content_layout.addWidget(toolbar)
|
||||
|
||||
# tests
|
||||
|
@ -188,7 +144,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
self._setup_usb_frame(5, 0, 1, 1)
|
||||
self._setup_test_table('manual', 6, 0, 4, 1)
|
||||
|
||||
camera_box = QGroupBox(self.get_text('camera'), self.tests)
|
||||
camera_box = QGroupBox(self.sl.get_text('camera'), self.tests)
|
||||
camera_box_layout = QVBoxLayout(camera_box)
|
||||
video_widget = QVideoWidget(camera_box)
|
||||
self.media_player = QMediaPlayer()
|
||||
|
@ -220,39 +176,39 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
|
||||
# set main content to window
|
||||
self.setCentralWidget(self.content)
|
||||
|
||||
|
||||
def _setup_info(self):
|
||||
info = QFrame(self.content)
|
||||
info_layout = QGridLayout(info)
|
||||
|
||||
cpu_model = QLabel(f'{self.get_text("cpu_model")}: {self._get_CPU_model()}', info)
|
||||
cpu_model = QLabel(f'{self.sl.get_text("cpu_model")}: {self._get_CPU_model()}', info)
|
||||
info_layout.addWidget(cpu_model, 0, 0)
|
||||
|
||||
cpu_freq = QLabel(f'{self.get_text("cpu_freq")}: {self._get_CPU_freq()} GHz', info)
|
||||
cpu_freq = QLabel(f'{self.sl.get_text("cpu_freq")}: {self._get_CPU_freq()} GHz', info)
|
||||
info_layout.addWidget(cpu_freq, 0, 1)
|
||||
|
||||
self.cpu_temp = QLabel(f'{self.get_text("cpu_temp")}: {self._get_CPU_Temp()} °C', info)
|
||||
|
||||
self.cpu_temp = QLabel(f'{self.sl.get_text("cpu_temp")}: {self._get_CPU_Temp()} °C', info)
|
||||
self._cpu_temp_timer = QTimer(self)
|
||||
self._cpu_temp_timer.timeout.connect(self.on_cpuTempUpdate)
|
||||
self._cpu_temp_timer.start(1000)
|
||||
self._cpu_temp_timer.start(1000)
|
||||
info_layout.addWidget(self.cpu_temp, 0, 2)
|
||||
|
||||
ddr_size = QLabel(f'{self.get_text("ddr_size")}: {self._get_DDR_size()} GB', info)
|
||||
ddr_size = QLabel(f'{self.sl.get_text("ddr_size")}: {self._get_DDR_size()} GB', info)
|
||||
info_layout.addWidget(ddr_size, 0, 3)
|
||||
|
||||
emmc_size = QLabel(f'{self.get_text("emmc_size")}: {self._get_eMMC_size()} GB', info)
|
||||
emmc_size = QLabel(f'{self.sl.get_text("emmc_size")}: {self._get_eMMC_size()} GB', info)
|
||||
info_layout.addWidget(emmc_size, 0, 4)
|
||||
|
||||
ssd_size = QLabel(f'{self.get_text("ssd_size")}: {self._get_SSD_size()} GB', info)
|
||||
ssd_size = QLabel(f'{self.sl.get_text("ssd_size")}: {self._get_SSD_size()} GB', info)
|
||||
info_layout.addWidget(ssd_size, 0, 5)
|
||||
|
||||
self.hdmi_model = QLabel(f'{self.get_text("hdmi_model")}: None', info)
|
||||
|
||||
self.hdmi_model = QLabel(f'{self.sl.get_text("hdmi_model")}: None', info)
|
||||
info_layout.addWidget(self.hdmi_model, 0, 6)
|
||||
|
||||
product_name = QLabel(f'{self.get_text("product_name")}: {self._get_product_name()}', info)
|
||||
product_name = QLabel(f'{self.sl.get_text("product_name")}: {self._get_product_name()}', info)
|
||||
info_layout.addWidget(product_name, 0, 7)
|
||||
|
||||
fw_version = QLabel(f'{self.get_text("fw_version")}: {self._get_fw_version()}', info)
|
||||
fw_version = QLabel(f'{self.sl.get_text("fw_version")}: {self._get_fw_version()}', info)
|
||||
info_layout.addWidget(fw_version, 0, 8)
|
||||
|
||||
self.content_layout.addWidget(info)
|
||||
|
@ -260,11 +216,11 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
def _setup_test_table(self, name, row, column, row_span, column_span):
|
||||
module = import_module(name)
|
||||
|
||||
box = QGroupBox(module.MODULE_NAME[self.current_lang], self.tests)
|
||||
box = QGroupBox(module.MODULE_NAME[self.sl.current_lang], self.tests)
|
||||
box.setStyleSheet("QGroupBox::title { font-weight: bold; }")
|
||||
layout = QVBoxLayout(box)
|
||||
|
||||
columns = self.get_text('test_table_head')
|
||||
columns = self.sl.get_text('test_table_head')
|
||||
|
||||
table = QTableWidget(box)
|
||||
table.setStyleSheet('QTableWidget { background-color: black; color: white; }')
|
||||
|
@ -287,14 +243,14 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
self.tests_layout.addWidget(box, row, column, row_span, column_span)
|
||||
|
||||
def _setup_others(self):
|
||||
self.others_box = QGroupBox(self.get_text('others'), self.tests)
|
||||
self.others_box = QGroupBox(self.sl.get_text('others'), self.tests)
|
||||
self.others_box_layout = QVBoxLayout(self.others_box)
|
||||
|
||||
# Comment the code below if you don't need it
|
||||
|
||||
# item
|
||||
self._setup_others_item()
|
||||
|
||||
|
||||
# status
|
||||
self._setup_others_status()
|
||||
|
||||
|
@ -304,8 +260,9 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
self.others_box_layout.addWidget(self.others_item)
|
||||
|
||||
self._setup_others_test()
|
||||
|
||||
self._setup_wifi_mac()
|
||||
|
||||
self.wifi_mac_view = WifiMacView(self.others_item)
|
||||
self.others_item_layout.addWidget(self.wifi_mac_view)
|
||||
|
||||
sn = self._get_sn()
|
||||
if sn:
|
||||
|
@ -320,38 +277,49 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
lcd_frame.setAutoFillBackground(True)
|
||||
lcd_frame.setPalette(QPalette(QColor('darkgray')))
|
||||
lcd_layout = QHBoxLayout(lcd_frame)
|
||||
|
||||
|
||||
# lcd_button = QPushButton(self.get_text('lcd'), lcd_frame)
|
||||
# lcd_button.clicked.connect(self.cmd_lcd)
|
||||
# lcd_layout.addWidget(lcd_button)
|
||||
|
||||
# lcd backlight
|
||||
backlight_label = QLabel(self.get_text('lcd_backlight')+" :", lcd_frame)
|
||||
backlight_label = QLabel(self.sl.get_text('lcd_backlight')+" :", lcd_frame)
|
||||
backlight_label.setAlignment( Qt.AlignVCenter)
|
||||
lcd_layout.addWidget(backlight_label)
|
||||
|
||||
|
||||
# Create a slider
|
||||
lcd_slider = QSlider(Qt.Horizontal, lcd_frame)
|
||||
lcd_slider.setRange(0, 255)
|
||||
lcd_slider.setValue(128)
|
||||
lcd_slider.setRange(0, 255)
|
||||
lcd_slider.setValue(128)
|
||||
lcd_slider.valueChanged.connect(self.set_brightness)
|
||||
lcd_layout.addWidget(lcd_slider)
|
||||
|
||||
|
||||
label_brightness = QLabel("128", lcd_frame)
|
||||
label_brightness.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
label_brightness.setFixedWidth(24)
|
||||
lcd_slider.valueChanged.connect(lambda value: label_brightness.setText(str(value)))
|
||||
lcd_layout.addWidget(label_brightness)
|
||||
|
||||
|
||||
others_test_layout.addWidget(lcd_frame)
|
||||
|
||||
# peripheral test
|
||||
peripheral_frame = QFrame(others_test)
|
||||
peripheral_frame.setAutoFillBackground(True)
|
||||
peripheral_frame.setPalette(QPalette(QColor('darkgray')))
|
||||
peripheral_layout = QHBoxLayout(peripheral_frame)
|
||||
self.peripheral_test_button = QPushButton(self.sl.get_text('peripheral_test'), peripheral_frame)
|
||||
self.peripheral_test_button.setAutoFillBackground(True)
|
||||
self.peripheral_test_button.clicked.connect(self.cmd_peripheral_test)
|
||||
peripheral_layout.addWidget(self.peripheral_test_button)
|
||||
others_test_layout.addWidget(peripheral_frame)
|
||||
|
||||
# aging test
|
||||
aging_test = QFrame(others_test)
|
||||
aging_test.setAutoFillBackground(True)
|
||||
aging_test.setPalette(QPalette(QColor('darkgray')))
|
||||
aging_test_layout = QVBoxLayout(aging_test)
|
||||
|
||||
self.aging_button = QPushButton(self.get_text('aging_test'), aging_test)
|
||||
self.aging_button = QPushButton(self.sl.get_text('aging_test'), aging_test)
|
||||
self.aging_button.setAutoFillBackground(True)
|
||||
self.aging_button.clicked.connect(self.cmd_aging)
|
||||
aging_test_layout.addWidget(self.aging_button)
|
||||
|
@ -374,7 +342,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
|
||||
aging_duration = QFrame(aging_test)
|
||||
aging_duration_layout = QHBoxLayout(aging_duration)
|
||||
aging_duration_label = QLabel(f'{self.get_text("aging_duration")}: ', aging_duration)
|
||||
aging_duration_label = QLabel(f'{self.sl.get_text("aging_duration")}: ', aging_duration)
|
||||
aging_duration_layout.addWidget(aging_duration_label)
|
||||
self.aging_duration_choice = QComboBox(aging_test)
|
||||
self.aging_duration_choice.addItems(['4', '8', '12', '24'])
|
||||
|
@ -383,40 +351,16 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
aging_test_layout.addWidget(aging_duration)
|
||||
|
||||
others_test_layout.addWidget(aging_test)
|
||||
|
||||
|
||||
self.others_item_layout.addWidget(others_test)
|
||||
|
||||
def _setup_wifi_mac(self):
|
||||
mac = self._get_wifi_mac()
|
||||
if mac:
|
||||
self._setup_wifi_mac_qrcode(mac)
|
||||
else:
|
||||
QTimer.singleShot(2000, self._setup_wifi_mac)
|
||||
|
||||
# wifi signal part
|
||||
|
||||
|
||||
# wifi signal part
|
||||
def _setup_others_status(self):
|
||||
self.others_status = QFrame(self.others_box)
|
||||
self.others_status_layout = QHBoxLayout(self.others_status)
|
||||
self.others_box_layout.addWidget(self.others_status)
|
||||
self._setup_wifi_view()
|
||||
|
||||
def _setup_wifi_view(self):
|
||||
wifi = QFrame(self.others_status)
|
||||
wifi_layout = QGridLayout(wifi)
|
||||
self.others_status_view = StatusView(self.others_box)
|
||||
self.others_box_layout.addWidget(self.others_status_view)
|
||||
|
||||
self.others_status_layout.addWidget(wifi)
|
||||
|
||||
wifi_label = QLabel(f'{self.get_text("wifi")}: ', wifi)
|
||||
wifi_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||
wifi_layout.addWidget(wifi_label, 0, 0)
|
||||
|
||||
self.wifi_signal_level = QProgressBar(wifi)
|
||||
self.wifi_signal_level.setAlignment(Qt.AlignLeft)
|
||||
self.wifi_signal_level.setMaximum(5)
|
||||
wifi_layout.addWidget(self.wifi_signal_level, 0, 1)
|
||||
|
||||
QTimer.singleShot(3000, lambda: self.on_wifiStatusUpdate())
|
||||
|
||||
# [start] Check the usb to see if the device is inserted
|
||||
def usb_loop(self, label, usb_path):
|
||||
while True:
|
||||
|
@ -441,17 +385,17 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
def _setup_usb_frame(self, row, column, row_span, column_span):
|
||||
self.usb_frame = QFrame(self.tests)
|
||||
self.usb_frame_layout = QGridLayout(self.usb_frame)
|
||||
|
||||
|
||||
self._add_usb_test('USB A口 (左上) 2.0', 0, 0,
|
||||
'/sys/bus/usb/devices/usb2/2-1/2-1.1/product')
|
||||
self._add_usb_test('USB A口 (左上) 3.0', 1, 0,
|
||||
'/sys/bus/usb/devices/usb3/3-1/3-1.1/product')
|
||||
|
||||
|
||||
self._add_usb_test('USB A口 (左下) 2.0', 0, 1,
|
||||
'/sys/bus/usb/devices/usb2/2-1/2-1.4/product')
|
||||
self._add_usb_test('USB A口 (左下) 3.0', 1, 1,
|
||||
'/sys/bus/usb/devices/usb3/3-1/3-1.4/product')
|
||||
|
||||
|
||||
self._add_usb_test('USB A口 (右上) 2.0', 0, 2,
|
||||
'/sys/bus/usb/devices/usb2/2-1/2-1.3/product')
|
||||
self._add_usb_test('USB A口 (右上) 3.0', 1, 2,
|
||||
|
@ -461,7 +405,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
'/sys/bus/usb/devices/usb2/2-1/2-1.2/product')
|
||||
self._add_usb_test('USB A口 (右下) 3.0', 1, 3,
|
||||
'/sys/bus/usb/devices/usb3/3-1/3-1.2/product')
|
||||
|
||||
|
||||
self.tests_layout.addWidget(self.usb_frame, row, column, row_span, column_span)
|
||||
# [end] Check the usb to see if the device is inserted
|
||||
|
||||
|
@ -488,26 +432,13 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
qr_label.setPixmap(self._create_qrcode(sn))
|
||||
sn_qrcode_layout.addWidget(qr_label)
|
||||
|
||||
sn_label = QLabel(f'{self.get_text("sn")}: {sn}', sn_qrcode)
|
||||
sn_label = QLabel(f'{self.sl.get_text("sn")}: {sn}', sn_qrcode)
|
||||
sn_label.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
|
||||
sn_qrcode_layout.addWidget(sn_label)
|
||||
|
||||
self.others_item_layout.addWidget(sn_qrcode)
|
||||
|
||||
def _setup_wifi_mac_qrcode(self, mac):
|
||||
mac_qrcode = QFrame(self.others_item)
|
||||
mac_qrcode_layout = QVBoxLayout(mac_qrcode)
|
||||
|
||||
qr_label = QLabel(mac_qrcode)
|
||||
qr_label.setAlignment(Qt.AlignCenter)
|
||||
qr_label.setPixmap(self._create_qrcode(mac))
|
||||
mac_qrcode_layout.addWidget(qr_label)
|
||||
|
||||
mac_label = QLabel(f'{self.get_text("wifi_mac")}: {mac}', mac_qrcode)
|
||||
mac_label.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
|
||||
mac_qrcode_layout.addWidget(mac_label)
|
||||
|
||||
self.others_item_layout.addWidget(mac_qrcode)
|
||||
######################################################
|
||||
# Handlers for setting a new project
|
||||
######################################################
|
||||
|
@ -521,7 +452,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
testcase = getattr(module, subModuleName)
|
||||
if hasattr(testcase, 'LANGUAGES'):
|
||||
langs = getattr(testcase, 'LANGUAGES')
|
||||
lang = langs.get(self.current_lang)
|
||||
lang = langs.get(self.sl.current_lang)
|
||||
if lang is not None:
|
||||
text = lang.get(key)
|
||||
if text is not None:
|
||||
|
@ -580,7 +511,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
pipeline = 'gst-pipeline: spacemitsrc location=/opt/factorytest/res/camtest_sensor0_mode0.json close-dmabuf=1 ! videoconvert ! video/x-raw,format=BGRx ! autovideosink sync=0'
|
||||
self.media_player.setMedia(QMediaContent(QUrl(pipeline)))
|
||||
self.media_player.play()
|
||||
|
||||
|
||||
self.hdmi_thread = threading.Thread(target=self.hdmi_loop)
|
||||
self.hdmi_thread.start()
|
||||
|
||||
|
@ -590,7 +521,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
self.cmd_run_all()
|
||||
|
||||
self.root.exec_()
|
||||
|
||||
|
||||
def hdmi_loop(self):
|
||||
card = '/sys/class/drm/card2-HDMI-A-1'
|
||||
if os.path.exists(card):
|
||||
|
@ -611,25 +542,25 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
if line.strip().startswith('Model'):
|
||||
model = line.strip().split(':')[1].strip()
|
||||
|
||||
self.hdmi_model.setText(f'{self.get_text("hdmi_model")}: {manufacturer} {model}')
|
||||
self.hdmi_model.setText(f'{self.sl.get_text("hdmi_model")}: {manufacturer} {model}')
|
||||
|
||||
def _play_wav(self, device, volume, path):
|
||||
cmd = f'amixer -c 1 cset numid=1,iface=MIXER,name="DAC Playback Volume" {volume}'
|
||||
proc = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
print(f'Set playback volume to {volume} return {proc.returncode}')
|
||||
# print(f'Set playback volume to {volume} return {proc.returncode}')
|
||||
|
||||
cmd = f'aplay -D{device} -r 48000 -f S16_LE {path}'
|
||||
proc = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
print(f'Play {path} on {device} return {proc.returncode}')
|
||||
# print(f'Play {path} on {device} return {proc.returncode}')
|
||||
|
||||
def _record_wav(self, device, volume, duration, path):
|
||||
cmd = f'amixer -c 1 cset numid=1,iface=MIXER,name="ADC Capture Volume" {volume},{volume}'
|
||||
proc = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
print(f'Set capture volume to {volume} return {proc.returncode}')
|
||||
# print(f'Set capture volume to {volume} return {proc.returncode}')
|
||||
|
||||
cmd = f'arecord -D{device} -r 48000 -f S16_LE -d {duration} {path}'
|
||||
proc = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
print(f'Record {path} on {device} in {duration}s return {proc.returncode}')
|
||||
# print(f'Record {path} on {device} in {duration}s return {proc.returncode}')
|
||||
|
||||
def audio_loop(self):
|
||||
# sleep for a while
|
||||
|
@ -661,7 +592,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
# color = self.lcd_color_list[self.lcd_color_index % len(self.lcd_color_list)]
|
||||
# self.lcd_color_index += 1
|
||||
# self.setPalette(QPalette(QColor(color)))
|
||||
|
||||
|
||||
def set_brightness(self, brightness = 128):
|
||||
path = '/sys/devices/platform/soc/soc:lcd_backlight/backlight/soc:lcd_backlight/brightness'
|
||||
try:
|
||||
|
@ -669,13 +600,13 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
f.write(f'{brightness}')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# def keyPressEvent(self, event):
|
||||
# super().keyPressEvent(event)
|
||||
|
||||
# def mousePressEvent(self, event):
|
||||
# super().mousePressEvent(event)
|
||||
|
||||
|
||||
######################################################
|
||||
# User commands
|
||||
######################################################
|
||||
|
@ -684,7 +615,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
# self.content.setVisible(False)
|
||||
# self.lcd_color_index = 0
|
||||
# self.update_lcd_color()
|
||||
|
||||
|
||||
def cmd_poweroff(self):
|
||||
self.media_player.stop()
|
||||
self.stop()
|
||||
|
@ -727,7 +658,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
if data is not None:
|
||||
labels.append(data)
|
||||
|
||||
if labels and (not self.executor[module] or
|
||||
if labels and (not self.executor[module] or
|
||||
not self.executor[module].is_running):
|
||||
self.run(module, labels=labels)
|
||||
|
||||
|
@ -738,7 +669,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
remaining_seconds = seconds % 60
|
||||
|
||||
return hours, minutes, remaining_seconds
|
||||
|
||||
|
||||
def update_aging_hints(self, error: str = None):
|
||||
hours, minutes, seconds = self._convert_seconds(self.aging_elapse)
|
||||
hints = '正在进行老化测试...\n'
|
||||
|
@ -747,7 +678,7 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
if error:
|
||||
hints += error
|
||||
self.aging_dialog.setLabelText(hints)
|
||||
|
||||
|
||||
def start_aging_test(self):
|
||||
self.cpu_aging_proc = None
|
||||
self.ddr_aging_proc = None
|
||||
|
@ -859,15 +790,15 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
self.vpu_aging_proc.kill()
|
||||
self.vpu_aging_proc.wait()
|
||||
self.vpu_aging_proc = None
|
||||
|
||||
|
||||
def cmd_aging(self):
|
||||
self.aging_duration = int(self.aging_duration_choice.currentText()) * 3600
|
||||
self.aging_elapse = 0
|
||||
self.aging_pass = True
|
||||
|
||||
self.aging_dialog = QProgressDialog('', f'{self.get_text("aging_cancel")}',
|
||||
self.aging_dialog = QProgressDialog('', f'{self.sl.get_text("aging_cancel")}',
|
||||
0, self.aging_duration, self)
|
||||
self.aging_dialog.setWindowTitle(self.get_text('aging_test'))
|
||||
self.aging_dialog.setWindowTitle(self.sl.get_text('aging_test'))
|
||||
self.update_aging_hints()
|
||||
self.aging_dialog.setValue(0)
|
||||
self.aging_dialog.setAutoClose(True)
|
||||
|
@ -893,6 +824,11 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
self.aging_button.setPalette(QPalette(QColor(PASS_COLOR)))
|
||||
else:
|
||||
self.aging_button.setPalette(QPalette(QColor(FAIL_COLOR)))
|
||||
|
||||
#
|
||||
def cmd_peripheral_test(self):
|
||||
self.peripheral_test_view.exec_()
|
||||
|
||||
######################################################
|
||||
# GUI Callbacks
|
||||
######################################################
|
||||
|
@ -902,77 +838,6 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
# update "run selected" button enabled state
|
||||
self.set_selected_button_state()
|
||||
|
||||
# wifi signal part
|
||||
def on_wifiStatusUpdate(self):
|
||||
self.set_wifi_signal_level()
|
||||
QTimer.singleShot(3000, lambda: self.on_wifiStatusUpdate())
|
||||
|
||||
def set_wifi_signal_level(self):
|
||||
ssid, signal_level = self._get_strongest_wifi()
|
||||
if not ssid:
|
||||
return
|
||||
|
||||
if signal_level <= -100:
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % FAIL_COLOR)
|
||||
value = 1
|
||||
elif signal_level <= -88: # (-100, -88]
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % FAIL_COLOR)
|
||||
value = 2
|
||||
elif signal_level <= -77: # (-88, -77]
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % FAIL_COLOR)
|
||||
value = 3
|
||||
elif signal_level <= -55: # (-77, -55]
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % PASS_COLOR)
|
||||
value = 4
|
||||
else: # > -55
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % PASS_COLOR)
|
||||
value = 5
|
||||
|
||||
self.wifi_signal_level.setFormat(f'{ssid}: {signal_level}')
|
||||
self.wifi_signal_level.setValue(value)
|
||||
|
||||
def _get_strongest_wifi(self):
|
||||
strongest_signal_level = -2147483648
|
||||
strongest_ssid = None
|
||||
|
||||
timeout = 10
|
||||
cmd = 'wpa_cli scan'
|
||||
scan = subprocess.run(cmd, capture_output=True, text=True, shell=True, timeout=timeout)
|
||||
if scan.returncode != 0:
|
||||
return strongest_ssid, strongest_signal_level
|
||||
|
||||
cmd = 'wpa_cli scan_results'
|
||||
proc = subprocess.run(cmd, capture_output=True, text=True, shell=True, timeout=timeout)
|
||||
if proc.returncode != 0:
|
||||
return strongest_ssid, strongest_signal_level
|
||||
|
||||
for line in proc.stdout.splitlines():
|
||||
if not line.strip() or line.startswith('Selected interface') or line.startswith('bssid'):
|
||||
continue
|
||||
|
||||
parts = line.split('\t')
|
||||
if len(parts) < 5:
|
||||
continue
|
||||
|
||||
signal_level = int(parts[2])
|
||||
ssid = parts[4]
|
||||
|
||||
if signal_level > strongest_signal_level:
|
||||
strongest_signal_level = signal_level
|
||||
strongest_ssid = ssid
|
||||
|
||||
return strongest_ssid, strongest_signal_level
|
||||
|
||||
# wifi mac part
|
||||
def _get_wifi_mac(self):
|
||||
cmd = 'ifconfig wlan0'
|
||||
proc = subprocess.run(cmd, capture_output=True, text=True, shell=True, timeout=2)
|
||||
|
||||
for line in proc.stdout.splitlines():
|
||||
pattern = 'HWaddr'
|
||||
if line.find(pattern) > 0:
|
||||
return line.split(pattern)[1].strip()
|
||||
|
||||
def _get_sn(self):
|
||||
path = '/proc/device-tree/serial-number'
|
||||
if os.path.exists(path):
|
||||
|
@ -1002,54 +867,54 @@ class MainWindow(QMainWindow, SimpleLang):
|
|||
if os.path.exists(path):
|
||||
with open(path, 'r') as f:
|
||||
return round(int(f.readline().strip()) / 1000 / 1000 / 2, 1)
|
||||
|
||||
|
||||
def _get_DDR_size(self):
|
||||
with open('/proc/meminfo', 'r') as f:
|
||||
for line in f.readlines():
|
||||
if line.startswith('MemTotal:'):
|
||||
return round(int(line.split()[1]) / 1024 / 1024, 0)
|
||||
|
||||
|
||||
def _get_CPU_model(self):
|
||||
with open('/proc/cpuinfo', 'r') as f:
|
||||
for line in f.readlines():
|
||||
if line.startswith('model name'):
|
||||
return line.split(':')[1].strip()
|
||||
|
||||
|
||||
def _get_CPU_freq(self):
|
||||
with open('/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq', 'r') as f:
|
||||
return round(int(f.readline().strip()) / 1000 / 1000, 1)
|
||||
|
||||
# cpu temp part
|
||||
def on_cpuTempUpdate(self):
|
||||
self.cpu_temp.setText(f'{self.get_text("cpu_temp")}: {self._get_CPU_Temp()} °C')
|
||||
|
||||
self.cpu_temp.setText(f'{self.sl.get_text("cpu_temp")}: {self._get_CPU_Temp()} °C')
|
||||
|
||||
def _get_CPU_Temp(self):
|
||||
thermal_base_path = "/sys/class/thermal/"
|
||||
ret = "None"
|
||||
|
||||
|
||||
try:
|
||||
# Traverse the thermal_zone* directory
|
||||
for zone in os.listdir(thermal_base_path):
|
||||
zone_path = os.path.join(thermal_base_path, zone)
|
||||
type_path = os.path.join(zone_path, "type")
|
||||
|
||||
|
||||
# Check whether the type file exists
|
||||
if os.path.isfile(type_path):
|
||||
with open(type_path, 'r') as type_file:
|
||||
type_content = type_file.read().strip()
|
||||
|
||||
|
||||
# Check whether the type file content matches
|
||||
if type_content == "cluster0_thermal":
|
||||
temp_path = os.path.join(zone_path, "temp")
|
||||
|
||||
|
||||
if os.path.isfile(temp_path):
|
||||
with open(temp_path, 'r') as temp_file:
|
||||
temp_content = temp_file.read().strip()
|
||||
temp_content = int(temp_content)//1000
|
||||
ret = str(temp_content)
|
||||
temp_content = int(temp_content)//1000
|
||||
ret = str(temp_content)
|
||||
except Exception as e:
|
||||
print(f"An error occurred when getting cpu temperature: {e}")
|
||||
|
||||
|
||||
return ret
|
||||
|
||||
def on_nodeStatusUpdate(self, node):
|
||||
|
|
22
cricket/cricket/singleton.py
Normal file
22
cricket/cricket/singleton.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
|
||||
def singleton(cls):
|
||||
instances = {}
|
||||
def get_instance(*args, **kwargs):
|
||||
if cls not in instances:
|
||||
instances[cls] = cls(*args, **kwargs)
|
||||
return instances[cls]
|
||||
return get_instance
|
||||
|
||||
|
||||
class SingletonMeta(type):
|
||||
"""
|
||||
A metaclass that ensures a class follows the Singleton pattern.
|
||||
All instances of the class and its subclasses share the same instance.
|
||||
"""
|
||||
_instances = {}
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super().__call__(*args, **kwargs)
|
||||
return cls._instances[cls]
|
170
cricket/cricket/statusview.py
Normal file
170
cricket/cricket/statusview.py
Normal file
|
@ -0,0 +1,170 @@
|
|||
from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtGui import QColor, QKeyEvent, QMouseEvent, QPixmap, QImage, QPalette
|
||||
from PyQt5.QtWidgets import QFrame, QHBoxLayout, QVBoxLayout, QGridLayout, QLabel, QProgressBar, QSlider
|
||||
import subprocess
|
||||
from cricket.lang import SimpleLang
|
||||
from cricket.loggermanager import LoggerManager
|
||||
from cricket.macro import *
|
||||
from cricket.utils import *
|
||||
|
||||
class StatusView(QFrame):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._setup_others_status()
|
||||
|
||||
def _setup_others_status(self):
|
||||
self.others_status_layout = QHBoxLayout(self)
|
||||
|
||||
# wifi signal
|
||||
self.wifi_signal_view = WifiSignalView(self)
|
||||
self.others_status_layout.addWidget(self.wifi_signal_view)
|
||||
self.wifi_signal_view.start_to_scan()
|
||||
|
||||
|
||||
class WifiSignalView(QFrame):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.sl = SimpleLang()
|
||||
self.log_manager = LoggerManager(name='WiFiSignalView')
|
||||
self.logger = self.log_manager.get_logger()
|
||||
|
||||
self.wifi_text = self.sl.get_text("wifi")
|
||||
self.wifi_ready = False
|
||||
|
||||
self.setup_wifi_signal_with_ui()
|
||||
|
||||
def setup_wifi_signal_with_ui(self):
|
||||
wifi_layout = QGridLayout(self)
|
||||
|
||||
wifi_label = QLabel(f'{self.wifi_text}: ', self)
|
||||
wifi_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||
wifi_layout.addWidget(wifi_label, 0, 0)
|
||||
|
||||
self.wifi_signal_level = QProgressBar(self)
|
||||
self.wifi_signal_level.setAlignment(Qt.AlignLeft)
|
||||
self.wifi_signal_level.setMaximum(100)
|
||||
|
||||
wifi_layout.addWidget(self.wifi_signal_level, 0, 1)
|
||||
|
||||
self.logger.info(f'{self.sl.get_text("wifi_signal_init")}')
|
||||
self.wifi_signal_level.setFormat(f'{self.sl.get_text("wifi_signal_init")}')
|
||||
self.wifi_signal_level.setValue(0)
|
||||
|
||||
def start_to_scan(self):
|
||||
self.on_wifiStatusUpdate()
|
||||
|
||||
def on_wifiStatusUpdate(self):
|
||||
interface = 'wlan0'
|
||||
status = self.check_interface_status(interface)
|
||||
wifi_module_name = '8852bs'
|
||||
kernel_module_wifi_status = self.check_module_loaded(wifi_module_name)
|
||||
wpa_supplicant_status = self.check_process_running('wpa_supplicant')
|
||||
if status and kernel_module_wifi_status and wpa_supplicant_status:
|
||||
self.wifi_ready = True
|
||||
pr = f"Interface {interface} is {status}"
|
||||
self.set_wifi_signal_level()
|
||||
else:
|
||||
pr = f"fail wifi: {interface}:{status}, {wifi_module_name}:{kernel_module_wifi_status}, wpa_supplicant:{wpa_supplicant_status}"
|
||||
self.logger.info(pr)
|
||||
self.wifi_signal_level.setFormat(f'{self.sl.get_text("wifi_signal_init")}')
|
||||
self.wifi_signal_level.setValue(0)
|
||||
|
||||
QTimer.singleShot(1000, lambda: self.on_wifiStatusUpdate())
|
||||
|
||||
def check_interface_status(self, interface):
|
||||
try:
|
||||
# Execute a command ip link show interface
|
||||
result = subprocess.run(['ip', 'link', 'show', interface], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
|
||||
# Check the return code of the command execution
|
||||
if result.returncode != 0:
|
||||
print(f"Error: {result.stderr}")
|
||||
return None
|
||||
|
||||
# Analytic output
|
||||
output = result.stdout
|
||||
if interface in output:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Exception occurred: {e}")
|
||||
return False
|
||||
|
||||
def check_module_loaded(self, module_name):
|
||||
"""Check whether the kernel module is loaded successfully"""
|
||||
result = subprocess.run(['lsmod'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if module_name in result.stdout:
|
||||
return True
|
||||
return False
|
||||
|
||||
def check_process_running(self, process_name):
|
||||
"""Check whether the process is running"""
|
||||
result = subprocess.run(['ps', 'aux'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if process_name in result.stdout:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_wifi_signal_level(self):
|
||||
ssid, signal_level = self._get_strongest_wifi()
|
||||
if not ssid:
|
||||
self.wifi_signal_level.setFormat(f'{self.sl.get_text("wifi_signal_init")}')
|
||||
# self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % FAIL_COLOR)
|
||||
self.wifi_signal_level.setValue(0)
|
||||
return
|
||||
|
||||
if signal_level <= -100:
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % FAIL_COLOR)
|
||||
value = 20
|
||||
elif signal_level <= -88: # (-100, -88]
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % FAIL_COLOR)
|
||||
value = 40
|
||||
elif signal_level <= -55: # (-88, -55]
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % FAIL_COLOR)
|
||||
value = 60
|
||||
elif signal_level <= -33: # (-33, -55]
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % PASS_COLOR)
|
||||
value = 80
|
||||
else: # > -33
|
||||
self.wifi_signal_level.setStyleSheet('QProgressBar { text-align: center; } QProgressBar::chunk { background-color: %s; }' % PASS_COLOR)
|
||||
value = 100
|
||||
|
||||
|
||||
# The value is a string encoded in UTF-8
|
||||
byte_str = bytes(ssid, 'latin1').decode('unicode_escape').encode('latin1')
|
||||
decoded_str = byte_str.decode('utf-8')
|
||||
self.wifi_signal_level.setFormat(f'{decoded_str}: {signal_level}')
|
||||
self.wifi_signal_level.setValue(value)
|
||||
|
||||
def _get_strongest_wifi(self):
|
||||
strongest_signal_level = -2147483648
|
||||
strongest_ssid = None
|
||||
|
||||
timeout = 5
|
||||
cmd = 'wpa_cli scan'
|
||||
scan = subprocess.run(cmd, capture_output=True, text=True, shell=True, timeout=timeout)
|
||||
# if scan.returncode != 0:
|
||||
# return strongest_ssid, strongest_signal_level
|
||||
|
||||
cmd = 'wpa_cli scan_results'
|
||||
proc = subprocess.run(cmd, capture_output=True, text=True, shell=True, timeout=timeout)
|
||||
if proc.returncode != 0:
|
||||
return strongest_ssid, strongest_signal_level
|
||||
|
||||
for line in proc.stdout.splitlines():
|
||||
if not line.strip() or line.startswith('Selected interface') or line.startswith('bssid'):
|
||||
continue
|
||||
|
||||
parts = line.split('\t')
|
||||
if len(parts) < 5:
|
||||
continue
|
||||
|
||||
signal_level = int(parts[2])
|
||||
ssid = parts[4]
|
||||
|
||||
if signal_level > strongest_signal_level:
|
||||
strongest_signal_level = signal_level
|
||||
strongest_ssid = ssid
|
||||
|
||||
return strongest_ssid, strongest_signal_level
|
||||
|
10
cricket/cricket/testlogmanager.py
Normal file
10
cricket/cricket/testlogmanager.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
from PyQt5.QtCore import Qt, QTimer, QObject
|
||||
|
||||
class DeviceStatusManager(QObject):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.time_sync = False
|
||||
self.wifi_sync = False
|
||||
self.check_mode = 1
|
||||
self.set_file_name_flag = False
|
27
cricket/cricket/utils.py
Normal file
27
cricket/cricket/utils.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from PyQt5.QtGui import QPixmap, QImage
|
||||
from PyQt5.QtCore import Qt, QTimer, QObject
|
||||
from PIL.ImageQt import ImageQt
|
||||
import os
|
||||
import qrcode
|
||||
|
||||
def get_product_name():
|
||||
path = '/proc/device-tree/model'
|
||||
if os.path.exists(path):
|
||||
with open(path, 'r') as f:
|
||||
model = f.readline().strip(b'\0x00'.decode())
|
||||
return model.replace('spacemit', '').replace('board', '').strip()
|
||||
|
||||
def create_qrcode(data):
|
||||
qr = qrcode.QRCode(
|
||||
version=1,
|
||||
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
||||
box_size=8,
|
||||
border=0,
|
||||
)
|
||||
qr.add_data(data)
|
||||
qr.make(fit=True)
|
||||
|
||||
img = qr.make_image(fill='black', back_color='white')
|
||||
qt_image = ImageQt(img).convertToFormat(QImage.Format_RGB32)
|
||||
return QPixmap.fromImage(qt_image)
|
||||
|
54
cricket/cricket/wifimacview.py
Normal file
54
cricket/cricket/wifimacview.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtWidgets import QFrame,QVBoxLayout,QLabel
|
||||
import subprocess
|
||||
from cricket.lang import SimpleLang
|
||||
from cricket.utils import *
|
||||
import re
|
||||
|
||||
class WifiMacView(QFrame):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.sl = SimpleLang()
|
||||
self.wifi_mac_text = self.sl.get_text("wifi_mac")
|
||||
|
||||
self.setup_wifi_mac_with_ui()
|
||||
|
||||
def setup_wifi_mac_with_ui(self):
|
||||
mac = self._get_wifi_mac()
|
||||
if mac:
|
||||
self._setup_wifi_mac_qrcode(mac)
|
||||
else:
|
||||
QTimer.singleShot(2000, self.setup_wifi_mac_with_ui)
|
||||
|
||||
def _get_wifi_mac(self):
|
||||
cmd = 'ifconfig wlan0'
|
||||
proc = subprocess.run(cmd, capture_output=True, text=True, shell=True, timeout=1)
|
||||
|
||||
text = proc.stdout
|
||||
pattern = r"HWaddr\s+([0-9A-Fa-f:]{17})"
|
||||
|
||||
match = re.search(pattern, text)
|
||||
if match:
|
||||
mac_address = match.group(1)
|
||||
return mac_address
|
||||
else:
|
||||
return None
|
||||
|
||||
def _setup_wifi_mac_qrcode(self, mac):
|
||||
mac_qrcode_layout = QVBoxLayout(self)
|
||||
|
||||
qr_label = QLabel(self)
|
||||
qr_label.setAlignment(Qt.AlignCenter)
|
||||
qr_label.setPixmap(create_qrcode(mac))
|
||||
mac_qrcode_layout.addWidget(qr_label)
|
||||
|
||||
mac_label = QLabel(f'{self.wifi_mac_text}: {mac}', self)
|
||||
mac_label.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
|
||||
mac_qrcode_layout.addWidget(mac_label)
|
||||
|
||||
self.mac_layout = mac_qrcode_layout
|
||||
|
||||
# wifi ip
|
||||
self.wifi_ip = QLabel(' ', self)
|
||||
self.wifi_ip.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
|
||||
self.mac_layout.addWidget(self.wifi_ip)
|
Loading…
Add table
Add a link
Reference in a new issue