#!/usr/bin/env python3 # -*-coding:utf-8-*- # SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 # # WARNING: we don't check for Python build-time dependencies until # check_environment() function below. If possible, avoid importing # any external libraries here - put in external script, or import in # their specific function instead. import sys import csv import json import re import os import argparse import pandas as pd import numpy as np import serial from os import path from os import mkdir from io import StringIO from PyQt5.Qt import * from pyqtgraph import PlotWidget from PyQt5 import QtCore import pyqtgraph as pq from PyQt5.QtCore import QDate, QDate, QTime, QDateTime import threading import base64 import time from datetime import datetime from multiprocessing import Process, Queue from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox # from PyQt5.QtChart import QChart, QLineSeries,QValueAxis from esp_csi_tool_gui import Ui_MainWindow from scipy import signal import signal as signal_key import socket CSI_SAMPLE_RATE = 100 # Remove invalid subcarriers # secondary channel : below, HT, 40 MHz, non STBC, v, HT-LTF: 0~63, -64~-1, 384 CSI_VAID_SUBCARRIER_INTERVAL = 5 csi_vaid_subcarrier_index = [] csi_vaid_subcarrier_color = [] color_step = 255 // (28 // CSI_VAID_SUBCARRIER_INTERVAL + 1) # LLTF: 52 # 26 red csi_vaid_subcarrier_index += [i for i in range( 0, 26, CSI_VAID_SUBCARRIER_INTERVAL)] csi_vaid_subcarrier_color += [(i * color_step, 0, 0) for i in range(1, 26 // CSI_VAID_SUBCARRIER_INTERVAL + 2)] # 26 green csi_vaid_subcarrier_index += [i for i in range( 26, 52, CSI_VAID_SUBCARRIER_INTERVAL)] csi_vaid_subcarrier_color += [(0, i * color_step, 0) for i in range(1, 26 // CSI_VAID_SUBCARRIER_INTERVAL + 2)] DEVICE_INFO_COLUMNS_NAMES = ['type', 'timestamp', 'compile_time', 'chip_name', 'chip_revision', 'app_revision', 'idf_revision', 'total_heap', 'free_heap', 'router_ssid', 'ip', 'port'] g_device_info_series = None CSI_DATA_INDEX = 500 # buffer size CSI_DATA_COLUMNS = len(csi_vaid_subcarrier_index) CSI_DATA_COLUMNS_NAMES = ['type', 'seq', 'timestamp', 'taget_seq', 'taget', 'mac', 'rssi', 'rate', 'sig_mode', 'mcs', 'cwb', 'smoothing', 'not_sounding', 'aggregation', 'stbc', 'fec_coding','sgi', 'noise_floor', 'ampdu_cnt', 'channel_primary', 'channel_secondary', 'local_timestamp', 'ant', 'sig_len', 'rx_state', 'agc_gain', 'fft_gain', 'len', 'first_word_invalid', 'data'] CSI_DATA_TARGETS = ['unknown', 'train', 'none', 'someone', 'static', 'move', 'front', 'after', 'left', 'right', 'go', 'jump', 'sit down', 'stand up', 'climb up', 'wave', 'applause'] RADAR_DATA_COLUMNS_NAMES = ['type', 'seq', 'timestamp', 'waveform_wander', 'wander_average', 'waveform_wander_threshold', 'someone_status', 'waveform_jitter', 'jitter_midean', 'waveform_jitter_threshold', 'move_status'] g_csi_amplitude_array = np.zeros( [CSI_DATA_INDEX, CSI_DATA_COLUMNS], dtype=np.int32) g_rssi_array = np.zeros(CSI_DATA_INDEX, dtype=np.int8) # 使用 object 类型以支持混合数据类型(字符串、数字、时间戳等) g_radio_header_pd = pd.DataFrame(np.empty([10, len( CSI_DATA_COLUMNS_NAMES[1:-1])], dtype=object), columns=CSI_DATA_COLUMNS_NAMES[1:-1]) RADAR_STATUS_RECORD = ['room', 'human', 'spend_time', 'start_time', 'stop_time'] g_status_record_pd = pd.DataFrame(np.zeros( [20, len(RADAR_STATUS_RECORD)], dtype=np.str_), columns=RADAR_STATUS_RECORD) RADAR_MOVE_RECORD = ['date', 'hour', 'minute', 'second', 'count'] g_move_record_pd = pd.DataFrame(columns=RADAR_MOVE_RECORD) RADAR_DATA = ['status', 'threshold', 'value', 'max', 'min', 'mean', 'std'] g_radar_data_room_pd = pd.DataFrame( np.zeros([10, len(RADAR_DATA)], dtype=np.float32), columns=RADAR_DATA) g_radar_data_human_pd = pd.DataFrame( np.zeros([10, len(RADAR_DATA)], dtype=np.float32), columns=RADAR_DATA) g_current_time = QDateTime.currentDateTime() RADAR_DATA_INDEX = 100 # buffer size ROOM_STATUS_NAMES = ['none', 'someone'] HUMAN_STATUS_NAMES = ['static', 'move'] RADAR_WAVEFORM_NAMES = ['wander', 'jitter'] RADAR_targetS_NAMES = ['someone', 'move'] RADAR_targetS_LEN = len(RADAR_targetS_NAMES) g_radar_eigenvalue_color = [(0, 0, 255), (0, 255, 0)] g_radar_eigenvalue_threshold_color = [(255, 255, 0), (255, 0, 255)] g_radar_eigenvalue_array = np.zeros( [RADAR_DATA_INDEX, RADAR_targetS_LEN], dtype=np.float32) g_radar_eigenvalue_threshold_array = np.zeros( [RADAR_DATA_INDEX, RADAR_targetS_LEN], dtype=np.float32) g_radar_status_array = np.zeros( [RADAR_DATA_INDEX, RADAR_targetS_LEN], dtype=np.int32) g_evaluate_statistics_array = np.zeros( [RADAR_targetS_LEN, RADAR_targetS_LEN], dtype=np.int32) g_display_raw_data = False g_display_radar_model = False g_display_eigenvalues_table = False def base64_decode_bin(str_data): try: # 清理数据:移除换行符、回车符、空格等无效字符 str_data = str(str_data).strip().replace('\n', '').replace('\r', '').replace(' ', '') # 如果数据包含日志信息(如 "->valid_len: 104"),只取 base64 部分 # 使用更智能的方式检测日志信息:查找常见的日志模式 # 例如:">valid_len", ": 104", "(120933)" 等 log_patterns = [ r'->valid_len', r':\s*\d+', # 冒号后跟数字(如 ": 104") r'\(\d+\)', # 括号中的数字(如 "(120933)") r'[DIWE]\s*\(', # 日志级别(如 "I (") ] # 查找日志模式的起始位置,只保留 base64 部分 min_log_start = len(str_data) for pattern in log_patterns: import re match = re.search(pattern, str_data) if match: min_log_start = min(min_log_start, match.start()) # 如果找到日志信息,只保留 base64 部分(至少保留一定长度,避免误判) if min_log_start < len(str_data) and min_log_start > 10: str_data = str_data[:min_log_start] # 如果数据长度不是4的倍数,尝试添加填充 missing_padding = len(str_data) % 4 if missing_padding: str_data += '=' * (4 - missing_padding) bin_data = base64.b64decode(str_data, validate=True) except Exception as e: print(f'Exception: {e}, data: {str_data[:100]}') # 解码失败时返回空列表,避免后续错误 return [] list_data = list(bin_data) for i in range(len(list_data)): if list_data[i] > 127: list_data[i] = list_data[i] - 256 return list_data def base64_encode_bin(list_data): for i in range(len(list_data)): if list_data[i] < 0: list_data[i] = 256 + list_data[i] # print(list_data) str_data = 'test' try: str_data = base64.b64encode(bytes(list_data)).decode('utf-8') except Exception as e: print(f'Exception: {e}, data: {list_data}') return str_data def get_label(folder_path): parts = str.split(folder_path, os.path.sep) return parts[-1] def evaluate_data_send(serial_queue_write, folder_path): label = get_label(folder_path) if label == 'train': command = f'radar --train_start' serial_queue_write.put(command) tcpCliSock = socket.socket() device_info_series = pd.read_csv('log/device_info.csv').iloc[-1] print(f"connect:{device_info_series['ip']},{device_info_series['port']}") tcpCliSock.connect((device_info_series['ip'], device_info_series['port'])) file_name_list = sorted(os.listdir(folder_path)) print(file_name_list) for file_name in file_name_list: file_path = folder_path + os.path.sep + file_name data_pd = pd.read_csv(file_path) for index, data_series in enumerate(data_pd.iloc): csi_raw_data = json.loads(data_series['data']) data_pd.loc[index, 'data'] = base64_encode_bin(csi_raw_data) temp_list = base64_decode_bin(data_pd.loc[index, 'data']) # print(f"temp_list: {temp_list}") data_str = ','.join(str(value) for value in data_pd.loc[index]) + '\n' data_str = data_str.encode('utf-8') # print(f"data_str: {data_str}") tcpCliSock.send(data_str) tcpCliSock.close() time.sleep(1) if label == 'train': command = 'radar --train_stop' serial_queue_write.put(command) sys.exit(0) class DataGraphicalWindow(QMainWindow, Ui_MainWindow): def __init__(self, serial_queue_write, csi_output_type='LLTF', parent=None): super(DataGraphicalWindow, self).__init__(parent) self.setupUi(self) self.csi_output_type = csi_output_type global g_display_raw_data global g_display_radar_model global display_eigenvalues_table with open('./config/gui_config.json') as file: gui_config = json.load(file) # print(f"gui_config: {gui_config}") if len(gui_config['router_ssid']) > 0: self.lineEdit_router_ssid.setText(gui_config['router_ssid']) if len(gui_config['router_password']) >= 8: self.lineEdit_router_password.setText( gui_config['router_password']) g_display_raw_data = gui_config['display_raw_data'] if g_display_raw_data: self.checkBox_raw_data.setChecked(True) else: self.checkBox_raw_data.setChecked(False) g_display_radar_model = gui_config['display_radar_model'] if g_display_radar_model: self.checkBox_radar_model.setChecked(True) else: self.checkBox_radar_model.setChecked(False) g_display_eigenvalues_table = gui_config['display_eigenvalues_table'] if g_display_eigenvalues_table: self.checkBox_display_eigenvalues_table.setChecked(True) else: self.checkBox_display_eigenvalues_table.setChecked(False) if gui_config['router_auto_connect']: self.checkBox_router_auto_connect.setChecked(True) else: self.checkBox_router_auto_connect.setChecked(False) self.curve_subcarrier_range = np.array([10, 20]) self.graphicsView_subcarrier.setYRange( self.curve_subcarrier_range[0], self.curve_subcarrier_range[1]) self.graphicsView_subcarrier.addLegend() self.curve_subcarrier = [] self.serial_queue_write = serial_queue_write for i in range(CSI_DATA_COLUMNS): curve = self.graphicsView_subcarrier.plot( g_csi_amplitude_array[:, i], name=str(i), pen=csi_vaid_subcarrier_color[i]) self.curve_subcarrier.append(curve) self.curve_rssi = self.graphicsView_rssi.plot( g_rssi_array, name='rssi', pen=(255, 255, 255)) self.wave_filtering_flag = self.checkBox_wave_filtering.isCheckable() self.checkBox_wave_filtering.released.connect( self.show_curve_subcarrier_filter) # self.graphicsView_rssi.setYRange(-10, -65) self.checkBox_router_auto_connect.released.connect( self.show_router_auto_connect) self.curve_radar_eigenvalue = [] self.curve_radar_eigenvalue_threshold = [] # self.graphicsView_eigenvalues.setYRange(0.95, 1.0) self.graphicsView_eigenvalues.addLegend() self.graphicsView_eigenvalues.showGrid(x=True, y=True) self.dateTimeEdit_statistics_time.setDateTime(g_current_time) self.statistic_config = pd.Series(index=['time', 'mode', 'auto_update'], data=[ self.dateTimeEdit_statistics_time.dateTime().toPyDateTime(), self.comboBox_statistics_mode.currentText(), self.checkBox_statistics_auto_update.isChecked() ]) for i in range(RADAR_targetS_LEN): curve_eigenvalue = self.graphicsView_eigenvalues.plot( g_radar_eigenvalue_array[:, i], name=RADAR_WAVEFORM_NAMES[i], pen=g_radar_eigenvalue_color[i]) curve_eigenvalue_threshold = self.graphicsView_eigenvalues.plot( g_radar_eigenvalue_threshold_array[:, i], name=RADAR_WAVEFORM_NAMES[i] + '_' + RADAR_targetS_NAMES[i] + '_threshold', pen=g_radar_eigenvalue_threshold_color[i]) self.curve_radar_eigenvalue.append(curve_eigenvalue) self.curve_radar_eigenvalue_threshold.append( curve_eigenvalue_threshold) self.model_radio_header = QStandardItemModel( 1, len(g_radio_header_pd.columns.values)) self.model_radio_header.setHorizontalHeaderLabels( g_radio_header_pd.columns.values) self.tableView_radioHeader.setModel(self.model_radio_header) self.tableView_radioHeader.horizontalHeader( ).setSectionResizeMode(QHeaderView.ResizeToContents) self.tableView_values = { 'sig_mode': ['non HT(11bg)', 'HT(11n)', 'VHT(11ac)'], 'mcs': [f'MSC{i}' for i in range(76)], 'cwb': ['20MHz', '40MHz'], 'aggregation': ['MPDU', 'AMPDU'], 'channel_secondary': ['none', 'above', 'below'], 'stbc': ['non STBC', 'STBC'], 'sgi': ['Long GI', 'Short GI'], } self.model_device_info = QStandardItemModel( len(DEVICE_INFO_COLUMNS_NAMES), 2) self.tableView_device_info.setModel(self.model_device_info) self.tableView_device_info.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) self.tableView_device_info.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.model_status_record = QStandardItemModel( 1, len(g_status_record_pd.columns.values)) self.model_status_record.setHorizontalHeaderLabels( g_status_record_pd.columns.values) self.tableView_status_record.setModel(self.model_status_record) self.tableView_status_record.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) self.tableView_status_record.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.model_radar_data_room = QStandardItemModel(len( g_radar_data_room_pd.columns.values), len(g_radar_data_room_pd.columns.values)) self.model_radar_data_room.setHorizontalHeaderLabels(g_radar_data_room_pd.columns.values) self.tableView_radar_data_room.setModel(self.model_radar_data_room) self.tableView_radar_data_room.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.model_radar_data_human = QStandardItemModel(len( g_radar_data_human_pd.columns.values), len(g_radar_data_human_pd.columns.values)) self.model_radar_data_human.setHorizontalHeaderLabels( g_radar_data_human_pd.columns.values) self.tableView_radar_data_human.setModel(self.model_radar_data_human) self.tableView_radar_data_human.horizontalHeader( ).setSectionResizeMode(QHeaderView.ResizeToContents) evaluate_STATISTICS_COLUMNS_NAMES = ['type', 'count', 'rate'] self.model_evaluate_statistics = QStandardItemModel( len(evaluate_STATISTICS_COLUMNS_NAMES), 3) self.model_evaluate_statistics.setHorizontalHeaderLabels( evaluate_STATISTICS_COLUMNS_NAMES) self.model_evaluate_statistics.setItem( 0, 0, QStandardItem('none static')) self.model_evaluate_statistics.setItem(1, 0, QStandardItem('none move')) self.model_evaluate_statistics.setItem( 2, 0, QStandardItem('someone static')) self.model_evaluate_statistics.setItem( 3, 0, QStandardItem('someone move')) self.pushButton_predict_config.released.connect(self.command_predict_config) self.pushButton_statistics_config.released.connect( self.show_statistics_status_record_move) self.comboBox_statistics_mode.activated.connect( self.show_statistics_status_record_move) # self.pushButton_evaluate_config.released.connect(self.command_evaluate_config) self.pushButton_router_connect.released.connect( self.command_router_connect) self.pushButton_command.released.connect(self.command_custom) self.comboBox_command.activated.connect(self.comboBox_command_show) self.pushButton_collect_start.released.connect( self.pushButton_collect_show) self.pushButton_train_start.released.connect( self.pushButton_train_show) self.pushButton_collect_clean.released.connect( self.pushButton_collect_clean_show) self.checkBox_raw_data.released.connect(self.checkBox_raw_data_show) self.checkBox_radar_model.released.connect(self.checkBox_radar_model_show) self.checkBox_display_eigenvalues_table.released.connect( self.checkBox_display_eigenvalues_table_show) self.splitter_eigenvalues.setStretchFactor(0, 8) self.splitter_eigenvalues.setStretchFactor(1, 1) self.splitter_status_record.setStretchFactor(0, 10) self.splitter_status_record.setStretchFactor(1, 1) self.splitter_raw_data.setStretchFactor(0, 1) self.splitter_raw_data.setStretchFactor(1, 8) self.splitter_raw_data.setStretchFactor(2, 2) self.textBrowser_log.setStyleSheet('background:black') self.timer_boot_command = QTimer() self.timer_boot_command.timeout.connect(self.command_boot) self.timer_boot_command.setInterval(3000) self.timer_boot_command.start() self.timer_curve_subcarrier = QTimer() self.timer_curve_subcarrier.timeout.connect(self.show_curve_subcarrier) self.timer_curve_subcarrier.setInterval(300) self.timer_curve_radar = QTimer() self.timer_curve_radar.timeout.connect(self.show_curve_eigenvalue) self.timer_curve_radar.setInterval(100) self.timer_eigenvalues_table = QTimer() self.timer_eigenvalues_table.timeout.connect( self.show_eigenvalue_table) self.timer_eigenvalues_table.setInterval(100) self.label_number = self.spinBox_collect_number.value() self.timer_collect_duration = QTimer() self.timer_collect_duration.timeout.connect( self.spinBox_collect_number_show) self.label_delay = self.timeEdit_collect_delay.time() self.timer_collect_delay = QTimer() self.timer_collect_delay.setInterval(1000) self.timer_collect_delay.timeout.connect(self.timeEdit_collect_delay_show) self.train_duration = self.timeEdit_train_duration.time() self.timer_train_duration = QTimer() self.timer_train_duration.setInterval(1000) self.timer_train_duration.timeout.connect( self.spinBox_train_duration_show) self.train_delay = self.timeEdit_train_delay.time() self.timer_train_delay = QTimer() self.timer_train_delay.setInterval(1000) self.timer_train_delay.timeout.connect(self.timeEdit_train_delay_show) self.timer_status_record = QTimer() self.timer_status_record.timeout.connect(self.show_statistics_status_record) self.timer_status_record.setInterval(1000) self.timer_evaluate_statistics = QTimer() self.timer_evaluate_statistics.timeout.connect(self.show_evaluate_statistics) self.timer_evaluate_statistics.setInterval(1000) self.checkBox_raw_data_show() self.checkBox_radar_model_show() self.checkBox_display_eigenvalues_table_show() def checkBox_raw_data_show(self): global g_display_raw_data g_display_raw_data = self.checkBox_raw_data.isChecked() if self.checkBox_raw_data.isChecked(): self.groupBox_raw_data.show() self.timer_curve_subcarrier.start() else: self.groupBox_raw_data.hide() self.timer_curve_subcarrier.stop() with open('./config/gui_config.json', 'r') as file: gui_config = json.load(file) gui_config['display_raw_data'] = self.checkBox_raw_data.isChecked() with open('./config/gui_config.json', 'w') as file: json.dump(gui_config, file) def checkBox_radar_model_show(self): global g_display_radar_model g_display_radar_model = self.checkBox_radar_model.isChecked() if self.checkBox_radar_model.isChecked(): self.groupBox_radar_model.show() self.timer_status_record.start() self.timer_curve_radar.start() else: self.groupBox_radar_model.hide() self.timer_status_record.stop() self.timer_curve_radar.stop() with open('./config/gui_config.json', 'r') as file: gui_config = json.load(file) gui_config['display_radar_model'] = self.checkBox_radar_model.isChecked() with open('./config/gui_config.json', 'w') as file: json.dump(gui_config, file) def checkBox_display_eigenvalues_table_show(self): global g_display_eigenvalues_table g_display_eigenvalues_table = self.checkBox_display_eigenvalues_table.isChecked() if self.checkBox_display_eigenvalues_table.isChecked(): self.tableView_eigenvalues.show() self.timer_eigenvalues_table.start() else: self.tableView_eigenvalues.hide() self.timer_eigenvalues_table.stop() with open('./config/gui_config.json', 'r') as file: gui_config = json.load(file) gui_config['display_eigenvalues_table'] = self.checkBox_display_eigenvalues_table.isChecked() with open('./config/gui_config.json', 'w') as file: json.dump(gui_config, file) def show_router_auto_connect(self): with open('./config/gui_config.json', 'r') as file: gui_config = json.load(file) gui_config['router_auto_connect'] = self.checkBox_router_auto_connect.isChecked() with open('./config/gui_config.json', 'w') as file: json.dump(gui_config, file) def median_filtering(self, waveform): tmp = waveform for i in range(1, waveform.shape[0] - 1): outliers_count = 0 for j in range(waveform.shape[1]): if ((waveform[i - 1, j] - waveform[i, j] > 2 and waveform[i + 1, j] - waveform[i, j] > 2) or (waveform[i - 1, j] - waveform[i, j] < -2 and waveform[i + 1, j] - waveform[i, j] < -2)): outliers_count += 1 continue if outliers_count > 16: for x in range(1, waveform.shape[1] - 1): tmp[i, x] = (waveform[i - 1, x] + waveform[i + 1, x]) / 2 waveform = tmp def show_curve_subcarrier(self): wn = 20 / (CSI_SAMPLE_RATE / 2) b, a = signal.butter(8, wn, 'lowpass') if self.wave_filtering_flag: self.median_filtering(g_csi_amplitude_array) csi_filtfilt_data = signal.filtfilt(b, a, g_csi_amplitude_array.T).T else: csi_filtfilt_data = g_csi_amplitude_array if self.curve_subcarrier_range[0] > csi_filtfilt_data.min() or self.curve_subcarrier_range[1] < csi_filtfilt_data.max(): if csi_filtfilt_data.min() > 0 and self.curve_subcarrier_range[0] > csi_filtfilt_data.min(): self.curve_subcarrier_range[0] = csi_filtfilt_data.min() - 1 if self.curve_subcarrier_range[1] < csi_filtfilt_data.max(): self.curve_subcarrier_range[1] = csi_filtfilt_data.max() + 1 self.graphicsView_subcarrier.setYRange( self.curve_subcarrier_range[0], self.curve_subcarrier_range[1]) for i in range(CSI_DATA_COLUMNS): self.curve_subcarrier[i].setData(csi_filtfilt_data[:, i]) if self.wave_filtering_flag: csi_filtfilt_rssi = signal.filtfilt( b, a, g_rssi_array).astype(np.int32) else: csi_filtfilt_rssi = g_rssi_array self.curve_rssi.setData(csi_filtfilt_rssi) for i in range(g_radio_header_pd.shape[0]): for j in range(g_radio_header_pd.shape[1]): cell_value = g_radio_header_pd.iloc[i, j] if cell_value is None or (isinstance(cell_value, float) and np.isnan(cell_value)): item = QStandardItem('') elif g_radio_header_pd.columns.values[j] in self.tableView_values.keys(): try: str_values = self.tableView_values[g_radio_header_pd.columns.values[j]][int(cell_value)] item = QStandardItem(str_values) except (ValueError, TypeError, KeyError): item = QStandardItem(str(cell_value)) else: # print(j, g_radio_header_pd.columns.values[j]) item = QStandardItem(str(cell_value) if cell_value is not None else '') self.model_radio_header.setItem(i, j, item) def show_curve_subcarrier_filter(self): self.wave_filtering_flag = self.checkBox_wave_filtering.isChecked() def show_curve_eigenvalue(self): for i in range(RADAR_targetS_LEN): self.curve_radar_eigenvalue[i].setData( g_radar_eigenvalue_array[:, i]) self.curve_radar_eigenvalue_threshold[i].setData( g_radar_eigenvalue_threshold_array[:, i]) curve_radar_title = f'{ROOM_STATUS_NAMES[g_radar_status_array[-1,0]]} {HUMAN_STATUS_NAMES[g_radar_status_array[-1,1]]}' self.graphicsView_eigenvalues.setTitle(curve_radar_title) def show_eigenvalue_table(self): for i in range(g_radar_data_room_pd.shape[0]): for j in range(g_radar_data_room_pd.shape[1]): # data_str = "%.5f" % 0.01 # print(f"{g_radar_data_room_pd.iloc[i,j]}, {type(g_radar_data_room_pd.iloc[i,j])}") data_str = '%.5f' % g_radar_data_room_pd.iloc[i, j] item = QStandardItem(data_str) self.model_radar_data_room.setItem(i, j, item) for i in range(g_radar_data_human_pd.shape[0]): for j in range(g_radar_data_human_pd.shape[1]): # print(f"{g_radar_data_human_pd.iloc[i,j]}, {type(g_radar_data_human_pd.iloc[i,j])}") data_str = '%.5f' % g_radar_data_human_pd.iloc[i, j] item = QStandardItem(data_str) self.model_radar_data_human.setItem(i, j, item) def show_device_info(self, device_info_series): # print(device_info_series) for i in range(len(device_info_series)): self.model_device_info.setItem( i, 0, QStandardItem(device_info_series.index[i])) self.model_device_info.setItem( i, 1, QStandardItem(str(device_info_series.values[i]))) # self.tableView_device_info.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) def get_statistic_config(self): self.statistic_config['time'] = self.dateTimeEdit_statistics_time.dateTime().toPyDateTime() self.statistic_config['mode'] = self.comboBox_statistics_mode.currentText() self.statistic_config['auto_update'] = self.checkBox_statistics_auto_update.isChecked() def show_statistics_status_record_move(self): self.get_statistic_config() if self.statistic_config['mode'] == 'day': statistic_move_array = np.zeros(24, dtype=np.int32) statistic_move_title = datetime.strftime( self.statistic_config['time'], '%Y-%m-%d') statistic_move_pd = g_move_record_pd[g_move_record_pd['date'] == self.statistic_config['time'].date()] if len(statistic_move_pd): statistic_move_hour = statistic_move_pd.groupby(by='hour')[ 'count'].sum() for index, value in statistic_move_hour.items(): statistic_move_array[index] = value elif self.statistic_config['mode'] == 'hour': statistic_move_array = np.zeros(60, dtype=np.int32) statistic_move_title = datetime.strftime( self.statistic_config['time'], '%Y-%m-%d %H') statistic_move_pd = g_move_record_pd[(g_move_record_pd['date'] == self.statistic_config['time'].date()) & ( g_move_record_pd['hour'] == self.statistic_config['time'].time().hour)] if len(statistic_move_pd): statistic_move_minute = statistic_move_pd.groupby(by='minute')[ 'count'].sum() for index, value in statistic_move_minute.items(): statistic_move_array[index] = value elif self.statistic_config['mode'] == 'minute': statistic_move_array = np.zeros(60, dtype=np.int32) statistic_move_title = datetime.strftime( self.statistic_config['time'], '%Y-%m-%d %H:%M') statistic_move_pd = g_move_record_pd[(g_move_record_pd['date'] == self.statistic_config['time'].date()) & (g_move_record_pd['hour'] == self.statistic_config['time'].time().hour) & (g_move_record_pd['hour'] == self.statistic_config['time'].time().hour) & (g_move_record_pd['hour'] == self.statistic_config['time'].time().hour) & (g_move_record_pd['minute'] == self.statistic_config['time'].time().minute)] if len(statistic_move_pd): statistic_move_second = statistic_move_pd.groupby(by='second')[ 'count'].sum() for index, value in statistic_move_second.items(): statistic_move_array[index] = value else: print(f"fail mode: {self.statistic_config['mode']}") try: self.graphicsView_status_record.removeItem(self.bg) except Exception as e: # print(e) pass try: self.bg = pq.BarGraphItem(x=range( len(statistic_move_array)), height=statistic_move_array, width=0.3, brush='g') self.graphicsView_status_record.addItem(self.bg) self.graphicsView_status_record.showGrid(x=True, y=True) self.graphicsView_status_record.setXRange( 0, len(statistic_move_array)) # print(statistic_move_title) self.graphicsView_status_record.setTitle( statistic_move_title + ' Move Count') except Exception as e: print(e) def show_statistics_status_record(self): if self.checkBox_statistics_auto_update.isChecked(): self.dateTimeEdit_statistics_time.setDateTime(g_current_time) self.show_statistics_status_record_move() # print(f"g_status_record table: {g_status_record_pd.shape}") for i in range(g_status_record_pd.shape[0]): for j in range(g_status_record_pd.shape[1]): item = QStandardItem(g_status_record_pd.iloc[i, j]) self.model_status_record.setItem(i, j, item) def show_evaluate_statistics(self): if not g_evaluate_statistics_array.sum(): return for i in range(g_evaluate_statistics_array.shape[0]): for j in range(g_evaluate_statistics_array.shape[1]): row = i * 2 + j item = QStandardItem(str(g_evaluate_statistics_array[i][j])) self.model_evaluate_statistics.setItem(row, 1, item) data_str = '%.2f%%' % ( g_evaluate_statistics_array[i][j] * 100 / g_evaluate_statistics_array.sum()) item = QStandardItem(data_str) self.model_evaluate_statistics.setItem(row, 2, item) def command_boot(self): command = f'radar --csi_output_type {self.csi_output_type} --csi_output_format base64' self.serial_queue_write.put(command) if self.checkBox_router_auto_connect.isChecked() and len(self.lineEdit_router_ssid.text()) > 0: self.command_router_connect() self.timer_boot_command.stop() def command_predict_config(self): command = (f'radar --predict_someone_sensitivity {self.doubleSpinBox_predict_someone_sensitivity.value()}' + f' --predict_move_sensitivity {self.doubleSpinBox_predict_move_sensitivity.value()}') self.serial_queue_write.put(command) command = (f'radar --predict_buff_size {self.spinBox_predict_buffer_size.text()}' + f' --predict_outliers_number {self.spinBox_predict_outliers_number.text()}') self.serial_queue_write.put(command) def command_router_connect(self): if self.pushButton_router_connect.text() == 'connect': self.pushButton_router_connect.setText('disconnect') self.pushButton_router_connect.setStyleSheet('color: red') command = 'wifi_config --ssid ' + ("\"%s\"" % self.lineEdit_router_ssid.text()) if len(self.lineEdit_router_password.text()) >= 8: command += ' --password ' + self.lineEdit_router_password.text() self.serial_queue_write.put(command) else: self.pushButton_router_connect.setText('connect') self.pushButton_router_connect.setStyleSheet('color: black') command = 'ping --abort' self.serial_queue_write.put(command) command = 'wifi_config --disconnect' self.serial_queue_write.put(command) time.sleep(3) command = 'radar --csi_output_type ' + self.csi_output_type + ' --csi_output_format base64' self.serial_queue_write.put(command) with open('./config/gui_config.json', 'r') as file: gui_config = json.load(file) gui_config['router_ssid'] = self.lineEdit_router_ssid.text() gui_config['router_password'] = self.lineEdit_router_password.text() with open('./config/gui_config.json', 'w') as file: json.dump(gui_config, file) def command_custom(self): command = self.lineEdit_command.text() self.serial_queue_write.put(command) def command_collect_target_start(self): command = (f'radar --collect_number {self.spinBox_collect_number.value()}' + f' --collect_tagets {self.comboBox_collect_target.currentText()}' + f' --collect_duration {self.spinBox_collect_duration.value()}') self.serial_queue_write.put(command) def command_collect_target_stop(self): command = 'radar --collect_number 0 --collect_tagets unknown' self.serial_queue_write.put(command) def spinBox_collect_number_show(self): number = self.spinBox_collect_number.value() if number >= 1: self.spinBox_collect_number.setValue(number - 1) self.timer_collect_duration.start() # self.command_collect_target_start() else: self.timer_collect_duration.stop() # self.command_collect_target_stop() self.spinBox_collect_number.setValue(self.label_number) self.timeEdit_collect_delay.setTime(self.label_delay) self.pushButton_collect_start.setStyleSheet('color: black') self.spinBox_collect_number.setStyleSheet('color: black') self.pushButton_collect_start.setText('start') def timeEdit_collect_delay_show(self): time_temp = self.timeEdit_collect_delay.time() second = time_temp.hour() * 3600 + time_temp.minute() * 60 + time_temp.second() if second > 0: self.timeEdit_collect_delay.setTime(time_temp.addSecs(-1)) self.timer_collect_delay.start() else: self.timer_collect_delay.stop() duration = self.spinBox_collect_duration.value() self.timer_collect_duration.setInterval(duration) self.timer_collect_duration.start() self.command_collect_target_start() self.spinBox_collect_number.setStyleSheet('color: red') self.timeEdit_collect_delay.setStyleSheet('color: black') def pushButton_collect_show(self): if self.pushButton_collect_start.text() == 'start': if self.comboBox_collect_target.currentIndex() == 0 or self.spinBox_collect_number.value() == 0: err = QErrorMessage(self) err.setWindowTitle('Label parameter error') err.showMessage( "Please check whether 'taget' or 'number' is set") err.show() return self.pushButton_collect_start.setText('stop') self.pushButton_collect_start.setStyleSheet('color: red') self.timeEdit_collect_delay.setStyleSheet('color: red') self.timer_collect_delay.start() self.label_number = self.spinBox_collect_number.value() self.label_delay = self.timeEdit_collect_delay.time() else: self.spinBox_collect_number.setValue(self.label_number) self.timeEdit_collect_delay.setTime(self.label_delay) self.spinBox_collect_number.setStyleSheet('color: black') self.pushButton_collect_start.setStyleSheet('color: black') self.timer_collect_delay.stop() self.timer_collect_duration.stop() self.command_collect_target_stop() self.pushButton_collect_start.setText('start') def pushButton_collect_clean_show(self): folder_path = 'data' message = QMessageBox.warning( self, 'Warning', "will delete all files in 'data'", QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok) if message == QMessageBox.Cancel: return for root, dirs, files in os.walk(folder_path, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) def command_train_start(self): command = f'radar --train_start' if self.checkBox_train_add.isChecked(): command += ' --train_add' self.serial_queue_write.put(command) def command_train_stop(self): command = 'radar --train_stop' self.serial_queue_write.put(command) def spinBox_train_duration_show(self): time_temp = self.timeEdit_train_duration.time() second = time_temp.hour() * 3600 + time_temp.minute() * 60 + time_temp.second() if second > 0: self.timeEdit_train_duration.setTime(time_temp.addSecs(-1)) self.timer_train_duration.start() else: self.timer_train_duration.stop() self.command_train_stop() self.timeEdit_train_delay.setTime(self.train_delay) self.timeEdit_train_duration.setTime(self.train_duration) self.timeEdit_train_duration.setStyleSheet('color: black') self.pushButton_train_start.setText('start') self.pushButton_train_start.setStyleSheet('color: black') def timeEdit_train_delay_show(self): time_temp = self.timeEdit_train_delay.time() second = time_temp.hour() * 3600 + time_temp.minute() * 60 + time_temp.second() if second > 0: self.timeEdit_train_delay.setTime(time_temp.addSecs(-1)) self.timer_train_delay.start() else: self.timer_train_delay.stop() self.command_train_start() self.spinBox_train_duration_show() self.timeEdit_train_duration.setStyleSheet('color: red') self.timeEdit_train_delay.setStyleSheet('color: black') def pushButton_train_show(self): if self.pushButton_train_start.text() == 'start': reply = QMessageBox.question(self, 'Note', 'During environmental calibration, it must be ensured that no one is in the room', QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Yes) if reply == QMessageBox.Cancel: return self.train_delay = self.timeEdit_train_delay.time() self.train_duration = self.timeEdit_train_duration.time() self.pushButton_train_start.setText('stop') self.pushButton_train_start.setStyleSheet('color: red') self.timeEdit_train_delay.setStyleSheet('color: red') self.timeEdit_train_delay_show() else: self.timer_train_delay.stop() self.timer_train_duration.stop() self.command_train_stop() self.timeEdit_train_delay.setTime(self.train_delay) self.timeEdit_train_duration.setTime(self.train_duration) self.pushButton_train_start.setText('start') self.pushButton_train_start.setStyleSheet('color: black') def comboBox_command_show(self): self.lineEdit_command.setText(self.comboBox_command.currentText()) def show_textBrowser_log(self, str): self.textBrowser_log.append(str) # self.textBrowser_log.moveCursor(self.textBrowser_log.textCursor().End) def closeEvent(self, event): self.serial_queue_write.put('exit') time.sleep(0.5) event.accept() try: os._exit(0) except Exception as e: print(f'GUI closeEvent: {e}') def csi_data_handle(self, data): # Rotate data g_csi_amplitude_array[:-1] = g_csi_amplitude_array[1:] g_rssi_array[:-1] = g_rssi_array[1:] g_radio_header_pd.iloc[1:] = g_radio_header_pd.iloc[:-1] csi_raw_data = data['data'] data_len = int(data['len']) if 'len' in data else len(csi_raw_data) if data_len == 104: for i in range(CSI_DATA_COLUMNS): idx = csi_vaid_subcarrier_index[i] if idx * 4 + 3 >= len(csi_raw_data): return real_high = csi_raw_data[idx * 4 + 1] imag_high = csi_raw_data[idx * 4 + 3] real_low = csi_raw_data[idx * 4] & 0xFF imag_low = csi_raw_data[idx * 4 + 2] & 0xFF real = (((int(real_high) << 12) >> 4) | real_low) imag = (((int(imag_high) << 12) >> 4) | imag_low) if real > 32767: real = real - 65536 if imag > 32767: imag = imag - 65536 g_csi_amplitude_array[-1][i] = np.abs(complex(real, imag)) else: for i in range(CSI_DATA_COLUMNS): if csi_vaid_subcarrier_index[i]*2+1 >= len(csi_raw_data): return g_csi_amplitude_array[-1][i] = np.abs(complex(csi_raw_data[csi_vaid_subcarrier_index[i]*2], csi_raw_data[csi_vaid_subcarrier_index[i]*2+1])) g_rssi_array[-1] = data['rssi'] g_radio_header_pd.loc[0] = data[1:len(CSI_DATA_COLUMNS_NAMES)-1] # print(g_radio_header_pd.loc[0]) return def radar_data_handle(self, data): g_radar_eigenvalue_array[:-1] = g_radar_eigenvalue_array[1:] g_radar_eigenvalue_threshold_array[:- 1] = g_radar_eigenvalue_threshold_array[1:] g_radar_status_array[:-1] = g_radar_status_array[1:] global g_current_time current_time_str = data['timestamp'] g_current_time = datetime.strptime( data['timestamp'], '%Y-%m-%d %H:%M:%S.%f') for taget_index in range(RADAR_targetS_LEN): g_radar_eigenvalue_array[-1][taget_index] = data[f'waveform_{RADAR_WAVEFORM_NAMES[taget_index]}'] g_radar_eigenvalue_threshold_array[-1][taget_index] = data[ f'waveform_{RADAR_WAVEFORM_NAMES[taget_index]}_threshold'] g_radar_status_array[-1][taget_index] = data[f'{RADAR_targetS_NAMES[taget_index]}_status'] if g_radar_status_array[-1][0] != g_radar_status_array[-2][0] or g_radar_status_array[-1][1] != g_radar_status_array[-2][1]: g_status_record_pd[1:] = g_status_record_pd[:-1] g_status_record_pd.loc[0, 'start_time'] = current_time_str g_status_record_pd.loc[0, 'room'] = ROOM_STATUS_NAMES[g_radar_status_array[-1][0]] g_status_record_pd.loc[0, 'human'] = HUMAN_STATUS_NAMES[g_radar_status_array[-1][1]] if len(g_status_record_pd.loc[1, 'start_time']): g_status_record_pd.loc[1, 'stop_time'] = current_time_str if len(g_status_record_pd.loc[0, 'start_time']): temp_time = g_current_time - \ datetime.strptime( g_status_record_pd.loc[0, 'start_time'], '%Y-%m-%d %H:%M:%S.%f') g_status_record_pd.loc[0, 'spend_time'] = f'{temp_time}'[:-3] if g_radar_status_array[-1][1]: index = len(g_move_record_pd) g_move_record_pd.loc[index] = [g_current_time.date(), g_current_time.time( ).hour, g_current_time.time().minute, g_current_time.time().second, 1] g_evaluate_statistics_array[g_radar_status_array[-1, 0], g_radar_status_array[-1, 1]] += 1 if (g_radar_eigenvalue_threshold_array[-1, 0] != g_radar_eigenvalue_threshold_array[-2, 0] or g_radar_eigenvalue_threshold_array[-1, 1] != g_radar_eigenvalue_threshold_array[-2, 1]): self.signal_wareform_threshold.emit() if g_display_eigenvalues_table: try: g_radar_data_room_pd[1:] = g_radar_data_room_pd[:-1] g_radar_data_room_pd.loc[0]['status'] = g_radar_status_array[-1, 0] g_radar_data_room_pd.loc[0]['threshold'] = g_radar_eigenvalue_threshold_array[-1, 0] g_radar_data_room_pd.loc[0]['value'] = g_radar_eigenvalue_array[-1, 0] value_buff = g_radar_eigenvalue_array[-10:, 0] g_radar_data_room_pd.loc[0]['max'] = np.max(value_buff) g_radar_data_room_pd.loc[0]['min'] = np.min(value_buff) g_radar_data_room_pd.loc[0]['mean'] = np.mean(value_buff) g_radar_data_room_pd.loc[0]['std'] = np.std(value_buff) g_radar_data_human_pd[1:] = g_radar_data_human_pd[:-1] g_radar_data_human_pd.loc[0]['status'] = g_radar_status_array[-1, 1] g_radar_data_human_pd.loc[0]['threshold'] = g_radar_eigenvalue_threshold_array[-1, 1] g_radar_data_human_pd.loc[0]['value'] = g_radar_eigenvalue_array[-1, 1] value_buff = g_radar_eigenvalue_array[-10:, 1] g_radar_data_human_pd.loc[0]['max'] = np.max(value_buff) g_radar_data_human_pd.loc[0]['min'] = np.min(value_buff) g_radar_data_human_pd.loc[0]['mean'] = np.mean(value_buff) g_radar_data_human_pd.loc[0]['std'] = np.std(value_buff) except Exception as e: print(e) return class DataHandleThread(QThread): signal_log_msg = pyqtSignal(str) signal_radar_time_domain = pyqtSignal(str) signal_exit = pyqtSignal() signal_device_info = pyqtSignal(pd.Series) signal_wareform_threshold = pyqtSignal() def __init__(self, serial_queue_read): super().__init__() self.serial_queue_read = serial_queue_read self.taget_count = 0 def run(self): while True: # print(f"g_display_raw_data: {g_display_raw_data}") series = self.serial_queue_read.get() if series['type'] == 'DEVICE_INFO' and g_display_raw_data: g_device_info_series = series.copy() self.signal_device_info.emit(series) elif series['type'] == 'CSI_DATA' and g_display_raw_data: csi_data_handle(self, series) elif series['type'] == 'RADAR_DADA' and g_display_radar_model: radar_data_handle(self, series) elif series['type'] == 'LOG_DATA' and g_display_raw_data: if series['tag'] == 'I': color = 'green' elif series['tag'] == 'W': color = 'yellow' elif series['tag'] == 'E': color = 'red' else: color = 'white' data = "%s (%s) %s " % ( color, series['tag'], series['timestamp'], series['data']) self.signal_log_msg.emit(data) elif series['type'] == 'FAIL_EVENT': print(f"Failed: {series['data']}") self.signal_exit.emit() time.sleep(1) sys.exit(0) else: # print("error: ", series) pass QApplication.processEvents() def serial_handle(queue_read, queue_write, port): try: set = serial.Serial(port=port, baudrate=2000000, bytesize=8, parity='N', stopbits=1, timeout=0.1) except Exception as e: print(f'serial_handle: {e}') data_series = pd.Series(index=['type', 'data'], data=['FAIL_EVENT', 'Failed to open serial port']) queue_read.put(data_series) sys.exit() return print('open serial port: ', port) # Wait a second to let the port initialize set.flushInput() folder_list = ['log', 'data'] for folder in folder_list: if not path.exists(folder): mkdir(folder) data_valid_list = pd.DataFrame(columns=['type', 'columns_names', 'file_name', 'file_fd', 'file_writer'], data=[['CSI_DATA', CSI_DATA_COLUMNS_NAMES, 'log/csi_data.csv', None, None], ['RADAR_DADA', RADAR_DATA_COLUMNS_NAMES, 'log/radar_data.csv', None, None], ['DEVICE_INFO', DEVICE_INFO_COLUMNS_NAMES, 'log/device_info.csv', None, None]]) for data_valid in data_valid_list.iloc: # print(type(data_valid), data_valid) # print(f"file_name: {data_valid['file_name']}") data_valid['file_fd'] = open(data_valid['file_name'], 'w') data_valid['file_writer'] = csv.writer(data_valid['file_fd']) data_valid['file_writer'].writerow(data_valid['columns_names']) log_data_writer = open('log/log_data.txt', 'w+') taget_last = 'unknown' taget_seq_last = 0 set.write('restart\r\n'.encode('utf-8')) time.sleep(0.01) while True: if not queue_write.empty(): command = queue_write.get() if command == 'exit': sys.exit() break command = command + '\r\n' set.write(command.encode('utf-8')) print(f'{datetime.now()}, serial write: {command}') continue try: strings = str(set.readline()) if not strings: continue except Exception as e: data_series = pd.Series(index=['type', 'data'], data=['FAIL_EVENT', 'Failed to read serial']) queue_read.put(data_series) sys.exit() strings = strings.lstrip('b\'').rstrip('\\r\\n\'') if not strings: continue # print(f"fail: {strings}") for data_valid in data_valid_list.iloc: index = strings.find(data_valid['type']) if index >= 0: strings = strings[index:] # 只取第一行,避免日志信息混入 first_line_end = strings.find('\n') if first_line_end > 0: strings = strings[:first_line_end] # 移除可能的回车符 strings = strings.rstrip('\r') csv_reader = csv.reader(StringIO(strings)) try: data = next(csv_reader) except StopIteration: continue if len(data) == len(data_valid['columns_names']): # 清理 base64 数据字段(最后一个字段),移除可能的日志信息 if data_valid['type'] == 'CSI_DATA' and len(data) > 0: data_field = data[-1] # 使用正则表达式查找日志模式,只保留 base64 部分 log_patterns = [ r'->valid_len', r':\s*\d+', # 冒号后跟数字 r'\(\d+\)', # 括号中的数字 r'[DIWE]\s*\(', # 日志级别 ] min_log_start = len(data_field) for pattern in log_patterns: match = re.search(pattern, data_field) if match: min_log_start = min(min_log_start, match.start()) # 如果找到日志信息且位置合理(避免误判),只保留 base64 部分 if min_log_start < len(data_field) and min_log_start > 10: data[-1] = data_field[:min_log_start] data_series = pd.Series( data, index=data_valid['columns_names']) try: datetime.strptime( data_series['timestamp'], '%Y-%m-%d %H:%M:%S.%f') except Exception as e: data_series['timestamp'] = datetime.now().strftime( '%Y-%m-%d %H:%M:%S.%f')[:-3] # print(e) # print(data_series) if data_series['type'] == 'CSI_DATA': try: # csi_raw_data = json.loads(data_series['data']) csi_raw_data = base64_decode_bin( data_series['data']) # 如果解码失败返回空列表,跳过这条数据 if len(csi_raw_data) == 0: print(f"CSI_DATA decode failed, skipping data: {data_series['data'][:50]}...") break if len(csi_raw_data) != int(data_series['len']): # if len(csi_raw_data) != 104 and len(csi_raw_data) != 216 and len(csi_raw_data) != 328 and len(csi_raw_data) != 552: print( f"CSI_DATA, expected: {data_series['len']}, actual: {len(csi_raw_data)}") break except Exception as e: print( f"json.JSONDecodeError: {e}, data: {data_series['data']}") break data_series['data'] = csi_raw_data if data_series['taget'] != 'unknown': if data_series['taget'] != taget_last or data_series['taget_seq'] != taget_seq_last: folder = f"data/{data_series['taget']}" if not path.exists(folder): mkdir(folder) csi_target_data_file_name = f"{folder}/{datetime.now().strftime('%Y-%m-%d_%H-%M-%S-%f')[:-3]}_{data_series['len']}_{data_series['taget_seq']}.csv" print(csi_target_data_file_name) csi_target_data_file_fd = open( csi_target_data_file_name, 'w+') taget_data_writer = csv.writer( csi_target_data_file_fd) taget_data_writer.writerow(data_series.index) taget_data_writer.writerow( data_series.astype(str)) taget_last = data_series['taget'] taget_seq_last = data_series['taget_seq'] if queue_read.full(): # print('============== queue_full ==========') pass else: # print("data_series", len(data_series), type(data_series), data_series) queue_read.put(data_series) else: queue_read.put(data_series) data_valid['file_writer'].writerow(data_series.astype(str)) data_valid['file_fd'].flush() break else: strings = re.sub(r'\\x1b.*?m', '', strings) log_data_writer.writelines(strings + '\n') log = re.match(r'.*([DIWE]) \((\d+)\) (.*)', strings, re.I) if not log: continue data_series = pd.Series(index=['type', 'tag', 'timestamp', 'data'], data=['LOG_DATA', log.group(1), log.group(2), log.group(3)]) if not queue_read.full(): queue_read.put(data_series) def quit(signum, frame): print('Exit the system') sys.exit() if __name__ == '__main__': if sys.version_info < (3, 6): print(' Python version should >= 3.6') exit() parser = argparse.ArgumentParser( description='Read CSI data from serial port and display it graphically') parser.add_argument('-p', '--port', dest='port', action='store', required=True, help='Serial port number of csv_recv device') parser.add_argument('-t', '--csi_output_type', dest='csi_output_type', action='store', choices=['LLTF', 'HT_LTF', 'HE_LTF', 'STBC-HT-LTF', 'STBC-HE-LTF'], default='LLTF', help='CSI output type: LLTF, HT_LTF, HE_LTF, STBC-HT-LTF, or STBC-HE-LTF (default: LLTF)') args = parser.parse_args() serial_port = args.port csi_output_type = args.csi_output_type serial_queue_read = Queue(maxsize=64) serial_queue_write = Queue(maxsize=64) signal_key.signal(signal_key.SIGINT, quit) signal_key.signal(signal_key.SIGTERM, quit) serial_handle_process = Process(target=serial_handle, args=( serial_queue_read, serial_queue_write, serial_port)) serial_handle_process.start() app = QApplication(sys.argv) app.setWindowIcon(QIcon('../../../docs/_static/icon.png')) window = DataGraphicalWindow(serial_queue_write, csi_output_type) data_handle_thread = DataHandleThread(serial_queue_read) data_handle_thread.signal_device_info.connect(window.show_device_info) data_handle_thread.signal_log_msg.connect(window.show_textBrowser_log) data_handle_thread.signal_exit.connect(window.close) data_handle_thread.start() window.show() sys.exit(app.exec()) serial_handle_process.join()