Доработана функции для считывания переменных

Добавлены бета-функции для считывания переменны по адресу

+фиксы багов

future:
- в селекторе сделать две таблички для всех переменных и для выборанных
- по кнопке переносить переменные из всех в выбранные
- переменные из выбранных и добавлять в основную табличку
- сделать отдельный класс для таблички - который будет принимать спиоск переменных для отображения
This commit is contained in:
Razvalyaev 2025-07-11 16:46:51 +03:00
parent d3f1e824fa
commit e4fcfd11d7
12 changed files with 2512 additions and 2053 deletions

Binary file not shown.

View File

@ -8,12 +8,11 @@ import xml.etree.ElementTree as ET
from generateVars import type_map from generateVars import type_map
from enum import IntEnum from enum import IntEnum
import threading import threading
from scanVars import run_scan
from generateVars import run_generate from generateVars import run_generate
import setupVars import setupVars
from VariableSelector import VariableSelectorDialog from VariableSelector import VariableSelectorDialog
from VariableTable import VariableTableWidget, rows from VariableTable import VariableTableWidget, rows
from scanVarGUI import ProcessOutputWindowDummy from scanVarGUI import ProcessOutputWindow
import scanVars import scanVars
import myXML import myXML
import time import time
@ -202,25 +201,10 @@ class VarEditor(QWidget):
# Создаём окно с кнопкой "Готово" # Создаём окно с кнопкой "Готово"
self.proc_win = ProcessOutputWindowDummy(self.__after_scanvars_finished) self.proc_win = ProcessOutputWindow(self.proj_path, self.makefile_path, self.xml_path,
self.emitting_stream = self.proc_win.emitting_stream # ключевая строка! on_done_callback=self.__after_scanvars_finished)
self.proc_win.show() self.proc_win.start_scan()
def run_scan_wrapper():
try:
old_stdout = sys.stdout
sys.stdout = self.emitting_stream
run_scan(self.proj_path, self.makefile_path, self.xml_path)
except Exception as e:
self.emitting_stream.text_written.emit(f"\n[ОШИБКА] {e}")
finally:
sys.stdout = old_stdout
self.emitting_stream.text_written.emit("\n--- Анализ завершён ---")
self.proc_win.btn_close.setEnabled(True)
threading.Thread(target=run_scan_wrapper, daemon=True).start()
def save_build(self): def save_build(self):
@ -433,17 +417,12 @@ class VarEditor(QWidget):
def delete_selected_rows(self): def delete_selected_rows(self):
selected_rows = sorted(set(index.row() for index in self.table.selectedIndexes()), reverse=True) selected_rows = sorted(set(index.row() for index in self.table.selectedIndexes()), reverse=True)
if not selected_rows: if not selected_rows:
return return
# Удаляем из vars_list те, у кого show_var == true и имя совпадает
filtered_vars = [v for v in self.vars_list if v.get('show_var', 'false') == 'true']
for row in selected_rows: for row in selected_rows:
if 0 <= row < len(filtered_vars): if 0 <= row < len(self.vars_list):
var_to_remove = filtered_vars[row] # Меняем флаг show_var для переменной с этим индексом
for v in self.vars_list: self.vars_list[row]['show_var'] = 'false'
if v['name'] == var_to_remove['name']:
v['show_var'] = 'false'
break
self.table.populate(self.vars_list, self.structs, self.write_to_xml) self.table.populate(self.vars_list, self.structs, self.write_to_xml)
self.write_to_xml() self.write_to_xml()
@ -454,7 +433,7 @@ class VarEditor(QWidget):
QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).") QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).")
return return
dlg = VariableSelectorDialog(self.vars_list, self.structs, self.typedef_map, self.xml_path, self) dlg = VariableSelectorDialog(self.table, self.vars_list, self.structs, self.typedef_map, self.xml_path, self)
if dlg.exec_(): if dlg.exec_():
self.write_to_xml() self.write_to_xml()
self.update() self.update()

View File

@ -1,10 +1,12 @@
import re import re
import xml.etree.ElementTree as ET
from PySide2.QtWidgets import ( from PySide2.QtWidgets import (
QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton, QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout
) )
from PySide2.QtGui import QKeySequence, QKeyEvent from PySide2.QtGui import QKeySequence, QKeyEvent
from PySide2.QtCore import Qt, QStringListModel, QSettings from PySide2.QtCore import Qt, QStringListModel, QSettings
import VariableTable
import setupVars import setupVars
import myXML import myXML
import time import time
@ -13,14 +15,14 @@ import time
array_re = re.compile(r'^(\w+)\[(\d+)\]$') array_re = re.compile(r'^(\w+)\[(\d+)\]$')
class VariableSelectorDialog(QDialog): class VariableSelectorDialog(QDialog):
def __init__(self, all_vars, structs, typedefs, xml_path=None, parent=None): def __init__(self, table, all_vars, structs, typedefs, xml_path=None, parent=None):
super().__init__(parent) super().__init__(parent)
self.setWindowTitle("Выбор переменных") self.setWindowTitle("Выбор переменных")
self.setAttribute(Qt.WA_DeleteOnClose) self.setAttribute(Qt.WA_DeleteOnClose)
self.resize(600, 500) self.resize(600, 500)
self.selected_names = [] self.selected_names = []
self._bckspc_pressed = False # флаг подавления добавления разделителя self._bckspc_pressed = False # флаг подавления добавления разделителя
self.table = table
self.all_vars = all_vars self.all_vars = all_vars
self.structs = structs self.structs = structs
self.typedefs = typedefs self.typedefs = typedefs
@ -28,6 +30,7 @@ class VariableSelectorDialog(QDialog):
self.var_map = {v['name']: v for v in all_vars} self.var_map = {v['name']: v for v in all_vars}
self.node_index = {} self.node_index = {}
self.xml_path = xml_path # сохраняем путь к xml self.xml_path = xml_path # сохраняем путь к xml
self.manual_completion_active = False
# --- Добавляем чекбокс для автодополнения --- # --- Добавляем чекбокс для автодополнения ---
self.autocomplete_checkbox = QCheckBox("Включить автодополнение") self.autocomplete_checkbox = QCheckBox("Включить автодополнение")
@ -289,8 +292,9 @@ class VariableSelectorDialog(QDialog):
if not name_parts: if not name_parts:
continue continue
last_part = name_parts[-1].lower() last_part = name_parts[-1].lower()
if prefix == '' or last_part.startswith(prefix): if prefix == '' or prefix in last_part: # здесь изменено
completions.append(name) completions.append(name)
self.completer.complete() self.completer.complete()
return completions return completions
@ -328,9 +332,16 @@ class VariableSelectorDialog(QDialog):
def eventFilter(self, obj, event): def eventFilter(self, obj, event):
if obj == self.search_input and isinstance(event, QKeyEvent): if obj == self.search_input and isinstance(event, QKeyEvent):
if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier: if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier:
self.manual_completion_active = True
text = self.search_input.text().strip() text = self.search_input.text().strip()
self.run_completions(text) self.run_completions(text)
return True elif event.key() == Qt.Key_Escape:
# Esc — выключаем ручной режим и скрываем подсказки, если autocomplete выключен
if not self.autocomplete_checkbox.isChecked():
self.manual_completion_active = False
self.completer.popup().hide()
return True
if event.key() == Qt.Key_Backspace: if event.key() == Qt.Key_Backspace:
self._bckspc_pressed = True self._bckspc_pressed = True
else: else:
@ -341,6 +352,9 @@ class VariableSelectorDialog(QDialog):
def run_completions(self, text): def run_completions(self, text):
completions = self.update_completions(text) completions = self.update_completions(text)
if not self.autocomplete_checkbox.isChecked() and self._bckspc_pressed:
text = text[:-1]
if len(completions) == 1 and completions[0].lower() == text.lower(): if len(completions) == 1 and completions[0].lower() == text.lower():
# Найдем узел с таким именем # Найдем узел с таким именем
def find_exact_item(name): def find_exact_item(name):
@ -391,6 +405,12 @@ class VariableSelectorDialog(QDialog):
text = self.search_input.text().strip() text = self.search_input.text().strip()
if self.autocomplete_checkbox.isChecked(): if self.autocomplete_checkbox.isChecked():
self.run_completions(text) self.run_completions(text)
else:
# Если выключено, показываем подсказки только если флаг ручного вызова True
if self.manual_completion_active:
self.run_completions(text)
else:
self.completer.popup().hide()
def on_add_clicked(self): def on_add_clicked(self):
self.selected_names = [] self.selected_names = []
@ -462,9 +482,7 @@ class VariableSelectorDialog(QDialog):
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.") QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
return return
import xml.etree.ElementTree as ET root, tree = myXML.safe_parse_xml(self.xml_path)
tree = ET.parse(self.xml_path)
root = tree.getroot()
if root is None: if root is None:
return return
@ -485,7 +503,6 @@ class VariableSelectorDialog(QDialog):
myXML.fwrite(root, self.xml_path) myXML.fwrite(root, self.xml_path)
self.populate_tree()
self.done(QDialog.Accepted) self.done(QDialog.Accepted)
@ -503,8 +520,50 @@ class VariableSelectorDialog(QDialog):
def delete_selected_vars(self): def delete_selected_vars(self):
selected_names = self._get_selected_var_names() selected_names = self._get_selected_var_names()
if not selected_names: if not selected_names:
print("nothing selected")
return return
# Обновляем var_map и all_vars
for name in selected_names:
if name in self.var_map:
self.var_map[name]['show_var'] = 'false'
self.var_map[name]['enable'] = 'false'
for v in self.all_vars:
if v['name'] == name:
v['show_var'] = 'false'
v['enable'] = 'false'
break
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
return
root, tree = myXML.safe_parse_xml(self.xml_path)
if root is None:
return
vars_section = root.find('variables')
if vars_section is None:
return
for var_elem in vars_section.findall('var'):
name = var_elem.attrib.get('name')
if name in selected_names:
def set_text(tag, value):
el = var_elem.find(tag)
if el is None:
el = ET.SubElement(var_elem, tag)
el.text = value
set_text('show_var', 'false')
set_text('enable', 'false')
myXML.fwrite(root, self.xml_path)
self.table.populate(self.all_vars, self.structs, None)
# Проверка пути к XML # Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path: if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox from PySide2.QtWidgets import QMessageBox
@ -512,8 +571,7 @@ class VariableSelectorDialog(QDialog):
return return
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
tree = ET.parse(self.xml_path) root, tree = myXML.safe_parse_xml(self.xml_path)
root = tree.getroot()
if root is None: if root is None:
return return
@ -532,10 +590,22 @@ class VariableSelectorDialog(QDialog):
# Удаляем из all_vars (глобально) # Удаляем из all_vars (глобально)
self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names] self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names]
# Удаляем из expanded_vars (тоже глобально)
def filter_out_selected(vars_list):
filtered = []
for v in vars_list:
if v['name'] not in selected_names:
# Рекурсивно фильтруем детей, если есть
if 'children' in v:
v = v.copy()
v['children'] = filter_out_selected(v['children'])
filtered.append(v)
return filtered
self.expanded_vars[:] = filter_out_selected(self.expanded_vars)
if removed_any: if removed_any:
myXML.fwrite(root, self.xml_path) myXML.fwrite(root, self.xml_path)
self.populate_tree()
self.filter_tree() self.filter_tree()
def _get_selected_var_names(self): def _get_selected_var_names(self):

View File

@ -1,6 +1,12 @@
import sys import sys
import re import re
import multiprocessing
import sys
import contextlib
import io
import json
from scanVars import run_scan
from VariableTable import VariableTableWidget, rows from VariableTable import VariableTableWidget, rows
from PySide2.QtWidgets import ( from PySide2.QtWidgets import (
@ -10,7 +16,7 @@ from PySide2.QtWidgets import (
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView, QProgressBar QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView, QProgressBar
) )
from PySide2.QtGui import QTextCursor, QKeyEvent from PySide2.QtGui import QTextCursor, QKeyEvent
from PySide2.QtCore import Qt, QProcess, QObject, Signal, QSettings from PySide2.QtCore import Qt, QProcess, QObject, Signal, QTimer
class EmittingStream(QObject): class EmittingStream(QObject):
@ -67,24 +73,28 @@ class EmittingStream(QObject):
self._buffer = "" self._buffer = ""
class ProcessOutputWindowDummy(QDialog):
def __init__(self, on_done_callback): class ProcessOutputWindow(QDialog):
def __init__(self, proj_path, makefile_path, xml_path, on_done_callback=None):
super().__init__() super().__init__()
self.setWindowTitle("Поиск переменных...") self.setWindowTitle("Поиск переменных...")
self.resize(600, 480) self.resize(600, 480)
self.setModal(True) self.setModal(True)
self.proj_path = proj_path
self.makefile_path = makefile_path
self.xml_path = xml_path
self._on_done_callback = on_done_callback
self.layout = QVBoxLayout(self) self.layout = QVBoxLayout(self)
self.output_edit = QTextEdit() self.output_edit = QTextEdit()
self.output_edit.setReadOnly(True) self.output_edit.setReadOnly(True)
self.layout.addWidget(self.output_edit) self.layout.addWidget(self.output_edit)
# Метка с именем прогрессбара
self.progress_label = QLabel("Progress:") self.progress_label = QLabel("Progress:")
self.layout.addWidget(self.progress_label) self.layout.addWidget(self.progress_label)
# Прогрессбар
self.progress_bar = QProgressBar() self.progress_bar = QProgressBar()
self.progress_bar.setMinimum(0) self.progress_bar.setMinimum(0)
self.progress_bar.setValue(0) self.progress_bar.setValue(0)
@ -93,33 +103,117 @@ class ProcessOutputWindowDummy(QDialog):
self.btn_close = QPushButton("Закрыть") self.btn_close = QPushButton("Закрыть")
self.btn_close.setEnabled(False) self.btn_close.setEnabled(False)
self.layout.addWidget(self.btn_close) self.layout.addWidget(self.btn_close)
self.btn_close.clicked.connect(self.__handle_done) self.btn_close.clicked.connect(self.__handle_done)
self._on_done_callback = on_done_callback
self.emitting_stream = EmittingStream() self.queue = None
self.emitting_stream.text_written.connect(self.append_text) self.proc = None
self.emitting_stream.progress_updated.connect(self.update_progress)
sys.stdout = self.emitting_stream
def __handle_done(self): def start_scan(self):
sys.stdout = sys.__stdout__ # восстановить stdout self.queue = multiprocessing.Queue()
if self._on_done_callback: self.proc = multiprocessing.Process(
self._on_done_callback() target=run_scan_process,
self.accept() args=(self.proj_path, self.makefile_path, self.xml_path, self.queue),
daemon=True)
self.proc.start()
self.timer = QTimer(self)
self.timer.timeout.connect(self.poll_queue)
self.timer.start(100)
self.show()
def poll_queue(self):
try:
while True:
msg = self.queue.get_nowait()
if msg is None:
# Конец процесса
self.btn_close.setEnabled(True)
self.append_text("\n--- Анализ завершён ---")
self.timer.stop()
return
# Пытаемся разобрать JSON-сообщение
if isinstance(msg, str) and msg.startswith("PROGRESS_MSG:"):
try:
data = json.loads(msg[len("PROGRESS_MSG:"):])
self.update_progress(data["bar_name"], data["current"], data["total"])
except Exception:
# Если не удалось распарсить, выводим как текст
self.append_text(msg)
else:
self.append_text(msg)
except Exception:
pass # Очередь пустая
def append_text(self, text): def append_text(self, text):
cursor = self.output_edit.textCursor() cursor = self.output_edit.textCursor()
cursor.movePosition(QTextCursor.End) cursor.movePosition(QTextCursor.End)
if not text.endswith('\n'): if not text.endswith('\n'):
text += '\n' text += '\n'
for line in text.splitlines(True): cursor.insertText(text)
cursor.insertText(line)
self.output_edit.setTextCursor(cursor) self.output_edit.setTextCursor(cursor)
self.output_edit.ensureCursorVisible() self.output_edit.ensureCursorVisible()
def update_progress(self, bar_name, current, total): def update_progress(self, bar_name, current, total):
self.progress_label.setText(f"{bar_name}") self.progress_label.setText(f"{bar_name}")
self.progress_bar.setMaximum(total) self.progress_bar.setMaximum(total)
self.progress_bar.setValue(current) self.progress_bar.setValue(current)
def __handle_done(self):
self.close()
def closeEvent(self, event):
if self.proc and self.proc.is_alive():
self.proc.terminate()
self.proc.join()
self.btn_close.setEnabled(True)
self.append_text("Сканирование прервано.")
def run_scan_process(proj_path, makefile_path, xml_path, queue):
class QueueWriter(io.TextIOBase):
def __init__(self):
self._buffer = ""
self._current_bar_name = None
def write(self, txt):
self._buffer += txt
while '\n' in self._buffer:
line, self._buffer = self._buffer.split('\n', 1)
# Обработка прогресса
if line.startswith('Progress: "') and line.endswith('"'):
# Название прогресс-бара
bar_name = line[len('Progress: "'):-1]
self._current_bar_name = bar_name
elif re.match(r'^Progress:\s*\d+\s*/\s*\d+$', line):
m = re.match(r'^Progress:\s*(\d+)\s*/\s*(\d+)$', line)
if m:
current = int(m.group(1))
total = int(m.group(2))
bar_name = self._current_bar_name or "Progress"
# Отправляем специальное сообщение в очередь в формате JSON
msg = {
"bar_name": bar_name,
"current": current,
"total": total
}
queue.put("PROGRESS_MSG:" + json.dumps(msg))
else:
# Обычный вывод
queue.put(line)
def flush(self):
if self._buffer.strip():
queue.put(self._buffer.strip())
self._buffer = ""
sys.stdout = QueueWriter()
sys.stderr = sys.stdout
try:
run_scan(proj_path, makefile_path, xml_path)
except Exception as e:
queue.put(f"[ОШИБКА] {e}")
finally:
queue.put(None) # сигнал окончания

View File

@ -14,7 +14,6 @@ from xml.dom import minidom
from parseMakefile import parse_makefile from parseMakefile import parse_makefile
from collections import deque from collections import deque
import argparse import argparse
from setupVars import make_relative_path
import myXML import myXML
BITFIELD_WIDTHS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} BITFIELD_WIDTHS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
@ -582,12 +581,12 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
} }
if makefile_path: if makefile_path:
rel_makefile = make_relative_path(makefile_path, proj_path) rel_makefile = myXML.make_relative_path(makefile_path, proj_path)
if not os.path.isabs(rel_makefile): if not os.path.isabs(rel_makefile):
analysis_attrs["makefile_path"] = rel_makefile.replace("\\", "/") analysis_attrs["makefile_path"] = rel_makefile.replace("\\", "/")
if structs_xml_path: if structs_xml_path:
rel_struct = make_relative_path(structs_xml_path, proj_path) rel_struct = myXML.make_relative_path(structs_xml_path, proj_path)
if not os.path.isabs(rel_struct): if not os.path.isabs(rel_struct):
analysis_attrs["structs_path"] = rel_struct.replace("\\", "/") analysis_attrs["structs_path"] = rel_struct.replace("\\", "/")
@ -919,6 +918,5 @@ def run_scan(proj_path, makefile_path, output_xml, verbose=2):
print("[XML] Creating vars.xml...") print("[XML] Creating vars.xml...")
generate_xml_output(proj_path, output_xml, vars, includes, externs, structs_xml, makefile_path) generate_xml_output(proj_path, output_xml, vars, includes, externs, structs_xml, makefile_path)
print("Progress: 2/2")
print('Progress: "Done"') print('Progress: "Done"')
print('Progress: 1/1') print("Progress: 2/2")

View File

@ -190,24 +190,44 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
return [] return []
# Вспомогательная функция для обработки массивов # Вспомогательная функция для обработки массивов
def process_array(prefix, base_type, dims): def process_array(prefix, type_str, structs, typedefs, var_attrs, depth=0):
array_tree = generate_array_names(prefix, dims) base_type, array_dims = parse_array_dims(type_str)
array_flat = flatten_array_tree(array_tree) if not array_dims:
for node in array_flat: return []
sub_items = expand_struct_recursively(node['name'], base_type, structs, typedefs, var_attrs, depth + 1)
if sub_items: # На текущем уровне берем первый размер массива
node['children'] = sub_items current_dim = array_dims[0]
else: # Оставшиеся размеры — все, кроме первого
node.update({ remaining_dims = array_dims[1:]
'type': base_type,
'pt_type': '', # Для создания типа с оставшимися размерами:
'iq_type': '', if remaining_dims:
'return_type': '', # Формируем строку типа для оставшихся измерений массива, например int[16]
'file': var_attrs.get('file'), remaining_type_str = f"{base_type}{''.join(f'[{d}]' for d in remaining_dims)}"
'extern': var_attrs.get('extern'), else:
'static': var_attrs.get('static'), remaining_type_str = base_type
})
return array_flat array_tree = []
for i in range(current_dim):
name = f"{prefix}[{i}]"
# Для каждого элемента передаем уже оставшийся тип массива
children = expand_struct_recursively(name, remaining_type_str, structs, typedefs, var_attrs, depth + 1)
node = {
'name': name,
'type': remaining_type_str if remaining_dims else base_type,
'pt_type': '',
'iq_type': '',
'return_type': '',
'file': var_attrs.get('file'),
'extern': var_attrs.get('extern'),
'static': var_attrs.get('static'),
}
if children:
node['children'] = children
array_tree.append(node)
return array_tree
# Если type_str — уже распарсенная структура (dict) # Если type_str — уже распарсенная структура (dict)
if isinstance(type_str, dict): if isinstance(type_str, dict):
@ -216,7 +236,7 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
# Проверяем, массив ли это # Проверяем, массив ли это
base_type, array_dims = parse_array_dims(type_str) base_type, array_dims = parse_array_dims(type_str)
if array_dims: if array_dims:
return process_array(prefix, base_type, array_dims) return process_array(prefix, type_str, structs, typedefs, var_attrs, depth)
# Ищем структуру по имени типа # Ищем структуру по имени типа
base_type = scanVars.strip_ptr_and_array(type_str) base_type = scanVars.strip_ptr_and_array(type_str)
@ -289,13 +309,9 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
if "(" in field_type_str and "*" in field_type_str and ")" in field_type_str: if "(" in field_type_str and "*" in field_type_str and ")" in field_type_str:
continue continue
# Проверим, является ли тип структурой (по имени) if isinstance(field_value, dict):
clean_type = scanVars.strip_ptr_and_array(field_type_str)
struct_fields = structs.get(clean_type)
if isinstance(struct_fields, dict):
# Это одиночная структура — раскрываем рекурсивно # Это одиночная структура — раскрываем рекурсивно
sub_items = expand_struct_recursively(full_name, field_type_str, structs, typedefs, var_attrs, depth + 1) sub_items = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1)
child = { child = {
'name': full_name, 'name': full_name,
'type': field_type_str, 'type': field_type_str,

View File

View File

@ -2,28 +2,133 @@
#include "IQmathLib.h" #include "IQmathLib.h"
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var); static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var);
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var, DebugVarIQType_t iq_type_final); static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var);
DebugVarIQType_t dbg_type = t_iq24;
long Debug_ReadVar(DebugVar_t *var, DebugVarIQType_t iq_type_final)
int Debug_LowLevel_ReadVar(DebugVar_t *var_ll, long *return_long)
{ {
long tmp_var; if (var_ll == NULL)
if((var->ptr_type == pt_struct) || (var->ptr_type == pt_union) || (var->ptr_type == pt_unknown)) return 1;
return;
convertDebugVarToIQx(var, &tmp_var, dbg_type); char *addr = var_ll->Ptr;
unsigned long addr_val = (unsigned long)addr;
// Ðàçðåø¸ííûå äèàïàçîíû ïàìÿòè íà TMS320F2812
if (!(
(addr_val <= 0x0007FF) || // RAMM0 + RAMM1
(addr_val >= 0x008000 && addr_val <= 0x009FFF) || // L0 + L1 SARAM
(addr_val >= 0x3F8000 && addr_val <= 0x3F9FFF) || // PRAMH0 + DRAMH0
(addr_val >= 0x3D8000 && addr_val <= 0x3EFFFF) || // Flash A-F
(addr_val >= 0x3FF000 && addr_val <= 0x3FFFFF) // Boot ROM / Reset
)) {
return 2; // àäðåñ âíå äîïóñòèìîãî äèàïàçîíà, èãíîðèðóåì
}
return tmp_var; convertDebugVarToIQx(var_ll, return_long);
return 0;
} }
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var, DebugVarIQType_t iq_type_final)
int Debug_ReadVar(DebugVar_t *var, long *return_long)
{
long tmp_var;
if (var == NULL)
return 1;
if((var->ptr_type == pt_struct) || (var->ptr_type == pt_union) ||
(var->ptr_type == pt_unknown) || (var->return_type == pt_unknown))
return 1;
convertDebugVarToIQx(var, return_long);
return 0;
}
int Debug_ReadVarName(DebugVar_t *var, char *name_ptr)
{
if((var == NULL)||(name_ptr == NULL))
return 1;
int i;
// Êîïèðîâàíèå ñ çàùèòîé îò ïåðåïîëíåíèÿ è ÿâíîé îñòàíîâêîé ïî '\0'
for (i = 0; i < sizeof(var->name); i++)
{
name_ptr[i] = var->name[i];
if (var->name[i] == '\0')
break;
}
// Ãàðàíòèðîâàííîå çàâåðøåíèå ñòðîêè (íà ñëó÷àé, åñëè â var->name íå áûëî '\0')
name_ptr[sizeof(var->name) - 1] = '\0';
return 0;
}
int Debug_LowLevel_Initialize(const uint8_t* external_date)
{
if (external_date == NULL) {
return -1;
}
// Ïðåîáðàçóåì external_date â ñòðóêòóðó
DateTimeHex ext;
ext.year = (external_date[0] << 8) | external_date[1];
ext.month = external_date[2];
ext.day = external_date[3];
ext.hour = external_date[4];
ext.minute = external_date[5];
// Ïàðñèì BUILD_FULL_DATE "YYYYMMDD_HHMM"
DateTimeHex build;
char buf[5] = {0};
// Ãîä
memcpy(buf, BUILD_FULL_DATE + 0, 4);
build.year = (uint16_t)atoi(buf);
// Ìåñÿö
memcpy(buf, BUILD_FULL_DATE + 4, 2);
build.month = (uint8_t)atoi(buf);
// Äåíü
memcpy(buf, BUILD_FULL_DATE + 6, 2);
build.day = (uint8_t)atoi(buf);
// ×àñ
memcpy(buf, BUILD_FULL_DATE + 9, 2);
build.hour = (uint8_t)atoi(buf);
// Ìèíóòû
memcpy(buf, BUILD_FULL_DATE + 11, 2);
build.minute = (uint8_t)atoi(buf);
// Ñðàâíåíèå âñåõ ïîëåé
if (ext.year == build.year &&
ext.month == build.month &&
ext.day == build.day &&
ext.hour == build.hour &&
ext.minute == build.minute)
{
return 0; // Ñîâïàëî
}
return 1; // Íå ñîâïàëî
}
/////////////////////----INTERNAL FUNCTIONS-----////////////////////////
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
{ {
long iq_numb, iq_united, iq_final; long iq_numb, iq_united, iq_final;
float float_numb; float float_numb;
if(getDebugVar(var, &iq_numb, &float_numb) == 1) if(getDebugVar(var, &iq_numb, &float_numb) != 0)
return 1; return 1;
// ïðèâåäåíèå ê îäíîìó IQ // ïðèâåäåíèå ê îäíîìó IQ
switch(var->iq_type) switch(var->iq_type)
@ -131,7 +236,7 @@ static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var, DebugVarIQType_t
} }
// ïðèâåäåíèå îáùåãî IQ ê çàïðàøèâàåìîìó // ïðèâåäåíèå îáùåãî IQ ê çàïðàøèâàåìîìó
switch(iq_type_final) switch(var->return_type)
{ {
case t_iq_none: case t_iq_none:
iq_final = (int)_IQtoF(iq_united); iq_final = (int)_IQtoF(iq_united);
@ -233,42 +338,53 @@ static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var, DebugVarIQType_t
} }
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var) static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
{ {
if (!var || !int_var || !float_var) if (!var || !int_var || !float_var || !var->Ptr)
return 1; // îøèáêà: null óêàçàòåëü return 1; // îøèáêà: null óêàçàòåëü
char *addr = var->Ptr;
unsigned long addr_val = (unsigned long)addr;
switch (var->ptr_type) switch (var->ptr_type)
{ {
case pt_int8: // signed char case pt_int8: // 8 áèò
*int_var = *((signed char *)var->Ptr); case pt_uint8:
// âûðàâíèâàíèå íå íóæíî äëÿ 8 áèò
*int_var = *((volatile char *)addr);
break; break;
case pt_int16: // int case pt_int16: // 16 áèò (int)
*int_var = *((int *)var->Ptr); case pt_uint16:
if (addr_val & 0x1) // ïðîâåðêà âûðàâíèâàíèÿ ïî 2 áàéòàì
return 2; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile int *)addr);
break; break;
case pt_int32: // long case pt_int32: // 32 áèò (long)
*int_var = *((long *)var->Ptr); case pt_uint32:
if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 áàéòàì
return 3; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile long *)addr);
break; break;
case pt_uint8: // unsigned char // case pt_int64: // 64 áèò (long long)
*int_var = *((unsigned char *)var->Ptr); // case pt_uint64:
break; // if (addr_val & 0x7) // ïðîâåðêà âûðàâíèâàíèÿ ïî 8 áàéòàì
// return 2; // îøèáêà âûðàâíèâàíèÿ
case pt_uint16: // unsigned int // // Òóò ïðîñòî ÷èòàåì, íî long long ìîæåò íå ïîìåñòèòüñÿ â *int_var
*int_var = *((unsigned int *)var->Ptr); // // Ìîæíî çàìåíèòü ëîãèêó ïîä 64-áèòíîå ÷òåíèå ïðè íåîáõîäèìîñòè
break; // *int_var = *((volatile long long *)addr);
// break;
case pt_uint32: // unsigned long
*int_var = *((unsigned long *)var->Ptr); case pt_float: // float (4 áàéòà)
break; if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 áàéòàì
return 4; // îøèáêà âûðàâíèâàíèÿ
case pt_float: // float *float_var = *((volatile float *)addr);
*float_var = *((float *)var->Ptr);
break; break;
default:
return 1; // íåïîääåðæèâàåìûé òèï
// äëÿ óêàçàòåëåé è ìàññèâîâ íå ïîääåðæèâàåòñÿ ÷òåíèå // äëÿ óêàçàòåëåé è ìàññèâîâ íå ïîääåðæèâàåòñÿ ÷òåíèå
// case pt_ptr_int8: // case pt_ptr_int8:
// case pt_ptr_int16: // case pt_ptr_int16:
@ -282,8 +398,6 @@ static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
// case pt_arr_uint8: // case pt_arr_uint8:
// case pt_arr_uint16: // case pt_arr_uint16:
// case pt_arr_uint32: // case pt_arr_uint32:
default:
return 1;
} }
return 0; // óñïåõ return 0; // óñïåõ

View File

@ -9,9 +9,11 @@ typedef enum
pt_int8, // signed char pt_int8, // signed char
pt_int16, // int pt_int16, // int
pt_int32, // long pt_int32, // long
pt_int64, // long
pt_uint8, // unsigned char pt_uint8, // unsigned char
pt_uint16, // unsigned int pt_uint16, // unsigned int
pt_uint32, // unsigned long pt_uint32, // unsigned long
pt_uint64, // unsigned long
pt_float, // float pt_float, // float
pt_struct, // struct pt_struct, // struct
pt_union, // struct pt_union, // struct
@ -70,12 +72,25 @@ typedef struct
char* Ptr; char* Ptr;
DebugVarPtrType_t ptr_type; DebugVarPtrType_t ptr_type;
DebugVarIQType_t iq_type; DebugVarIQType_t iq_type;
char name[10]; DebugVarIQType_t return_type;
char name[11]; // 10 ñèìâîëîâ + '\0'
}DebugVar_t; }DebugVar_t;
typedef struct {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
} DateTimeHex;
extern int DebugVar_Qnt; extern int DebugVar_Qnt;
extern DebugVar_t dbg_vars[]; extern DebugVar_t dbg_vars[];
long Debug_ReadVar(DebugVar_t *var, DebugVarIQType_t iq_type_final);
int Debug_LowLevel_ReadVar(DebugVar_t *var_ll, long *return_long);
int Debug_ReadVar(DebugVar_t *var, long *return_long);
int Debug_ReadVarName(DebugVar_t *var, char *name_ptr);
#endif //DEBUG_TOOLS #endif //DEBUG_TOOLS

View File

@ -3,33 +3,33 @@
// Èíêëþäû äëÿ äîñòóïà ê ïåðåìåííûì // Èíêëþäû äëÿ äîñòóïà ê ïåðåìåííûì
#include "vector.h"
#include "f281xpwm.h"
#include "log_can.h"
#include "RS_Functions_modbus.h" #include "RS_Functions_modbus.h"
#include "errors.h"
#include "pwm_vector_regul.h"
#include "xp_project.h" #include "xp_project.h"
#include "xp_write_xpwm_time.h" #include "xp_write_xpwm_time.h"
#include "teta_calc.h"
#include "vector.h"
#include "v_pwm24.h" #include "v_pwm24.h"
#include "errors.h"
#include "dq_to_alphabeta_cos.h"
#include "log_can.h"
#include "f281xpwm.h"
#include "pwm_vector_regul.h"
#include "adc_tools.h" #include "adc_tools.h"
#include "rotation_speed.h" #include "rotation_speed.h"
#include "dq_to_alphabeta_cos.h"
#include "teta_calc.h"
#include "CAN_Setup.h"
#include "log_to_memory.h"
#include "log_params.h"
#include "CRC_Functions.h"
#include "global_time.h"
#include "RS_Functions.h" #include "RS_Functions.h"
#include "detect_phase_break2.h"
#include "x_parallel_bus.h"
#include "x_serial_bus.h"
#include "Spartan2E_Functions.h"
#include "xp_controller.h" #include "xp_controller.h"
#include "xPeriphSP6_loader.h" #include "xPeriphSP6_loader.h"
#include "xp_rotation_sensor.h" #include "xp_rotation_sensor.h"
#include "x_serial_bus.h"
#include "Spartan2E_Functions.h"
#include "x_parallel_bus.h"
#include "svgen_dq.h" #include "svgen_dq.h"
#include "detect_phase_break2.h"
#include "log_to_memory.h"
#include "CRC_Functions.h"
#include "global_time.h"
#include "CAN_Setup.h"
#include "log_params.h"
#include "pid_reg3.h" #include "pid_reg3.h"
#include "IQmathLib.h" #include "IQmathLib.h"
#include "doors_control.h" #include "doors_control.h"
@ -314,9 +314,26 @@ extern int zero_ADC[20];
// Îïðåäåëåíèå ìàññèâà ñ óêàçàòåëÿìè íà ïåðåìåííûå äëÿ îòëàäêè // Îïðåäåëåíèå ìàññèâà ñ óêàçàòåëÿìè íà ïåðåìåííûå äëÿ îòëàäêè
int DebugVar_Qnt = 2; int DebugVar_Qnt = 19;
#pragma DATA_SECTION(dbg_vars,".dbgvar_info") #pragma DATA_SECTION(dbg_vars,".dbgvar_info")
DebugVar_t dbg_vars[] = {\ DebugVar_t dbg_vars[] = {\
{(char *)&ADC0finishAddr, pt_uint8, t_iq7, pt_uint8, "asdasjjjjj" }, \ {(char *)&ADC1startAddr, pt_int16, t_iq_none, pt_int16, "ADC1StrAdr" }, \
{(char *)&project.cds_tk.count_elements_pbus, pt_uint16, t_iq_none, pt_uint16, "project.cd" }, \ {(char *)&project.cds_tk[0].plane_address, pt_uint16, t_iq_none, pt_uint16, "tk0_Adr" }, \
{(char *)&ADC_sf[0][0], pt_int16, t_iq_none, pt_int16, "ADC_sf00" }, \
{(char *)&ADC_sf[0][1], pt_int16, t_iq_none, pt_int16, "ADC_sf01" }, \
{(char *)&ADC_sf[0][2], pt_int16, t_iq_none, pt_int16, "ADC_sf02" }, \
{(char *)&ADC_sf[0][3], pt_int16, t_iq_none, pt_int16, "ADC_sf03" }, \
{(char *)&ADC_sf[0][4], pt_int16, t_iq_none, pt_int16, "ADC_sf04" }, \
{(char *)&ADC_sf[0][5], pt_int16, t_iq_none, pt_int16, "ADC_sf05" }, \
{(char *)&ADC_sf[0][6], pt_int16, t_iq_none, pt_int16, "ADC_sf06" }, \
{(char *)&ADC_sf[0][7], pt_int16, t_iq_none, pt_int16, "ADC_sf07" }, \
{(char *)&ADC_sf[0][8], pt_int16, t_iq_none, pt_int16, "ADC_sf08" }, \
{(char *)&ADC_sf[0][9], pt_int16, t_iq_none, pt_int16, "ADC_sf09" }, \
{(char *)&ADC_sf[0][10], pt_int16, t_iq_none, pt_int16, "ADC_sf010" }, \
{(char *)&ADC_sf[0][11], pt_int16, t_iq_none, pt_int16, "ADC_sf011" }, \
{(char *)&ADC_sf[0][12], pt_int16, t_iq_none, pt_int16, "ADC_sf012" }, \
{(char *)&ADC_sf[0][13], pt_int16, t_iq_none, pt_int16, "ADC_sf013" }, \
{(char *)&ADC_sf[0][14], pt_int16, t_iq_none, pt_int16, "ADC_sf014" }, \
{(char *)&ADC_sf[0][15], pt_int16, t_iq_none, pt_int16, "ADC_sf015" }, \
{(char *)&project.cds_tk[0].read.sbus.mask_protect_tk.all, pt_uint16, t_iq_none, pt_uint16, "project.cd" }, \
}; };

File diff suppressed because it is too large Load Diff

1108
vars.xml

File diff suppressed because it is too large Load Diff