Compare commits
7 Commits
05bde87c38
...
v1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
369cfa808c | ||
|
|
c32dc161f8 | ||
|
|
abfc507e4e | ||
|
|
cb496bca0f | ||
|
|
7b720cbdf4 | ||
|
|
6428e523df | ||
|
|
c738acd871 |
BIN
DebugVarEdit.exe
BIN
DebugVarEdit.exe
Binary file not shown.
138
README.md
Normal file
138
README.md
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# DebugVarEdit — Утилита для генерации переменных для отладки
|
||||||
|
|
||||||
|
**DebugVarEdit** — графическое приложение для Windows, предназначенное для настройки и генерации отладочных переменных (`debug_vars.c`) на основе исходного C-проекта. Работает с `makefile` проекта, сохраняет изменения в XML и позволяет удобно редактировать переменные и их типы через интерфейс.
|
||||||
|
|
||||||
|
Программа — один исполняемый файл `DebugVarEdit.exe`, не требующий установки и дополнительных зависимостей.
|
||||||
|
|
||||||
|
> Требуется Windows 7 или новее.
|
||||||
|
|
||||||
|
> [Для разработчиков](#для-разработчиков)
|
||||||
|
---
|
||||||
|
|
||||||
|
## Как использовать
|
||||||
|
|
||||||
|
1. Запустите **DebugVarEdit.exe.**
|
||||||
|
|
||||||
|
2. Укажите пути:
|
||||||
|
- **Путь к XML** — новый или существующий файл настроек переменных;
|
||||||
|
- **Путь к проекту** — путь к корню проека (папка, которая является корнем для проекта в Code Composer);
|
||||||
|
- **Путь к makefile** — путь к `makefile` относительно корня проекта;
|
||||||
|
- **Путь для debug_vars.c** — папка, куда будет сгенерирован файл `debug_vars.c` с переменными.
|
||||||
|
|
||||||
|
3. Нажмите **Сканировать переменные**:
|
||||||
|
- Программа проанализирует исходники, указанные в makefile, и найдёт все переменные.
|
||||||
|
- Результат сохранится в двух XML-файлах:
|
||||||
|
- `structs.xml` — информация обо всех структурах и typedef;
|
||||||
|
- `<ваш_файл>.xml` — список всех найденных переменных.
|
||||||
|
|
||||||
|
4. Нажмите **Добавить переменные**:
|
||||||
|
- В **левой таблице** отображаются все найденные переменные.
|
||||||
|
Для добавления переменной в проект дважды кликните по ней или нажмите кнопку `>`, чтобы переместить в правую таблицу.
|
||||||
|
- В **правой таблице** находятся переменные, выбранные для использования.
|
||||||
|
Чтобы убрать переменную из проекта, переместите её обратно в левую таблицу двойным кликом или кнопкой `<`.
|
||||||
|
- После выбора переменных нажмите **Применить**, чтобы обновить основной список переменных и включить их в проект.
|
||||||
|
|
||||||
|
5. Настройте параметры выбранных переменных:
|
||||||
|
- **En** — включение или отключение переменной для генерации;
|
||||||
|
- **Base Type** — базовый тип переменной (например, int8, uint16 и т.д.);
|
||||||
|
- **IQ Type** — формат IQ, если применимо;
|
||||||
|
- **Return Type** — формат возвращаемого значения (IQ-тип или целочисленный);
|
||||||
|
- **Shortname** — короткое имя переменной для для терминалки.
|
||||||
|
|
||||||
|
Все параметры выбираются из выпадающих списков, которые можно настроить, чтобы отображались только нужные опции.
|
||||||
|
|
||||||
|
6. Нажмите **Сгенерировать файл** для создания файла `debug_vars.c` с выбранными переменными.
|
||||||
|
---
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- Загрузка и сохранение настроек переменных в XML-файлах.
|
||||||
|
- Автоматическое определение исходных файлов с переменными для удобства работы.
|
||||||
|
- Редактирование переменных: включение, короткого имени и типов через удобные списки.
|
||||||
|
- Подсветка ошибок при вводе (неправильные имена, слишком длинные короткие имена).
|
||||||
|
- Быстрая фильтрация переменных по столбцам.
|
||||||
|
- Автоматическая генерация файла debug_vars.c с выбранными переменными.
|
||||||
|
- Возможность сразу открыть сгенерированный файл в редакторе.
|
||||||
|
- Умное автодополнение имён переменных и полей структур.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Пример XML-файла
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<project proj_path="C:/myproj" makefile_path="Debug/Makefile" structs_path="debugVars/structs.xml">
|
||||||
|
<variables>
|
||||||
|
<var name="g_myvar">
|
||||||
|
<enable>true</enable>
|
||||||
|
<show_var>true</show_var>
|
||||||
|
<shortname>myv</shortname>
|
||||||
|
<pt_type>pt_float</pt_type>
|
||||||
|
<iq_type>t_iq24</iq_type>
|
||||||
|
<return_type>t_iq24</return_type>
|
||||||
|
<type>float</type>
|
||||||
|
<file>Src/main/main.c</file>
|
||||||
|
<extern>true</extern>
|
||||||
|
<static>false</static>
|
||||||
|
</var>
|
||||||
|
</variables>
|
||||||
|
</project>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Для разработчиков
|
||||||
|
|
||||||
|
### Структура проекта:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Src
|
||||||
|
├── build/
|
||||||
|
│ └── build_and_clean.py # Билдинг проекта в .exe (через nuitka или pyinstaller)
|
||||||
|
├── DebugVarEdit_GUI.py # Главное окно
|
||||||
|
├── var_table.py # Таблица выбранных переменных
|
||||||
|
├── var_selector_window.py # Окно выбора переменных
|
||||||
|
├── var_selector_table.py # Таблица переменных в окне выбора переменных
|
||||||
|
├── scan_progress_gui.py # Отображение процесса сканирования переменных
|
||||||
|
├── scan_vars.py # Сканирование переменных среди .c/.h файлов
|
||||||
|
├── generate_debug_vars.py # Генерация debug_vars.c
|
||||||
|
├── myXML.py # Утилиты для XML
|
||||||
|
├── makefile_parser.py # Парсинг makefile на .c/.h файлы
|
||||||
|
├── var_setup.py # Подготовка переменных для окна выбора переменных
|
||||||
|
├── libclang.dll # Бибилиотека clang
|
||||||
|
├── icon.ico # Иконка
|
||||||
|
```
|
||||||
|
|
||||||
|
### Зависимости
|
||||||
|
|
||||||
|
Для запуска приложения:
|
||||||
|
- **Python 3.7+**
|
||||||
|
- **clang** — используется для парсинга C-кода (требуется `libclang.dll`)
|
||||||
|
- **PySide2** — GUI-фреймворк
|
||||||
|
- **lxml** — работа с XML
|
||||||
|
> Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7
|
||||||
|
|
||||||
|
Для сборки `.exe`:
|
||||||
|
- **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей
|
||||||
|
- **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен)
|
||||||
|
|
||||||
|
|
||||||
|
### Сборка:
|
||||||
|
Если вы хотите собрать `DebugVarEdit.exe` самостоятельно из исходников, используйте скрипт **build/build_and_clean.py**. Он автоматически собирает проект с помощью Nuitka или PyInstaller:
|
||||||
|
- Собирает проект в `DebugVarEdit.exe` в корневой папке.
|
||||||
|
- Включает:
|
||||||
|
- все необходимые `.dll` (например, `libclang.dll`),
|
||||||
|
- иконку (`icon.ico`),
|
||||||
|
- плагины PySide2.
|
||||||
|
- Очищает временные папки после сборки:
|
||||||
|
- `build_temp`
|
||||||
|
- `__pycache__`
|
||||||
|
- `DebugVarEdit_GUI.*`
|
||||||
|
|
||||||
|
> Все пути, имена файлов, временные папки и выбор между Nuitka и PyInstaller можно настроить в начале файла `build_and_clean.py`.
|
||||||
|
|
||||||
|
### Установка зависимостей
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install PySide2 lxml nuitka pyinstaller
|
||||||
|
```
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
# build command
|
# build command
|
||||||
# pyinstaller --onefile --name DebugVarEdit --add-binary "build/libclang.dll;build" --distpath ./ --workpath ./build_temp --specpath ./build_temp setupVars_GUI.py
|
# pyinstaller --onefile --name DebugVarEdit --add-binary "build/libclang.dll;build" --distpath ./ --workpath ./build_temp --specpath ./build_temp var_setup_GUI.py
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import xml.etree.ElementTree as ET
|
import lxml.etree as ET
|
||||||
from generateVars import type_map
|
from generate_debug_vars import type_map
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
import threading
|
import threading
|
||||||
from generateVars import run_generate
|
from generate_debug_vars import run_generate
|
||||||
import setupVars
|
import var_setup
|
||||||
from VariableSelector import VariableSelectorDialog
|
from var_selector_window import VariableSelectorDialog
|
||||||
from VariableTable import VariableTableWidget, rows
|
from var_table import VariableTableWidget, rows
|
||||||
from scanVarGUI import ProcessOutputWindow
|
from scan_progress_gui import ProcessOutputWindow
|
||||||
import scanVars
|
import scan_vars
|
||||||
import myXML
|
import myXML
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -31,12 +31,18 @@ var_edit_title = "Редактор переменных для отладки"
|
|||||||
xml_path_title = "Путь к XML:"
|
xml_path_title = "Путь к XML:"
|
||||||
proj_path_title = "Путь к проекту:"
|
proj_path_title = "Путь к проекту:"
|
||||||
makefile_path_title = "Пусть к makefile (относительно проекта)"
|
makefile_path_title = "Пусть к makefile (относительно проекта)"
|
||||||
output_path_title = "Папка для debug_vars.c:"
|
output_path_title = "Путь для для debug_vars.c:"
|
||||||
scan_title = "Сканировать переменные"
|
scan_title = "Сканировать переменные"
|
||||||
build_title = "Сгенерировать файл"
|
build_title = "Сгенерировать файл"
|
||||||
add_vars_title = "Добавить переменные"
|
add_vars_title = "Добавить переменные"
|
||||||
open_output_title = "Открыть файл"
|
open_output_title = "Открыть файл"
|
||||||
|
|
||||||
|
def set_sub_elem_text(parent, tag, text):
|
||||||
|
el = parent.find(tag)
|
||||||
|
if el is None:
|
||||||
|
el = ET.SubElement(parent, tag)
|
||||||
|
el.text = str(text)
|
||||||
|
|
||||||
# 3. UI: таблица с переменными
|
# 3. UI: таблица с переменными
|
||||||
class VarEditor(QWidget):
|
class VarEditor(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -57,7 +63,7 @@ class VarEditor(QWidget):
|
|||||||
def initUI(self):
|
def initUI(self):
|
||||||
self.setWindowTitle(var_edit_title)
|
self.setWindowTitle(var_edit_title)
|
||||||
|
|
||||||
base_path = scanVars.get_base_path()
|
base_path = scan_vars.get_base_path()
|
||||||
icon_path = os.path.join(base_path, "icon.ico")
|
icon_path = os.path.join(base_path, "icon.ico")
|
||||||
if os.path.exists(icon_path):
|
if os.path.exists(icon_path):
|
||||||
self.setWindowIcon(QIcon(icon_path))
|
self.setWindowIcon(QIcon(icon_path))
|
||||||
@@ -202,7 +208,7 @@ class VarEditor(QWidget):
|
|||||||
|
|
||||||
# Создаём окно с кнопкой "Готово"
|
# Создаём окно с кнопкой "Готово"
|
||||||
self.proc_win = ProcessOutputWindow(self.proj_path, self.makefile_path, self.xml_path,
|
self.proc_win = ProcessOutputWindow(self.proj_path, self.makefile_path, self.xml_path,
|
||||||
on_done_callback=self.__after_scanvars_finished)
|
self.__after_scan_vars_finished, self)
|
||||||
self.proc_win.start_scan()
|
self.proc_win.start_scan()
|
||||||
|
|
||||||
|
|
||||||
@@ -222,8 +228,8 @@ class VarEditor(QWidget):
|
|||||||
var_data = {
|
var_data = {
|
||||||
'name': name_edit.text(),
|
'name': name_edit.text(),
|
||||||
'type': 'pt_' + pt_type_combo.currentText(),
|
'type': 'pt_' + pt_type_combo.currentText(),
|
||||||
'iq_type': iq_combo.currentText(),
|
'iq_type': 't_' + iq_combo.currentText(),
|
||||||
'return_type': ret_combo.currentText() if ret_combo.currentText() else 'int',
|
'return_type': 't_' + ret_combo.currentText() if ret_combo.currentText() else 't_iq_none',
|
||||||
'short_name': short_name_edit.text(),
|
'short_name': short_name_edit.text(),
|
||||||
}
|
}
|
||||||
vars_out.append(var_data)
|
vars_out.append(var_data)
|
||||||
@@ -242,8 +248,8 @@ class VarEditor(QWidget):
|
|||||||
QMessageBox.critical(self, "Ошибка при генерации", str(e))
|
QMessageBox.critical(self, "Ошибка при генерации", str(e))
|
||||||
|
|
||||||
|
|
||||||
def update(self):
|
def update(self, force=0):
|
||||||
if self._updating:
|
if self._updating and (force==0):
|
||||||
return # Уже в процессе обновления — выходим, чтобы избежать рекурсии
|
return # Уже в процессе обновления — выходим, чтобы избежать рекурсии
|
||||||
self._updating = True
|
self._updating = True
|
||||||
|
|
||||||
@@ -296,11 +302,11 @@ class VarEditor(QWidget):
|
|||||||
structs_path_full = myXML.make_absolute_path(structs_path, self.proj_path)
|
structs_path_full = myXML.make_absolute_path(structs_path, self.proj_path)
|
||||||
if structs_path_full and os.path.isfile(structs_path_full):
|
if structs_path_full and os.path.isfile(structs_path_full):
|
||||||
self.structs_path = structs_path_full
|
self.structs_path = structs_path_full
|
||||||
self.structs, self.typedef_map = setupVars.parse_structs(structs_path_full)
|
self.structs, self.typedef_map = var_setup.parse_structs(structs_path_full)
|
||||||
else:
|
else:
|
||||||
self.structs_path = None
|
self.structs_path = None
|
||||||
|
|
||||||
self.vars_list = setupVars.parse_vars(self.xml_path, self.typedef_map)
|
self.vars_list = var_setup.parse_vars(self.xml_path, self.typedef_map)
|
||||||
self.table.populate(self.vars_list, self.structs, self.write_to_xml)
|
self.table.populate(self.vars_list, self.structs, self.write_to_xml)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
|
QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
|
||||||
@@ -398,22 +404,24 @@ class VarEditor(QWidget):
|
|||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
|
||||||
def __after_scanvars_finished(self):
|
def __after_scan_vars_finished(self):
|
||||||
self.update_all_paths()
|
|
||||||
if not os.path.isfile(self.xml_path):
|
if not os.path.isfile(self.xml_path):
|
||||||
|
self.makefile_path = None
|
||||||
|
self.structs_path = None
|
||||||
|
self.proj_path = None
|
||||||
QMessageBox.critical(self, "Ошибка", f"Файл не найден: {self.xml_path}")
|
QMessageBox.critical(self, "Ошибка", f"Файл не найден: {self.xml_path}")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
self.update(1)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
self.makefile_path = None
|
self.makefile_path = None
|
||||||
self.structs_path = None
|
self.structs_path = None
|
||||||
self.proj_path = None
|
self.proj_path = None
|
||||||
self.update()
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить переменные:\n{e}")
|
QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить переменные:\n{e}")
|
||||||
|
|
||||||
|
|
||||||
def delete_selected_rows(self):
|
def delete_selected_rows(self):
|
||||||
# Получаем имена всех выбранных переменных из первого столбца
|
# Получаем имена всех выбранных переменных из первого столбца
|
||||||
selected_names = self.table.get_selected_var_names()
|
selected_names = self.table.get_selected_var_names()
|
||||||
@@ -435,14 +443,26 @@ class VarEditor(QWidget):
|
|||||||
QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).")
|
QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.update()
|
||||||
dlg = VariableSelectorDialog(self.table, 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()
|
||||||
|
|
||||||
|
|
||||||
def write_to_xml(self, dummy=None):
|
def write_to_xml(self, dummy=None):
|
||||||
|
t0 = time.time()
|
||||||
self.update_all_paths()
|
self.update_all_paths()
|
||||||
|
def get_val(name, default=''):
|
||||||
|
return str(v_table[name] if v_table and name in v_table else v.get(name, default))
|
||||||
|
|
||||||
|
def element_differs(elem, values: dict):
|
||||||
|
for tag, new_val in values.items():
|
||||||
|
current_elem = elem.find(tag)
|
||||||
|
current_val = (current_elem.text or '').strip()
|
||||||
|
new_val_str = str(new_val or '').strip()
|
||||||
|
if current_val != new_val_str:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
if not self.xml_path or not os.path.isfile(self.xml_path):
|
if not self.xml_path or not os.path.isfile(self.xml_path):
|
||||||
print("XML файл не найден или путь пустой")
|
print("XML файл не найден или путь пустой")
|
||||||
@@ -467,7 +487,6 @@ class VarEditor(QWidget):
|
|||||||
|
|
||||||
if self.makefile_path and os.path.isfile(self.makefile_path):
|
if self.makefile_path and os.path.isfile(self.makefile_path):
|
||||||
rel_makefile = myXML.make_relative_path(self.makefile_path, self.proj_path)
|
rel_makefile = myXML.make_relative_path(self.makefile_path, self.proj_path)
|
||||||
root.set("makefile_path", rel_makefile)
|
|
||||||
# Если результат — абсолютный путь, не записываем
|
# Если результат — абсолютный путь, не записываем
|
||||||
if not os.path.isabs(rel_makefile):
|
if not os.path.isabs(rel_makefile):
|
||||||
root.set("makefile_path", rel_makefile)
|
root.set("makefile_path", rel_makefile)
|
||||||
@@ -478,6 +497,7 @@ class VarEditor(QWidget):
|
|||||||
if not os.path.isabs(rel_struct):
|
if not os.path.isabs(rel_struct):
|
||||||
root.set("structs_path", rel_struct)
|
root.set("structs_path", rel_struct)
|
||||||
|
|
||||||
|
t1 = time.time()
|
||||||
|
|
||||||
vars_elem = root.find('variables')
|
vars_elem = root.find('variables')
|
||||||
if vars_elem is None:
|
if vars_elem is None:
|
||||||
@@ -492,6 +512,7 @@ class VarEditor(QWidget):
|
|||||||
'extern': var_elem.findtext('extern', ''),
|
'extern': var_elem.findtext('extern', ''),
|
||||||
'static': var_elem.findtext('static', '')
|
'static': var_elem.findtext('static', '')
|
||||||
}
|
}
|
||||||
|
var_elements_by_name = {ve.attrib.get('name'): ve for ve in vars_elem.findall('var')}
|
||||||
|
|
||||||
# Читаем переменные из таблицы (активные/изменённые)
|
# Читаем переменные из таблицы (активные/изменённые)
|
||||||
table_vars = {v['name']: v for v in self.table.read_data()}
|
table_vars = {v['name']: v for v in self.table.read_data()}
|
||||||
@@ -500,63 +521,73 @@ class VarEditor(QWidget):
|
|||||||
|
|
||||||
# Объединённый список переменных для записи
|
# Объединённый список переменных для записи
|
||||||
all_names = list(all_vars_by_name.keys())
|
all_names = list(all_vars_by_name.keys())
|
||||||
|
t2 = time.time()
|
||||||
for name in all_names:
|
for name in all_names:
|
||||||
v = all_vars_by_name[name]
|
v = all_vars_by_name[name]
|
||||||
v_table = table_vars.get(name)
|
v_table = table_vars.get(name)
|
||||||
var_elem = None
|
var_elem = None
|
||||||
|
|
||||||
# Ищем уже существующий <var> в XML
|
pt_type_val = get_val('pt_type').lower()
|
||||||
for ve in vars_elem.findall('var'):
|
|
||||||
if ve.attrib.get('name') == name:
|
|
||||||
var_elem = ve
|
|
||||||
break
|
|
||||||
if var_elem is None:
|
|
||||||
var_elem = ET.SubElement(vars_elem, 'var', {'name': name})
|
|
||||||
|
|
||||||
def set_sub_elem_text(parent, tag, text):
|
|
||||||
el = parent.find(tag)
|
|
||||||
if el is None:
|
|
||||||
el = ET.SubElement(parent, tag)
|
|
||||||
el.text = str(text)
|
|
||||||
|
|
||||||
pt_type_val = v_table['pt_type'] if v_table and 'pt_type' in v_table else v.get('pt_type', '')
|
|
||||||
|
|
||||||
if 'arr' in pt_type_val or 'struct' in pt_type_val or 'union' in pt_type_val:
|
if 'arr' in pt_type_val or 'struct' in pt_type_val or 'union' in pt_type_val:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
show_var_val = str(v.get('show_var', 'false')).lower()
|
show_var_val = str(v.get('show_var', 'false')).lower()
|
||||||
enable_val = str(v_table['enable'] if v_table and 'enable' in v_table else v.get('enable', 'false')).lower()
|
enable_val = get_val('enable').lower()
|
||||||
|
|
||||||
set_sub_elem_text(var_elem, 'show_var', show_var_val)
|
|
||||||
set_sub_elem_text(var_elem, 'enable', enable_val)
|
|
||||||
|
|
||||||
# Тут подтягиваем из таблицы, если есть, иначе из v
|
# Тут подтягиваем из таблицы, если есть, иначе из v
|
||||||
shortname_val = v_table['shortname'] if v_table and 'shortname' in v_table else v.get('shortname', '')
|
shortname_val = get_val('shortname')
|
||||||
iq_type_val = v_table['iq_type'] if v_table and 'iq_type' in v_table else v.get('iq_type', '')
|
iq_type_val = get_val('iq_type')
|
||||||
ret_type_val = v_table['return_type'] if v_table and 'return_type' in v_table else v.get('return_type', '')
|
ret_type_val = get_val('return_type')
|
||||||
|
|
||||||
set_sub_elem_text(var_elem, 'shortname', shortname_val)
|
|
||||||
set_sub_elem_text(var_elem, 'pt_type', pt_type_val)
|
|
||||||
set_sub_elem_text(var_elem, 'iq_type', iq_type_val)
|
|
||||||
set_sub_elem_text(var_elem, 'return_type', ret_type_val)
|
|
||||||
set_sub_elem_text(var_elem, 'type', v.get('type', ''))
|
|
||||||
|
|
||||||
# file/extern/static: из original_info, либо из v
|
# file/extern/static: из original_info, либо из v
|
||||||
file_val = v.get('file') or original_info.get(name, {}).get('file', '')
|
file_val = v.get('file') or original_info.get(name, {}).get('file', '')
|
||||||
extern_val = v.get('extern') or original_info.get(name, {}).get('extern', '')
|
extern_val = v.get('extern') or original_info.get(name, {}).get('extern', '')
|
||||||
static_val = v.get('static') or original_info.get(name, {}).get('static', '')
|
static_val = v.get('static') or original_info.get(name, {}).get('static', '')
|
||||||
|
|
||||||
set_sub_elem_text(var_elem, 'file', file_val)
|
values_to_write = {
|
||||||
set_sub_elem_text(var_elem, 'extern', extern_val)
|
'show_var': show_var_val,
|
||||||
set_sub_elem_text(var_elem, 'static', static_val)
|
'enable': enable_val,
|
||||||
|
'shortname': shortname_val,
|
||||||
|
'pt_type': pt_type_val,
|
||||||
|
'iq_type': iq_type_val,
|
||||||
|
'return_type': ret_type_val,
|
||||||
|
'type': v.get('type', ''),
|
||||||
|
'file': file_val,
|
||||||
|
'extern': extern_val,
|
||||||
|
'static': static_val
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ищем уже существующий <var> в XML
|
||||||
|
var_elem = var_elements_by_name.get(name)
|
||||||
|
# Если элемента нет, это новая переменная — сразу пишем
|
||||||
|
if var_elem is None:
|
||||||
|
var_elem = ET.SubElement(vars_elem, 'var', {'name': name})
|
||||||
|
var_elements_by_name[name] = var_elem
|
||||||
|
write_all = True # обязательно записать все поля
|
||||||
|
else:
|
||||||
|
write_all = element_differs(var_elem, values_to_write)
|
||||||
|
|
||||||
|
if not write_all:
|
||||||
|
continue # Пропускаем, если нет изменений
|
||||||
|
|
||||||
|
for tag, text in values_to_write.items():
|
||||||
|
set_sub_elem_text(var_elem, tag, text)
|
||||||
|
|
||||||
|
t3 = time.time()
|
||||||
# Преобразуем дерево в строку
|
# Преобразуем дерево в строку
|
||||||
self.table.check()
|
|
||||||
myXML.fwrite(root, self.xml_path)
|
myXML.fwrite(root, self.xml_path)
|
||||||
|
self.table.check()
|
||||||
|
t4 = time.time()
|
||||||
|
'''print(f"[T1] parse + set paths: {t1 - t0:.3f} сек")
|
||||||
|
print(f"[T2] prepare variables: {t2 - t1:.3f} сек")
|
||||||
|
print(f"[T3] loop + updates: {t3 - t2:.3f} сек")
|
||||||
|
print(f"[T4] write to file: {t4 - t3:.3f} сек")
|
||||||
|
print(f"[TOTAL] write_to_xml total: {t4 - t0:.3f} сек")'''
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ошибка при сохранении XML: {e}")
|
print(f"Ошибка при сохранении XML: {e}")
|
||||||
|
|
||||||
|
|
||||||
def __open_output_file_with_program(self):
|
def __open_output_file_with_program(self):
|
||||||
output_path = self.get_output_path()
|
output_path = self.get_output_path()
|
||||||
if not output_path:
|
if not output_path:
|
||||||
|
|||||||
55
Src/README_DEVELOP.md
Normal file
55
Src/README_DEVELOP.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Для разработчиков
|
||||||
|
|
||||||
|
### Структура проекта:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Src
|
||||||
|
├── build/
|
||||||
|
│ └── build_and_clean.py # Билдинг проекта в .exe (через nuitka или pyinstaller)
|
||||||
|
├── DebugVarEdit_GUI.py # Главное окно
|
||||||
|
├── var_table.py # Таблица выбранных переменных
|
||||||
|
├── var_selector_window.py # Окно выбора переменных
|
||||||
|
├── var_selector_table.py # Таблица переменных в окне выбора переменных
|
||||||
|
├── scan_progress_gui.py # Отображение процесса сканирования переменных
|
||||||
|
├── scan_vars.py # Сканирование переменных среди .c/.h файлов
|
||||||
|
├── generate_debug_vars.py # Генерация debug_vars.c
|
||||||
|
├── myXML.py # Утилиты для XML
|
||||||
|
├── makefile_parser.py # Парсинг makefile на .c/.h файлы
|
||||||
|
├── var_setup.py # Подготовка переменных для окна выбора переменных
|
||||||
|
├── libclang.dll # Бибилиотека clang
|
||||||
|
├── icon.ico # Иконка
|
||||||
|
```
|
||||||
|
|
||||||
|
### Зависимости
|
||||||
|
|
||||||
|
Для запуска приложения:
|
||||||
|
- **Python 3.7+**
|
||||||
|
- **clang** — используется для парсинга C-кода (требуется `libclang.dll`)
|
||||||
|
- **PySide2** — GUI-фреймворк
|
||||||
|
- **lxml** — работа с XML
|
||||||
|
> Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7
|
||||||
|
|
||||||
|
Для сборки `.exe`:
|
||||||
|
- **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей
|
||||||
|
- **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен)
|
||||||
|
|
||||||
|
|
||||||
|
### Сборка:
|
||||||
|
Если вы хотите собрать `DebugVarEdit.exe` самостоятельно из исходников, используйте скрипт **build/build_and_clean.py**. Он автоматически собирает проект с помощью Nuitka или PyInstaller:
|
||||||
|
- Собирает проект в `DebugVarEdit.exe` в корневой папке.
|
||||||
|
- Включает:
|
||||||
|
- все необходимые `.dll` (например, `libclang.dll`),
|
||||||
|
- иконку (`icon.ico`),
|
||||||
|
- плагины PySide2.
|
||||||
|
- Очищает временные папки после сборки:
|
||||||
|
- `build_temp`
|
||||||
|
- `__pycache__`
|
||||||
|
- `DebugVarEdit_GUI.*`
|
||||||
|
|
||||||
|
> Все пути, имена файлов, временные папки и выбор между Nuitka и PyInstaller можно настроить в начале файла `build_and_clean.py`.
|
||||||
|
|
||||||
|
### Установка зависимостей
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install PySide2 lxml nuitka pyinstaller
|
||||||
|
```
|
||||||
@@ -2,13 +2,11 @@ import subprocess
|
|||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PIL import Image # нужна библиотека Pillow для конвертации PNG в ICO
|
|
||||||
import PySide2
|
import PySide2
|
||||||
from PyInstaller.utils.hooks import collect_data_files
|
from PyInstaller.utils.hooks import collect_data_files
|
||||||
# install:
|
# install: pip install PySide2 lxml nuitka pyinstaller
|
||||||
# - PyInstaller
|
# - PyInstaller
|
||||||
# - nuitka
|
# - nuitka
|
||||||
# - Pillow
|
|
||||||
# - PySide2
|
# - PySide2
|
||||||
# - clang
|
# - clang
|
||||||
|
|
||||||
@@ -25,6 +23,13 @@ SPEC_PATH = WORK_PATH
|
|||||||
ICON_PATH = SRC_PATH / "icon.png"
|
ICON_PATH = SRC_PATH / "icon.png"
|
||||||
ICON_ICO_PATH = SRC_PATH / "icon.ico"
|
ICON_ICO_PATH = SRC_PATH / "icon.ico"
|
||||||
|
|
||||||
|
TEMP_FOLDERS = [
|
||||||
|
"build_temp",
|
||||||
|
"__pycache__",
|
||||||
|
"DebugVarEdit_GUI.build",
|
||||||
|
"DebugVarEdit_GUI.onefile-build",
|
||||||
|
"DebugVarEdit_GUI.dist"
|
||||||
|
]
|
||||||
# === Пути к DLL и прочим зависимостям ===
|
# === Пути к DLL и прочим зависимостям ===
|
||||||
LIBS = {
|
LIBS = {
|
||||||
"libclang.dll": SRC_PATH / "libclang.dll"
|
"libclang.dll": SRC_PATH / "libclang.dll"
|
||||||
@@ -48,7 +53,7 @@ for name, path in LIBS.items():
|
|||||||
print(f"WARNING: {path.name} не найден — он не будет включён в сборку")
|
print(f"WARNING: {path.name} не найден — он не будет включён в сборку")
|
||||||
|
|
||||||
def clean_temp():
|
def clean_temp():
|
||||||
for folder in ["build_temp", "__pycache__", "DebugVarEdit_GUI.build", "DebugVarEdit_GUI.dist", "DebugVarEdit_GUI.onefile-build"]:
|
for folder in TEMP_FOLDERS:
|
||||||
path = Path(folder)
|
path = Path(folder)
|
||||||
if path.exists():
|
if path.exists():
|
||||||
shutil.rmtree(path, ignore_errors=True)
|
shutil.rmtree(path, ignore_errors=True)
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
# build command
|
# build command
|
||||||
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build generateVars.py
|
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build generate_debug_vars.py
|
||||||
# start script
|
# start script
|
||||||
# generateVars.exe F:\Work\Projects\TMS\TMS_new_bus\ Src/DebugTools/vars.xml Src/DebugTools
|
# generate_debug_vars.exe F:\Work\Projects\TMS\TMS_new_bus\ Src/DebugTools/vars.xml Src/DebugTools
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import xml.etree.ElementTree as ET
|
import lxml.etree as ET
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
import myXML
|
import myXML
|
||||||
36
Src/myXML.py
36
Src/myXML.py
@@ -1,5 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
import xml.etree.ElementTree as ET
|
from lxml import etree
|
||||||
|
|
||||||
def make_absolute_path(path, base_path):
|
def make_absolute_path(path, base_path):
|
||||||
if not os.path.isabs(path) and os.path.isdir(base_path):
|
if not os.path.isabs(path) and os.path.isdir(base_path):
|
||||||
@@ -33,44 +33,38 @@ def make_relative_path(abs_path, base_path):
|
|||||||
return abs_path.replace("\\", "/")
|
return abs_path.replace("\\", "/")
|
||||||
|
|
||||||
def indent_xml(elem, level=0):
|
def indent_xml(elem, level=0):
|
||||||
indent = " "
|
# Убираем strip() — они медленные, и текст мы всё равно перезаписываем
|
||||||
i = "\n" + level * indent
|
i = "\n" + level * " "
|
||||||
if len(elem):
|
if len(elem):
|
||||||
if not elem.text or not elem.text.strip():
|
elem.text = elem.text or i + " "
|
||||||
elem.text = i + indent
|
|
||||||
for child in elem:
|
for child in elem:
|
||||||
indent_xml(child, level + 1)
|
indent_xml(child, level + 1)
|
||||||
if not elem.tail or not elem.tail.strip():
|
elem[-1].tail = elem[-1].tail or i
|
||||||
elem.tail = i
|
|
||||||
else:
|
else:
|
||||||
if level and (not elem.tail or not elem.tail.strip()):
|
elem.tail = elem.tail or i
|
||||||
elem.tail = i
|
|
||||||
|
|
||||||
|
|
||||||
def fwrite(root, xml_full_path):
|
def fwrite(root, xml_full_path):
|
||||||
indent_xml(root)
|
#indent_xml(root)
|
||||||
ET.ElementTree(root).write(xml_full_path, encoding="utf-8", xml_declaration=True)
|
#ET.ElementTree(root).write(xml_full_path, encoding="utf-8", xml_declaration=True)
|
||||||
|
rough_string = etree.tostring(root, encoding="utf-8")
|
||||||
|
parsed = etree.fromstring(rough_string)
|
||||||
|
with open(xml_full_path, "wb") as f:
|
||||||
|
f.write(etree.tostring(parsed, pretty_print=True, encoding="utf-8", xml_declaration=True))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def safe_parse_xml(xml_path):
|
def safe_parse_xml(xml_path):
|
||||||
"""
|
|
||||||
Безопасно парсит XML-файл.
|
|
||||||
|
|
||||||
Возвращает кортеж (root, tree) или (None, None) при ошибках.
|
|
||||||
"""
|
|
||||||
if not xml_path or not os.path.isfile(xml_path):
|
if not xml_path or not os.path.isfile(xml_path):
|
||||||
print(f"Файл '{xml_path}' не найден или путь пустой")
|
print(f"Файл '{xml_path}' не найден или путь пустой")
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if os.path.getsize(xml_path) == 0:
|
if os.path.getsize(xml_path) == 0:
|
||||||
return None, None
|
return None, None
|
||||||
|
tree = etree.parse(xml_path)
|
||||||
tree = ET.parse(xml_path)
|
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
return root, tree
|
return root, tree
|
||||||
|
except etree .XMLSyntaxError as e:
|
||||||
except ET.ParseError as e:
|
|
||||||
print(f"Ошибка парсинга XML файла '{xml_path}': {e}")
|
print(f"Ошибка парсинга XML файла '{xml_path}': {e}")
|
||||||
return None, None
|
return None, None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Binary file not shown.
@@ -6,8 +6,8 @@ import sys
|
|||||||
import contextlib
|
import contextlib
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
from scanVars import run_scan
|
from scan_vars import run_scan
|
||||||
from VariableTable import VariableTableWidget, rows
|
from var_table import VariableTableWidget, rows
|
||||||
|
|
||||||
from PySide2.QtWidgets import (
|
from PySide2.QtWidgets import (
|
||||||
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
||||||
@@ -73,13 +73,13 @@ class EmittingStream(QObject):
|
|||||||
self._buffer = ""
|
self._buffer = ""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessOutputWindow(QDialog):
|
class ProcessOutputWindow(QDialog):
|
||||||
def __init__(self, proj_path, makefile_path, xml_path, on_done_callback=None):
|
def __init__(self, proj_path, makefile_path, xml_path, on_done_callback=None, parent=None):
|
||||||
super().__init__()
|
super().__init__(parent)
|
||||||
self.setWindowTitle("Поиск переменных...")
|
self.setWindowTitle("Поиск переменных...")
|
||||||
self.resize(600, 480)
|
self.resize(600, 480)
|
||||||
self.setModal(True)
|
self.setModal(True)
|
||||||
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||||
|
|
||||||
self.proj_path = proj_path
|
self.proj_path = proj_path
|
||||||
self.makefile_path = makefile_path
|
self.makefile_path = makefile_path
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# build command
|
# build command
|
||||||
# pyinstaller --onefile scanVars.py --add-binary "F:\Work\Projects\TMS\TMS_new_bus\Src\DebugTools/build/libclang.dll;." --distpath . --workpath ./build --specpath ./build
|
# pyinstaller --onefile scan_vars.py --add-binary "F:\Work\Projects\TMS\TMS_new_bus\Src\DebugTools/build/libclang.dll;." --distpath . --workpath ./build --specpath ./build
|
||||||
# start script
|
# start script
|
||||||
# scanVars.exe F:\Work\Projects\TMS\TMS_new_bus\ F:\Work\Projects\TMS\TMS_new_bus\Debug\makefile
|
# scan_vars.exe F:\Work\Projects\TMS\TMS_new_bus\ F:\Work\Projects\TMS\TMS_new_bus\Debug\makefile
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@@ -9,9 +9,9 @@ import re
|
|||||||
import clang.cindex
|
import clang.cindex
|
||||||
from clang import cindex
|
from clang import cindex
|
||||||
from clang.cindex import Config
|
from clang.cindex import Config
|
||||||
import xml.etree.ElementTree as ET
|
import lxml.etree as ET
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
from parseMakefile import parse_makefile
|
from makefile_parser import parse_makefile
|
||||||
from collections import deque
|
from collections import deque
|
||||||
import argparse
|
import argparse
|
||||||
import myXML
|
import myXML
|
||||||
@@ -545,7 +545,7 @@ def read_vars_from_xml(xml_path):
|
|||||||
'shortname': var_elem.findtext('shortname', name),
|
'shortname': var_elem.findtext('shortname', name),
|
||||||
'pt_type': var_elem.findtext('pt_type', ''),
|
'pt_type': var_elem.findtext('pt_type', ''),
|
||||||
'iq_type': var_elem.findtext('iq_type', ''),
|
'iq_type': var_elem.findtext('iq_type', ''),
|
||||||
'return_type': var_elem.findtext('return_type', 'int'),
|
'return_type': var_elem.findtext('return_type', 't_iq_none'),
|
||||||
'type': var_elem.findtext('type', 'unknown'),
|
'type': var_elem.findtext('type', 'unknown'),
|
||||||
'file': var_elem.findtext('file', ''),
|
'file': var_elem.findtext('file', ''),
|
||||||
'extern': get_bool('extern'),
|
'extern': get_bool('extern'),
|
||||||
@@ -608,7 +608,7 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
|
|||||||
'shortname': info.get('shortname', name),
|
'shortname': info.get('shortname', name),
|
||||||
'pt_type': info.get('pt_type', ''),
|
'pt_type': info.get('pt_type', ''),
|
||||||
'iq_type': info.get('iq_type', ''),
|
'iq_type': info.get('iq_type', ''),
|
||||||
'return_type': info.get('return_type', 'int'),
|
'return_type': info.get('return_type', 't_iq_none'),
|
||||||
'type': info.get('type', 'unknown'),
|
'type': info.get('type', 'unknown'),
|
||||||
'file': info.get('file', ''),
|
'file': info.get('file', ''),
|
||||||
'extern': info.get('extern', False),
|
'extern': info.get('extern', False),
|
||||||
@@ -627,7 +627,7 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
|
|||||||
ET.SubElement(var_elem, "shortname").text = info.get('shortname', name)
|
ET.SubElement(var_elem, "shortname").text = info.get('shortname', name)
|
||||||
ET.SubElement(var_elem, "pt_type").text = info.get('pt_type', '')
|
ET.SubElement(var_elem, "pt_type").text = info.get('pt_type', '')
|
||||||
ET.SubElement(var_elem, "iq_type").text = info.get('iq_type', '')
|
ET.SubElement(var_elem, "iq_type").text = info.get('iq_type', '')
|
||||||
ET.SubElement(var_elem, "return_type").text = info.get('return_type', 'int')
|
ET.SubElement(var_elem, "return_type").text = info.get('return_type', 't_iq_none')
|
||||||
|
|
||||||
ET.SubElement(var_elem, "type").text = info.get('type', 'unknown')
|
ET.SubElement(var_elem, "type").text = info.get('type', 'unknown')
|
||||||
rel_file = make_relative_if_possible(info.get('file', ''), proj_path).replace("\\", "/")
|
rel_file = make_relative_if_possible(info.get('file', ''), proj_path).replace("\\", "/")
|
||||||
@@ -7,6 +7,10 @@ from PySide2.QtGui import QKeyEvent
|
|||||||
from PySide2.QtCore import Qt, QStringListModel
|
from PySide2.QtCore import Qt, QStringListModel
|
||||||
import pickle
|
import pickle
|
||||||
import time
|
import time
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
def compute_vars_hash(vars_list):
|
||||||
|
return hashlib.sha1(pickle.dumps(vars_list)).hexdigest()
|
||||||
|
|
||||||
# Вспомогательные функции, которые теперь будут использоваться виджетом
|
# Вспомогательные функции, которые теперь будут использоваться виджетом
|
||||||
def split_path(path):
|
def split_path(path):
|
||||||
@@ -59,35 +63,136 @@ def split_path(path):
|
|||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
# Функция парсит имя с индексами в (базовое_имя, список_индексов)
|
def is_lazy_item(item):
|
||||||
def parse_name_with_indices(name):
|
return item.childCount() == 1 and item.child(0).text(0) == 'lazy_marker'
|
||||||
# Регулярка для имени и индексов:
|
|
||||||
# имя - подряд букв/цифр/подчёркиваний,
|
|
||||||
# индексы в квадратных скобках
|
|
||||||
base_match = re.match(r'^([a-zA-Z_]\w*)', name)
|
|
||||||
if not base_match:
|
|
||||||
return name, [] # если не совпало, возвращаем как есть
|
|
||||||
|
|
||||||
base_name = base_match.group(1)
|
|
||||||
indices = re.findall(r'\[(\d+)\]', name)
|
|
||||||
indices = list(map(int, indices))
|
|
||||||
return base_name, indices
|
|
||||||
|
|
||||||
def match_path_part(search_part, node_part):
|
|
||||||
# Если часть — индекс (вида [N]), требуем точное совпадение
|
|
||||||
if search_part.startswith('[') and search_part.endswith(']'):
|
|
||||||
return search_part == node_part
|
|
||||||
|
|
||||||
# Если search_part содержит '[', значит поиск неполный индекс
|
|
||||||
if '[' in search_part:
|
|
||||||
return node_part.startswith(search_part)
|
|
||||||
|
|
||||||
# Иначе — обычное имя: допускаем совпадение по префиксу
|
|
||||||
return node_part.startswith(search_part)
|
|
||||||
|
|
||||||
|
|
||||||
|
class VariableSelectWidget(QWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.expanded_vars = []
|
||||||
|
self.node_index = {}
|
||||||
|
self.is_autocomplete_on = True # <--- ДОБАВИТЬ ЭТУ СТРОКУ
|
||||||
|
self._bckspc_pressed = False
|
||||||
|
self.manual_completion_active = False
|
||||||
|
self._vars_hash = None
|
||||||
|
|
||||||
def show_matching_path(item, path_parts, level=0):
|
# --- UI Элементы ---
|
||||||
|
self.search_input = QLineEdit(self)
|
||||||
|
self.search_input.setPlaceholderText("Поиск...")
|
||||||
|
|
||||||
|
self.tree = QTreeWidget(self)
|
||||||
|
self.tree.setHeaderLabels(["Имя переменной", "Тип"])
|
||||||
|
self.tree.setSelectionMode(QTreeWidget.ExtendedSelection)
|
||||||
|
self.tree.setRootIsDecorated(True)
|
||||||
|
self.tree.setUniformRowHeights(True)
|
||||||
|
self.tree.setStyleSheet("""
|
||||||
|
QTreeWidget::item:selected { background-color: #87CEFA; color: black; }
|
||||||
|
QTreeWidget::item:hover { background-color: #D3D3D3; }
|
||||||
|
""")
|
||||||
|
self.tree.itemExpanded.connect(self.on_item_expanded)
|
||||||
|
|
||||||
|
self.completer = QCompleter(self)
|
||||||
|
self.completer.setCompletionMode(QCompleter.PopupCompletion)
|
||||||
|
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
|
||||||
|
self.completer.setFilterMode(Qt.MatchContains)
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
|
|
||||||
|
# --- Layout ---
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.addWidget(self.search_input)
|
||||||
|
layout.addWidget(self.tree)
|
||||||
|
|
||||||
|
# --- Соединения ---
|
||||||
|
#self.search_input.textChanged.connect(self.on_search_text_changed)
|
||||||
|
self.search_input.textChanged.connect(lambda text: self.on_search_text_changed(text))
|
||||||
|
self.search_input.installEventFilter(self)
|
||||||
|
self.completer.activated[str].connect(lambda text: self.insert_completion(text))
|
||||||
|
|
||||||
|
# --- Публичные методы для управления виджетом снаружи ---
|
||||||
|
|
||||||
|
def set_autocomplete(self, enabled: bool):
|
||||||
|
"""Включает или выключает режим автодополнения."""
|
||||||
|
self.is_autocomplete_on = enabled
|
||||||
|
|
||||||
|
def set_data(self, vars_list):
|
||||||
|
"""Основной метод для загрузки данных в виджет."""
|
||||||
|
self.expanded_vars = pickle.loads(pickle.dumps(vars_list, protocol=pickle.HIGHEST_PROTOCOL))
|
||||||
|
# self.build_completion_list() # Если нужна полная перестройка списка
|
||||||
|
self.populate_tree()
|
||||||
|
|
||||||
|
|
||||||
|
def populate_tree(self, vars_list=None):
|
||||||
|
if vars_list is None:
|
||||||
|
vars_list = self.expanded_vars
|
||||||
|
|
||||||
|
new_hash = compute_vars_hash(vars_list)
|
||||||
|
if self._vars_hash == new_hash:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._vars_hash = new_hash
|
||||||
|
self.tree.setUpdatesEnabled(False)
|
||||||
|
self.tree.blockSignals(True)
|
||||||
|
self.tree.clear()
|
||||||
|
self.node_index.clear()
|
||||||
|
|
||||||
|
for var in vars_list:
|
||||||
|
self.add_tree_item_lazy(None, var)
|
||||||
|
|
||||||
|
self.tree.setUpdatesEnabled(True)
|
||||||
|
self.tree.blockSignals(False)
|
||||||
|
header = self.tree.header()
|
||||||
|
header.setSectionResizeMode(QHeaderView.Interactive)
|
||||||
|
header.setSectionResizeMode(1, QHeaderView.Stretch)
|
||||||
|
self.tree.setColumnWidth(0, 400)
|
||||||
|
|
||||||
|
def on_item_expanded(self, item):
|
||||||
|
if is_lazy_item(item):
|
||||||
|
item.removeChild(item.child(0))
|
||||||
|
var = item.data(0, Qt.UserRole + 100)
|
||||||
|
if var:
|
||||||
|
for child_var in var.get('children', []):
|
||||||
|
self.add_tree_item_lazy(item, child_var)
|
||||||
|
|
||||||
|
|
||||||
|
def get_full_item_name(self, item):
|
||||||
|
fullname = item.text(0)
|
||||||
|
# Заменяем '->' на '.'
|
||||||
|
fullname = fullname.replace('->', '.')
|
||||||
|
fullname = fullname.replace('[', '.[')
|
||||||
|
return fullname
|
||||||
|
|
||||||
|
def add_tree_item_lazy(self, parent, var):
|
||||||
|
name = var['name']
|
||||||
|
type_str = var.get('type', '')
|
||||||
|
item = QTreeWidgetItem([name, type_str])
|
||||||
|
item.setData(0, Qt.UserRole, name)
|
||||||
|
full_name = self.get_full_item_name(item)
|
||||||
|
self.node_index[full_name.lower()] = item
|
||||||
|
|
||||||
|
if "(bitfield:" in type_str:
|
||||||
|
item.setDisabled(True)
|
||||||
|
self.set_tool(item, "Битовые поля недоступны для выбора")
|
||||||
|
|
||||||
|
for i, attr in enumerate(['file', 'extern', 'static']):
|
||||||
|
item.setData(0, Qt.UserRole + 1 + i, var.get(attr))
|
||||||
|
|
||||||
|
if parent is None:
|
||||||
|
self.tree.addTopLevelItem(item)
|
||||||
|
else:
|
||||||
|
parent.addChild(item)
|
||||||
|
|
||||||
|
# Если есть дети — добавляем заглушку (чтобы можно было раскрыть)
|
||||||
|
if var.get('children'):
|
||||||
|
dummy = QTreeWidgetItem(["lazy_marker"])
|
||||||
|
item.addChild(dummy)
|
||||||
|
|
||||||
|
# Кэшируем детей для подгрузки по событию
|
||||||
|
item.setData(0, Qt.UserRole + 100, var) # Сохраняем var целиком
|
||||||
|
|
||||||
|
|
||||||
|
def show_matching_path(self, item, path_parts, level=0):
|
||||||
node_name = item.text(0).lower()
|
node_name = item.text(0).lower()
|
||||||
node_parts = split_path(node_name)
|
node_parts = split_path(node_name)
|
||||||
|
|
||||||
@@ -111,9 +216,10 @@ def show_matching_path(item, path_parts, level=0):
|
|||||||
# Точное совпадение — показываем узел, идём вглубь только по совпадениям
|
# Точное совпадение — показываем узел, идём вглубь только по совпадениям
|
||||||
item.setHidden(False)
|
item.setHidden(False)
|
||||||
matched_any = False
|
matched_any = False
|
||||||
|
self.on_item_expanded(item)
|
||||||
for i in range(item.childCount()):
|
for i in range(item.childCount()):
|
||||||
child = item.child(i)
|
child = item.child(i)
|
||||||
if show_matching_path(child, path_parts, level + 1):
|
if self.show_matching_path(child, path_parts, level + 1):
|
||||||
matched_any = True
|
matched_any = True
|
||||||
item.setExpanded(matched_any)
|
item.setExpanded(matched_any)
|
||||||
return matched_any or item.childCount() == 0
|
return matched_any or item.childCount() == 0
|
||||||
@@ -136,133 +242,6 @@ def show_matching_path(item, path_parts, level=0):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class VariableSelectWidget(QWidget):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.expanded_vars = []
|
|
||||||
self.node_index = {}
|
|
||||||
self.is_autocomplete_on = True # <--- ДОБАВИТЬ ЭТУ СТРОКУ
|
|
||||||
self._bckspc_pressed = False
|
|
||||||
self.manual_completion_active = False
|
|
||||||
|
|
||||||
# --- UI Элементы ---
|
|
||||||
self.search_input = QLineEdit()
|
|
||||||
self.search_input.setPlaceholderText("Поиск...")
|
|
||||||
|
|
||||||
self.tree = QTreeWidget()
|
|
||||||
self.tree.setHeaderLabels(["Имя переменной", "Тип"])
|
|
||||||
self.tree.setSelectionMode(QTreeWidget.ExtendedSelection)
|
|
||||||
self.tree.setRootIsDecorated(True)
|
|
||||||
self.tree.setUniformRowHeights(True)
|
|
||||||
self.tree.setStyleSheet("""
|
|
||||||
QTreeWidget::item:selected { background-color: #87CEFA; color: black; }
|
|
||||||
QTreeWidget::item:hover { background-color: #D3D3D3; }
|
|
||||||
""")
|
|
||||||
|
|
||||||
self.completer = QCompleter()
|
|
||||||
self.completer.setCompletionMode(QCompleter.PopupCompletion)
|
|
||||||
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
|
|
||||||
self.completer.setFilterMode(Qt.MatchContains)
|
|
||||||
self.completer.setWidget(self.search_input)
|
|
||||||
|
|
||||||
# --- Layout ---
|
|
||||||
layout = QVBoxLayout(self)
|
|
||||||
layout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
layout.addWidget(self.search_input)
|
|
||||||
layout.addWidget(self.tree)
|
|
||||||
|
|
||||||
# --- Соединения ---
|
|
||||||
self.search_input.textChanged.connect(self.on_search_text_changed)
|
|
||||||
self.search_input.installEventFilter(self)
|
|
||||||
self.completer.activated[str].connect(self.insert_completion)
|
|
||||||
|
|
||||||
# --- Публичные методы для управления виджетом снаружи ---
|
|
||||||
|
|
||||||
def set_autocomplete(self, enabled: bool):
|
|
||||||
"""Включает или выключает режим автодополнения."""
|
|
||||||
self.is_autocomplete_on = enabled
|
|
||||||
|
|
||||||
def set_data(self, vars_list):
|
|
||||||
"""Основной метод для загрузки данных в виджет."""
|
|
||||||
self.expanded_vars = pickle.loads(pickle.dumps(vars_list, protocol=pickle.HIGHEST_PROTOCOL))
|
|
||||||
# self.build_completion_list() # Если нужна полная перестройка списка
|
|
||||||
self.populate_tree()
|
|
||||||
|
|
||||||
|
|
||||||
def populate_tree(self, vars_list=None):
|
|
||||||
if vars_list is None:
|
|
||||||
vars_list = self.expanded_vars
|
|
||||||
self.tree.setUpdatesEnabled(False)
|
|
||||||
self.tree.blockSignals(True)
|
|
||||||
self.tree.clear()
|
|
||||||
self.node_index.clear()
|
|
||||||
start_add = time.perf_counter()
|
|
||||||
stats = {'count': 0, 'time': 0.0}
|
|
||||||
for var in vars_list:
|
|
||||||
self.add_tree_item_recursively(None, var, stats)
|
|
||||||
end_add = time.perf_counter()
|
|
||||||
|
|
||||||
print(f" add items: {end_add - start_add:.6f} s")
|
|
||||||
print(f" └ recursive only: {stats['time']:.6f} s")
|
|
||||||
print(f" └ total items: {stats['count']} шт")
|
|
||||||
|
|
||||||
self.tree.setUpdatesEnabled(True)
|
|
||||||
self.tree.blockSignals(False)
|
|
||||||
header = self.tree.header()
|
|
||||||
header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять
|
|
||||||
self.tree.setColumnWidth(0, 400)
|
|
||||||
self.tree.resizeColumnToContents(1)
|
|
||||||
|
|
||||||
|
|
||||||
def get_full_item_name(self, item):
|
|
||||||
names = []
|
|
||||||
while item:
|
|
||||||
names.append(item.text(0))
|
|
||||||
item = item.parent()
|
|
||||||
fullname = '.'.join(reversed(names))
|
|
||||||
# Заменяем '->' на '.'
|
|
||||||
fullname = fullname.replace('->', '.')
|
|
||||||
return fullname
|
|
||||||
|
|
||||||
|
|
||||||
def add_tree_item_recursively(self, parent, var, stats=None, parent_path=""):
|
|
||||||
if stats is None:
|
|
||||||
stats = {'count': 0, 'time': 0.0}
|
|
||||||
|
|
||||||
start = time.perf_counter()
|
|
||||||
|
|
||||||
name = var['name']
|
|
||||||
full_name = f"{parent_path}.{name}" if parent_path else name
|
|
||||||
full_name = full_name.replace('->', '.') # если нужно
|
|
||||||
|
|
||||||
type_str = var.get('type', '')
|
|
||||||
item = QTreeWidgetItem([name, type_str])
|
|
||||||
item.setData(0, Qt.UserRole, name)
|
|
||||||
self.node_index[full_name.lower()] = item
|
|
||||||
|
|
||||||
if "(bitfield:" in type_str:
|
|
||||||
item.setDisabled(True)
|
|
||||||
self.set_tool(item, "Битовые поля недоступны для выбора")
|
|
||||||
|
|
||||||
for i, attr in enumerate(['file', 'extern', 'static']):
|
|
||||||
item.setData(0, Qt.UserRole + 1 + i, var.get(attr))
|
|
||||||
|
|
||||||
if parent is None:
|
|
||||||
self.tree.addTopLevelItem(item)
|
|
||||||
else:
|
|
||||||
parent.addChild(item)
|
|
||||||
|
|
||||||
stats['count'] += 1
|
|
||||||
|
|
||||||
for child in var.get('children', []):
|
|
||||||
self.add_tree_item_recursively(item, child, stats, parent_path=full_name)
|
|
||||||
|
|
||||||
end = time.perf_counter()
|
|
||||||
stats['time'] += end - start
|
|
||||||
return stats
|
|
||||||
|
|
||||||
|
|
||||||
def filter_tree(self):
|
def filter_tree(self):
|
||||||
text = self.search_input.text().strip().lower()
|
text = self.search_input.text().strip().lower()
|
||||||
path_parts = split_path(text) if text else []
|
path_parts = split_path(text) if text else []
|
||||||
@@ -279,7 +258,7 @@ class VariableSelectWidget(QWidget):
|
|||||||
else:
|
else:
|
||||||
for i in range(self.tree.topLevelItemCount()):
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
item = self.tree.topLevelItem(i)
|
item = self.tree.topLevelItem(i)
|
||||||
show_matching_path(item, path_parts, 0)
|
self.show_matching_path(item, path_parts, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -373,7 +352,7 @@ class VariableSelectWidget(QWidget):
|
|||||||
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): # ← строго startswith
|
if prefix == '' or prefix in last_part: # ← строго startswith
|
||||||
completions.append(name)
|
completions.append(name)
|
||||||
|
|
||||||
self.completer.setModel(QStringListModel(completions))
|
self.completer.setModel(QStringListModel(completions))
|
||||||
@@ -386,6 +365,7 @@ class VariableSelectWidget(QWidget):
|
|||||||
if name is None:
|
if name is None:
|
||||||
return None
|
return None
|
||||||
normalized_name = name.replace('->', '.').lower()
|
normalized_name = name.replace('->', '.').lower()
|
||||||
|
normalized_name = normalized_name.replace('[', '.[').lower()
|
||||||
return self.node_index.get(normalized_name)
|
return self.node_index.get(normalized_name)
|
||||||
|
|
||||||
def insert_completion(self, text):
|
def insert_completion(self, text):
|
||||||
@@ -484,6 +464,10 @@ class VariableSelectWidget(QWidget):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def on_search_text_changed(self, text):
|
def on_search_text_changed(self, text):
|
||||||
|
sender_widget = self.sender()
|
||||||
|
sender_name = sender_widget.objectName() if sender_widget else "Unknown Sender"
|
||||||
|
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
self.filter_tree()
|
self.filter_tree()
|
||||||
if text == None:
|
if text == None:
|
||||||
text = self.search_input.text().strip()
|
text = self.search_input.text().strip()
|
||||||
@@ -496,6 +480,18 @@ class VariableSelectWidget(QWidget):
|
|||||||
else:
|
else:
|
||||||
self.completer.popup().hide()
|
self.completer.popup().hide()
|
||||||
|
|
||||||
|
def focusInEvent(self, event):
|
||||||
|
if self.completer.widget() != self.search_input:
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
|
super().focusInEvent(event)
|
||||||
|
|
||||||
|
def _custom_focus_in_event(self, event):
|
||||||
|
# Принудительно установить виджет для completer при получении фокуса
|
||||||
|
if self.completer.widget() != self.search_input:
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
|
super(QLineEdit, self.search_input).focusInEvent(event) # Вызвать оригинальный обработчик
|
||||||
|
|
||||||
|
|
||||||
def build_completion_list(self):
|
def build_completion_list(self):
|
||||||
completions = []
|
completions = []
|
||||||
|
|
||||||
@@ -514,13 +510,17 @@ class VariableSelectWidget(QWidget):
|
|||||||
item.setToolTip(1, text)
|
item.setToolTip(1, text)
|
||||||
|
|
||||||
def get_all_items(self):
|
def get_all_items(self):
|
||||||
"""Возвращает все конечные (leaf) элементы, исключая битовые поля и элементы с детьми."""
|
"""Возвращает все конечные (leaf) элементы, исключая битовые поля и элементы с детьми (реальными)."""
|
||||||
def collect_leaf_items(parent):
|
def collect_leaf_items(parent):
|
||||||
leaf_items = []
|
leaf_items = []
|
||||||
for i in range(parent.childCount()):
|
for i in range(parent.childCount()):
|
||||||
child = parent.child(i)
|
child = parent.child(i)
|
||||||
if child.isHidden():
|
if child.isHidden():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Если есть заглушка — раскрываем
|
||||||
|
self.on_item_expanded(child)
|
||||||
|
|
||||||
if child.childCount() == 0:
|
if child.childCount() == 0:
|
||||||
item_type = child.text(1)
|
item_type = child.text(1)
|
||||||
if item_type and 'bitfield' in str(item_type).lower():
|
if item_type and 'bitfield' in str(item_type).lower():
|
||||||
@@ -533,6 +533,10 @@ class VariableSelectWidget(QWidget):
|
|||||||
all_leaf_items = []
|
all_leaf_items = []
|
||||||
for i in range(self.tree.topLevelItemCount()):
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
top = self.tree.topLevelItem(i)
|
top = self.tree.topLevelItem(i)
|
||||||
|
|
||||||
|
# Раскрываем lazy, если надо
|
||||||
|
self.on_item_expanded(top)
|
||||||
|
|
||||||
if top.childCount() == 0:
|
if top.childCount() == 0:
|
||||||
item_type = top.text(1)
|
item_type = top.text(1)
|
||||||
if item_type and 'bitfield' in str(item_type).lower():
|
if item_type and 'bitfield' in str(item_type).lower():
|
||||||
@@ -543,17 +547,17 @@ class VariableSelectWidget(QWidget):
|
|||||||
return all_leaf_items
|
return all_leaf_items
|
||||||
|
|
||||||
|
|
||||||
def get_all_var_names(self):
|
|
||||||
"""Возвращает имена всех конечных (leaf) переменных, исключая битовые поля и группы."""
|
|
||||||
return [item.text(0) for item in self.get_all_items() if item.text(0)]
|
|
||||||
|
|
||||||
|
|
||||||
def _get_internal_selected_items(self):
|
def _get_internal_selected_items(self):
|
||||||
"""Возвращает выделенные элементы и всех их потомков."""
|
"""Возвращает выделенные элементы и всех их потомков, включая lazy."""
|
||||||
selected = self.tree.selectedItems()
|
selected = self.tree.selectedItems()
|
||||||
all_items = []
|
all_items = []
|
||||||
|
|
||||||
def collect_children(item):
|
def collect_children(item):
|
||||||
|
# Раскрываем при необходимости
|
||||||
|
# Раскрываем lazy, если надо
|
||||||
|
self.on_item_expanded(item)
|
||||||
|
|
||||||
items = [item]
|
items = [item]
|
||||||
for i in range(item.childCount()):
|
for i in range(item.childCount()):
|
||||||
child = item.child(i)
|
child = item.child(i)
|
||||||
@@ -565,26 +569,38 @@ class VariableSelectWidget(QWidget):
|
|||||||
|
|
||||||
return all_items
|
return all_items
|
||||||
|
|
||||||
def _get_internal_selected_var_names(self):
|
|
||||||
"""Возвращает имена выделенных переменных."""
|
|
||||||
return [item.text(0) for item in self._get_internal_selected_items() if item.text(0)]
|
|
||||||
|
|
||||||
def get_selected_items(self):
|
def get_selected_items(self):
|
||||||
"""Возвращает только конечные (leaf) выделенные элементы, исключая bitfield."""
|
"""Возвращает только конечные (leaf) выделенные элементы, исключая bitfield."""
|
||||||
selected = self.tree.selectedItems()
|
selected = self.tree.selectedItems()
|
||||||
leaf_items = []
|
leaf_items = []
|
||||||
for item in selected:
|
for item in selected:
|
||||||
# Проверка: если нет выбранных/видимых детей — это лист
|
# Раскрываем lazy, если надо
|
||||||
|
self.on_item_expanded(item)
|
||||||
|
|
||||||
|
# Если у узла нет видимых/выделенных детей — он лист
|
||||||
if all(item.child(i).isHidden() or not item.child(i).isSelected() for i in range(item.childCount())):
|
if all(item.child(i).isHidden() or not item.child(i).isSelected() for i in range(item.childCount())):
|
||||||
item_type = item.data(0, Qt.UserRole)
|
item_type = item.data(0, Qt.UserRole)
|
||||||
if item_type and 'bitfield' in str(item_type).lower():
|
if item_type and 'bitfield' in str(item_type).lower():
|
||||||
continue # Пропускаем битовые поля
|
continue
|
||||||
leaf_items.append(item)
|
leaf_items.append(item)
|
||||||
return leaf_items
|
return leaf_items
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_var_names(self):
|
||||||
|
"""Возвращает имена всех конечных (leaf) переменных, исключая битовые поля и группы."""
|
||||||
|
return [item.text(0) for item in self.get_all_items() if item.text(0)]
|
||||||
|
|
||||||
|
|
||||||
|
def _get_internal_selected_var_names(self):
|
||||||
|
"""Возвращает имена выделенных переменных."""
|
||||||
|
return [item.text(0) for item in self._get_internal_selected_items() if item.text(0)]
|
||||||
|
|
||||||
|
|
||||||
def get_selected_var_names(self):
|
def get_selected_var_names(self):
|
||||||
"""Возвращает имена только конечных (leaf) переменных из выделенных."""
|
"""Возвращает имена только конечных (leaf) переменных из выделенных."""
|
||||||
return [item.text(0) for item in self.get_selected_items() if item.text(0)]
|
return [item.text(0) for item in self.get_selected_items() if item.text(0)]
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self.completer.setWidget(None)
|
||||||
|
self.completer.deleteLater()
|
||||||
|
super().closeEvent(event)
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import re
|
import re
|
||||||
import xml.etree.ElementTree as ET
|
import lxml.etree 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, QSizePolicy
|
QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout, QSizePolicy
|
||||||
)
|
)
|
||||||
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 var_table
|
||||||
import setupVars
|
import var_setup
|
||||||
import myXML
|
import myXML
|
||||||
import time
|
import time
|
||||||
import selectTable
|
import var_selector_table
|
||||||
|
|
||||||
|
|
||||||
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
|
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
|
||||||
@@ -52,18 +52,39 @@ class VariableSelectorDialog(QDialog):
|
|||||||
self.btn_left.clicked.connect(self.on_move_left)
|
self.btn_left.clicked.connect(self.on_move_left)
|
||||||
|
|
||||||
# Создаем кнопки, они остаются в диалоге
|
# Создаем кнопки, они остаются в диалоге
|
||||||
self.btn_add = QPushButton("Добавить выбранные")
|
self.btn_accept = QPushButton("Применить")
|
||||||
self.btn_delete = QPushButton("Удалить выбранные")
|
|
||||||
|
|
||||||
# Создаем экземпляр вашего готового виджета
|
# Создаем экземпляр вашего готового виджета
|
||||||
self.vars_widget = selectTable.VariableSelectWidget(self)
|
self.vars_widget = var_selector_table.VariableSelectWidget(self)
|
||||||
self.selected_vars_widget = selectTable.VariableSelectWidget(self)
|
self.vars_widget.tree.itemDoubleClicked.connect(self.on_left_tree_double_click)
|
||||||
|
self.vars_widget.setObjectName("LeftTable")
|
||||||
|
self.selected_vars_widget = var_selector_table.VariableSelectWidget(self)
|
||||||
|
self.selected_vars_widget.tree.itemDoubleClicked.connect(self.on_rigth_tree_double_click)
|
||||||
|
self.selected_vars_widget.setObjectName("RightTable")
|
||||||
|
|
||||||
|
# Подписи над таблицами
|
||||||
|
label_all = QLabel("Все переменные")
|
||||||
|
label_all.setStyleSheet("font-weight: bold; font-size: 14px;")
|
||||||
|
|
||||||
|
label_selected = QLabel("Выбранные переменные")
|
||||||
|
label_selected.setStyleSheet("font-weight: bold; font-size: 14px;")
|
||||||
|
|
||||||
|
|
||||||
# --- Лэйауты ---
|
# --- Лэйауты ---
|
||||||
main_layout = QVBoxLayout(self) # главный вертикальный layout окна
|
main_layout = QVBoxLayout(self) # главный вертикальный layout окна
|
||||||
|
|
||||||
tables_layout = QHBoxLayout() # горизонтальный layout с таблицами и кнопками
|
# Чекбокс автодополнения — первый в главном layout
|
||||||
|
main_layout.addWidget(self.autocomplete_checkbox)
|
||||||
|
|
||||||
|
# Подписи над таблицами
|
||||||
|
labels_layout = QHBoxLayout()
|
||||||
|
labels_layout.addWidget(label_all)
|
||||||
|
labels_layout.addStretch()
|
||||||
|
labels_layout.addWidget(label_selected)
|
||||||
|
main_layout.addLayout(labels_layout)
|
||||||
|
|
||||||
|
# Горизонтальный layout с таблицами и кнопками
|
||||||
|
tables_layout = QHBoxLayout()
|
||||||
|
|
||||||
# Левая таблица
|
# Левая таблица
|
||||||
self.vars_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
self.vars_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
@@ -86,8 +107,7 @@ class VariableSelectorDialog(QDialog):
|
|||||||
|
|
||||||
# Кнопки "Добавить выбранные" и "Удалить выбранные" под таблицами
|
# Кнопки "Добавить выбранные" и "Удалить выбранные" под таблицами
|
||||||
buttons_layout = QVBoxLayout()
|
buttons_layout = QVBoxLayout()
|
||||||
buttons_layout.addWidget(self.btn_add)
|
buttons_layout.addWidget(self.btn_accept)
|
||||||
buttons_layout.addWidget(self.btn_delete)
|
|
||||||
main_layout.addLayout(buttons_layout)
|
main_layout.addLayout(buttons_layout)
|
||||||
|
|
||||||
# Важно, если окно — QDialog или QWidget, установи layout
|
# Важно, если окно — QDialog или QWidget, установи layout
|
||||||
@@ -96,17 +116,16 @@ class VariableSelectorDialog(QDialog):
|
|||||||
|
|
||||||
|
|
||||||
# Соединяем сигналы кнопок с методами диалога
|
# Соединяем сигналы кнопок с методами диалога
|
||||||
self.btn_add.clicked.connect(self.on_add_clicked)
|
self.btn_accept.clicked.connect(self.on_apply_clicked)
|
||||||
self.btn_delete.clicked.connect(self.on_delete_clicked)
|
|
||||||
|
|
||||||
# Соединяем чекбокс с методом виджета
|
# Соединяем чекбокс с методом виджета
|
||||||
self.autocomplete_checkbox.stateChanged.connect(self.vars_widget.set_autocomplete)
|
self.autocomplete_checkbox.stateChanged.connect(self.set_autocomplete_tables)
|
||||||
# Устанавливаем начальное состояние автодополнения в виджете
|
# Устанавливаем начальное состояние автодополнения в виджете
|
||||||
self.vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
self.vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
||||||
self.selected_vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
self.selected_vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
||||||
|
|
||||||
# --- Код в конце __init__ ---
|
# --- Код в конце __init__ ---
|
||||||
self.expanded_vars = setupVars.expand_vars(self.all_vars, self.structs, self.typedefs)
|
self.expanded_vars = var_setup.expand_vars(self.all_vars, self.structs, self.typedefs)
|
||||||
self.update_vars_widget()
|
self.update_vars_widget()
|
||||||
|
|
||||||
def on_move_right(self):
|
def on_move_right(self):
|
||||||
@@ -119,6 +138,7 @@ class VariableSelectorDialog(QDialog):
|
|||||||
for var in data:
|
for var in data:
|
||||||
if var['name'] in selected:
|
if var['name'] in selected:
|
||||||
var['show_var'] = 'true'
|
var['show_var'] = 'true'
|
||||||
|
var['enable'] = 'true'
|
||||||
if 'children' in var:
|
if 'children' in var:
|
||||||
mark_selected_show_var(var['children'])
|
mark_selected_show_var(var['children'])
|
||||||
mark_selected_show_var(self.expanded_vars)
|
mark_selected_show_var(self.expanded_vars)
|
||||||
@@ -142,21 +162,32 @@ class VariableSelectorDialog(QDialog):
|
|||||||
self.update_vars_widget()
|
self.update_vars_widget()
|
||||||
|
|
||||||
def update_vars_widget(self):
|
def update_vars_widget(self):
|
||||||
self.selected_vars, self.unselected_vars = setupVars.split_vars_by_show_flag(self.expanded_vars)
|
t_start = time.perf_counter()
|
||||||
|
|
||||||
|
t1 = time.perf_counter()
|
||||||
|
self.selected_vars, self.unselected_vars = var_setup.split_vars_by_show_flag(self.expanded_vars)
|
||||||
|
|
||||||
|
t2 = time.perf_counter()
|
||||||
self.vars_widget.set_data(self.unselected_vars)
|
self.vars_widget.set_data(self.unselected_vars)
|
||||||
|
|
||||||
|
t3 = time.perf_counter()
|
||||||
self.vars_widget.filter_tree()
|
self.vars_widget.filter_tree()
|
||||||
|
|
||||||
|
t4 = time.perf_counter()
|
||||||
self.selected_vars_widget.set_data(self.selected_vars)
|
self.selected_vars_widget.set_data(self.selected_vars)
|
||||||
|
|
||||||
|
t5 = time.perf_counter()
|
||||||
self.selected_vars_widget.filter_tree()
|
self.selected_vars_widget.filter_tree()
|
||||||
|
|
||||||
|
def on_apply_clicked(self):
|
||||||
def on_add_clicked(self):
|
# Получаем имена всех переменных из правой таблицы (selected_vars_widget)
|
||||||
# Получаем все переменные из правой таблицы (selected_vars_widget)
|
right_var_names = set(self.selected_vars_widget.get_all_var_names())
|
||||||
var_names = self.selected_vars_widget.get_all_var_names()
|
|
||||||
all_items = self.selected_vars_widget.get_all_items()
|
all_items = self.selected_vars_widget.get_all_items()
|
||||||
if not all_items:
|
if not all_items:
|
||||||
return
|
return
|
||||||
|
|
||||||
def add_to_var_map_recursively(item):
|
# Устанавливаем show_var=true и enable=true для переменных из правой таблицы
|
||||||
|
def add_or_update_var(item):
|
||||||
name = item.text(0)
|
name = item.text(0)
|
||||||
type_str = item.text(1)
|
type_str = item.text(1)
|
||||||
|
|
||||||
@@ -169,9 +200,15 @@ class VariableSelectorDialog(QDialog):
|
|||||||
extern_val = item.data(0, Qt.UserRole + 2)
|
extern_val = item.data(0, Qt.UserRole + 2)
|
||||||
static_val = item.data(0, Qt.UserRole + 3)
|
static_val = item.data(0, Qt.UserRole + 3)
|
||||||
new_var = {
|
new_var = {
|
||||||
'name': name, 'type': type_str, 'show_var': 'true',
|
'name': name,
|
||||||
'enable': 'true', 'shortname': name, 'pt_type': '', 'iq_type': '',
|
'type': type_str,
|
||||||
'return_type': 'iq_none', 'file': file_val,
|
'show_var': 'true',
|
||||||
|
'enable': 'true',
|
||||||
|
'shortname': name,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': 't_iq_none',
|
||||||
|
'file': file_val,
|
||||||
'extern': str(extern_val).lower() if extern_val else 'false',
|
'extern': str(extern_val).lower() if extern_val else 'false',
|
||||||
'static': str(static_val).lower() if static_val else 'false',
|
'static': str(static_val).lower() if static_val else 'false',
|
||||||
}
|
}
|
||||||
@@ -179,70 +216,66 @@ class VariableSelectorDialog(QDialog):
|
|||||||
self.var_map[name] = new_var
|
self.var_map[name] = new_var
|
||||||
|
|
||||||
for item in all_items:
|
for item in all_items:
|
||||||
add_to_var_map_recursively(item)
|
add_or_update_var(item)
|
||||||
|
|
||||||
|
# Сбрасываем show_var и enable у всех переменных, которых нет в правой таблице
|
||||||
|
for var in self.all_vars:
|
||||||
|
if var['name'] not in right_var_names:
|
||||||
|
var['show_var'] = 'false'
|
||||||
|
var['enable'] = 'false'
|
||||||
|
|
||||||
|
# Обновляем expanded_vars чтобы отразить новые show_var и enable
|
||||||
|
def update_expanded_vars(data):
|
||||||
|
for v in data:
|
||||||
|
name = v['name']
|
||||||
|
if name in self.var_map:
|
||||||
|
v['show_var'] = self.var_map[name]['show_var']
|
||||||
|
v['enable'] = self.var_map[name]['enable']
|
||||||
|
if 'children' in v:
|
||||||
|
update_expanded_vars(v['children'])
|
||||||
|
update_expanded_vars(self.expanded_vars)
|
||||||
|
|
||||||
|
# Обновляем отображение в виджетах
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
# Закрываем диалог
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
def on_delete_clicked(self):
|
# Обнови on_left_tree_double_click:
|
||||||
# Получаем все элементы (QTreeWidgetItem) из правой таблицы
|
def on_left_tree_double_click(self, item, column):
|
||||||
all_items = self.selected_vars_widget.get_all_items()
|
selected_names = [item.text(0)]
|
||||||
if not all_items:
|
if not selected_names:
|
||||||
return
|
return
|
||||||
|
|
||||||
affected_names = []
|
def mark_selected_show_var(data):
|
||||||
|
for var in data:
|
||||||
|
if var['name'] in selected_names:
|
||||||
|
var['show_var'] = 'true'
|
||||||
|
var['enable'] = 'true'
|
||||||
|
if 'children' in var:
|
||||||
|
mark_selected_show_var(var['children'])
|
||||||
|
mark_selected_show_var(self.expanded_vars)
|
||||||
|
|
||||||
def disable_var_recursively(item):
|
self.update_vars_widget()
|
||||||
name = item.text(0)
|
|
||||||
if name in self.var_map:
|
|
||||||
self.var_map[name]['show_var'] = 'false'
|
|
||||||
self.var_map[name]['enable'] = 'false'
|
|
||||||
affected_names.append(name)
|
|
||||||
|
|
||||||
# Рекурсивно отключаем детей
|
# Добавь обработчик двойного клика справа (если нужно):
|
||||||
for i in range(item.childCount()):
|
def on_rigth_tree_double_click(self, item, column):
|
||||||
child = item.child(i)
|
selected_names = [item.text(0)]
|
||||||
disable_var_recursively(child)
|
if not selected_names:
|
||||||
|
return
|
||||||
|
|
||||||
for item in all_items:
|
def mark_selected_hide_var(data):
|
||||||
disable_var_recursively(item)
|
for var in data:
|
||||||
|
if var['name'] in selected_names:
|
||||||
|
var['show_var'] = 'false'
|
||||||
|
if 'children' in var:
|
||||||
|
mark_selected_hide_var(var['children'])
|
||||||
|
mark_selected_hide_var(self.expanded_vars)
|
||||||
|
|
||||||
# Обновляем XML и таблицу
|
|
||||||
self.update_xml_vars(affected_names, 'false', 'false')
|
|
||||||
self.update_vars_widget()
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
|
||||||
def update_xml_vars(self, names, show, enable):
|
|
||||||
"""Обновляет флаги show_var и enable в XML файле, только если у переменной нет вложенных структур."""
|
|
||||||
if not self.xml_path:
|
|
||||||
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'):
|
|
||||||
if var_elem.attrib.get('name') in names:
|
|
||||||
# Проверяем наличие вложенных структур или объединений
|
|
||||||
has_nested_structs = any(
|
|
||||||
var_elem.find(tag) is not None for tag in ('struct', 'union')
|
|
||||||
)
|
|
||||||
if not has_nested_structs:
|
|
||||||
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', show)
|
|
||||||
set_text('enable', enable)
|
|
||||||
|
|
||||||
myXML.fwrite(root, self.xml_path)
|
|
||||||
|
|
||||||
|
|
||||||
def save_checkbox_state(self):
|
|
||||||
self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
|
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
if event.key() == Qt.Key_Delete:
|
if event.key() == Qt.Key_Delete:
|
||||||
@@ -303,7 +336,6 @@ 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)
|
root, tree = myXML.safe_parse_xml(self.xml_path)
|
||||||
if root is None:
|
if root is None:
|
||||||
return
|
return
|
||||||
@@ -352,3 +384,9 @@ class VariableSelectorDialog(QDialog):
|
|||||||
|
|
||||||
def save_checkbox_state(self):
|
def save_checkbox_state(self):
|
||||||
self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
|
self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def set_autocomplete_tables(self, state):
|
||||||
|
self.vars_widget.set_autocomplete(state)
|
||||||
|
self.selected_vars_widget.set_autocomplete(state)
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import xml.etree.ElementTree as ET
|
import lxml.etree as ET
|
||||||
from generateVars import map_type_to_pt, get_iq_define, type_map
|
from generate_debug_vars import map_type_to_pt, get_iq_define, type_map
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
import scanVars
|
import scan_vars
|
||||||
import myXML
|
import myXML
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ def parse_vars(filename, typedef_map=None):
|
|||||||
'shortname': var.findtext('shortname', name),
|
'shortname': var.findtext('shortname', name),
|
||||||
'pt_type': pt_type,
|
'pt_type': pt_type,
|
||||||
'iq_type': iq_type,
|
'iq_type': iq_type,
|
||||||
'return_type': var.findtext('return_type', ''),
|
'return_type': var.findtext('return_type', 't_iq_none'),
|
||||||
'type': var_type,
|
'type': var_type,
|
||||||
'file': var.findtext('file', ''),
|
'file': var.findtext('file', ''),
|
||||||
'extern': var.findtext('extern', 'false') == 'true',
|
'extern': var.findtext('extern', 'false') == 'true',
|
||||||
@@ -291,7 +291,7 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
|
|||||||
return process_array(prefix, type_str, structs, typedefs, var_attrs, depth)
|
return process_array(prefix, type_str, structs, typedefs, var_attrs, depth)
|
||||||
|
|
||||||
# Ищем структуру по имени типа
|
# Ищем структуру по имени типа
|
||||||
base_type = scanVars.strip_ptr_and_array(type_str)
|
base_type = scan_vars.strip_ptr_and_array(type_str)
|
||||||
fields = structs.get(base_type)
|
fields = structs.get(base_type)
|
||||||
if not isinstance(fields, dict):
|
if not isinstance(fields, dict):
|
||||||
# Не структура и не массив — просто возвращаем пустой список
|
# Не структура и не массив — просто возвращаем пустой список
|
||||||
@@ -568,19 +568,52 @@ def split_vars_by_show_flag(expanded_vars):
|
|||||||
nodes.extend(collect_selected_nodes(child))
|
nodes.extend(collect_selected_nodes(child))
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
def exists_by_path(tree, full_name):
|
||||||
|
"""
|
||||||
|
Проверяет, существует ли переменная в дереве, следуя по частям пути (например: project → adc → status).
|
||||||
|
Каждая часть ('project', 'project.adc', ...) должна иметь точное совпадение с 'name' в узле.
|
||||||
|
"""
|
||||||
|
path_parts = split_path(full_name)
|
||||||
|
full_names = build_full_names(path_parts, full_name)
|
||||||
|
|
||||||
|
current_level = tree
|
||||||
|
for name in full_names:
|
||||||
|
found = False
|
||||||
|
for var in current_level:
|
||||||
|
if var.get('name') == name:
|
||||||
|
current_level = var.get('children', [])
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
selected_nodes = []
|
selected_nodes = []
|
||||||
for var in expanded_vars:
|
for var in expanded_vars:
|
||||||
|
full_name = var['name']
|
||||||
|
# Проверка: если имя содержит вложенность, но целиком есть в корне — пропускаем
|
||||||
|
if ('.' in full_name or '[' in full_name or '->' in full_name):
|
||||||
|
path_parts = split_path(full_name)
|
||||||
|
if exists_by_path(expanded_vars, full_name):
|
||||||
|
# Удалим лишнюю копию из корня unselected_vars
|
||||||
|
find_and_remove(unselected_vars, full_name)
|
||||||
|
else:
|
||||||
|
add_to_nested_tree(unselected_vars, var, path_parts, source_tree=expanded_vars)
|
||||||
|
find_and_remove(unselected_vars, full_name)
|
||||||
selected_nodes.extend(collect_selected_nodes(var))
|
selected_nodes.extend(collect_selected_nodes(var))
|
||||||
|
|
||||||
for node in selected_nodes:
|
for node in selected_nodes:
|
||||||
path_parts = split_path(node['name'])
|
full_name = node['name']
|
||||||
|
|
||||||
|
|
||||||
|
path_parts = split_path(full_name)
|
||||||
|
|
||||||
# Вырезать из unselected_vars
|
# Вырезать из unselected_vars
|
||||||
removed = find_and_remove(unselected_vars, node['name'])
|
removed = find_and_remove(unselected_vars, full_name)
|
||||||
if removed:
|
if removed:
|
||||||
add_to_nested_tree(selected_vars, removed, path_parts)
|
add_to_nested_tree(selected_vars, removed, path_parts, source_tree=expanded_vars)
|
||||||
else:
|
else:
|
||||||
# вдруг удалённый родитель — создаём вручную
|
# вдруг удалённый родитель — создаём вручную
|
||||||
add_to_nested_tree(selected_vars, node, path_parts)
|
add_to_nested_tree(selected_vars, node, path_parts, source_tree=expanded_vars)
|
||||||
|
|
||||||
return selected_vars, unselected_vars
|
return selected_vars, unselected_vars
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
from PySide2.QtWidgets import (
|
from PySide2.QtWidgets import (
|
||||||
QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
|
QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
|
||||||
QAbstractItemView, QHeaderView, QLabel
|
QAbstractItemView, QHeaderView, QLabel,
|
||||||
|
QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QScrollArea, QWidget
|
||||||
)
|
)
|
||||||
from PySide2.QtGui import QColor, QBrush, QPalette
|
from PySide2.QtGui import QColor, QBrush, QPalette
|
||||||
from PySide2.QtCore import Qt
|
from PySide2.QtCore import Qt
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from generateVars import type_map
|
from generate_debug_vars import type_map
|
||||||
|
import time
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
class rows(IntEnum):
|
class rows(IntEnum):
|
||||||
No = 0
|
No = 0
|
||||||
@@ -17,6 +20,52 @@ class rows(IntEnum):
|
|||||||
ret_type = 6
|
ret_type = 6
|
||||||
short_name = 7
|
short_name = 7
|
||||||
|
|
||||||
|
class FilterDialog(QDialog):
|
||||||
|
def __init__(self, parent, options, selected, title="Выберите значения"):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.resize(250, 300)
|
||||||
|
self.selected = set(selected)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
|
||||||
|
scroll = QScrollArea(self)
|
||||||
|
scroll.setWidgetResizable(True)
|
||||||
|
container = QWidget()
|
||||||
|
scroll.setWidget(container)
|
||||||
|
|
||||||
|
self.checkboxes = []
|
||||||
|
vbox = QVBoxLayout(container)
|
||||||
|
|
||||||
|
for opt in options:
|
||||||
|
cb = QCheckBox(opt)
|
||||||
|
cb.setChecked(opt in self.selected)
|
||||||
|
vbox.addWidget(cb)
|
||||||
|
self.checkboxes.append(cb)
|
||||||
|
|
||||||
|
layout.addWidget(scroll)
|
||||||
|
|
||||||
|
btn_layout = QHBoxLayout()
|
||||||
|
btn_ok = QPushButton("OK")
|
||||||
|
btn_cancel = QPushButton("Отмена")
|
||||||
|
btn_layout.addWidget(btn_ok)
|
||||||
|
btn_layout.addWidget(btn_cancel)
|
||||||
|
|
||||||
|
layout.addLayout(btn_layout)
|
||||||
|
|
||||||
|
btn_ok.clicked.connect(self.accept)
|
||||||
|
btn_cancel.clicked.connect(self.reject)
|
||||||
|
|
||||||
|
def get_selected(self):
|
||||||
|
return [cb.text() for cb in self.checkboxes if cb.isChecked()]
|
||||||
|
|
||||||
|
|
||||||
|
class CtrlScrollComboBox(QComboBox):
|
||||||
|
def wheelEvent(self, event):
|
||||||
|
if event.modifiers() & Qt.ControlModifier:
|
||||||
|
super().wheelEvent(event)
|
||||||
|
else:
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
class VariableTableWidget(QTableWidget):
|
class VariableTableWidget(QTableWidget):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
@@ -27,7 +76,7 @@ class VariableTableWidget(QTableWidget):
|
|||||||
'En',
|
'En',
|
||||||
'Name',
|
'Name',
|
||||||
'Origin Type',
|
'Origin Type',
|
||||||
'Pointer Type',
|
'Base Type',
|
||||||
'IQ Type',
|
'IQ Type',
|
||||||
'Return Type',
|
'Return Type',
|
||||||
'Short Name'
|
'Short Name'
|
||||||
@@ -36,9 +85,19 @@ class VariableTableWidget(QTableWidget):
|
|||||||
self.var_list = []
|
self.var_list = []
|
||||||
|
|
||||||
self.type_options = list(dict.fromkeys(type_map.values()))
|
self.type_options = list(dict.fromkeys(type_map.values()))
|
||||||
self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
|
self.pt_types_all = [t.replace('pt_', '') for t in self.type_options]
|
||||||
self.iq_types = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
|
self.iq_types_all = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
|
||||||
|
# Задаём базовые iq-типы (без префикса 'iq_')
|
||||||
|
self.iq_types = ['iq_none', 'iq', 'iq10', 'iq15', 'iq19', 'iq24']
|
||||||
|
# Фильтруем типы из type_map.values() исключая те, что содержат 'arr' или 'ptr'
|
||||||
|
type_options = [t for t in dict.fromkeys(type_map.values()) if 'arr' not in t and 'ptr' not in t and
|
||||||
|
'struct' not in t and 'union' not in t and '64' not in t]
|
||||||
|
# Формируем display_type_options без префикса 'pt_'
|
||||||
|
self.pt_types = [t.replace('pt_', '') for t in type_options]
|
||||||
|
|
||||||
|
self._iq_type_filter = list(self.iq_types) # Текущий фильтр iq типов (по умолчанию все)
|
||||||
|
self._pt_type_filter = list(self.pt_types)
|
||||||
|
self._ret_type_filter = list(self.iq_types)
|
||||||
header = self.horizontalHeader()
|
header = self.horizontalHeader()
|
||||||
# Для остальных колонок — растяжение (Stretch), чтобы они заняли всю оставшуюся ширину
|
# Для остальных колонок — растяжение (Stretch), чтобы они заняли всю оставшуюся ширину
|
||||||
|
|
||||||
@@ -60,13 +119,11 @@ class VariableTableWidget(QTableWidget):
|
|||||||
self.setColumnWidth(rows.type, 100)
|
self.setColumnWidth(rows.type, 100)
|
||||||
self._resizing = False
|
self._resizing = False
|
||||||
self.horizontalHeader().sectionResized.connect(self.on_section_resized)
|
self.horizontalHeader().sectionResized.connect(self.on_section_resized)
|
||||||
|
self.horizontalHeader().sectionClicked.connect(self.on_header_clicked)
|
||||||
|
|
||||||
|
|
||||||
def populate(self, vars_list, structs, on_change_callback):
|
def populate(self, vars_list, structs, on_change_callback):
|
||||||
self.var_list = vars_list
|
self.var_list = vars_list
|
||||||
self.type_options = list(dict.fromkeys(type_map.values()))
|
|
||||||
self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
|
|
||||||
iq_types = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
|
|
||||||
|
|
||||||
# --- ДО: удаляем отображение структур и union-переменных
|
# --- ДО: удаляем отображение структур и union-переменных
|
||||||
for var in vars_list:
|
for var in vars_list:
|
||||||
@@ -115,19 +172,18 @@ class VariableTableWidget(QTableWidget):
|
|||||||
self.setItem(row, rows.type, origin_item)
|
self.setItem(row, rows.type, origin_item)
|
||||||
|
|
||||||
# pt_type
|
# pt_type
|
||||||
pt_combo = QComboBox()
|
pt_combo = CtrlScrollComboBox()
|
||||||
pt_combo.addItems(self.display_type_options)
|
pt_combo.addItems(self.pt_types)
|
||||||
value = var['pt_type'].replace('pt_', '')
|
value = var['pt_type'].replace('pt_', '')
|
||||||
if value not in self.display_type_options:
|
if value not in self.pt_types:
|
||||||
pt_combo.addItem(value)
|
pt_combo.addItem(value)
|
||||||
pt_combo.setCurrentText(value)
|
pt_combo.setCurrentText(value)
|
||||||
pt_combo.currentTextChanged.connect(on_change_callback)
|
pt_combo.currentTextChanged.connect(on_change_callback)
|
||||||
pt_combo.setStyleSheet(style_with_padding)
|
pt_combo.setStyleSheet(style_with_padding)
|
||||||
pt_combo.wheelEvent = lambda e: e.ignore()
|
|
||||||
self.setCellWidget(row, rows.pt_type, pt_combo)
|
self.setCellWidget(row, rows.pt_type, pt_combo)
|
||||||
|
|
||||||
# iq_type
|
# iq_type
|
||||||
iq_combo = QComboBox()
|
iq_combo = CtrlScrollComboBox()
|
||||||
iq_combo.addItems(self.iq_types)
|
iq_combo.addItems(self.iq_types)
|
||||||
value = var['iq_type'].replace('t_', '')
|
value = var['iq_type'].replace('t_', '')
|
||||||
if value not in self.iq_types:
|
if value not in self.iq_types:
|
||||||
@@ -138,9 +194,10 @@ class VariableTableWidget(QTableWidget):
|
|||||||
self.setCellWidget(row, rows.iq_type, iq_combo)
|
self.setCellWidget(row, rows.iq_type, iq_combo)
|
||||||
|
|
||||||
# return_type
|
# return_type
|
||||||
ret_combo = QComboBox()
|
ret_combo = CtrlScrollComboBox()
|
||||||
ret_combo.addItems(self.iq_types)
|
ret_combo.addItems(self.iq_types)
|
||||||
ret_combo.setCurrentText(var.get('return_type', ''))
|
value = var['return_type'].replace('t_', '')
|
||||||
|
ret_combo.setCurrentText(value)
|
||||||
ret_combo.currentTextChanged.connect(on_change_callback)
|
ret_combo.currentTextChanged.connect(on_change_callback)
|
||||||
ret_combo.setStyleSheet(style_with_padding)
|
ret_combo.setStyleSheet(style_with_padding)
|
||||||
self.setCellWidget(row, rows.ret_type, ret_combo)
|
self.setCellWidget(row, rows.ret_type, ret_combo)
|
||||||
@@ -155,25 +212,28 @@ class VariableTableWidget(QTableWidget):
|
|||||||
self.check()
|
self.check()
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
warning_color = (QColor("#FFFACD")) # Жёлтый для длинных shortname
|
warning_color = QColor("#FFFACD")
|
||||||
error_color = (QColor("#FFB6C1")) # Светло-красный для отсутствующих переменных
|
error_color = QColor("#FFB6C1")
|
||||||
tooltip_shortname = "Short Name длиннее 10 символов — будет обрезано при генерации"
|
tooltip_shortname = "Short Name длиннее 10 символов — будет обрезано при генерации"
|
||||||
tooltip_missing = f'Имя переменной не найдено среди переменных. Добавьте её через кнопку "Добавить переменные"'
|
tooltip_missing = 'Имя переменной не найдено среди переменных. Добавьте её через кнопку "Добавить переменные"'
|
||||||
|
|
||||||
|
var_names_set = {v.get('name') for v in self.var_list if v.get('name')}
|
||||||
|
|
||||||
|
t0 = time.time()
|
||||||
|
self.setUpdatesEnabled(False)
|
||||||
for row in range(self.rowCount()):
|
for row in range(self.rowCount()):
|
||||||
# Получаем имя переменной (столбец `name`)
|
t1 = time.time()
|
||||||
name_widget = self.cellWidget(row, rows.name)
|
name_widget = self.cellWidget(row, rows.name)
|
||||||
|
t2 = time.time()
|
||||||
name = name_widget.text() if name_widget else ""
|
name = name_widget.text() if name_widget else ""
|
||||||
|
|
||||||
# Получаем shortname
|
|
||||||
short_name_edit = self.cellWidget(row, rows.short_name)
|
short_name_edit = self.cellWidget(row, rows.short_name)
|
||||||
|
t3 = time.time()
|
||||||
shortname = short_name_edit.text() if short_name_edit else ""
|
shortname = short_name_edit.text() if short_name_edit else ""
|
||||||
|
|
||||||
# Флаги ошибок
|
|
||||||
long_shortname = len(shortname) > 10
|
long_shortname = len(shortname) > 10
|
||||||
found = any(v.get('name') == name for v in self.var_list)
|
found = name in var_names_set
|
||||||
|
|
||||||
# Выбираем цвет и подсказку
|
|
||||||
color = None
|
color = None
|
||||||
tooltip = ""
|
tooltip = ""
|
||||||
if not found:
|
if not found:
|
||||||
@@ -184,6 +244,10 @@ class VariableTableWidget(QTableWidget):
|
|||||||
tooltip = tooltip_shortname
|
tooltip = tooltip_shortname
|
||||||
|
|
||||||
self.highlight_row(row, color, tooltip)
|
self.highlight_row(row, color, tooltip)
|
||||||
|
t4 = time.time()
|
||||||
|
|
||||||
|
self.setUpdatesEnabled(True)
|
||||||
|
#print(f"Row {row}: cellWidget(name) {t2-t1:.4f}s, cellWidget(shortname) {t3-t2:.4f}s, highlight_row {t4-t3:.4f}s")
|
||||||
|
|
||||||
|
|
||||||
def read_data(self):
|
def read_data(self):
|
||||||
@@ -209,6 +273,53 @@ class VariableTableWidget(QTableWidget):
|
|||||||
})
|
})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def on_header_clicked(self, logicalIndex):
|
||||||
|
if logicalIndex == rows.pt_type:
|
||||||
|
dlg = FilterDialog(self, self.pt_types_all, self._pt_type_filter, "Выберите базовые типы")
|
||||||
|
if dlg.exec_():
|
||||||
|
self._pt_type_filter = dlg.get_selected()
|
||||||
|
self.update_comboboxes({rows.pt_type: self._pt_type_filter})
|
||||||
|
|
||||||
|
elif logicalIndex == rows.iq_type:
|
||||||
|
dlg = FilterDialog(self, self.iq_types_all, self._iq_type_filter, "Выберите IQ типы")
|
||||||
|
if dlg.exec_():
|
||||||
|
self._iq_type_filter = dlg.get_selected()
|
||||||
|
self.update_comboboxes({rows.iq_type: self._iq_type_filter})
|
||||||
|
|
||||||
|
elif logicalIndex == rows.ret_type:
|
||||||
|
dlg = FilterDialog(self, self.iq_types_all, self._ret_type_filter, "Выберите IQ типы")
|
||||||
|
if dlg.exec_():
|
||||||
|
self._ret_type_filter = dlg.get_selected()
|
||||||
|
self.update_comboboxes({rows.ret_type: self._ret_type_filter})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def update_comboboxes(self, columns_filters: Dict[int, List[str]]):
|
||||||
|
"""
|
||||||
|
Обновляет combobox-ячейки в указанных столбцах таблицы.
|
||||||
|
|
||||||
|
:param columns_filters: dict, где ключ — индекс столбца,
|
||||||
|
значение — список допустимых вариантов для combobox.
|
||||||
|
"""
|
||||||
|
for row in range(self.rowCount()):
|
||||||
|
for col, allowed_items in columns_filters.items():
|
||||||
|
combo = self.cellWidget(row, col)
|
||||||
|
if combo:
|
||||||
|
current = combo.currentText()
|
||||||
|
combo.blockSignals(True)
|
||||||
|
combo.clear()
|
||||||
|
|
||||||
|
combo.addItems(allowed_items)
|
||||||
|
if current in allowed_items:
|
||||||
|
combo.setCurrentText(current)
|
||||||
|
else:
|
||||||
|
combo.setCurrentIndex(0)
|
||||||
|
combo.blockSignals(False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def on_section_resized(self, logicalIndex, oldSize, newSize):
|
def on_section_resized(self, logicalIndex, oldSize, newSize):
|
||||||
if self._resizing:
|
if self._resizing:
|
||||||
return # предотвращаем рекурсию
|
return # предотвращаем рекурсию
|
||||||
@@ -256,20 +367,22 @@ class VariableTableWidget(QTableWidget):
|
|||||||
item = self.item(row, col)
|
item = self.item(row, col)
|
||||||
widget = self.cellWidget(row, col)
|
widget = self.cellWidget(row, col)
|
||||||
|
|
||||||
# Подсветка обычной item-ячейки (например, тип переменной)
|
|
||||||
if item is not None:
|
if item is not None:
|
||||||
if color:
|
current_bg = item.background().color() if item.background() else None
|
||||||
|
if color and current_bg != color:
|
||||||
item.setBackground(QBrush(color))
|
item.setBackground(QBrush(color))
|
||||||
item.setToolTip(tooltip)
|
item.setToolTip(tooltip)
|
||||||
else:
|
elif not color and current_bg is not None:
|
||||||
item.setBackground(QBrush(Qt.NoBrush))
|
item.setBackground(QBrush(Qt.NoBrush))
|
||||||
item.setToolTip("")
|
item.setToolTip("")
|
||||||
|
|
||||||
# Подсветка виджетов — здесь главная доработка
|
|
||||||
elif widget is not None:
|
elif widget is not None:
|
||||||
# Надёжная подсветка: через styleSheet
|
if widget.styleSheet() != css_color:
|
||||||
widget.setStyleSheet(css_color)
|
widget.setStyleSheet(css_color)
|
||||||
widget.setToolTip(tooltip if color else "")
|
current_tip = widget.toolTip()
|
||||||
|
if color and current_tip != tooltip:
|
||||||
|
widget.setToolTip(tooltip)
|
||||||
|
elif not color and current_tip:
|
||||||
|
widget.setToolTip("")
|
||||||
|
|
||||||
def get_selected_var_names(self):
|
def get_selected_var_names(self):
|
||||||
selected_indexes = self.selectedIndexes()
|
selected_indexes = self.selectedIndexes()
|
||||||
550
debug_tools.c
550
debug_tools.c
@@ -8,13 +8,15 @@ static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var);
|
|||||||
|
|
||||||
///////////////////////////----EXAPLE-----//////////////////////////////
|
///////////////////////////----EXAPLE-----//////////////////////////////
|
||||||
long var_numb = 1;
|
long var_numb = 1;
|
||||||
|
DebugVarName_t var_name;
|
||||||
long return_var;
|
long return_var;
|
||||||
long return_ll_var;
|
long return_ll_var;
|
||||||
int result;
|
int result;
|
||||||
char ext_date[] = {7, 233, 11, 07, 16, 50};
|
char ext_date[] = {7, 233, 11, 07, 16, 50};
|
||||||
void Debug_Test_Example(void)
|
void Debug_Test_Example(void)
|
||||||
{
|
{
|
||||||
result = Debug_ReadVar(&dbg_vars[var_numb], &return_var);
|
result = Debug_ReadVar(var_numb, &return_var);
|
||||||
|
result = Debug_ReadVarName(var_numb, var_name);
|
||||||
|
|
||||||
|
|
||||||
if(Debug_LowLevel_Initialize(ext_date) == 0)
|
if(Debug_LowLevel_Initialize(ext_date) == 0)
|
||||||
@@ -22,6 +24,47 @@ void Debug_Test_Example(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////----PUBLIC-----//////////////////////////////
|
///////////////////////////----PUBLIC-----//////////////////////////////
|
||||||
|
int Debug_ReadVar(int var_ind, long *return_long)
|
||||||
|
{
|
||||||
|
if(return_long == NULL)
|
||||||
|
return 1;
|
||||||
|
long tmp_var;
|
||||||
|
|
||||||
|
if (var_ind >= DebugVar_Qnt)
|
||||||
|
return 1;
|
||||||
|
if((dbg_vars[var_numb].ptr_type == pt_struct) || (dbg_vars[var_numb].ptr_type == pt_union) ||
|
||||||
|
(dbg_vars[var_numb].ptr_type == pt_unknown))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return convertDebugVarToIQx(&dbg_vars[var_numb], return_long);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr)
|
||||||
|
{
|
||||||
|
if(name_ptr == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (var_ind >= DebugVar_Qnt)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
// Êîïèðîâàíèå ñ çàùèòîé îò ïåðåïîëíåíèÿ è ÿâíîé îñòàíîâêîé ïî '\0'
|
||||||
|
for (i = 0; i < sizeof(dbg_vars[var_numb].name); i++)
|
||||||
|
{
|
||||||
|
name_ptr[i] = dbg_vars[var_numb].name[i];
|
||||||
|
if (dbg_vars[var_numb].name[i] == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Ãàðàíòèðîâàííîå çàâåðøåíèå ñòðîêè (íà ñëó÷àé, åñëè â var->name íå áûëî '\0')
|
||||||
|
name_ptr[sizeof(dbg_vars[var_numb].name) - 1] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Debug_LowLevel_ReadVar(long *return_long)
|
int Debug_LowLevel_ReadVar(long *return_long)
|
||||||
{
|
{
|
||||||
if (return_long == NULL)
|
if (return_long == NULL)
|
||||||
@@ -46,46 +89,11 @@ int Debug_LowLevel_ReadVar(long *return_long)
|
|||||||
return 2; // Çàïðåù¸ííûé àäðåñ — íåëüçÿ ÷èòàòü
|
return 2; // Çàïðåù¸ííûé àäðåñ — íåëüçÿ ÷èòàòü
|
||||||
}
|
}
|
||||||
|
|
||||||
convertDebugVarToIQx(&debug_ll.dbg_var, return_long);
|
return convertDebugVarToIQx(&debug_ll.dbg_var, return_long);
|
||||||
|
;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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))
|
|
||||||
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 char* external_date)
|
int Debug_LowLevel_Initialize(const char* external_date)
|
||||||
{
|
{
|
||||||
if (external_date == NULL) {
|
if (external_date == NULL) {
|
||||||
@@ -121,6 +129,18 @@ int Debug_LowLevel_Initialize(const char* external_date)
|
|||||||
|
|
||||||
|
|
||||||
/////////////////////----INTERNAL FUNCTIONS-----////////////////////////
|
/////////////////////----INTERNAL FUNCTIONS-----////////////////////////
|
||||||
|
static int iqTypeToQ(DebugVarIQType_t t)
|
||||||
|
{
|
||||||
|
if (t == t_iq_none)
|
||||||
|
return 0; // áåç IQ, float, int
|
||||||
|
else if (t == t_iq)
|
||||||
|
return GLOBAL_Q; // îáùèé IQ, íàïðèìåð 24
|
||||||
|
else if (t >= t_iq1 && t <= t_iq30)
|
||||||
|
return (int)t - (int)t_iq1 + 1; // íàïðèìåð t_iq1 -> 1, t_iq2 -> 2 è ò.ä.
|
||||||
|
else
|
||||||
|
return -1; // îøèáêà
|
||||||
|
}
|
||||||
|
|
||||||
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
|
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
|
||||||
{
|
{
|
||||||
long iq_numb, iq_united, iq_final;
|
long iq_numb, iq_united, iq_final;
|
||||||
@@ -129,214 +149,53 @@ static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
|
|||||||
if(getDebugVar(var, &iq_numb, &float_numb) != 0)
|
if(getDebugVar(var, &iq_numb, &float_numb) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// ïðèâåäåíèå ê îäíîìó IQ
|
int src_q = iqTypeToQ(var->iq_type);
|
||||||
switch(var->iq_type)
|
int dst_q = iqTypeToQ(var->return_type);
|
||||||
{
|
|
||||||
case t_iq_none:
|
if (src_q < 0 || dst_q < 0)
|
||||||
if(var->ptr_type == pt_float)
|
return 2; // íåïðàâèëüíûé ôîðìàò
|
||||||
{
|
|
||||||
iq_united = _IQ(float_numb);
|
long long iq_united64 = 0;
|
||||||
|
long long iq_final64 = 0;
|
||||||
|
|
||||||
|
// Êîíâåðòàöèÿ ê GLOBAL_Q (64-áèò)
|
||||||
|
if (var->iq_type == t_iq_none) {
|
||||||
|
if (var->ptr_type == pt_float) {
|
||||||
|
// float_numb óìíîæàåì íà 2^GLOBAL_Q (2^24=16777216)
|
||||||
|
// Ðåçóëüòàò ïðèâîäèì ê long long
|
||||||
|
iq_united64 = (long long)(float_numb * 16777216.0f);
|
||||||
|
} else {
|
||||||
|
iq_united64 = ((long long)iq_numb) << GLOBAL_Q;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
int shift = GLOBAL_Q - src_q;
|
||||||
|
if (shift >= 0)
|
||||||
|
iq_united64 = ((long long)iq_numb) << shift;
|
||||||
else
|
else
|
||||||
{
|
iq_united64 = ((long long)iq_numb) >> (-shift);
|
||||||
iq_united = _IQ(iq_numb);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case t_iq1:
|
|
||||||
iq_united = _IQ1toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq2:
|
|
||||||
iq_united = _IQ2toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq3:
|
|
||||||
iq_united = _IQ3toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq4:
|
|
||||||
iq_united = _IQ4toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq5:
|
|
||||||
iq_united = _IQ5toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq6:
|
|
||||||
iq_united = _IQ6toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq7:
|
|
||||||
iq_united = _IQ7toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq8:
|
|
||||||
iq_united = _IQ8toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq9:
|
|
||||||
iq_united = _IQ9toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq10:
|
|
||||||
iq_united = _IQ10toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq11:
|
|
||||||
iq_united = _IQ11toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq12:
|
|
||||||
iq_united = _IQ12toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq13:
|
|
||||||
iq_united = _IQ13toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq14:
|
|
||||||
iq_united = _IQ14toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq15:
|
|
||||||
iq_united = _IQ15toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq16:
|
|
||||||
iq_united = _IQ16toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq17:
|
|
||||||
iq_united = _IQ17toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq18:
|
|
||||||
iq_united = _IQ18toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq19:
|
|
||||||
iq_united = _IQ19toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq20:
|
|
||||||
iq_united = _IQ20toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq21:
|
|
||||||
iq_united = _IQ21toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq22:
|
|
||||||
iq_united = _IQ22toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq23:
|
|
||||||
iq_united = _IQ23toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq24:
|
|
||||||
iq_united = _IQ24toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq25:
|
|
||||||
iq_united = _IQ25toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq26:
|
|
||||||
iq_united = _IQ26toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq27:
|
|
||||||
iq_united = _IQ27toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq28:
|
|
||||||
iq_united = _IQ28toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq29:
|
|
||||||
iq_united = _IQ29toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq30:
|
|
||||||
iq_united = _IQ30toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ïðèâåäåíèå îáùåãî IQ ê çàïðàøèâàåìîìó
|
// Êîíâåðòàöèÿ èç GLOBAL_Q â öåëåâîé IQ (64-áèò)
|
||||||
switch(var->return_type)
|
if (var->return_type == t_iq_none) {
|
||||||
{
|
// Âîçâðàùàåì öåëîå, îòáðîñèâ äðîáíóþ ÷àñòü
|
||||||
case t_iq_none:
|
*ret_var = (long)(iq_united64 >> GLOBAL_Q);
|
||||||
iq_final = (long)_IQtoF(iq_united);
|
} else {
|
||||||
break;
|
int shift = dst_q - GLOBAL_Q;
|
||||||
case t_iq1:
|
if (shift >= 0)
|
||||||
iq_final = _IQtoIQ1(iq_united);
|
iq_final64 = iq_united64 << shift;
|
||||||
break;
|
else
|
||||||
case t_iq2:
|
iq_final64 = iq_united64 >> (-shift);
|
||||||
iq_final = _IQtoIQ2(iq_united);
|
|
||||||
break;
|
// Ïðîâåðÿåì ïåðåïîëíåíèå int32_t
|
||||||
case t_iq3:
|
if (iq_final64 > LONG_MAX || iq_final64 < LONG_MIN)
|
||||||
iq_final = _IQtoIQ3(iq_united);
|
return 3; // ïåðåïîëíåíèå
|
||||||
break;
|
|
||||||
case t_iq4:
|
*ret_var = (long)iq_final64;
|
||||||
iq_final = _IQtoIQ4(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq5:
|
|
||||||
iq_final = _IQtoIQ5(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq6:
|
|
||||||
iq_final = _IQtoIQ6(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq7:
|
|
||||||
iq_final = _IQtoIQ7(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq8:
|
|
||||||
iq_final = _IQtoIQ8(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq9:
|
|
||||||
iq_final = _IQtoIQ9(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq10:
|
|
||||||
iq_final = _IQtoIQ10(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq11:
|
|
||||||
iq_final = _IQtoIQ11(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq12:
|
|
||||||
iq_final = _IQtoIQ12(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq13:
|
|
||||||
iq_final = _IQtoIQ13(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq14:
|
|
||||||
iq_final = _IQtoIQ14(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq15:
|
|
||||||
iq_final = _IQtoIQ15(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq16:
|
|
||||||
iq_final = _IQtoIQ16(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq17:
|
|
||||||
iq_final = _IQtoIQ17(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq18:
|
|
||||||
iq_final = _IQtoIQ18(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq19:
|
|
||||||
iq_final = _IQtoIQ19(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq20:
|
|
||||||
iq_final = _IQtoIQ20(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq21:
|
|
||||||
iq_final = _IQtoIQ21(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq22:
|
|
||||||
iq_final = _IQtoIQ22(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq23:
|
|
||||||
iq_final = _IQtoIQ23(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq24:
|
|
||||||
iq_final = _IQtoIQ24(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq25:
|
|
||||||
iq_final = _IQtoIQ25(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq26:
|
|
||||||
iq_final = _IQtoIQ26(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq27:
|
|
||||||
iq_final = _IQtoIQ27(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq28:
|
|
||||||
iq_final = _IQtoIQ28(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq29:
|
|
||||||
iq_final = _IQtoIQ29(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq30:
|
|
||||||
iq_final = _IQtoIQ30(iq_united);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret_var = iq_final;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 || !var->Ptr)
|
if (!var || !int_var || !float_var || !var->Ptr)
|
||||||
@@ -355,21 +214,19 @@ static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
|
|||||||
|
|
||||||
case pt_int16: // 16 áèò (int)
|
case pt_int16: // 16 áèò (int)
|
||||||
case pt_uint16:
|
case pt_uint16:
|
||||||
if (addr_val & 0x1) // ïðîâåðêà âûðàâíèâàíèÿ ïî 2 áàéòàì
|
|
||||||
return 2; // îøèáêà âûðàâíèâàíèÿ
|
|
||||||
*int_var = *((volatile int *)addr);
|
*int_var = *((volatile int *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pt_int32: // 32 áèò (long)
|
case pt_int32: // 32 áèò (long)
|
||||||
case pt_uint32:
|
case pt_uint32:
|
||||||
if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 áàéòàì
|
if (addr_val & 0x1) // ïðîâåðÿåì âûðàâíèâàíèå ïî 2 ñëîâàì (4 áàéòà)
|
||||||
return 3; // îøèáêà âûðàâíèâàíèÿ
|
return 3; // îøèáêà âûðàâíèâàíèÿ
|
||||||
*int_var = *((volatile long *)addr);
|
*int_var = *((volatile long *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case pt_int64: // 64 áèò (long long)
|
// case pt_int64: // 64 áèò (long long)
|
||||||
// case pt_uint64:
|
// case pt_uint64:
|
||||||
// if (addr_val & 0x7) // ïðîâåðêà âûðàâíèâàíèÿ ïî 8 áàéòàì
|
// if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 ñëîâàì (8 áàéòàì)
|
||||||
// return 2; // îøèáêà âûðàâíèâàíèÿ
|
// return 2; // îøèáêà âûðàâíèâàíèÿ
|
||||||
// // Òóò ïðîñòî ÷èòàåì, íî long long ìîæåò íå ïîìåñòèòüñÿ â *int_var
|
// // Òóò ïðîñòî ÷èòàåì, íî long long ìîæåò íå ïîìåñòèòüñÿ â *int_var
|
||||||
// // Ìîæíî çàìåíèòü ëîãèêó ïîä 64-áèòíîå ÷òåíèå ïðè íåîáõîäèìîñòè
|
// // Ìîæíî çàìåíèòü ëîãèêó ïîä 64-áèòíîå ÷òåíèå ïðè íåîáõîäèìîñòè
|
||||||
@@ -377,7 +234,7 @@ static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
|
|||||||
// break;
|
// break;
|
||||||
|
|
||||||
case pt_float: // float (4 áàéòà)
|
case pt_float: // float (4 áàéòà)
|
||||||
if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 áàéòàì
|
if (addr_val & 0x1) // ïðîâåðêà âûðàâíèâàíèÿ ïî 2 ñëîâàì
|
||||||
return 4; // îøèáêà âûðàâíèâàíèÿ
|
return 4; // îøèáêà âûðàâíèâàíèÿ
|
||||||
*float_var = *((volatile float *)addr);
|
*float_var = *((volatile float *)addr);
|
||||||
break;
|
break;
|
||||||
@@ -401,3 +258,212 @@ static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
|
|||||||
|
|
||||||
return 0; // óñïåõ
|
return 0; // óñïåõ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////// OUTDATE ////////////////
|
||||||
|
|
||||||
|
//
|
||||||
|
// // ïðèâåäåíèå ê îäíîìó IQ
|
||||||
|
// switch(var->iq_type)
|
||||||
|
// {
|
||||||
|
// case t_iq_none:
|
||||||
|
// if(var->ptr_type == pt_float)
|
||||||
|
// {
|
||||||
|
// iq_united = _IQ(float_numb);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// iq_united = _IQ(iq_numb);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case t_iq1:
|
||||||
|
// iq_united = _IQ1toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq2:
|
||||||
|
// iq_united = _IQ2toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq3:
|
||||||
|
// iq_united = _IQ3toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq4:
|
||||||
|
// iq_united = _IQ4toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq5:
|
||||||
|
// iq_united = _IQ5toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq6:
|
||||||
|
// iq_united = _IQ6toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq7:
|
||||||
|
// iq_united = _IQ7toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq8:
|
||||||
|
// iq_united = _IQ8toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq9:
|
||||||
|
// iq_united = _IQ9toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq10:
|
||||||
|
// iq_united = _IQ10toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq11:
|
||||||
|
// iq_united = _IQ11toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq12:
|
||||||
|
// iq_united = _IQ12toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq13:
|
||||||
|
// iq_united = _IQ13toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq14:
|
||||||
|
// iq_united = _IQ14toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq15:
|
||||||
|
// iq_united = _IQ15toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq16:
|
||||||
|
// iq_united = _IQ16toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq17:
|
||||||
|
// iq_united = _IQ17toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq18:
|
||||||
|
// iq_united = _IQ18toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq19:
|
||||||
|
// iq_united = _IQ19toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq20:
|
||||||
|
// iq_united = _IQ20toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq21:
|
||||||
|
// iq_united = _IQ21toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq22:
|
||||||
|
// iq_united = _IQ22toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq23:
|
||||||
|
// iq_united = _IQ23toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq24:
|
||||||
|
// iq_united = _IQ24toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq25:
|
||||||
|
// iq_united = _IQ25toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq26:
|
||||||
|
// iq_united = _IQ26toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq27:
|
||||||
|
// iq_united = _IQ27toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq28:
|
||||||
|
// iq_united = _IQ28toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq29:
|
||||||
|
// iq_united = _IQ29toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// case t_iq30:
|
||||||
|
// iq_united = _IQ30toIQ(iq_numb);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // ïðèâåäåíèå îáùåãî IQ ê çàïðàøèâàåìîìó
|
||||||
|
// switch(var->return_type)
|
||||||
|
// {
|
||||||
|
// case t_iq_none:
|
||||||
|
// iq_final = (long)_IQtoF(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq1:
|
||||||
|
// iq_final = _IQtoIQ1(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq2:
|
||||||
|
// iq_final = _IQtoIQ2(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq3:
|
||||||
|
// iq_final = _IQtoIQ3(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq4:
|
||||||
|
// iq_final = _IQtoIQ4(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq5:
|
||||||
|
// iq_final = _IQtoIQ5(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq6:
|
||||||
|
// iq_final = _IQtoIQ6(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq7:
|
||||||
|
// iq_final = _IQtoIQ7(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq8:
|
||||||
|
// iq_final = _IQtoIQ8(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq9:
|
||||||
|
// iq_final = _IQtoIQ9(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq10:
|
||||||
|
// iq_final = _IQtoIQ10(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq11:
|
||||||
|
// iq_final = _IQtoIQ11(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq12:
|
||||||
|
// iq_final = _IQtoIQ12(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq13:
|
||||||
|
// iq_final = _IQtoIQ13(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq14:
|
||||||
|
// iq_final = _IQtoIQ14(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq15:
|
||||||
|
// iq_final = _IQtoIQ15(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq16:
|
||||||
|
// iq_final = _IQtoIQ16(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq17:
|
||||||
|
// iq_final = _IQtoIQ17(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq18:
|
||||||
|
// iq_final = _IQtoIQ18(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq19:
|
||||||
|
// iq_final = _IQtoIQ19(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq20:
|
||||||
|
// iq_final = _IQtoIQ20(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq21:
|
||||||
|
// iq_final = _IQtoIQ21(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq22:
|
||||||
|
// iq_final = _IQtoIQ22(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq23:
|
||||||
|
// iq_final = _IQtoIQ23(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq24:
|
||||||
|
// iq_final = _IQtoIQ24(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq25:
|
||||||
|
// iq_final = _IQtoIQ25(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq26:
|
||||||
|
// iq_final = _IQtoIQ26(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq27:
|
||||||
|
// iq_final = _IQtoIQ27(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq28:
|
||||||
|
// iq_final = _IQtoIQ28(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq29:
|
||||||
|
// iq_final = _IQtoIQ29(iq_united);
|
||||||
|
// break;
|
||||||
|
// case t_iq30:
|
||||||
|
// iq_final = _IQtoIQ30(iq_united);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// *ret_var = iq_final;
|
||||||
|
|||||||
@@ -67,13 +67,14 @@ typedef enum
|
|||||||
t_iq30
|
t_iq30
|
||||||
}DebugVarIQType_t;
|
}DebugVarIQType_t;
|
||||||
|
|
||||||
|
typedef char DebugVarName_t[11];
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char* Ptr;
|
char* Ptr;
|
||||||
DebugVarPtrType_t ptr_type;
|
DebugVarPtrType_t ptr_type;
|
||||||
DebugVarIQType_t iq_type;
|
DebugVarIQType_t iq_type;
|
||||||
DebugVarIQType_t return_type;
|
DebugVarIQType_t return_type;
|
||||||
char name[11]; // 10 ñèìâîëîâ + '\0'
|
DebugVarName_t name;
|
||||||
}DebugVar_t;
|
}DebugVar_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -102,9 +103,9 @@ extern DebugVar_t dbg_vars[];
|
|||||||
|
|
||||||
void Debug_Test_Example(void);
|
void Debug_Test_Example(void);
|
||||||
|
|
||||||
|
int Debug_ReadVar(int var_ind, long *return_long);
|
||||||
|
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr);
|
||||||
int Debug_LowLevel_ReadVar(long *return_long);
|
int Debug_LowLevel_ReadVar(long *return_long);
|
||||||
int Debug_ReadVar(DebugVar_t *var, long *return_long);
|
|
||||||
int Debug_ReadVarName(DebugVar_t *var, char *name_ptr);
|
|
||||||
int Debug_LowLevel_Initialize(const char* external_date);
|
int Debug_LowLevel_Initialize(const char* external_date);
|
||||||
|
|
||||||
#endif //DEBUG_TOOLS
|
#endif //DEBUG_TOOLS
|
||||||
|
|||||||
346
debug_vars.c
346
debug_vars.c
@@ -1,346 +0,0 @@
|
|||||||
// Ýòîò ôàéë ñãåíåðèðîâàí àâòîìàòè÷åñêè
|
|
||||||
#include "debug_tools.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Èíêëþäû äëÿ äîñòóïà ê ïåðåìåííûì
|
|
||||||
#include "v_pwm24.h"
|
|
||||||
#include "f281xpwm.h"
|
|
||||||
#include "xp_project.h"
|
|
||||||
#include "RS_Functions_modbus.h"
|
|
||||||
#include "pwm_vector_regul.h"
|
|
||||||
#include "errors.h"
|
|
||||||
#include "rotation_speed.h"
|
|
||||||
#include "teta_calc.h"
|
|
||||||
#include "vector.h"
|
|
||||||
#include "adc_tools.h"
|
|
||||||
#include "log_can.h"
|
|
||||||
#include "xp_write_xpwm_time.h"
|
|
||||||
#include "dq_to_alphabeta_cos.h"
|
|
||||||
#include "svgen_dq.h"
|
|
||||||
#include "x_parallel_bus.h"
|
|
||||||
#include "x_serial_bus.h"
|
|
||||||
#include "xPeriphSP6_loader.h"
|
|
||||||
#include "Spartan2E_Functions.h"
|
|
||||||
#include "xp_controller.h"
|
|
||||||
#include "xp_rotation_sensor.h"
|
|
||||||
#include "RS_Functions.h"
|
|
||||||
#include "detect_phase_break2.h"
|
|
||||||
#include "pid_reg3.h"
|
|
||||||
#include "log_params.h"
|
|
||||||
#include "CRC_Functions.h"
|
|
||||||
#include "global_time.h"
|
|
||||||
#include "CAN_Setup.h"
|
|
||||||
#include "log_to_memory.h"
|
|
||||||
#include "IQmathLib.h"
|
|
||||||
#include "doors_control.h"
|
|
||||||
#include "isolation.h"
|
|
||||||
#include "main22220.h"
|
|
||||||
#include "optical_bus.h"
|
|
||||||
#include "alarm_log_can.h"
|
|
||||||
#include "bender.h"
|
|
||||||
#include "can_watercool.h"
|
|
||||||
#include "detect_phase_break.h"
|
|
||||||
#include "modbus_read_table.h"
|
|
||||||
#include "rmp_cntl_my1.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Ýêñòåðíû äëÿ äîñòóïà ê ïåðåìåííûì
|
|
||||||
extern int ADC0finishAddr;
|
|
||||||
extern int ADC0startAddr;
|
|
||||||
extern int ADC1finishAddr;
|
|
||||||
extern int ADC1startAddr;
|
|
||||||
extern int ADC2finishAddr;
|
|
||||||
extern int ADC2startAddr;
|
|
||||||
extern int ADC_f[2][16];
|
|
||||||
extern int ADC_sf[2][16];
|
|
||||||
extern int ADDR_FOR_ALL;
|
|
||||||
extern int BUSY;
|
|
||||||
extern BENDER Bender[2];
|
|
||||||
extern int CAN_answer_wait[32];
|
|
||||||
extern int CAN_count_cycle_input_units[8];
|
|
||||||
extern int CAN_no_answer[32];
|
|
||||||
extern int CAN_refresh_cicle[32];
|
|
||||||
extern int CAN_request_sent[32];
|
|
||||||
extern int CAN_timeout[32];
|
|
||||||
extern int CAN_timeout_cicle[32];
|
|
||||||
extern int CNTRL_ADDR;
|
|
||||||
extern const int CNTRL_ADDR_UNIVERSAL;
|
|
||||||
extern _iq CONST_15;
|
|
||||||
extern _iq CONST_23;
|
|
||||||
extern int CanOpenUnites[30];
|
|
||||||
extern int CanTimeOutErrorTR;
|
|
||||||
extern XControll_reg Controll;
|
|
||||||
extern int Dpwm;
|
|
||||||
extern int Dpwm2;
|
|
||||||
extern int Dpwm4;
|
|
||||||
extern int EvaTimer1InterruptCount;
|
|
||||||
extern int EvaTimer2InterruptCount;
|
|
||||||
extern int EvbTimer3InterruptCount;
|
|
||||||
extern int EvbTimer4InterruptCount;
|
|
||||||
extern int Fpwm;
|
|
||||||
extern int IN0finishAddr;
|
|
||||||
extern int IN0startAddr;
|
|
||||||
extern int IN1finishAddr;
|
|
||||||
extern int IN1startAddr;
|
|
||||||
extern int IN2finishAddr;
|
|
||||||
extern int IN2startAddr;
|
|
||||||
extern float IQ_OUT_NOM;
|
|
||||||
extern long I_OUT_1_6_NOMINAL_IQ;
|
|
||||||
extern long I_OUT_1_8_NOMINAL_IQ;
|
|
||||||
extern float I_OUT_NOMINAL;
|
|
||||||
extern long I_OUT_NOMINAL_IQ;
|
|
||||||
extern long I_ZPT_NOMINAL_IQ;
|
|
||||||
extern _iq Id_out_max_full;
|
|
||||||
extern _iq Id_out_max_low_speed;
|
|
||||||
extern _iq Iq_out_max;
|
|
||||||
extern _iq Iq_out_nom;
|
|
||||||
extern const unsigned long K_LEM_ADC[20];
|
|
||||||
extern float KmodTerm;
|
|
||||||
extern int ROTfinishAddr;
|
|
||||||
extern unsigned int RS_Len[70];
|
|
||||||
extern const unsigned int R_ADC[20];
|
|
||||||
extern int RotPlaneStartAddr;
|
|
||||||
extern _iq SQRT_32;
|
|
||||||
extern int Unites[8][128];
|
|
||||||
extern int VAR_FREQ_PWM_XTICS;
|
|
||||||
extern int VAR_PERIOD_MAX_XTICS;
|
|
||||||
extern int VAR_PERIOD_MIN_BR_XTICS;
|
|
||||||
extern int VAR_PERIOD_MIN_XTICS;
|
|
||||||
extern int Zpwm;
|
|
||||||
extern WINDING a;
|
|
||||||
extern volatile AddrToSent addrToSent;
|
|
||||||
extern unsigned int adr_read_from_modbus3;
|
|
||||||
extern ALARM_LOG_CAN alarm_log_can;
|
|
||||||
extern ALARM_LOG_CAN_SETUP alarm_log_can_setup;
|
|
||||||
extern ANALOG_VALUE analog;
|
|
||||||
extern int ar_sa_all[3][6][4][7];
|
|
||||||
extern _iq ar_tph[7];
|
|
||||||
extern int block_size_counter_fast;
|
|
||||||
extern int block_size_counter_slow;
|
|
||||||
extern _iq break_result_1;
|
|
||||||
extern _iq break_result_2;
|
|
||||||
extern _iq break_result_3;
|
|
||||||
extern _iq break_result_4;
|
|
||||||
extern Byte byte;
|
|
||||||
extern long c_s;
|
|
||||||
extern int calibration1;
|
|
||||||
extern int calibration2;
|
|
||||||
extern test_functions callfunc;
|
|
||||||
extern CANOPEN_CAN_SETUP canopen_can_setup;
|
|
||||||
extern unsigned int capnum0;
|
|
||||||
extern unsigned int capnum1;
|
|
||||||
extern unsigned int capnum2;
|
|
||||||
extern unsigned int capnum3;
|
|
||||||
extern unsigned int chNum;
|
|
||||||
extern BREAK_PHASE_I chanell1;
|
|
||||||
extern BREAK_PHASE_I chanell2;
|
|
||||||
extern int cmd_3_or_16;
|
|
||||||
extern int compress_size;
|
|
||||||
extern ControlReg controlReg;
|
|
||||||
extern COS_FI_STRUCT cos_fi;
|
|
||||||
extern unsigned int count_error_sync;
|
|
||||||
extern int count_modbus_table_changed;
|
|
||||||
extern int count_run_pch;
|
|
||||||
extern WORD crc_16_tab[256];
|
|
||||||
extern char crypt[34];
|
|
||||||
extern int cur_position_buf_modbus16_can;
|
|
||||||
extern CYCLE cycle[32];
|
|
||||||
extern int delta_capnum;
|
|
||||||
extern int delta_error;
|
|
||||||
extern volatile DOORS_STATUS doors;
|
|
||||||
extern int enable_can;
|
|
||||||
extern int enable_can_recive_after_units_box;
|
|
||||||
extern _iq err_level_adc;
|
|
||||||
extern _iq err_level_adc_on_go;
|
|
||||||
extern unsigned int err_main;
|
|
||||||
extern int err_modbus16;
|
|
||||||
extern int err_modbus3;
|
|
||||||
extern ERRORS errors;
|
|
||||||
extern FLAG f;
|
|
||||||
extern volatile int fail;
|
|
||||||
extern FAULTS faults;
|
|
||||||
extern FIFO fifo;
|
|
||||||
extern ANALOG_VALUE filter;
|
|
||||||
extern int flag_buf;
|
|
||||||
extern int flag_enable_can_from_mpu;
|
|
||||||
extern int flag_enable_can_from_terminal;
|
|
||||||
extern int flag_on_off_pch;
|
|
||||||
extern unsigned int flag_received_first_mess_from_MPU;
|
|
||||||
extern unsigned int flag_reverse;
|
|
||||||
extern unsigned int flag_send_answer_rs;
|
|
||||||
extern int flag_test_tabe_filled;
|
|
||||||
extern int flag_we_int_pwm_on;
|
|
||||||
extern _iq freq1;
|
|
||||||
extern float freqTerm;
|
|
||||||
extern GLOBAL_TIME global_time;
|
|
||||||
extern int hb_logs_data;
|
|
||||||
extern int i;
|
|
||||||
extern BREAK2_PHASE i1_out;
|
|
||||||
extern BREAK2_PHASE i2_out;
|
|
||||||
extern int init_log[3];
|
|
||||||
extern _iq19 iq19_k_norm_ADC[20];
|
|
||||||
extern _iq19 iq19_zero_ADC[20];
|
|
||||||
extern _iq iq_alfa_coef;
|
|
||||||
extern _iq iq_k_norm_ADC[20];
|
|
||||||
extern IQ_LOGSPARAMS iq_logpar;
|
|
||||||
extern _iq iq_max;
|
|
||||||
extern _iq iq_norm_ADC[20];
|
|
||||||
extern ISOLATION isolation1;
|
|
||||||
extern ISOLATION isolation2;
|
|
||||||
extern _iq k1;
|
|
||||||
extern float kI_D;
|
|
||||||
extern float kI_D_Inv31;
|
|
||||||
extern float kI_Q;
|
|
||||||
extern float kI_Q_Inv31;
|
|
||||||
extern float kP_D;
|
|
||||||
extern float kP_D_Inv31;
|
|
||||||
extern float kP_Q;
|
|
||||||
extern float kP_Q_Inv31;
|
|
||||||
extern _iq koef_Base_stop_run;
|
|
||||||
extern _iq koef_Iabc_filter;
|
|
||||||
extern _iq koef_Im_filter;
|
|
||||||
extern _iq koef_Im_filter_long;
|
|
||||||
extern _iq koef_K_stop_run;
|
|
||||||
extern _iq koef_Krecup;
|
|
||||||
extern _iq koef_Min_recup;
|
|
||||||
extern _iq koef_TemperBSU_long_filter;
|
|
||||||
extern _iq koef_Ud_fast_filter;
|
|
||||||
extern _iq koef_Ud_long_filter;
|
|
||||||
extern _iq koef_Wlong;
|
|
||||||
extern _iq koef_Wout_filter;
|
|
||||||
extern _iq koef_Wout_filter_long;
|
|
||||||
extern long koeff_Fs_filter;
|
|
||||||
extern long koeff_Idq_filter;
|
|
||||||
extern _iq koeff_Iq_filter;
|
|
||||||
extern long koeff_Iq_filter_slow;
|
|
||||||
extern long koeff_Ud_filter;
|
|
||||||
extern long koeff_Uq_filter;
|
|
||||||
extern volatile unsigned long length;
|
|
||||||
extern _iq level_on_off_break[13][2];
|
|
||||||
extern logcan_TypeDef log_can;
|
|
||||||
extern LOG_CAN_SETUP log_can_setup;
|
|
||||||
extern TYPE_LOG_PARAMS log_params;
|
|
||||||
extern long logbuf_sync1[10];
|
|
||||||
extern LOGSPARAMS logpar;
|
|
||||||
extern int m_PWM;
|
|
||||||
extern MAILBOXS_CAN_SETUP mailboxs_can_setup;
|
|
||||||
extern int manufactorerAndProductID;
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_can_in;
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_can_out;
|
|
||||||
extern MODBUS_REG_STRUCT modbus_table_in[450];
|
|
||||||
extern MODBUS_REG_STRUCT modbus_table_out[450];
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_rs_in;
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_rs_out;
|
|
||||||
extern MODBUS_REG_STRUCT modbus_table_test[450];
|
|
||||||
extern MPU_CAN_SETUP mpu_can_setup;
|
|
||||||
extern NEW_CYCLE_FIFO new_cycle_fifo;
|
|
||||||
extern int no_write;
|
|
||||||
extern int no_write_slow;
|
|
||||||
extern int number_modbus_table_changed;
|
|
||||||
extern OPTICAL_BUS_DATA optical_read_data;
|
|
||||||
extern OPTICAL_BUS_DATA optical_write_data;
|
|
||||||
extern MODBUS_REG_STRUCT options_controller[200];
|
|
||||||
extern _iq pidCur_Ki;
|
|
||||||
extern PIDREG3 pidD;
|
|
||||||
extern PIDREG3 pidD2;
|
|
||||||
extern PIDREG3 pidFvect;
|
|
||||||
extern int pidFvectKi_test;
|
|
||||||
extern int pidFvectKp_test;
|
|
||||||
extern PIDREG3 pidPvect;
|
|
||||||
extern PIDREG3 pidQ;
|
|
||||||
extern PIDREG3 pidQ2;
|
|
||||||
extern PIDREG_KOEFFICIENTS pidReg_koeffs;
|
|
||||||
extern PIDREG3 pidTetta;
|
|
||||||
extern POWER_RATIO power_ratio;
|
|
||||||
extern int prev_flag_buf;
|
|
||||||
extern unsigned int prev_status_received;
|
|
||||||
extern T_project project;
|
|
||||||
extern PWMGEND pwmd;
|
|
||||||
extern T_controller_read r_c_sbus;
|
|
||||||
extern T_controller_read r_controller;
|
|
||||||
extern FIFO refo;
|
|
||||||
extern TMS_TO_TERMINAL_STRUCT reply;
|
|
||||||
extern TMS_TO_TERMINAL_TEST_ALL_STRUCT reply_test_all;
|
|
||||||
extern long return_var;
|
|
||||||
extern RMP_MY1 rmp_freq;
|
|
||||||
extern RMP_MY1 rmp_wrot;
|
|
||||||
extern T_rotation_sensor rotation_sensor;
|
|
||||||
extern ROTOR_VALUE rotor;
|
|
||||||
extern RS_DATA_STRUCT rs_a;
|
|
||||||
extern RS_DATA_STRUCT rs_b;
|
|
||||||
extern unsigned int sincronisationFault;
|
|
||||||
extern char size_cmd15;
|
|
||||||
extern char size_cmd16;
|
|
||||||
extern int size_fast_done;
|
|
||||||
extern int size_slow_done;
|
|
||||||
extern int stop_log;
|
|
||||||
extern int stop_log_slow;
|
|
||||||
extern SVGENDQ svgen_dq_1;
|
|
||||||
extern SVGENDQ svgen_dq_2;
|
|
||||||
extern SVGEN_PWM24 svgen_pwm24_1;
|
|
||||||
extern SVGEN_PWM24 svgen_pwm24_2;
|
|
||||||
extern unsigned int temp;
|
|
||||||
extern _iq temperature_limit_koeff;
|
|
||||||
extern INVERTER_TEMPERATURES temperature_warning_BI1;
|
|
||||||
extern INVERTER_TEMPERATURES temperature_warning_BI2;
|
|
||||||
extern RECTIFIER_TEMPERATURES temperature_warning_BV1;
|
|
||||||
extern RECTIFIER_TEMPERATURES temperature_warning_BV2;
|
|
||||||
extern TERMINAL_CAN_SETUP terminal_can_setup;
|
|
||||||
extern TETTA_CALC tetta_calc;
|
|
||||||
extern int timCNT_alg;
|
|
||||||
extern int timCNT_prev;
|
|
||||||
extern unsigned int time;
|
|
||||||
extern float time_alg;
|
|
||||||
extern long time_pause_enable_can_from_mpu;
|
|
||||||
extern long time_pause_enable_can_from_terminal;
|
|
||||||
extern int time_pause_logs;
|
|
||||||
extern int time_pause_titles;
|
|
||||||
extern volatile int tryNumb;
|
|
||||||
extern UNITES_CAN_SETUP unites_can_setup;
|
|
||||||
extern long var_numb;
|
|
||||||
extern VECTOR_CONTROL vect_control;
|
|
||||||
extern WaterCooler water_cooler;
|
|
||||||
extern _iq winding_displacement;
|
|
||||||
extern Word word;
|
|
||||||
extern WordReversed wordReversed;
|
|
||||||
extern WordToReverse wordToReverse;
|
|
||||||
extern X_PARALLEL_BUS x_parallel_bus_project;
|
|
||||||
extern X_SERIAL_BUS x_serial_bus_project;
|
|
||||||
extern unsigned int xeeprom_controll_fast;
|
|
||||||
extern unsigned int xeeprom_controll_store;
|
|
||||||
extern XPWM_TIME xpwm_time;
|
|
||||||
extern _iq zadan_Id_min;
|
|
||||||
extern int zero_ADC[20];
|
|
||||||
|
|
||||||
|
|
||||||
// Îïðåäåëåíèå ìàññèâà ñ óêàçàòåëÿìè íà ïåðåìåííûå äëÿ îòëàäêè
|
|
||||||
int DebugVar_Qnt = 26;
|
|
||||||
#pragma DATA_SECTION(dbg_vars,".dbgvar_info")
|
|
||||||
DebugVar_t dbg_vars[] = {\
|
|
||||||
{(char *)&ADC0finishAddr, pt_int16, t_iq_none, t_iq_none, "ADC0finish" }, \
|
|
||||||
{(char *)&ADC_f[0][11], pt_int32, t_iq_none, t_iq_none, "ADC_f[0][1" }, \
|
|
||||||
{(char *)&ADC_f[0][12], pt_int16, t_iq_none, t_iq_none, "ADC_f[0][1" }, \
|
|
||||||
{(char *)&ADC_f[0][13], pt_int32, t_iq_none, t_iq_none, "ADC_f[0][1" }, \
|
|
||||||
{(char *)&ADC_f[0][14], pt_int16, t_iq_none, t_iq_none, "ADC_f[0][1" }, \
|
|
||||||
{(char *)&ADC_f[0][15], pt_int16, t_iq_none, t_iq_none, "ADC_f[0][1" }, \
|
|
||||||
{(char *)&ADC_f[1][0], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][0" }, \
|
|
||||||
{(char *)&ADC_f[1][1], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][1" }, \
|
|
||||||
{(char *)&ADC_f[1][2], pt_int64, t_iq_none, t_iq_none, "ADC_f[1][2" }, \
|
|
||||||
{(char *)&ADC_f[1][3], pt_int32, t_iq_none, t_iq_none, "ADC_f[1][3" }, \
|
|
||||||
{(char *)&ADC_f[1][4], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][4" }, \
|
|
||||||
{(char *)&ADC_f[1][5], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][5" }, \
|
|
||||||
{(char *)&ADC_f[1][6], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][6" }, \
|
|
||||||
{(char *)&ADC_f[1][7], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][7" }, \
|
|
||||||
{(char *)&ADC_f[1][8], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][8" }, \
|
|
||||||
{(char *)&ADC_f[1][9], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][9" }, \
|
|
||||||
{(char *)&ADC_f[1][10], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][1" }, \
|
|
||||||
{(char *)&ADC_f[1][11], pt_int16, t_iq1, t_iq_none, "ADC_f[1][1" }, \
|
|
||||||
{(char *)&ADC_f[1][12], pt_int32, t_iq_none, t_iq_none, "ADC_f[1][1" }, \
|
|
||||||
{(char *)&ADC_f[1][13], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][1" }, \
|
|
||||||
{(char *)&ADC_f[1][14], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][1" }, \
|
|
||||||
{(char *)&ADC_f[1][15], pt_int16, t_iq_none, t_iq_none, "ADC_f[1][1" }, \
|
|
||||||
{(char *)&project.cds_in[0].plane_address, pt_uint16, t_iq_none, t_iq_none, "project.cd" }, \
|
|
||||||
{(char *)&Bender[0].KOhms, pt_uint16, t_iq_none, t_iq_none, "Bender[0]." }, \
|
|
||||||
{(char *)&Bender[0].Times, pt_uint16, t_iq_none, t_iq_none, "Bender[0]." }, \
|
|
||||||
{(char *)&Bender[0].Error.all, pt_uint16, t_iq_none, t_iq_none, "Bender[0]." }, \
|
|
||||||
};
|
|
||||||
20181
structs.xml
20181
structs.xml
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user