Compare commits

...

2 commits

Author SHA1 Message Date
James Deng
bb8f6f2c92 Update for v1.0.14 2024-08-31 14:23:34 +08:00
James Deng
bd7463643a add LICENSE.
Signed-off-by: James Deng <james.deng@spacemit.com>
2024-08-12 20:22:25 +08:00
12 changed files with 786 additions and 243 deletions

28
LICENSE Normal file
View 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.

View file

@ -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'

View file

@ -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"
}
}

View 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
View 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',
}

View 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}"

View file

@ -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):

View 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]

View 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

View 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
View 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)

View 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)