31 Commits

Author SHA1 Message Date
Razvalyaev
10dd2a6987 Добавлено автообновление 2025-07-25 16:05:05 +03:00
Razvalyaev
910bf0a585 Обновлены readme 2025-07-23 18:18:19 +03:00
Razvalyaev
502046091c опять кууууча всего:
базово доделаны терминалки до более менее итогового состояния
2025-07-23 17:13:28 +03:00
Razvalyaev
e99de603e6 попытка сделать в parse_xml парсинг вложенных массивов [][]
определяет вложенные массивы но не определяет их размерности (нули)
2025-07-22 18:57:59 +03:00
Razvalyaev
788ad19464 кууууча всего по терминалке, надо резгребать и структурировать
базово:
+сделан lowlevel для кучи переменных (пока работает медленно)
+сделан сохранение принимаемых значений в лог
+ gui терминалок подогнаны под один стиль плюс минус
2025-07-22 18:05:12 +03:00
Razvalyaev
96496a0256 все неплохо работает.
сейв перед попыткой улучшить lowlevel debug
2025-07-21 13:40:52 +03:00
Razvalyaev
f89aff1b1c Улучшена скорость полла Watch (переделано формирование таблицы) 2025-07-19 18:17:00 +03:00
Razvalyaev
6830743477 Начата работа над lowlevel терминалкой (по адресам из xml) 2025-07-19 18:01:40 +03:00
Razvalyaev
171f176d63 добавлен exe для парса всех переменных из .out 2025-07-19 11:36:32 +03:00
Razvalyaev
f2c4b7b3cd структурирован код debug_tools
доработана демо-терминалка для считывания tms переменных и встроена в DebugVarEdit
2025-07-19 10:56:46 +03:00
Razvalyaev
c94a7e711c сделана бета терминалка для опроса переменных 2025-07-18 17:43:23 +03:00
Razvalyaev
5be6343c33 бета терминалка для опроса 2025-07-18 16:47:18 +03:00
Razvalyaev
043359fe66 + фикс кривых проверок на наличие uint8_t
+ фикс перевод float в iq
+ фикс поиска вручнуб добавленных переменных в debug_vars.c
2025-07-17 10:37:58 +03:00
Razvalyaev
c55f38ef1c + пример debug_vars.c
+ exe
+ опечатка в readme
+ коррекции по абзацам в комментах
2025-07-17 09:26:57 +03:00
Razvalyaev
ae2c90160e +библиотека .c/.h переписана под универсальные дефайны intX_t uintX_t
+сделано задание размера короткого имени
+ добавлена бета поддержка stm:+
   - парс переменных из файла преокта Keil или makefile CubeIDE
   - запись в utf-8 для STM, вместо cp1251 для TMS
   - другой размер int (32 бита, вместо 16 бит) для STM
2025-07-17 09:18:03 +03:00
Razvalyaev
4de53090a1 добавлены комменты к debug_tools.c/.h
начата работа над поддержкой stm32 и кейл проектов
2025-07-15 19:05:52 +03:00
Razvalyaev
742c4e9e1b readme для .c файлов 2025-07-15 15:56:47 +03:00
Razvalyaev
369cfa808c чистка для релиза
переструктурировано чуть

и всякие мелкие фиксы
2025-07-15 15:37:29 +03:00
Razvalyaev
c32dc161f8 переструктурирвоаны исходники проекта 2025-07-15 13:31:18 +03:00
Razvalyaev
abfc507e4e регулярнка не работает в clean_remp 2025-07-15 13:13:08 +03:00
Razvalyaev
cb496bca0f добавлен readme
другая библиотека для xml (более быстрая)
сделан выбор элементов в выпадающем списке типов
исправлено вроде кривое выставлениеп return_type
изменено окно выбора переменых
    - кнопки добавит, удалить заменены на применить
    - исправлены кривые подсказки в .exe версии
2025-07-15 13:03:11 +03:00
Razvalyaev
7b720cbdf4 криво работает return_type, надо разобратся
чет поделано в коде для тмс
2025-07-14 17:54:49 +03:00
Razvalyaev
6428e523df сделано ленивое раскрытие подпеременных в структурах
(баово заглушки и если они раскрываются,то подставляются реальнгые)
2025-07-14 14:57:32 +03:00
Razvalyaev
c738acd871 фикс мелочей в таблицах выбора
+exe
+3.13 python installer заменен на 3.9 (3.13 не имеет PySide2)
2025-07-14 07:35:28 +03:00
Razvalyaev
05bde87c38 +exe 2025-07-13 22:53:58 +03:00
Razvalyaev
02f3124224 ну вроде чуть поменьше тормозит, но все равно неприятно. надо еще подумать 2025-07-13 22:47:33 +03:00
Razvalyaev
21082a38e0 ну вроде работает, но опять тормозит 2025-07-13 22:17:45 +03:00
Razvalyaev
42ac3eb65d наконец-то вроде сделан поиск.
есть кривости в подскасках
начата работа надо двумя таблицами (всех и выбранных переменных)
2025-07-13 18:53:01 +03:00
Razvalyaev
69c0bf1574 почему-то внуки, правнуки и так далее в поиске на находятся... 2025-07-12 18:13:51 +03:00
Razvalyaev
4f949e9854 таблица выбора элементов вынесена в отдельный класс 2025-07-12 08:54:53 +03:00
Razvalyaev
0d54031dd5 исправлен поиск и фильтрация
плюс делание всякого по коду для мк
2025-07-11 17:57:29 +03:00
33 changed files with 6601 additions and 26996 deletions

2
.gitignore vendored
View File

@@ -5,3 +5,5 @@
/DebugVarEdit_GUI.build
/DebugVarEdit_GUI.dist
/DebugVarEdit_GUI.onefile-build
/parse_xml/build/
/parse_xml/Src/__pycache__/

Binary file not shown.

BIN
DebugVarTerminal.exe Normal file

Binary file not shown.

282
README.md Normal file
View File

@@ -0,0 +1,282 @@
# DebugTools - Просмотр переменных по указателям
## Содержание
1. [Описание модуля](#программный-модуль-debugtools)
2. [Описание приложения для настройки](#debugvaredit---настройка-переменных)
3. [Описание терминалки для считывания](#debugvarterminal---считывание-переменных-для-tms)
4. [Для разработчиков](#для-разработчиков)
# Программный модуль DebugTools
Модуль состоит из трех файлов:
- **debug_tools.c** - реализация считывания переменных
- **debug_tools.h** - объявление всякого для считывания переменных
- **debug_vars.c** - определение массива считываемых переменных
Этот модуль предоставляет функциональность для чтения значений переменных во встроенной системе, включая работу с IQ-форматами, защиту доступа и проверку диапазонов памяти.
Для чтения переменных можно использовать функции:
```c
/* Читает значение переменной по индексу */
int Debug_ReadVar(int var_ind, int32_t *return_long);
/* Читает имя переменной по индексу */
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr, int *length);
/* Читает возвращаемый тип (IQ) переменной по индексу */
int Debug_ReadVarReturnType(int var_ind, int *vartype);
/* Читает тип переменной по индексу */
int Debug_ReadVarType(int var_ind, int *vartype);
/* Читает значение переменной с нижнего уровня */
int Debug_LowLevel_ReadVar(int32_t *return_long);
/* Инициализирует отладку нижнего уровня */
int Debug_LowLevel_Initialize(DateTime_t *external_date);
/* Читает возвращаемый тип (IQ) низкоуровнено заданной переменной */
int Debug_LowLevel_ReadVarReturnType(int *vartype);
/* Читает тип низкоуровнено заданной переменной.*/
int Debug_LowLevel_ReadVarType(int *vartype);
```
Переменные доступные для чтения определяются в **debug_vars.c** (их можно прописывать вручную или генерировать через **DebugVarEdit**):
```c
// Определение массива с указателями на переменные для отладки
int DebugVar_Qnt = 5;
#pragma DATA_SECTION(dbg_vars,".dbgvar_info")
// pointer_type iq_type return_iq_type short_name
DebugVar_t dbg_vars[] = {\
{(uint8_t *)&freqTerm, pt_float, t_iq_none, t_iq10, "freqT" }, \
{(uint8_t *)&ADC_sf[0][0], pt_int16, t_iq_none, t_iq_none, "ADC_sf00" }, \
{(uint8_t *)&ADC_sf[0][1], pt_int16, t_iq_none, t_iq_none, "ADC_sf01" }, \
{(uint8_t *)&ADC_sf[0][2], pt_int16, t_iq_none, t_iq_none, "ADC_sf02" }, \
{(uint8_t *)&ADC_sf[0][3], pt_int16, t_iq_none, t_iq_none, "ADC_sf03" }, \
{(uint8_t *)&Bender[0].KOhms, pt_uint16, t_iq, t_iq10, "Bend0.KOhm" }, \
{(uint8_t *)&Bender[0].Times, pt_uint16, t_iq_none, t_iq_none, "Bend0.Time" }, \
};
```
## LowLevel - Просмотр абсолютно любых переменных
Также присутствует утилита `parse_xml.exe`, которая генерирует `.xml` файл с всеми переменными в программе и их адрессами
Для её подключения:
- В Pre-Build Steps добавить следующую команду. Это удаление `debug_tools.obj` файла для его перекомпиялции с актуальной датой компиляции
```
cmd /c del /Q "${CWD}\Src\DebugTools\debug_tools.obj"
```
- В Post-Build Steps добавить следующую команду. Это:
- формирование с помощью утилиты компилятора `ofd2000` `.xml` файла с полной отладочной информацией.
- формирование отладочной информации в текстовом файле (для получения таймштампа)
- запуск утилиты `parse_xml.exe` для формирования итогового `<projname>_allVars.xml` с информацией о переменных и адресах
```
"${CG_TOOL_ROOT}/bin/ofd2000" --obj_display=symbols --dwarf --dwarf_display=all --xml --xml_indent=1 --output="${BuildArtifactFileBaseName}_ofd_dump.xml" "${BuildArtifactFilePath}"
"${CG_TOOL_ROOT}/bin/ofd2000" "${BuildArtifactFilePath}" > ${CCS_PROJECT_DIR}/bin/temp.txt
"${CCS_PROJECT_DIR}/Src/DebugTools/parse_xml/parse_xml.exe" ${BuildArtifactFileBaseName}_ofd_dump.xml ${CCS_PROJECT_DIR}/bin/temp.txt ${BuildArtifactFileBaseName}_allVars.xml"
```
После, с использованием терминалки можно прочитать любые переменные по адресам. (должен совпадать таймштапм в прошивке и `.xml` файла, иначе контроллер ответит ошибкой)
# 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` с переменными.
- **МК** — TMS или STM. Они отличаются размером int, и также принятыми кодировками файлов (utf-8/cp1251)
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="Src/DebugTools/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>
```
---
# DebugVarTerminal - Считывание переменных (для TMS)
**DebugVarTerminal** — терминалка для считывания переменных по RS-232 протоколу RS_Functions.
Программа — один исполняемый файл `DebugVarTerminal.exe`, не требующий установки и дополнительных зависимостей.
> Требуется Windows 7 или новее.
---
## Как использовать приложение
1. Запустите **DebugVarTerminal.exe.**
2. Выберите COM Port и скорость Baud. Нажмиите **Open**
3. Для считывания переменных заданных в `*debug_vars.c`:
- Откройте вкладку **Watch**.
- Выберите стартовый индекс переменной и количество переменных для считывания.
- Нажмите одну из кнопок:
- **Update Service** - считывает информацию об именах и возвращаемых IQ типах переемнных
- **Read Value(s)** - считывает и форматирует значения переменных в соответствии с IQ типами
- **Start Polling** - начать опрос выбранных переменных с заданным интервалом. При старте опроса, имя и тип переменных считываются автоматически
4. Для считывания переменных по адресам:
- Откройте вкладку **LowLevel**.
- Выберите `projname_allVars.xml` в папке bin рядом с бинарником. Из него подгрузятся все доступные для считывания переменные
- Выберите переменные кнопкной **Выбрать переменные**
- Задайте IQ тип и возвращаемый IQ тип если требуется
- Нажмите одну из кнопок:
- **Read Once** - считывает выбранные переменные один раз
- **Start Polling** - начать опрос выбранных переменных с заданным интервалом
5. Запись в CSV:
- Можно записывавать считываемые переменные в CSV файл, с разделителем `;`
- Нажмите кнопку **Начать запись в CSV**
- Когда нужная выборка будет накоплена нажмите **Остаовить запись в CSV**
- Нажмите **Выбрать файл CSV** для выбора пути для сохранения файла и нажмите **Сохранить данные в CSV** чтобы сохранить
- Генерируется совместимый с LogView `.csv` файл
Все параметры выбираются из выпадающих списков, которые можно настроить, чтобы отображались только нужные опции.
---
## Возможности
Режим "Watch":
- Быстрое и удобное чтение одной или нескольких переменных по их индексу.
- Автоматическое получение имен, типов и параметров масштабирования (IQ) переменных.
- Запуск постоянного опроса для отслеживания изменений значений в реальном времени.
- Наглядное представление данных в таблице с отображением как сырых, так и масштабированных значений.
Режим "LowLevel":
- Прямое чтение данных из памяти по заданным адресам.
- Возможность указания типов указателей, IQ-масштабирования и форматов возвращаемых данных.
- Аналогично режиму "Watch", поддерживается постоянный опрос выбранных низкоуровневых переменных.
- Умное автодополнение имён переменных и полей структур.
Логирование в CSV
- Записывайте все полученные значения в файл формата CSV для последующего анализа.
- Легкое управление записью: запуск, остановка и сохранение данных в любой момент.
---
---
# Для разработчиков
### Структура проекта:
```bash
Src
├── build/
│ └── build_and_clean.py # Билдинг проекта в .exe (через nuitka или pyinstaller)
├── DebugVarEdit_GUI.py # Главное окно
├── tms_debugvar_term.py # Терминал DebugVarTerminal
├── tms_debugvar_lowlevel.py # Виджет для выбора переменных для LowLevel Watch
├── 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
├── allvars_xml_parser.py # Парсинг XML со всеми переменными и структурами
├── csv_logger.py # Логирование переменных в CSV
├── myXML.py # Утилиты для XML
├── makefile_parser.py # Парсинг makefile на .c/.h файлы
├── var_setup.py # Подготовка переменных для окна выбора переменных
├── path_hints.py # Подсказки для автодополнения путей переменных
├── libclang.dll # Бибилиотека clang
├── icon.ico # Иконка
```
### Зависимости
Для запуска приложения:
- **Python 3.7+**
- **clang** — используется для парсинга C-кода (требуется `libclang.dll`, лежит в папке Src)
- **PySide2** — GUI-фреймворк
- **lxml** — работа с XML
> Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7
Для сборки `.exe`:
- **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей
- **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен для запуска `.exe`)
### Сборка:
Если вы хотите собрать `DebugVarEdit.exe` самостоятельно из исходников, используйте скрипт **build/build_and_clean.py**. Он автоматически собирает проект с помощью Nuitka или PyInstaller:
- Собирает проект в `DebugVarEdit.exe` в корневой папке.
- Включает:
- все необходимые `.dll` (например, `libclang.dll`),
- иконку (`icon.ico`),
- плагины PySide2.
- Очищает временные папки после сборки:
- `build_temp`
- `__pycache__`
- `<MAIN_SCRIPT_NAME>.*`
> Все пути, имена файлов, временные папки и выбор между Nuitka и PyInstaller можно настроить в начале файла `build_and_clean.py`.
### Установка зависимостей
```bash
pip install clang PySide2 lxml nuitka pyinstaller
```

View File

@@ -1,28 +1,31 @@
# 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 os
import subprocess
import xml.etree.ElementTree as ET
from generateVars import type_map
import lxml.etree as ET
from generate_debug_vars import type_map, choose_type_map
from enum import IntEnum
from tms_debugvar_term import _DemoWindow
import threading
from generateVars import run_generate
import setupVars
from VariableSelector import VariableSelectorDialog
from VariableTable import VariableTableWidget, rows
from scanVarGUI import ProcessOutputWindow
import scanVars
from generate_debug_vars import run_generate
import var_setup
from var_selector_window import VariableSelectorDialog
from var_table import VariableTableWidget, rows
from scan_progress_gui import ProcessOutputWindow
import scan_vars
import myXML
import time
import auto_updater
from PySide2.QtWidgets import (
QApplication, QWidget, QTableWidget, QTableWidgetItem,
QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton,
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit,
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView
)
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView,
QMenuBar, QMenu, QAction
)
from PySide2.QtGui import QTextCursor, QKeyEvent, QIcon, QFont
from PySide2.QtCore import Qt, QProcess, QObject, Signal, QSettings
@@ -31,12 +34,18 @@ var_edit_title = "Редактор переменных для отладки"
xml_path_title = "Путь к XML:"
proj_path_title = "Путь к проекту:"
makefile_path_title = "Пусть к makefile (относительно проекта)"
output_path_title = "Папка для debug_vars.c:"
output_path_title = "Путь для для debug_vars.c:"
scan_title = "Сканировать переменные"
build_title = "Сгенерировать файл"
add_vars_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: таблица с переменными
class VarEditor(QWidget):
def __init__(self):
@@ -52,12 +61,13 @@ class VarEditor(QWidget):
self.output_path = None
self._updating = False # Флаг блокировки рекурсии
self._resizing = False # флаг блокировки повторного вызова
self.target = 'TMS'
self.initUI()
def initUI(self):
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")
if os.path.exists(icon_path):
self.setWindowIcon(QIcon(icon_path))
@@ -116,6 +126,43 @@ class VarEditor(QWidget):
self.btn_update_vars = QPushButton(scan_title)
self.btn_update_vars.clicked.connect(self.update_vars_data)
# Добавляем чекбокс для выбора типовой карты
# --- Создаем верхнее меню ---
menubar = QMenuBar(self)
menubar.setToolTip('Разные размеры int и кодировки файлов')
self.target_menu = QMenu("МК:", menubar)
# Создаем действия для выбора Target
self.action_tms = QAction("TMS", self, checkable=True)
self.action_stm = QAction("STM", self, checkable=True)
# Инициализируем QSettings с именем организации и приложения
self.settings = QSettings("SET", "DebugVarEdit_MainWindow")
# Восстанавливаем сохранённое состояние, если есть
mcu = self.settings.value("mcu_choosen", True, type=str)
self.on_target_selected(mcu)
self.target_menu.setToolTip(f'TMS: Размер int 16 бит. Кодировка cp1251\nSTM: Размер int 32 бита. Кодировка utf-8')
# Группируем действия чтобы выбирался только один
self.action_tms.triggered.connect(lambda: self.on_target_selected("TMS"))
self.action_tms.setToolTip('Размер int 16 бит. Кодировка cp1251')
self.action_stm.triggered.connect(lambda: self.on_target_selected("STM"))
self.action_stm.setToolTip('Размер int 32 бита. Кодировка utf-8')
self.target_menu.addAction(self.action_tms)
self.target_menu.addAction(self.action_stm)
self.terminal_menu = QMenu("Открыть Терминал", menubar)
self.action_terminal_tms = QAction("TMS DemoTerminal", self)
self.action_terminal_modbus = QAction("Modbus DemoTerminal", self)
self.action_terminal_tms.triggered.connect(lambda: self.open_terminal("TMS"))
self.action_terminal_modbus.triggered.connect(lambda: self.open_terminal("MODBUS"))
self.terminal_menu.addAction(self.action_terminal_tms)
#self.terminal_menu.addAction(self.action_terminal_modbus)
menubar.addMenu(self.target_menu)
menubar.addMenu(self.terminal_menu)
# Кнопка сохранения
btn_save = QPushButton(build_title)
btn_save.clicked.connect(self.save_build)
@@ -131,6 +178,7 @@ class VarEditor(QWidget):
self.table = VariableTableWidget()
# Основной layout
layout = QVBoxLayout()
layout.setMenuBar(menubar) # прикрепляем menubar в layout сверху
layout.addLayout(xml_layout)
layout.addLayout(proj_layout)
layout.addLayout(makefile_layout)
@@ -144,6 +192,53 @@ class VarEditor(QWidget):
self.setLayout(layout)
def open_terminal(self, target):
target = target.lower()
if target == "tms":
exe_name = "DebugVarTerminal.exe"
# Путь к exe в текущей директории запуска программы
exe_path = os.path.join(os.getcwd(), exe_name)
if not os.path.isfile(exe_path):
# Файл не найден — попросим пользователя выбрать путь к exe
msg = QMessageBox()
msg.setIcon(QMessageBox.Warning)
msg.setWindowTitle("Файл не найден")
msg.setText(f"Файл {exe_name} не найден в текущей папке.\nВыберите путь к {exe_name}.")
msg.exec_()
# Открываем диалог выбора файла
selected_path, _ = QFileDialog.getOpenFileName(
None, "Выберите файл " + exe_name, os.getcwd(), "Executable Files (*.exe)"
)
if not selected_path:
# Пользователь отменил выбор — ничего не делаем
return
exe_path = selected_path
# Запускаем exe (отдельное окно терминала)
subprocess.Popen([exe_path], creationflags=subprocess.CREATE_NEW_CONSOLE)
elif target == "modbus":
a = 1
def on_target_selected(self, target):
self.target_menu.setTitle(f'МК: {target}')
self.settings.setValue("mcu_choosen", target)
self.target = target.lower()
if self.target == "stm":
choose_type_map(True)
self.action_stm.setChecked(True)
self.action_tms.setChecked(False)
else:
choose_type_map(False)
self.action_tms.setChecked(True)
self.action_stm.setChecked(False)
def get_xml_path(self):
xml_path = self.xml_output_edit.text().strip()
@@ -202,7 +297,7 @@ class VarEditor(QWidget):
# Создаём окно с кнопкой "Готово"
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()
@@ -222,8 +317,8 @@ class VarEditor(QWidget):
var_data = {
'name': name_edit.text(),
'type': 'pt_' + pt_type_combo.currentText(),
'iq_type': iq_combo.currentText(),
'return_type': ret_combo.currentText() if ret_combo.currentText() else 'int',
'iq_type': 't_' + iq_combo.currentText(),
'return_type': 't_' + ret_combo.currentText() if ret_combo.currentText() else 't_iq_none',
'short_name': short_name_edit.text(),
}
vars_out.append(var_data)
@@ -235,15 +330,15 @@ class VarEditor(QWidget):
return
try:
run_generate(self.proj_path, self.xml_path, self.output_path)
run_generate(self.proj_path, self.xml_path, self.output_path, self.table._shortname_size)
QMessageBox.information(self, "Готово", "Файл debug_vars.c успешно сгенерирован.")
self.update()
except Exception as e:
QMessageBox.critical(self, "Ошибка при генерации", str(e))
def update(self):
if self._updating:
def update(self, force=0):
if self._updating and (force==0):
return # Уже в процессе обновления — выходим, чтобы избежать рекурсии
self._updating = True
@@ -296,11 +391,11 @@ class VarEditor(QWidget):
structs_path_full = myXML.make_absolute_path(structs_path, self.proj_path)
if structs_path_full and os.path.isfile(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:
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)
except Exception as e:
QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
@@ -352,10 +447,20 @@ class VarEditor(QWidget):
super().keyPressEvent(event)
def __browse_makefile(self):
if self.target == 'stm':
file_filter = "Makefile или Keil-проект (*.uvprojx *.uvproj makefile);;Все файлы (*)"
dialog_title = "Выберите Makefile или Keil-проект"
else: # 'TMS' или по умолчанию
file_filter = "Makefile (makefile);;Все файлы (*)"
dialog_title = "Выберите Makefile"
file_path, _ = QFileDialog.getOpenFileName(
self, "Выберите Makefile", filter="Makefile (makefile);;All Files (*)"
self,
dialog_title,
filter=file_filter
)
if file_path and self.proj_path:
if file_path:
if self.proj_path:
path = myXML.make_relative_path(file_path, self.proj_path)
else:
path = file_path
@@ -398,37 +503,42 @@ class VarEditor(QWidget):
self.update()
def __after_scanvars_finished(self):
self.update_all_paths()
def __after_scan_vars_finished(self):
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}")
return
try:
self.update(1)
except Exception as e:
self.makefile_path = None
self.structs_path = None
self.proj_path = None
self.update()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить переменные:\n{e}")
def delete_selected_rows(self):
selected_rows = sorted(set(index.row() for index in self.table.selectedIndexes()), reverse=True)
if not selected_rows:
# Получаем имена всех выбранных переменных из первого столбца
selected_names = self.table.get_selected_var_names()
if not selected_names:
return
for row in selected_rows:
if 0 <= row < len(self.vars_list):
# Меняем флаг show_var для переменной с этим индексом
self.vars_list[row]['show_var'] = 'false'
# Меняем флаг show_var по имени
for var in self.vars_list:
if var.get('name') in selected_names:
var['show_var'] = 'false'
self.table.populate(self.vars_list, self.structs, self.write_to_xml)
self.write_to_xml()
def __open_variable_selector(self):
self.update()
if not self.vars_list:
QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).")
return
@@ -438,9 +548,20 @@ class VarEditor(QWidget):
self.write_to_xml()
self.update()
def write_to_xml(self, dummy=None):
t0 = time.time()
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):
print("XML файл не найден или путь пустой")
@@ -465,7 +586,6 @@ class VarEditor(QWidget):
if self.makefile_path and os.path.isfile(self.makefile_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):
root.set("makefile_path", rel_makefile)
@@ -476,6 +596,7 @@ class VarEditor(QWidget):
if not os.path.isabs(rel_struct):
root.set("structs_path", rel_struct)
t1 = time.time()
vars_elem = root.find('variables')
if vars_elem is None:
@@ -490,6 +611,7 @@ class VarEditor(QWidget):
'extern': var_elem.findtext('extern', ''),
'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()}
@@ -498,59 +620,73 @@ class VarEditor(QWidget):
# Объединённый список переменных для записи
all_names = list(all_vars_by_name.keys())
t2 = time.time()
for name in all_names:
v = all_vars_by_name[name]
v_table = table_vars.get(name)
var_elem = None
# Ищем уже существующий <var> в XML
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 = get_val('pt_type').lower()
if 'arr' in pt_type_val or 'struct' in pt_type_val or 'union' in pt_type_val:
continue
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()
set_sub_elem_text(var_elem, 'show_var', show_var_val)
set_sub_elem_text(var_elem, 'enable', enable_val)
enable_val = get_val('enable').lower()
# Тут подтягиваем из таблицы, если есть, иначе из v
shortname_val = v_table['shortname'] if v_table and 'shortname' in v_table else v.get('shortname', '')
pt_type_val = v_table['pt_type'] if v_table and 'pt_type' in v_table else v.get('pt_type', '')
iq_type_val = v_table['iq_type'] if v_table and 'iq_type' in v_table else v.get('iq_type', '')
ret_type_val = v_table['return_type'] if v_table and 'return_type' in v_table else v.get('return_type', '')
shortname_val = get_val('shortname')
iq_type_val = get_val('iq_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_val = v.get('file') or original_info.get(name, {}).get('file', '')
extern_val = v.get('extern') or original_info.get(name, {}).get('extern', '')
static_val = v.get('static') or original_info.get(name, {}).get('static', '')
set_sub_elem_text(var_elem, 'file', file_val)
set_sub_elem_text(var_elem, 'extern', extern_val)
set_sub_elem_text(var_elem, 'static', static_val)
values_to_write = {
'show_var': show_var_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)
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:
print(f"Ошибка при сохранении XML: {e}")
def __open_output_file_with_program(self):
output_path = self.get_output_path()
if not output_path:
@@ -581,6 +717,13 @@ class VarEditor(QWidget):
if __name__ == "__main__":
app = QApplication(sys.argv)
auto_updater.check_and_update(
current_version="1.2.1",
git_releases_url="https://git.arktika.cyou/Razvalyaev/debugVarTool/releases",
exe_name="DebugVarEdit.exe",
zip_name="DebugToolsRelease.rar",
parent_widget=None
)
editor = VarEditor()
editor.resize(900, 600)
editor.show()

62
Src/README_DEVELOP.md Normal file
View File

@@ -0,0 +1,62 @@
# Для разработчиков
### Структура проекта:
```bash
Src
├── build/
│ └── build_and_clean.py # Билдинг проекта в .exe (через nuitka или pyinstaller)
├── DebugVarEdit_GUI.py # Главное окно
├── tms_debugvar_term.py # Терминал DebugVarTerminal
├── tms_debugvar_lowlevel.py # Виджет для выбора переменных для LowLevel Watch
├── 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
├── allvars_xml_parser.py # Парсинг XML со всеми переменными и структурами
├── csv_logger.py # Логирование переменных в CSV
├── myXML.py # Утилиты для XML
├── makefile_parser.py # Парсинг makefile на .c/.h файлы
├── var_setup.py # Подготовка переменных для окна выбора переменных
├── path_hints.py # Подсказки для автодополнения путей переменных
├── libclang.dll # Бибилиотека clang
├── icon.ico # Иконка
```
### Зависимости
Для запуска приложения:
- **Python 3.7+**
- **clang** — используется для парсинга C-кода (требуется `libclang.dll`, лежит в папке Src)
- **PySide2** — GUI-фреймворк
- **lxml** — работа с XML
> Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7
Для сборки `.exe`:
- **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей
- **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен для запуска `.exe`)
### Сборка:
Если вы хотите собрать `DebugVarEdit.exe` самостоятельно из исходников, используйте скрипт **build/build_and_clean.py**. Он автоматически собирает проект с помощью Nuitka или PyInstaller:
- Собирает проект в `DebugVarEdit.exe` в корневой папке.
- Включает:
- все необходимые `.dll` (например, `libclang.dll`),
- иконку (`icon.ico`),
- плагины PySide2.
- Очищает временные папки после сборки:
- `build_temp`
- `__pycache__`
- `<MAIN_SCRIPT_NAME>.*`
> Все пути, имена файлов, временные папки и выбор между Nuitka и PyInstaller можно настроить в начале файла `build_and_clean.py`.
### Установка зависимостей
```bash
pip install clang PySide2 lxml nuitka pyinstaller
```

View File

@@ -1,698 +0,0 @@
import re
import xml.etree.ElementTree as ET
from PySide2.QtWidgets import (
QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout
)
from PySide2.QtGui import QKeySequence, QKeyEvent
from PySide2.QtCore import Qt, QStringListModel, QSettings
import VariableTable
import setupVars
import myXML
import time
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
class VariableSelectorDialog(QDialog):
def __init__(self, table, all_vars, structs, typedefs, xml_path=None, parent=None):
super().__init__(parent)
self.setWindowTitle("Выбор переменных")
self.setAttribute(Qt.WA_DeleteOnClose)
self.resize(600, 500)
self.selected_names = []
self._bckspc_pressed = False # флаг подавления добавления разделителя
self.table = table
self.all_vars = all_vars
self.structs = structs
self.typedefs = typedefs
self.expanded_vars = []
self.var_map = {v['name']: v for v in all_vars}
self.node_index = {}
self.xml_path = xml_path # сохраняем путь к xml
self.manual_completion_active = False
# --- Добавляем чекбокс для автодополнения ---
self.autocomplete_checkbox = QCheckBox("Включить автодополнение")
self.autocomplete_checkbox.setChecked(True)
# Инициализируем QSettings с именем организации и приложения
self.settings = QSettings("SET", "DebugVarEdit_VarsSelector")
# Восстанавливаем сохранённое состояние чекбокса, если есть
checked = self.settings.value("autocomplete_enabled", True, type=bool)
self.autocomplete_checkbox.setChecked(checked)
# При изменении состояния чекбокса сохраняем его
self.autocomplete_checkbox.stateChanged.connect(self.save_checkbox_state)
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("Поиск по имени переменной...")
self.search_input.textChanged.connect(self.on_search_text_changed)
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.btn_add = QPushButton("Добавить выбранные")
self.btn_add.clicked.connect(self.on_add_clicked)
self.btn_delete = QPushButton("Удалить выбранные")
self.btn_delete.clicked.connect(self.on_delete_clicked)
self.completer = QCompleter()
self.completer.setCompletionMode(QCompleter.PopupCompletion) # важно!
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.completer.setFilterMode(Qt.MatchContains)
self.completer.setWidget(self.search_input)
self.search_input.installEventFilter(self)
# Создаем горизонтальный layout для "Поиск:" и чекбокса справа
search_layout = QHBoxLayout()
label_search = QLabel("Поиск:")
search_layout.addWidget(label_search, alignment=Qt.AlignLeft)
search_layout.addStretch() # чтобы чекбокс прижался вправо
search_layout.addWidget(self.autocomplete_checkbox, alignment=Qt.AlignRight)
self.completer.activated[str].connect(self.insert_completion)
layout = QVBoxLayout()
layout.addLayout(search_layout) # заменили label и чекбокс
layout.addWidget(self.search_input)
layout.addWidget(self.tree)
layout.addWidget(self.btn_add)
layout.addWidget(self.btn_delete)
self.setLayout(layout)
self.expanded_vars = setupVars.expand_vars(self.all_vars, self.structs, self.typedefs)
self.build_completion_list()
self.populate_tree()
def get_full_item_name(self, item):
names = []
while item:
names.append(item.text(0))
item = item.parent()
return '.'.join(reversed(names))
def build_completion_list(self):
# Собираем список полных имён всех переменных и вложенных полей
completions = []
def recurse(var, prefix=''):
fullname = f"{prefix}.{var['name']}" if prefix else var['name']
completions.append(fullname)
for child in var.get('children', []):
recurse(child, fullname)
for v in self.expanded_vars:
recurse(v)
self.all_completions = completions
def add_tree_item_recursively(self, parent, var):
"""
Рекурсивно добавляет переменную и её дочерние поля в дерево.
Если parent == None, добавляет на верхний уровень.
"""
name = var['name']
type_str = var.get('type', '')
show_var = var.get('show_var', 'false') == 'true'
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
# Делаем bitfield-поля неактивными
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 show_var:
item.setForeground(0, Qt.gray)
item.setForeground(1, Qt.gray)
self.set_tool(item, "Уже добавлена")
if parent is None:
self.tree.addTopLevelItem(item)
else:
parent.addChild(item)
for child in var.get('children', []):
self.add_tree_item_recursively(item, child)
def populate_tree(self, vars_list=None):
if vars_list is None:
vars_list = self.expanded_vars
self.tree.clear()
self.node_index.clear()
for var in vars_list:
self.add_tree_item_recursively(None, var)
header = self.tree.header()
header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять
self.tree.setColumnWidth(0, 400)
self.tree.resizeColumnToContents(1)
def expand_to_level(self, item, level, current_level=0):
"""
Рекурсивно раскрывает узлы до заданного уровня.
"""
if current_level < level:
item.setExpanded(True)
else:
item.setExpanded(False)
for i in range(item.childCount()):
self.expand_to_level(item.child(i), level, current_level + 1)
def filter_tree(self):
text = self.search_input.text().strip().lower()
path_parts = text.split('.') if text else []
filtered_vars = filter_vars(self.expanded_vars, path_parts)
# Сначала перерисовываем дерево
self.populate_tree(filtered_vars)
# Теперь node_index уже пересоздан — можно работать
expand_level = len(path_parts) - 1 if path_parts else 0
for i in range(self.tree.topLevelItemCount()):
item = self.tree.topLevelItem(i)
self.expand_to_level(item, expand_level)
# Раскрываем путь до точного совпадения
if path_parts:
fullname = '.'.join(path_parts)
node = self.node_index.get(fullname.lower())
if node:
parent = node.parent()
while parent:
parent.setExpanded(True)
parent = parent.parent()
def find_node_by_path(self, root_vars, path_list):
current_level = root_vars
node = None
for part in path_list:
node = None
for var in current_level:
if var['name'] == part:
node = var
break
if node is None:
return None
current_level = node.get('children', [])
return node
def update_completions(self, text=None):
if text is None:
text = self.search_input.text().strip()
else:
text = text.strip()
parts = self.split_path(text)
path_parts = parts[:-1] if parts else []
prefix = parts[-1].lower() if parts else ''
ends_with_sep = text.endswith('.') or text.endswith('->') or text.endswith('[')
is_index_suggestion = text.endswith('[')
completions = []
def find_exact_node(parts):
# Ищем точный узел по полному пути, используя node_index
# Постепенно собираем fullname из parts
if not parts:
return None
fullname = parts[0]
for p in parts[1:]:
fullname += '.' + p
return self.node_index.get(fullname.lower())
if is_index_suggestion:
base_text = text[:-1] # убираем '['
parent_node = self.find_node_by_fullname(base_text)
if not parent_node:
# если base_text может содержать индекс типа foo[12], попробуем очистить
base_text_clean = re.sub(r'\[\d+\]$', '', base_text)
parent_node = self.find_node_by_fullname(base_text_clean)
if parent_node:
seen = set()
for i in range(parent_node.childCount()):
child = parent_node.child(i)
cname = child.text(0)
m = re.match(rf'^{re.escape(base_text)}\[(\d+)\]$', cname)
if m and cname not in seen:
completions.append(cname)
seen.add(cname)
self.completer.setModel(QStringListModel(completions))
return completions
if ends_with_sep:
# Путь завершен, показываем детей узла
node = self.find_node_by_fullname(text[:-1])
if node:
completions.extend(node.child(i).text(0) for i in range(node.childCount()))
elif not path_parts:
# Первый уровень — по вхождению
for i in range(self.tree.topLevelItemCount()):
item = self.tree.topLevelItem(i)
name = item.text(0).lower()
if prefix in name:
completions.append(item.text(0))
else:
node = find_exact_node(path_parts)
if node:
for i in range(node.childCount()):
child = node.child(i)
name = child.text(0)
# Оптимизируем split_path - кэширование
name_parts = child.data(0, Qt.UserRole + 10)
if name_parts is None:
name_parts = self.split_path(name)
child.setData(0, Qt.UserRole + 10, name_parts)
if not name_parts:
continue
last_part = name_parts[-1].lower()
if prefix == '' or prefix in last_part: # здесь изменено
completions.append(name)
self.completer.complete()
return completions
# Функция для поиска узла с полным именем
def find_node_by_fullname(self, name):
return self.node_index.get(name.lower())
def insert_completion(self, text):
node = self.find_node_by_fullname(text)
if node and node.childCount() > 0 and not (text.endswith('.') or text.endswith('->') or text.endswith('[')):
# Определяем разделитель по имени первого ребёнка
child_name = node.child(0).text(0)
if child_name.startswith(text + '->'):
text += '->'
elif child_name.startswith(text + '.'):
text += '.'
elif '[' in child_name:
text += '[' # для массивов
else:
text += '.' # fallback
if not self._bckspc_pressed:
self.search_input.setText(text)
self.search_input.setCursorPosition(len(text))
self.run_completions(text)
else:
self.search_input.setText(text)
self.search_input.setCursorPosition(len(text))
def eventFilter(self, obj, event):
if obj == self.search_input and isinstance(event, QKeyEvent):
if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier:
self.manual_completion_active = True
text = self.search_input.text().strip()
self.run_completions(text)
elif event.key() == Qt.Key_Escape:
# Esc — выключаем ручной режим и скрываем подсказки, если autocomplete выключен
if not self.autocomplete_checkbox.isChecked():
self.manual_completion_active = False
self.completer.popup().hide()
return True
if event.key() == Qt.Key_Backspace:
self._bckspc_pressed = True
else:
self._bckspc_pressed = False
return super().eventFilter(obj, event)
def run_completions(self, text):
completions = self.update_completions(text)
if not self.autocomplete_checkbox.isChecked() and self._bckspc_pressed:
text = text[:-1]
if len(completions) == 1 and completions[0].lower() == text.lower():
# Найдем узел с таким именем
def find_exact_item(name):
stack = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
while stack:
node = stack.pop()
if node.text(0).lower() == name.lower():
return node
for i in range(node.childCount()):
stack.append(node.child(i))
return None
node = find_exact_item(completions[0])
if node and node.childCount() > 0:
# Используем первую подсказку, чтобы определить нужный разделитель
completions = self.update_completions(text + '.')
suggestion = completions[0]
# Ищем, какой символ идёт после текущего текста
separator = '.'
if suggestion.startswith(text):
rest = suggestion[len(text):]
if rest.startswith(text + '->'):
separator += '->'
elif rest.startswith(text + '.'):
separator += '.'
elif '[' in rest:
separator += '[' # для массивов
else:
separator += '.' # fallback
if not self._bckspc_pressed:
self.search_input.setText(text + separator)
completions = self.update_completions(text)
self.completer.setModel(QStringListModel(completions))
self.completer.complete()
return True
# Иначе просто показываем подсказки
self.completer.setModel(QStringListModel(completions))
if completions:
self.completer.complete()
return True
def on_search_text_changed(self, text):
self.filter_tree()
if text == None:
text = self.search_input.text().strip()
if self.autocomplete_checkbox.isChecked():
self.run_completions(text)
else:
# Если выключено, показываем подсказки только если флаг ручного вызова True
if self.manual_completion_active:
self.run_completions(text)
else:
self.completer.popup().hide()
def on_add_clicked(self):
self.selected_names = []
self.tree.setFocus()
for item in self.tree.selectedItems():
name = item.text(0) # имя переменной (в колонке 1)
type_str = item.text(1) # тип переменной (в колонке 2)
if not name:
continue
self.selected_names.append((name, type_str))
if name in self.var_map:
# Если переменная уже есть, просто включаем её и показываем
var = self.var_map[name]
var['show_var'] = 'true'
var['enable'] = 'true'
else:
# Создаём новый элемент переменной
# Получаем родительские параметры
file_val = item.data(0, Qt.UserRole + 1)
extern_val = item.data(0, Qt.UserRole + 2)
static_val = item.data(0, Qt.UserRole + 3)
new_var = {
'name': name,
'type': type_str,
'show_var': 'true',
'enable': 'true',
'shortname': name,
'pt_type': '',
'iq_type': '',
'return_type': 'iq_none',
'file': file_val,
'extern': str(extern_val).lower() if extern_val else 'false',
'static': str(static_val).lower() if static_val else 'false',
}
# Добавляем в список переменных
self.all_vars.append(new_var)
self.var_map[name] = new_var # Чтобы в будущем не добавлялось повторно
self.done(QDialog.Accepted)
def on_delete_clicked(self):
selected_names = self._get_selected_var_names()
if not selected_names:
print("nothing selected")
return
# Обновляем var_map и all_vars
for name in selected_names:
if name in self.var_map:
self.var_map[name]['show_var'] = 'false'
self.var_map[name]['enable'] = 'false'
for v in self.all_vars:
if v['name'] == name:
v['show_var'] = 'false'
v['enable'] = 'false'
break
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
return
root, tree = myXML.safe_parse_xml(self.xml_path)
if root is None:
return
vars_section = root.find('variables')
if vars_section is None:
return
for var_elem in vars_section.findall('var'):
name = var_elem.attrib.get('name')
if name in selected_names:
def set_text(tag, value):
el = var_elem.find(tag)
if el is None:
el = ET.SubElement(var_elem, tag)
el.text = value
set_text('show_var', 'false')
set_text('enable', 'false')
myXML.fwrite(root, self.xml_path)
self.done(QDialog.Accepted)
def set_tool(self, item, text):
item.setToolTip(0, text)
item.setToolTip(1, text)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Delete:
self.delete_selected_vars()
else:
super().keyPressEvent(event)
def delete_selected_vars(self):
selected_names = self._get_selected_var_names()
if not selected_names:
print("nothing selected")
return
# Обновляем var_map и all_vars
for name in selected_names:
if name in self.var_map:
self.var_map[name]['show_var'] = 'false'
self.var_map[name]['enable'] = 'false'
for v in self.all_vars:
if v['name'] == name:
v['show_var'] = 'false'
v['enable'] = 'false'
break
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
return
root, tree = myXML.safe_parse_xml(self.xml_path)
if root is None:
return
vars_section = root.find('variables')
if vars_section is None:
return
for var_elem in vars_section.findall('var'):
name = var_elem.attrib.get('name')
if name in selected_names:
def set_text(tag, value):
el = var_elem.find(tag)
if el is None:
el = ET.SubElement(var_elem, tag)
el.text = value
set_text('show_var', 'false')
set_text('enable', 'false')
myXML.fwrite(root, self.xml_path)
self.table.populate(self.all_vars, self.structs, None)
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно удалить переменные.")
return
import xml.etree.ElementTree as ET
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
removed_any = False
for var_elem in list(vars_section.findall('var')):
name = var_elem.attrib.get('name')
if name in selected_names:
vars_section.remove(var_elem)
removed_any = True
self.var_map.pop(name, None)
# Удаляем из all_vars (глобально)
self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names]
# Удаляем из expanded_vars (тоже глобально)
def filter_out_selected(vars_list):
filtered = []
for v in vars_list:
if v['name'] not in selected_names:
# Рекурсивно фильтруем детей, если есть
if 'children' in v:
v = v.copy()
v['children'] = filter_out_selected(v['children'])
filtered.append(v)
return filtered
self.expanded_vars[:] = filter_out_selected(self.expanded_vars)
if removed_any:
myXML.fwrite(root, self.xml_path)
self.filter_tree()
def _get_selected_var_names(self):
self.tree.setFocus()
return [item.text(0) for item in self.tree.selectedItems() if item.text(0)]
def save_checkbox_state(self):
self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
def split_path(self, path):
"""
Разбивает путь на компоненты:
- 'foo[2].bar[1]->baz' → ['foo', [2]', 'bar', '[1]' 'baz']
"""
tokens = []
token = ''
i = 0
while i < len(path):
c = path[i]
# Разделители: '->' и '.'
if c == '-' and path[i:i+2] == '->':
if token:
tokens.append(token)
token = ''
i += 2
continue
elif c == '.':
if token:
tokens.append(token)
token = ''
i += 1
continue
elif c == '[':
# Заканчиваем текущий токен, если есть
if token:
tokens.append(token)
token = ''
# Собираем индекс [N]
idx = ''
while i < len(path) and path[i] != ']':
idx += path[i]
i += 1
if i < len(path) and path[i] == ']':
idx += ']'
i += 1
tokens.append(idx)
continue
else:
token += c
i += 1
if token:
tokens.append(token)
return tokens
def filter_vars(vars_list, path_parts):
"""Рекурсивно фильтруем vars_list по path_parts и возвращаем только подходящие."""
filtered = []
def matches_path(name, search_parts):
name_parts = name.lower().split('.')
if len(name_parts) < len(search_parts):
return False
for sp, np in zip(search_parts, name_parts):
if not np.startswith(sp):
return False
return True
for var in vars_list:
fullname = var.get('fullname', var['name']) # желательно иметь полное имя
# Если фильтра нет — берем всё
if not path_parts or matches_path(fullname, path_parts):
# Копируем узел с рекурсией по детям
new_var = var.copy()
if 'children' in var:
new_var['children'] = filter_vars(var['children'], path_parts)
filtered.append(new_var)
else:
# Но даже если этот узел не подходит, может подойти его потомок
if 'children' in var:
child_filtered = filter_vars(var['children'], path_parts)
if child_filtered:
new_var = var.copy()
new_var['children'] = child_filtered
filtered.append(new_var)
return filtered

View File

@@ -1,271 +0,0 @@
from PySide2.QtWidgets import (
QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
QAbstractItemView, QHeaderView, QLabel
)
from PySide2.QtGui import QColor, QBrush, QPalette
from PySide2.QtCore import Qt
from enum import IntEnum
from generateVars import type_map
class rows(IntEnum):
No = 0
include = 1
name = 2
type = 3
pt_type = 4
iq_type = 5
ret_type = 6
short_name = 7
class VariableTableWidget(QTableWidget):
def __init__(self, parent=None):
super().__init__(0, 8, parent)
# Таблица переменных
self.setHorizontalHeaderLabels([
'№', # новый столбец
'En',
'Name',
'Origin Type',
'Pointer Type',
'IQ Type',
'Return Type',
'Short Name'
])
self.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.var_list = []
self.type_options = list(dict.fromkeys(type_map.values()))
self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
self.iq_types = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
header = self.horizontalHeader()
# Для остальных колонок — растяжение (Stretch), чтобы они заняли всю оставшуюся ширину
for col in range(self.columnCount()):
if col == self.columnCount() - 1:
header.setSectionResizeMode(col, QHeaderView.Stretch)
else:
header.setSectionResizeMode(col, QHeaderView.Interactive)
parent_widget = self.parentWidget()
# Сделаем колонки с номерами фиксированной ширины
self.setColumnWidth(rows.No, 30)
self.setColumnWidth(rows.include, 30)
self.setColumnWidth(rows.pt_type, 85)
self.setColumnWidth(rows.iq_type, 85)
self.setColumnWidth(rows.ret_type, 85)
self.setColumnWidth(rows.name, 300)
self.setColumnWidth(rows.type, 100)
self._resizing = False
self.horizontalHeader().sectionResized.connect(self.on_section_resized)
def populate(self, vars_list, structs, on_change_callback):
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-переменных
for var in vars_list:
pt_type = var.get('pt_type', '')
if 'struct' in pt_type or 'union' in pt_type:
var['show_var'] = 'false'
var['enable'] = 'false'
filtered_vars = [v for v in vars_list if v.get('show_var', 'false') == 'true']
self.setRowCount(len(filtered_vars))
self.verticalHeader().setVisible(False)
style_with_padding = "padding-left: 5px; padding-right: 5px; font-size: 14pt; font-family: 'Segoe UI';"
for row, var in enumerate(filtered_vars):
# №
no_item = QTableWidgetItem(str(row))
no_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(row, rows.No, no_item)
# Enable
cb = QCheckBox()
cb.setChecked(var.get('enable', 'false') == 'true')
cb.stateChanged.connect(on_change_callback)
cb.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.include, cb)
# Name
name_edit = QLineEdit(var['name'])
if var['type'] in structs:
completer = QCompleter(structs[var['type']].keys())
completer.setCaseSensitivity(Qt.CaseInsensitive)
name_edit.setCompleter(completer)
name_edit.textChanged.connect(on_change_callback)
name_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.name, name_edit)
# Origin Type (readonly)
origin_item = QTableWidgetItem(var.get('type', ''))
origin_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
origin_item.setToolTip(var.get('type', '')) # Всплывающая подсказка
origin_item.setForeground(QBrush(Qt.black))
self.setItem(row, rows.type, origin_item)
# pt_type
pt_combo = QComboBox()
pt_combo.addItems(self.display_type_options)
value = var['pt_type'].replace('pt_', '')
if value not in self.display_type_options:
pt_combo.addItem(value)
pt_combo.setCurrentText(value)
pt_combo.currentTextChanged.connect(on_change_callback)
pt_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.pt_type, pt_combo)
# iq_type
iq_combo = QComboBox()
iq_combo.addItems(self.iq_types)
value = var['iq_type'].replace('t_', '')
if value not in self.iq_types:
iq_combo.addItem(value)
iq_combo.setCurrentText(value)
iq_combo.currentTextChanged.connect(on_change_callback)
iq_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.iq_type, iq_combo)
# return_type
ret_combo = QComboBox()
ret_combo.addItems(self.iq_types)
ret_combo.setCurrentText(var.get('return_type', ''))
ret_combo.currentTextChanged.connect(on_change_callback)
ret_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.ret_type, ret_combo)
# short_name
short_name_val = var.get('shortname', var['name'])
short_name_edit = QLineEdit(short_name_val)
short_name_edit.textChanged.connect(on_change_callback)
short_name_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.short_name, short_name_edit)
self.check()
def check(self):
warning_color = (QColor("#FFFACD")) # Жёлтый для длинных shortname
error_color = (QColor("#FFB6C1")) # Светло-красный для отсутствующих переменных
tooltip_shortname = "Short Name длиннее 10 символов — будет обрезано при генерации"
tooltip_missing = f'Имя переменной не найдено среди переменных. Добавьте её через кнопку "Добавить переменные"'
for row in range(self.rowCount()):
# Получаем имя переменной (столбец `name`)
name_widget = self.cellWidget(row, rows.name)
name = name_widget.text() if name_widget else ""
# Получаем shortname
short_name_edit = self.cellWidget(row, rows.short_name)
shortname = short_name_edit.text() if short_name_edit else ""
# Флаги ошибок
long_shortname = len(shortname) > 10
found = any(v.get('name') == name for v in self.var_list)
# Выбираем цвет и подсказку
color = None
tooltip = ""
if not found:
color = error_color
tooltip = tooltip_missing
elif long_shortname:
color = warning_color
tooltip = tooltip_shortname
self.highlight_row(row, color, tooltip)
def read_data(self):
result = []
for row in range(self.rowCount()):
cb = self.cellWidget(row, rows.include)
name = self.cellWidget(row, rows.name).text()
pt = self.cellWidget(row, rows.pt_type).currentText()
iq = self.cellWidget(row, rows.iq_type).currentText()
ret = self.cellWidget(row, rows.ret_type).currentText()
shortname = self.cellWidget(row, rows.short_name).text()
origin_type = self.item(row, rows.type).text()
result.append({
'show_var': True,
'enable': cb.isChecked(),
'name': name,
'pt_type': f'pt_{pt}',
'iq_type': f't_{iq}',
'return_type': f't_{ret}',
'shortname': shortname,
'type': origin_type,
})
return result
def on_section_resized(self, logicalIndex, oldSize, newSize):
if self._resizing:
return # предотвращаем рекурсию
min_width = 50
delta = newSize - oldSize
right_index = logicalIndex + 1
if right_index >= self.columnCount():
# Если правая колока - нет соседа, ограничиваем минимальную ширину
if newSize < min_width:
self._resizing = True
self.setColumnWidth(logicalIndex, min_width)
self._resizing = False
return
self._resizing = True
try:
right_width = self.columnWidth(right_index)
new_right_width = right_width - delta
# Если соседняя колонка станет уже минимальной - подкорректируем левую
if new_right_width < min_width:
new_right_width = min_width
newSize = oldSize + (right_width - min_width)
self.setColumnWidth(logicalIndex, newSize)
self.setColumnWidth(right_index, new_right_width)
finally:
self._resizing = False
def highlight_row(self, row: int, color: QColor = None, tooltip: str = ""):
"""
Подсвечивает строку таблицы цветом `color`, не меняя шрифт.
Работает с QLineEdit, QComboBox, QCheckBox (включая обёртки).
Если `color=None`, сбрасывает подсветку.
"""
css_reset = "background-color: none; font: inherit;"
css_color = f"background-color: {color.name()};" if color else css_reset
for col in range(self.columnCount()):
item = self.item(row, col)
widget = self.cellWidget(row, col)
# Подсветка обычной item-ячейки (например, тип переменной)
if item is not None:
if color:
item.setBackground(QBrush(color))
item.setToolTip(tooltip)
else:
item.setBackground(QBrush(Qt.NoBrush))
item.setToolTip("")
# Подсветка виджетов — здесь главная доработка
elif widget is not None:
# Надёжная подсветка: через styleSheet
widget.setStyleSheet(css_color)
widget.setToolTip(tooltip if color else "")

500
Src/allvars_xml_parser.py Normal file
View File

@@ -0,0 +1,500 @@
"""
VariablesXML + get_all_vars_data
---------------------------------
Поддержка вложенных структур, указателей на структуры ("->"),
и многомерных массивов (индексация [i][j]...).
Требования пользователя:
- size (без индекса) = общий размер массива в байтах (НЕ измерение!).
- size1..sizeN = размеры измерений массива.
- В результирующем плоском списке (flattened) должны присутствовать ВСЕ промежуточные
пути: var, var[0], var[0][0], var[0][0].field, var[0][0].field->subfield, ...
- Аналогично для членов структур.
Пример желаемого формата:
project
project.adc
project.adc[0]
project.adc[0][0]
project.adc[0][0].bus
project.adc[0][0].bus->status
Данный модуль реализует:
- Разбор XML (parse) с извлечением размеров размерностей в поле `dims`.
- Генерацию плоского списка словарей `flattened()`.
- Построение иерархии словарей `get_all_vars_data()`.
"""
from __future__ import annotations
import re
import xml.etree.ElementTree as ET
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Tuple, Any
import var_setup # ожидается split_path(...)
from generate_debug_vars import choose_type_map, type_map # используется для выбора карт типов
# --------------------------- константы ----------------------------
DATE_FIELD_SET = {"year", "month", "day", "hour", "minute"}
# --------------------------- dataclasses --------------------------
@dataclass
class MemberNode:
name: str
offset: int = 0
type_str: str = ""
size: Optional[int] = None # общий размер (байты), если известен
children: List["MemberNode"] = field(default_factory=list)
# --- доп.поля ---
kind: Optional[str] = None # 'array', 'union', ...
dims: Optional[List[int]] = None
def is_date_struct(self) -> bool:
if not self.children:
return False
child_names = {c.name for c in self.children}
return DATE_FIELD_SET.issubset(child_names)
@dataclass
class VariableNode:
name: str
address: int
type_str: str
size: Optional[int]
members: List[MemberNode] = field(default_factory=list)
# --- доп.поля ---
kind: Optional[str] = None # 'array'
dims: Optional[List[int]] = None # полный список размеров [size1, size2, ...]
def base_address_hex(self) -> str:
return f"0x{self.address:06X}"
# --------------------------- класс парсера -----------------------
class VariablesXML:
"""
Читает XML и предоставляет методы:
- flattened(): плоский список всех путей.
- date_struct_candidates(): как раньше.
Правила формирования путей:
* Структурные поля: '.'
* Поля через указатель на структуру: '->'
* Массивы: [index] (каждое измерение).
"""
# предполагаемые размеры примитивов (MCU: int=2)
_PRIM_SIZE = {
'char': 1, 'signed char': 1, 'unsigned char': 1,
'uint8_t': 1, 'int8_t': 1,
'short': 2, 'short int': 2, 'signed short': 2, 'unsigned short': 2,
'uint16_t': 2, 'int16_t': 2,
'int': 2, 'signed int': 2, 'unsigned int': 2,
'long': 4, 'unsigned long': 4, 'int32_t': 4, 'uint32_t': 4,
'float': 4,
'long long': 8, 'unsigned long long': 8, 'int64_t': 8, 'uint64_t': 8, 'double': 8,
}
def __init__(self, path: str):
self.path = path
self.timestamp: str = ""
self.variables: List[VariableNode] = []
choose_type_map(0) # инициализация карт типов (если требуется)
self._parse()
# ------------------ утилиты ------------------
@staticmethod
def _parse_int_guess(txt: Optional[str]) -> Optional[int]:
if not txt:
return None
txt = txt.strip()
if txt.startswith(('0x', '0X')):
return int(txt, 16)
# если в строке есть A-F, попробуем hex
if any(c in 'abcdefABCDEF' for c in txt):
try:
return int(txt, 16)
except ValueError:
pass
try:
return int(txt, 10)
except ValueError:
return None
@staticmethod
def _is_pointer_to_struct(t: str) -> bool:
if not t:
return False
low = t.replace('\t', ' ').replace('\n', ' ')
return 'struct ' in low and '*' in low
@staticmethod
def _is_struct_or_union(t: str) -> bool:
if not t:
return False
low = t.strip()
return low.startswith('struct ') or low.startswith('union ')
@staticmethod
def _is_union(t: str) -> bool:
if not t:
return False
low = t.strip()
return low.startswith('union ')
@staticmethod
def _strip_array_suffix(t: str) -> str:
t = t.strip()
while t.endswith('[]'):
t = t[:-2].strip()
return t
def _guess_primitive_size(self, type_str: str) -> Optional[int]:
if not type_str:
return None
base = type_str
for tok in ('volatile', 'const'):
base = base.replace(tok, '')
base = base.replace('*', ' ')
base = base.replace('[', ' ').replace(']', ' ')
base = ' '.join(base.split()).strip()
return self._PRIM_SIZE.get(base)
# ------------------ XML read ------------------
def _parse(self) -> None:
try:
tree = ET.parse(self.path)
root = tree.getroot()
ts = root.find('timestamp')
self.timestamp = ts.text.strip() if ts is not None and ts.text else ''
def parse_member(elem: ET.Element, base_offset=0) -> MemberNode:
name = elem.get('name', '')
offset = int(elem.get('offset', '0'), 16) if elem.get('offset') else 0
t = elem.get('type', '') or ''
size_attr = elem.get('size')
size = int(size_attr, 16) if size_attr else None
kind = elem.get('kind')
abs_offset = base_offset + offset
# Собираем размеры, если есть
dims: List[int] = []
i = 1
while True:
size_key = f"size{i}"
size_val = elem.get(size_key)
if size_val is None:
break
parsed = self._parse_int_guess(size_val) # предполагается твоя функция парсинга int
if parsed is not None:
dims.append(parsed)
i += 1
node = MemberNode(
name=name,
offset=abs_offset,
type_str=t,
size=size,
kind=kind,
dims=dims if dims else None,
)
# Для детей
for ch in elem.findall('member'):
if kind == 'union':
# Для union детей НЕ добавляем их offset, просто передаём abs_offset
child = parse_member(ch, base_offset=abs_offset)
child.offset = abs_offset # выравниваем offset, игнорируем offset детей
else:
# Для struct/array суммируем offset нормально
child = parse_member(ch, base_offset=abs_offset)
node.children.append(child)
# Аналогично для pointee
pointee_elem = elem.find('pointee')
if pointee_elem is not None:
for ch in pointee_elem.findall('member'):
if kind == 'union':
child = parse_member(ch, base_offset=abs_offset)
child.offset = abs_offset
else:
child = parse_member(ch, base_offset=abs_offset)
node.children.append(child)
size_p = pointee_elem.get('size')
if size_p:
node.size = int(size_p, 16)
return node
for var in root.findall('variable'):
addr = int(var.get('address', '0'), 16)
name = var.get('name', '')
t = var.get('type', '') or ''
size_attr = var.get('size') # общий размер байт
size = int(size_attr, 16) if size_attr else None
kind = var.get('kind')
dims: List[int] = []
i = 1
while True:
key = f'size{i}'
val = var.get(key)
if val is None:
break
parsed = self._parse_int_guess(val)
if parsed is not None:
dims.append(parsed)
i += 1
members = [parse_member(m) for m in var.findall('member')]
v = VariableNode(
name=name,
address=addr,
type_str=t,
size=size,
members=members,
kind=kind,
dims=dims if dims else None,
)
self.variables.append(v)
except FileNotFoundError:
self.variables = []
except ET.ParseError:
self.variables = []
# ------------------ helpers для flattened ---------------------
def _elem_size_bytes(self, total_size: Optional[int], dims: List[int], base_type: str, members: List[MemberNode]) -> int:
"""Оценка размера одного *листового* элемента (последнего измерения).
Если total_size и dims все известны — берём size / prod(dims).
Иначе — пробуем примитивный размер; иначе 1.
(Не учитываем выравнивание структур; при необходимости можно расширить.)
"""
if total_size is not None and dims:
prod = 1
for d in dims:
if d is None or d == 0:
prod = None
break
prod *= d
if prod and prod > 0:
return max(1, total_size // prod)
prim = self._guess_primitive_size(base_type)
if prim:
return prim
# Если структура и у неё есть size по детям? Пока fallback=1.
return 1
# ------------------ flattened ------------------
def flattened(self, max_array_elems: Optional[int] = None) -> List[Dict[str, Any]]:
"""Возвращает плоский список всех путей (каждый путь = dict).
Включает промежуточные узлы массивов (var[0], var[0][0], ...).
"""
out: List[Dict[str, Any]] = []
def mk(name: str, addr: Optional[int], type_str: str, size: Optional[int], kind: Optional[str], dims_for_node: Optional[List[int]]):
if 'Bender' in name:
a=1
out.append({
'name': name,
'address': addr,
'type': type_str,
'size': size,
'kind': kind,
'dims': dims_for_node[:] if dims_for_node else None,
})
def expand_members(prefix: str, base_addr: int, members: List[MemberNode], parent_is_ptr_struct: bool, parent_is_union: bool) -> None:
# Выбираем разделитель пути: '.' если обычный член, '->' если указатель на структуру
join = '->' if parent_is_ptr_struct else '.'
for m in members:
path_m = f"{prefix}{join}{m.name}" if prefix else m.name
is_union = m.kind == 'union' or parent_is_union
if is_union:
# Все поля union начинаются с одного адреса
addr_m = base_addr
else:
addr_m = base_addr + m.offset
dims = m.dims or []
mk(path_m, addr_m, m.type_str, m.size, m.kind, dims)
if m.kind == 'array' and dims:
base_t = self._strip_array_suffix(m.type_str)
elem_sz = m.size
# Для массива внутри структуры: первый уровень — '.' для доступа,
# внутри массива раскрываем по обычной логике с parent_is_ptr_struct=False
expand_dims(path_m, addr_m, dims, base_t, m.children, elem_sz, parent_is_ptr_struct=False)
else:
if m.children:
# Проверяем, является ли поле указателем на структуру
is_ptr = self._is_pointer_to_struct(m.type_str)
# Рекурсивно раскрываем дочерние поля, выбирая правильный разделитель
expand_members(path_m, addr_m, m.children, is_ptr, is_union)
def expand_dims(name: str, base_addr: int, dims: List[int], base_type: str, children: List[MemberNode], elem_size: int, parent_is_ptr_struct: bool) -> None:
prods: List[int] = []
acc = 1
for d in reversed(dims[1:]):
acc *= (d if d else 1)
prods.append(acc)
prods.reverse()
def rec(k: int, cur_name: str, cur_addr: int) -> None:
if k == len(dims):
# Листовой элемент массива
mk(cur_name, cur_addr, base_type, elem_size, None, None)
# Если элемент — структура или указатель на структуру, раскрываем вложения
if children and self._is_struct_or_union(base_type):
expand_members(cur_name, cur_addr, children, parent_is_ptr_struct=False, parent_is_union=self._is_union(base_type))
elif self._is_pointer_to_struct(base_type):
expand_members(cur_name, cur_addr, children, parent_is_ptr_struct=True, parent_is_union=self._is_union(base_type))
return
dim_sz = dims[k] or 0
if max_array_elems is not None:
dim_sz = min(dim_sz, max_array_elems)
stride = elem_size * prods[k] if k < len(prods) else elem_size
if len(dims) > 2:
a=1
for i in range(dim_sz):
child_name = f"{cur_name}[{i}]"
child_addr = (cur_addr + i * stride) if cur_addr is not None else None
remaining = dims[k+1:]
mk(child_name, child_addr, base_type + '[]' * len(remaining), stride if remaining else elem_size, 'array' if remaining else None, remaining)
rec(k + 1, child_name, child_addr)
rec(0, name, base_addr)
# --- цикл по топ‑левел переменным ---
for v in self.variables:
dims = v.dims or []
mk(v.name, v.address, v.type_str, v.size, v.kind, dims)
if (v.kind == 'array' or v.type_str.endswith('[]')) and dims:
base_t = self._strip_array_suffix(v.type_str)
elem_sz = v.size
expand_dims(v.name, v.address, dims, base_t, v.members, elem_sz, parent_is_ptr_struct=False)
else:
if v.members:
is_ptr = self._is_pointer_to_struct(v.type_str)
is_union = self._is_union(v.type_str)
expand_members(v.name, v.address, v.members, is_ptr, is_union)
return out
# -------------------- date candidates (как раньше) -------------
def date_struct_candidates(self) -> List[Tuple[str, int]]:
cands = []
for v in self.variables:
# top level (if all date fields are present)
direct_names = {mm.name for mm in v.members}
if DATE_FIELD_SET.issubset(direct_names):
cands.append((v.name, v.address))
# check first-level members
for m in v.members:
if m.is_date_struct():
cands.append((f"{v.name}.{m.name}", v.address + m.offset))
return cands
# ------------------------------------------------------------------
# Построение иерархического дерева из flattened()
# ------------------------------------------------------------------
def get_all_vars_data(self) -> List[Dict[str, Any]]:
"""
Строит иерархию словарей из плоского списка переменных.
Каждый узел = {
'name': <полный путь>,
'address': <адрес или None>,
'type': <тип>,
'size': <байты>,
'kind': <'array' | ...>,
'dims': [size1, size2, ...] или None,
'children': [...список дочерних узлов]
}
Возвращает список корневых узлов (top-level переменных).
"""
flat_data = self.flattened(max_array_elems=None)
# Быстрое отображение имя -> узел (словарь с детьми)
all_nodes: Dict[str, Dict[str, Any]] = {}
for item in flat_data:
node = dict(item)
node['children'] = []
all_nodes[item['name']] = node
def _parent_struct_split(path: str) -> Optional[str]:
# Ищем последний '.' или '->' для определения родителя
dot_idx = path.rfind('.')
arrow_idx = path.rfind('->')
cut_idx = max(dot_idx, arrow_idx)
if cut_idx == -1:
return None
# '->' занимает 2 символа, нужно взять срез до начала '->'
if arrow_idx > dot_idx:
return path[:arrow_idx]
else:
return path[:dot_idx]
def find_parent(path: str) -> Optional[str]:
"""
Возвращает полный путь родителя, учитывая '.', '->' и индексы [] в конце.
Если путь заканчивается индексом [k], удаляет последний индекс и проверяет наличие родителя.
Иначе пытается найти последний сепаратор '.' или '->'.
"""
# Если есть trailing индекс в конце, убираем его
m = re.search(r'\[[0-9]+\]$', path)
if m:
base = path[:m.start()] # убираем последний [k]
# Если базовый путь есть в узлах, считаем его родителем
if base in all_nodes:
return base
# Иначе пытаемся найти родителя от базового пути
return _parent_struct_split(base)
else:
# Если нет индекса, просто ищем последний разделитель
return _parent_struct_split(path)
# Строим иерархию: parent -> children
roots: List[Dict[str, Any]] = []
for full_name, node in all_nodes.items():
parent_name = find_parent(full_name)
if parent_name and parent_name in all_nodes:
all_nodes[parent_name]['children'].append(node)
else:
roots.append(node)
# Рекурсивно сортируем детей по имени для порядка
def sort_nodes(nodes: List[Dict[str, Any]]):
nodes.sort(key=lambda n: n['name'])
for n in nodes:
if n['children']:
sort_nodes(n['children'])
sort_nodes(roots)
return roots

239
Src/auto_updater.py Normal file
View File

@@ -0,0 +1,239 @@
import os
import sys
import shutil
import tempfile
import requests
import subprocess
from packaging.version import Version, InvalidVersion
from bs4 import BeautifulSoup
from PySide2.QtWidgets import (
QApplication, QMessageBox, QProgressDialog
)
from PySide2.QtCore import QThread, Signal
class DownloadThread(QThread):
progress = Signal(int)
finished = Signal(bool, str)
def __init__(self, url, dest_path):
super().__init__()
self.url = url
self.dest_path = dest_path
def run(self):
try:
with requests.get(self.url, stream=True) as r:
r.raise_for_status()
total = int(r.headers.get("content-length", 0))
downloaded = 0
with open(self.dest_path, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
downloaded += len(chunk)
if total > 0:
self.progress.emit(int(downloaded * 100 / total))
self.finished.emit(True, "")
except Exception as e:
self.finished.emit(False, str(e))
def check_and_update(
current_version: str,
git_releases_url: str,
exe_name: str,
zip_name: str = None,
parent_widget=None
):
print(f"[Updater] Текущая версия: {current_version}")
latest_ver, rel_page = _get_latest_release_info(git_releases_url)
if not latest_ver:
return
try:
current_ver_obj = Version(current_version)
except InvalidVersion:
return
if latest_ver <= current_ver_obj:
print(f"[Updater] Приложение актуально (v{current_version}).")
return
if not _ask_update_dialog(latest_ver, parent_widget):
return
file_url = _get_download_link(rel_page, exe_name, zip_name)
if not file_url:
_show_error("Не удалось найти файл для скачивания.", parent_widget)
return
temp_exe = os.path.join(tempfile.gettempdir(), f"new_{exe_name}")
if file_url.endswith(".zip") or file_url.endswith(".rar"):
# Выбираем расширение временного файла согласно скачиваемому файлу
ext = ".zip" if file_url.endswith(".zip") else ".rar"
temp_archive = temp_exe.replace(".exe", ext)
'''_start_download_gui(file_url, temp_archive, parent_widget, on_finished=lambda ok, err:
_handle_archive_download(ok, err, temp_archive, exe_name, temp_exe, parent_widget))'''
else:
_start_download_gui(file_url, temp_exe, parent_widget, on_finished=lambda ok, err:
_handle_exe_download(ok, err, temp_exe, parent_widget))
'''def _handle_archive_download(success, error, archive_path, exe_name, exe_dest, parent):
if not success:
_show_error(f"Ошибка при скачивании архива: {error}", parent)
return
ok = False
if archive_path.endswith(".zip"):
ok = _extract_exe_from_zip(archive_path, exe_name, exe_dest)
elif archive_path.endswith(".rar"):
ok = _extract_exe_from_rar(archive_path, exe_name, exe_dest)
if not ok:
_show_error(f"Не удалось извлечь {exe_name} из архива.", parent)
return
_update_self(exe_dest)'''
'''def _extract_exe_from_rar(rar_path, exe_name, dest_path):
try:
with rarfile.RarFile(rar_path) as rar_ref:
for file in rar_ref.namelist():
if file.endswith(exe_name):
rar_ref.extract(file, os.path.dirname(dest_path))
src = os.path.join(os.path.dirname(dest_path), file)
shutil.move(src, dest_path)
return True
except Exception as e:
print(f"[Updater] Ошибка при распаковке RAR архива: {e}")
return False'''
def _handle_exe_download(success, error, exe_path, parent):
if not success:
_show_error(f"Ошибка при скачивании файла: {error}", parent)
return
_update_self(exe_path)
def _start_download_gui(url, dest_path, parent, on_finished):
dialog = QProgressDialog("Скачивание обновления...", "Отмена", 0, 100, parent)
dialog.setWindowTitle("Обновление")
dialog.setMinimumDuration(0)
dialog.setAutoClose(False)
dialog.setAutoReset(False)
thread = DownloadThread(url, dest_path)
thread.progress.connect(dialog.setValue)
thread.finished.connect(lambda ok, err: (
dialog.close(),
on_finished(ok, err)
))
thread.start()
dialog.exec_()
def _ask_update_dialog(latest_ver, parent):
msg = QMessageBox(parent)
msg.setIcon(QMessageBox.Information)
msg.setWindowTitle("Доступно обновление")
msg.setText(f"Доступна новая версия: v{latest_ver}\nЖелаете обновиться?")
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
return msg.exec_() == QMessageBox.Yes
def _show_error(text, parent):
msg = QMessageBox(parent)
msg.setIcon(QMessageBox.Critical)
msg.setWindowTitle("Ошибка обновления")
msg.setText(text)
msg.exec_()
def _get_latest_release_info(base_url):
try:
parts = base_url.strip("/").split("/")
owner, repo = parts[-3], parts[-2]
tags_url = f"https://git.arktika.cyou/api/v1/repos/{owner}/{repo}/tags"
response = requests.get(tags_url, timeout=10)
response.raise_for_status()
tags = response.json()
versions = []
for tag in tags:
raw_tag = tag.get("name", "")
norm_tag = raw_tag.lstrip("v")
try:
parsed_ver = Version(norm_tag)
versions.append((parsed_ver, raw_tag))
except InvalidVersion:
continue
if not versions:
return None, None
versions.sort(reverse=True)
latest_ver, latest_tag = versions[0]
release_url = f"https://git.arktika.cyou/{owner}/{repo}/releases/tag/{latest_tag}"
return latest_ver, release_url
except Exception as e:
print(f"[Updater] Ошибка при получении тега через API: {e}")
return None, None
def _get_download_link(release_page_url, exe_name, zip_name=None):
try:
resp = requests.get(release_page_url, timeout=10)
soup = BeautifulSoup(resp.text, "html.parser")
links = soup.select("a[href]")
def normalize(href):
if href.startswith("http"):
return href
return "https://git.arktika.cyou" + href
for link in links:
href = link["href"]
if href.endswith(exe_name):
return normalize(href)
if zip_name:
for link in links:
href = link["href"]
if href.endswith(zip_name):
return normalize(href)
except Exception as e:
print(f"[Updater] Ошибка при поиске файла обновления: {e}")
return None
'''def _extract_exe_from_zip(zip_path, exe_name, dest_path):
try:
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
for file in zip_ref.namelist():
if file.endswith(exe_name):
zip_ref.extract(file, os.path.dirname(dest_path))
src = os.path.join(os.path.dirname(dest_path), file)
shutil.move(src, dest_path)
return True
except Exception as e:
print(f"[Updater] Ошибка при распаковке архива: {e}")
return False'''
def _update_self(new_exe_path):
cur_path = os.path.abspath(sys.executable if getattr(sys, 'frozen', False) else sys.argv[0])
bat_path = os.path.join(tempfile.gettempdir(), "update.bat")
with open(bat_path, "w") as bat:
bat.write(f"""@echo off
timeout /t 2 > nul
taskkill /F /IM "{os.path.basename(cur_path)}" > nul 2>&1
move /Y "{new_exe_path}" "{cur_path}" > nul
start "" "{cur_path}"
del "%~f0"
""")
subprocess.Popen(["cmd", "/c", bat_path])
sys.exit(0)

View File

@@ -2,22 +2,22 @@ import subprocess
import shutil
import os
from pathlib import Path
from PIL import Image # нужна библиотека Pillow для конвертации PNG в ICO
import PySide2
from PyInstaller.utils.hooks import collect_data_files
# install:
# install: pip install PySide2 lxml nuitka pyinstaller
# - PyInstaller
# - nuitka
# - Pillow
# - PySide2
# - clang
# === Конфигурация ===
USE_NUITKA = True # True — сборка через Nuitka, False — через PyInstaller
MAIN_SCRIPT_NAME = "DebugVarEdit_GUI"
OUTPUT_NAME = "DebugVarEdit"
SRC_PATH = Path("./Src/")
SCRIPT_PATH = SRC_PATH / "DebugVarEdit_GUI.py"
OUTPUT_NAME = "DebugVarEdit"
SCRIPT_PATH = SRC_PATH / (MAIN_SCRIPT_NAME + ".py")
DIST_PATH = Path("./").resolve()
WORK_PATH = Path("./build_temp").resolve()
@@ -25,6 +25,13 @@ SPEC_PATH = WORK_PATH
ICON_PATH = SRC_PATH / "icon.png"
ICON_ICO_PATH = SRC_PATH / "icon.ico"
TEMP_FOLDERS = [
"build_temp",
"__pycache__",
MAIN_SCRIPT_NAME + ".build",
MAIN_SCRIPT_NAME + ".onefile-build",
MAIN_SCRIPT_NAME + ".dist"
]
# === Пути к DLL и прочим зависимостям ===
LIBS = {
"libclang.dll": SRC_PATH / "libclang.dll"
@@ -48,7 +55,7 @@ for name, path in LIBS.items():
print(f"WARNING: {path.name} не найден — он не будет включён в сборку")
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)
if path.exists():
shutil.rmtree(path, ignore_errors=True)

224
Src/csv_logger.py Normal file
View File

@@ -0,0 +1,224 @@
import csv
import numbers
import time
from datetime import datetime
from PySide2 import QtWidgets
class CsvLogger:
"""
Логгер, совместимый по формату с C-реализацией CSV_AddTitlesLine / CSV_AddLogLine.
Публичный API сохранён:
set_titles(varnames)
set_value(timestamp, varname, varvalue)
select_file(parent=None) -> bool
write_to_csv()
Использование:
1) set_titles([...])
2) многократно set_value(ts, name, value)
3) select_file() (по желанию)
4) write_to_csv()
"""
def __init__(self, filename="log.csv", delimiter=';'):
self._filename = filename
self._delimiter = delimiter
# Пользовательские заголовки
self.variable_names_ordered = []
# Полные заголовки CSV (Ticks(X), Ticks(Y), Time(Y), ...)
self.headers = ['t'] # до вызова set_titles placeholder
# Данные: {timestamp_key: {varname: value, ...}}
# timestamp_key = то, что передано в set_value (float/int/etc)
self.data_rows = {}
# Внутренние структуры для генерации CSV-формата С
self._row_wall_dt = {} # {timestamp_key: datetime при первой записи}
self._base_ts = None # timestamp_key первой строки (число)
self._base_ts_val = 0.0 # float значение первой строки (для delta)
self._tick_x_start = 0 # начальный тик (можно менять вручную при необходимости)
# ---- Свойства ----
@property
def filename(self):
return self._filename
# ---- Публичные методы ----
def set_titles(self, varnames):
"""
Устанавливает имена переменных.
Формирует полные заголовки CSV в формате С-лога.
"""
if not isinstance(varnames, list):
raise TypeError("Varnames must be a list of strings.")
if not all(isinstance(name, str) for name in varnames):
raise ValueError("All variable names must be strings.")
self.variable_names_ordered = varnames
self.headers = ["Ticks(X)", "Ticks(Y)", "Time(Y)"] + self.variable_names_ordered
# Сброс данных (структура изменилась)
self.data_rows.clear()
self._row_wall_dt.clear()
self._base_ts = None
self._base_ts_val = 0.0
def set_value(self, timestamp, varname, varvalue):
"""
Установить ОДНО значение в ОДНУ колонку для заданного timestampа.
timestamp — float секунд с эпохи (time.time()).
"""
if varname not in self.variable_names_ordered:
return # игнор, как у тебя было
# Новая строка?
if timestamp not in self.data_rows:
# Инициализируем поля переменных значением None
self.data_rows[timestamp] = {vn: None for vn in self.variable_names_ordered}
# Дата/время строки из ПЕРЕДАННОГО timestamp (а не datetime.now()!)
try:
ts_float = float(timestamp)
except Exception:
# если какая-то дичь прилетела, пусть будет 0 (эпоха) чтобы не упасть
ts_float = 0.0
self._row_wall_dt[timestamp] = datetime.fromtimestamp(ts_float)
# База для расчёта Ticks(Y) — первая строка
if self._base_ts is None:
self._base_ts = timestamp
self._base_ts_val = ts_float
# Записываем значение
self.data_rows[timestamp][varname] = varvalue
def select_file(self, parent=None) -> bool:
"""
Диалог выбора файла.
"""
options = QtWidgets.QFileDialog.Options()
filename, _ = QtWidgets.QFileDialog.getSaveFileName(
parent,
"Сохранить данные CSV",
self._filename,
"CSV Files (*.csv);;All Files (*)",
options=options
)
if filename:
if not filename.lower().endswith('.csv'):
filename += '.csv'
self._filename = filename
return True
else:
return False
def write_to_csv(self):
"""
Формирует CSV в формате C:
Ticks(X);Ticks(Y);Time(Y);Var1;Var2;...
0;0,000000;22/07/2025 13:45:12:0123;...;...
Правила значений:
- Тик X: автоинкремент от 0 (или self._tick_x_start) по порядку сортировки timestamp.
- Ticks(Y): дельта (секунды,микросекунды) между текущим timestamp и первым timestamp.
- Time(Y): wallclock строки (datetime.now() при первом появлении timestamp).
- Значение < 0 -> пустая ячейка (как if(raw_data[i] >= 0) else ;)
- None -> пустая ячейка.
"""
if len(self.headers) <= 3: # только служебные поля без переменных
print("Ошибка: Заголовки не установлены или не содержат переменных. Вызовите set_titles() перед записью.")
return
if not self._filename:
print("Ошибка: Имя файла не определено. select_file() или задайте при инициализации.")
return
if not self.data_rows:
print("Предупреждение: Нет данных для записи.")
# всё равно создадим файл с одними заголовками
try:
with open(self._filename, 'w', newline='', encoding='utf-8') as csvfile:
# QUOTE_NONE + escapechar для чистого формата без кавычек (как в С-строке)
writer = csv.writer(
csvfile,
delimiter=self._delimiter,
quoting=csv.QUOTE_NONE,
escapechar='\\',
lineterminator='\r\n'
)
# Пишем заголовки
writer.writerow(self.headers)
if self.data_rows:
sorted_ts = sorted(self.data_rows.keys(), key=self._ts_sort_key)
# убедимся, что база была зафиксирована
if self._base_ts is None:
self._base_ts = sorted_ts[0]
self._base_ts_val = self._coerce_ts_to_float(self._base_ts)
tick_x = self._tick_x_start
for ts in sorted_ts:
row_dict = self.data_rows[ts]
# delta по timestamp
cur_ts_val = self._coerce_ts_to_float(ts)
delta_us = int(round((cur_ts_val - self._base_ts_val) * 1_000_000))
if delta_us < 0:
delta_us = 0 # защита
seconds = delta_us // 1_000_000
micros = delta_us % 1_000_000
# wallclock строки
dt = self._row_wall_dt.get(ts, datetime.now())
# Формат DD/MM/YYYY HH:MM:SS:мммм (4 цифры ms, как в C: us/1000)
time_str = dt.strftime("%d/%m/%Y %H:%M:%S") + f":{dt.microsecond // 1000:04d}"
# Значения
row_vals = []
for vn in self.variable_names_ordered:
v = row_dict.get(vn)
if v is None:
row_vals.append("") # нет данных
else:
# если числовое и <0 -> пусто (как в C: если raw_data[i] >= 0 else ;)
if isinstance(v, numbers.Number) and v < 0:
row_vals.append("")
else:
row_vals.append(v)
csv_row = [tick_x, f"{seconds},{micros:06d}", time_str] + row_vals
writer.writerow(csv_row)
tick_x += 1
print(f"Данные успешно записаны в '{self._filename}'")
except Exception as e:
print(f"Ошибка при записи в файл '{self._filename}': {e}")
# ---- Вспомогательные ----
def _coerce_ts_to_float(self, ts):
"""
Пробуем привести переданный timestamp к float.
Разрешаем int/float/str, остальное -> индекс по порядку (0).
"""
if isinstance(ts, numbers.Number):
return float(ts)
try:
return float(ts)
except Exception:
# fallback: нечисловой ключ -> используем порядковый индекс
# (таких почти не должно быть, но на всякий)
return 0.0
def _ts_sort_key(self, ts):
"""
Ключ сортировки timestampов — сначала попытка float, потом str.
"""
if isinstance(ts, numbers.Number):
return (0, float(ts))
try:
return (0, float(ts))
except Exception:
return (1, str(ts))

View File

@@ -1,20 +1,21 @@
# build command
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build generateVars.py
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build generate_debug_vars.py
# 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 os
import re
import xml.etree.ElementTree as ET
import lxml.etree as ET
from pathlib import Path
from xml.dom import minidom
import myXML
import argparse
shortnameSize = 10
# === Словарь соответствия типов XML → DebugVarType_t ===
type_map = dict([
type_map_tms = dict([
*[(k, 'pt_int8') for k in ('signed char', 'char')],
*[(k, 'pt_int16') for k in ('int', 'int16', 'short')],
*[(k, 'pt_int32') for k in ('long', 'int32', '_iqx')],
@@ -52,6 +53,150 @@ type_map = dict([
('struct[]', 'pt_arr_struct'),
('union[]', 'pt_arr_union'),
])
# === Словарь соответствия типов XML → DebugVarType_t ===
type_map_stm32 = dict([
*[(k, 'pt_int8') for k in (
'int8_t', 'signed char', 'char'
)],
# --- 8-bit unsigned ---
*[(k, 'pt_uint8') for k in (
'uint8_t', 'unsigned char'
)],
# --- 16-bit signed ---
*[(k, 'pt_int16') for k in (
'int16_t', 'short', 'short int', 'signed short', 'signed short int'
)],
# --- 16-bit unsigned ---
*[(k, 'pt_uint16') for k in (
'uint16_t', 'unsigned short', 'unsigned short int'
)],
# --- 32-bit signed ---
*[(k, 'pt_int32') for k in (
'int32_t', 'int', 'signed', 'signed int'
)],
# --- 32-bit unsigned ---
*[(k, 'pt_uint32') for k in (
'uint32_t', 'unsigned', 'unsigned int'
)],
# --- 64-bit signed ---
*[(k, 'pt_int64') for k in (
'int64_t', 'long long', 'signed long long', 'signed long long int'
)],
# --- 64-bit unsigned ---
*[(k, 'pt_uint64') for k in (
'uint64_t', 'unsigned long long', 'unsigned long long int'
)],
# --- Float ---
*[(k, 'pt_float') for k in (
'float', 'float32_t'
)],
# --- Struct and Union ---
('struct', 'pt_struct'),
('union', 'pt_union'),
('struct*', 'pt_ptr_struct'),
('union*', 'pt_ptr_union'),
('struct[]', 'pt_arr_struct'),
('union[]', 'pt_arr_union'),
# === POINTERS ===
# 8-bit
*[(k, 'pt_ptr_int8') for k in (
'int8_t*', 'signed char*', 'char*'
)],
*[(k, 'pt_ptr_uint8') for k in (
'uint8_t*', 'unsigned char*'
)],
# 16-bit
*[(k, 'pt_ptr_int16') for k in (
'int16_t*', 'short*', 'short int*', 'signed short*', 'signed short int*'
)],
*[(k, 'pt_ptr_uint16') for k in (
'uint16_t*', 'unsigned short*', 'unsigned short int*'
)],
# 32-bit
*[(k, 'pt_ptr_int32') for k in (
'int32_t*', 'int*', 'signed*', 'signed int*'
)],
*[(k, 'pt_ptr_uint32') for k in (
'uint32_t*', 'unsigned*', 'unsigned int*'
)],
# 64-bit
*[(k, 'pt_ptr_int64') for k in (
'int64_t*', 'long long*', 'signed long long*', 'signed long long int*'
)],
*[(k, 'pt_ptr_uint64') for k in (
'uint64_t*', 'unsigned long long*', 'unsigned long long int*'
)],
# float*
*[(k, 'pt_ptr_float') for k in (
'float*', 'float32_t*'
)],
# === ARRAYS ===
# 8-bit
*[(k, 'pt_arr_int8') for k in (
'int8_t[]', 'signed char[]', 'char[]'
)],
*[(k, 'pt_arr_uint8') for k in (
'uint8_t[]', 'unsigned char[]'
)],
# 16-bit
*[(k, 'pt_arr_int16') for k in (
'int16_t[]', 'short[]', 'short int[]', 'signed short[]', 'signed short int[]'
)],
*[(k, 'pt_arr_uint16') for k in (
'uint16_t[]', 'unsigned short[]', 'unsigned short int[]'
)],
# 32-bit
*[(k, 'pt_arr_int32') for k in (
'int32_t[]', 'int[]', 'signed[]', 'signed int[]'
)],
*[(k, 'pt_arr_uint32') for k in (
'uint32_t[]', 'unsigned[]', 'unsigned int[]'
)],
# 64-bit
*[(k, 'pt_arr_int64') for k in (
'int64_t[]', 'long long[]', 'signed long long[]', 'signed long long int[]'
)],
*[(k, 'pt_arr_uint64') for k in (
'uint64_t[]', 'unsigned long long[]', 'unsigned long long int[]'
)],
# float[]
*[(k, 'pt_arr_float') for k in (
'float[]', 'float32_t[]'
)],
])
type_map = type_map_tms
stm_flag_global = 0
def choose_type_map(stm_flag):
global type_map # объявляем, что будем менять глобальную переменную
global stm_flag_global # объявляем, что будем менять глобальную переменную
if stm_flag:
type_map = type_map_stm32
stm_flag_global = 1
else:
type_map = type_map_tms
stm_flag_global = 0
def map_type_to_pt(typename, varname=None, typedef_map=None):
typename_orig = typename.strip()
@@ -140,20 +285,26 @@ def add_new_vars_to_xml(proj_path, xml_rel_path, output_path):
Возвращает True если что-то добавлено и XML перезаписан, иначе False.
"""
pattern = re.compile(
r'{\s*\(uint8_t\s*\*\)\s*&([a-zA-Z_][a-zA-Z0-9_]*(?:\[.*?\])?(?:(?:\.|->)[a-zA-Z_][a-zA-Z0-9_]*(?:\[.*?\])?)*)\s*,\s*'
r'(pt_\w+)\s*,\s*'
r'(t?_?iq\w+)\s*,\s*'
r'(t?_?iq\w+)\s*,\s*'
r'"([^"]+)"'
)
# Считываем существующие переменные
parsed_vars = {}
if os.path.isfile(output_path):
with open(output_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
# {(char *)&some.deep.var.name , pt_uint16 , t_iq15 , "ShortName"},
m = re.match(
r'{\s*\(char\s*\*\)\s*&([a-zA-Z_][a-zA-Z0-9_]*)\s*,\s*(pt_\w+)\s*,\s*(t?iq_\w+)\s*,\s*"([^"]+)"',
line)
# {(uint8_t *)&some.deep.var.name , pt_uint16 , t_iq15 , t_iq10, "ShortName"},
m = pattern.search(line)
if m:
full_varname = m.group(1) # e.g., some.deep.var.name
pt_type = m.group(2)
iq_type = m.group(3)
shortname = m.group(4)
return_type = m.group(4)
shortname = m.group(5)
parsed_vars[full_varname] = {
'pt_type': pt_type,
@@ -161,7 +312,7 @@ def add_new_vars_to_xml(proj_path, xml_rel_path, output_path):
'enable': True,
'show_var': True,
'shortname': shortname,
'return_type': 'int',
'return_type': return_type,
'type': '', # Можешь дополнить из externs
'file': '', # Можешь дополнить из externs
'extern': False,
@@ -284,12 +435,27 @@ def read_vars_from_xml(proj_path, xml_rel_path):
return unique_vars, include_files, vars_need_extern
def read_file_try_encodings(filepath):
if not os.path.isfile(filepath):
# Файл не существует — просто вернуть пустую строку или None
return "", None
for enc in ['utf-8', 'cp1251']:
try:
with open(filepath, 'r', encoding=enc) as f:
content = f.read()
return content, enc
except UnicodeDecodeError:
continue
raise UnicodeDecodeError(f"Не удалось прочитать файл {filepath} с кодировками utf-8 и cp1251")
def generate_vars_file(proj_path, xml_path, output_dir):
output_dir = os.path.join(proj_path, output_dir)
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, 'debug_vars.c')
LIBC_path = os.path.join(output_dir, 'debug_tools.c')
LIBH_path = os.path.join(output_dir, 'debug_tools.h')
# Запись новых переменных для в XML
@@ -330,15 +496,14 @@ def generate_vars_file(proj_path, xml_path, output_dir):
if not pt_type:
pt_type = map_type_to_pt(vtype, vname)
ret_type = info.get('pt_type')
ret_type = info.get('return_type')
if not ret_type:
pt_type = 't_iq_none'
# Дополнительные поля, например комментарий
comment = info.get("comment", "")
short_name = info.get("shortname", f'"{vname}"')
short_trimmed = short_name[:10] # ограничиваем длину до 10
short_trimmed = short_name[:shortnameSize] # ограничиваем длину до 10
if pt_type not in ('pt_struct', 'pt_union'):
f_name = f'{vname},'
@@ -348,7 +513,7 @@ def generate_vars_file(proj_path, xml_path, output_dir):
f_short_name = f'"{short_trimmed}"' # оборачиваем в кавычки
# Добавим комментарий после записи, если он есть
comment_str = f' // {comment}' if comment else ''
line = f'{{(char *)&{f_name:<45} {f_type:<15} {f_iq:<15} {f_ret_iq:<15} {f_short_name:<21}}}, \\{comment_str}'
line = f'{{(uint8_t *)&{f_name:<58} {f_type:<15} {f_iq:<15} {f_ret_iq:<15} {f_short_name:<21}}}, \\{comment_str}'
new_debug_vars[vname] = line
else:
@@ -394,14 +559,19 @@ def generate_vars_file(proj_path, xml_path, output_dir):
out_lines.append(f'\n\n// Определение массива с указателями на переменные для отладки')
out_lines.append(f'int DebugVar_Qnt = {len(all_debug_lines)};')
if stm_flag_global == 0:
out_lines.append('#pragma DATA_SECTION(dbg_vars,".dbgvar_info")')
out_lines.append('// pointer_type iq_type return_iq_type short_name')
out_lines.append('DebugVar_t dbg_vars[] = {\\')
out_lines.extend(all_debug_lines)
out_lines.append('};')
out_lines.append('')
# Выберем кодировку для записи файла
# Если встречается несколько, возьмем первую из set
if stm_flag_global == 0:
enc_to_write = 'cp1251'
else:
enc_to_write = 'utf-8'
#print("== GLOBAL VARS FOUND ==")
#for vname, (vtype, path) in vars_in_c.items():
@@ -411,6 +581,16 @@ def generate_vars_file(proj_path, xml_path, output_dir):
with open(output_path, 'w', encoding=enc_to_write) as f:
f.write('\n'.join(out_lines))
if os.path.isfile(LIBC_path):
libc_code, _ = read_file_try_encodings(LIBC_path)
with open(LIBC_path, 'w', encoding=enc_to_write) as f:
f.write(libc_code)
if os.path.isfile(LIBH_path):
libh_code, _ = read_file_try_encodings(LIBH_path)
with open(LIBH_path, 'w', encoding=enc_to_write) as f:
f.write(libh_code)
print(f'Файл debug_vars.c сгенерирован в кодировке, переменных: {len(all_debug_lines)}')
@@ -472,16 +652,17 @@ Usage example:
print(f"Error: Project path '{proj_path}' не является директорией или не существует.")
sys.exit(1)
generate_vars_file(proj_path, xml_path_rel, output_dir_rel)
generate_vars_file(proj_path, xml_path_rel, output_dir_rel, 0)
if __name__ == "__main__":
main()
def run_generate(proj_path, xml_path, output_dir):
def run_generate(proj_path, xml_path, output_dir, shortname_size):
import os
global shortnameSize
shortnameSize = shortname_size
# Normalize absolute paths
proj_path = os.path.abspath(proj_path)
xml_path_abs = os.path.abspath(xml_path)

242
Src/makefile_parser.py Normal file
View File

@@ -0,0 +1,242 @@
import os
import re
from lxml import etree as ET
def strip_single_line_comments(code):
# Удалим // ... до конца строки
return re.sub(r'//.*?$', '', code, flags=re.MULTILINE)
def read_file_try_encodings(filepath):
if not os.path.isfile(filepath):
# Файл не существует — просто вернуть пустую строку или None
return "", None
for enc in ['utf-8', 'cp1251']:
try:
with open(filepath, 'r', encoding=enc) as f:
content = f.read()
content = strip_single_line_comments(content)
return content, enc
except UnicodeDecodeError:
continue
raise UnicodeDecodeError(f"Не удалось прочитать файл {filepath} с кодировками utf-8 и cp1251")
def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
"""
Рекурсивно ищет все include-файлы начиная с заданных c_files.
Возвращает множество ПОЛНЫХ ПУТЕЙ к найденным include-файлам.
include_dirs — список директорий, в которых ищем include-файлы.
processed_files — множество уже обработанных файлов (для избежания циклов).
"""
if processed_files is None:
processed_files = set()
include_files = set()
include_pattern = re.compile(r'#include\s+"([^"]+)"')
for cfile in c_files:
norm_path = os.path.normpath(cfile)
if norm_path in processed_files:
continue
processed_files.add(norm_path)
content, _ = read_file_try_encodings(cfile)
if content is None:
continue
includes = include_pattern.findall(content)
for inc in includes:
# Ищем полный путь к include-файлу в include_dirs
inc_full_path = None
for dir_ in include_dirs:
candidate = os.path.normpath(os.path.join(dir_, inc))
if os.path.isfile(candidate):
inc_full_path = os.path.abspath(candidate)
break
if inc_full_path:
include_files.add(inc_full_path)
# Рекурсивный обход вложенных includes
if inc_full_path not in processed_files:
nested_includes = find_all_includes_recursive(
[inc_full_path], include_dirs, processed_files
)
include_files.update(nested_includes)
return include_files
def parse_objects_list(objects_list_path, project_root):
c_files = []
include_dirs = set()
if not os.path.isfile(objects_list_path):
return c_files, include_dirs
with open(objects_list_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
line = line.strip().strip('"').replace("\\", "/")
if line.endswith(".o"):
c_file = re.sub(r"\.o$", ".c", line)
abs_path = os.path.normpath(os.path.join(project_root, c_file))
if os.path.isfile(abs_path):
if not any(x in abs_path for x in ["DebugTools", "v120", "v100"]):
c_files.append(abs_path)
include_dirs.add(os.path.dirname(abs_path))
return c_files, include_dirs
def parse_uvprojx(uvprojx_path):
import xml.etree.ElementTree as ET
import os
tree = ET.parse(uvprojx_path)
root = tree.getroot()
project_dir = os.path.dirname(os.path.abspath(uvprojx_path))
c_files = []
include_dirs = set()
defines = set()
# Найдём C-файлы и директории
for file_elem in root.findall(".//FilePath"):
file_path = file_elem.text
if file_path:
abs_path = os.path.normpath(os.path.join(project_dir, file_path))
if os.path.isfile(abs_path):
if abs_path.endswith(".c"):
c_files.append(abs_path)
include_dirs.add(os.path.dirname(abs_path))
# Включаем IncludePath
for inc_path_elem in root.findall(".//IncludePath"):
path_text = inc_path_elem.text
if path_text:
paths = path_text.split(';')
for p in paths:
p = p.strip()
if p:
abs_inc_path = os.path.normpath(os.path.join(project_dir, p))
if os.path.isdir(abs_inc_path):
include_dirs.add(abs_inc_path)
# Добавим <Define>
for define_elem in root.findall(".//Define"):
def_text = define_elem.text
if def_text:
for d in def_text.split(','):
d = d.strip()
if d:
defines.add(d)
h_files = find_all_includes_recursive(c_files, include_dirs)
return sorted(c_files), sorted(h_files), sorted(include_dirs), sorted(defines)
def parse_makefile(makefile_path, proj_path):
import os
import re
project_root = os.path.abspath(proj_path)
c_files = []
include_dirs = set()
defines = [] # Заглушка: нет define-параметров из Makefile
with open(makefile_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
raw_entries = []
collecting = False
for line in lines:
stripped = line.strip()
if (("ORDERED_OBJS" in stripped or "C_SOURCES" in stripped) and ("+=" in stripped or "=" in stripped)):
collecting = True
if collecting:
line_clean = stripped.rstrip("\\").strip()
if line_clean:
line_clean = re.sub(r"\$\([^)]+\)", "", line_clean)
line_clean = re.sub(r"\$\{[^}]+\}", "", line_clean)
raw_entries.append(line_clean)
if not stripped.endswith("\\"):
collecting = False
for entry in raw_entries:
for token in entry.split():
token = token.strip('"')
if not token:
continue
token = token.replace("\\", "/")
if token.endswith(".obj"):
token = re.sub(r"\.obj$", ".c", token)
elif token.endswith(".o"):
token = re.sub(r"\.o$", ".c", token)
if token.endswith(".c"):
abs_path = os.path.normpath(os.path.join(project_root, token))
if os.path.isfile(abs_path):
if not any(x in abs_path for x in ["DebugTools", "v120", "v100"]):
c_files.append(abs_path)
include_dirs.add(os.path.dirname(abs_path))
if not c_files:
makefile_dir = os.path.dirname(os.path.abspath(makefile_path))
objects_list_path = os.path.join(makefile_dir, "objects.list")
c_from_objects, inc_from_objects = parse_objects_list(objects_list_path, project_root)
c_files.extend(c_from_objects)
include_dirs.update(inc_from_objects)
for line in lines:
if "-I" in line or "C_INCLUDES" in line:
matches = re.findall(r"-I\s*([^\s\\]+)", line)
for match in matches:
match = match.strip('"').replace("\\", "/")
abs_include = os.path.normpath(os.path.join(project_root, match))
if os.path.isdir(abs_include):
include_dirs.add(abs_include)
# Добавляем пути с заменой 'Src' на 'Inc', если путь заканчивается на 'Src'
additional_includes = set()
for inc in include_dirs:
if inc.endswith(os.sep + "Src") or inc.endswith("/Src"):
inc_inc = inc[:-3] + "Inc" # заменяем 'Src' на 'Inc'
if os.path.isdir(inc_inc):
additional_includes.add(inc_inc)
include_dirs.update(additional_includes)
h_files = find_all_includes_recursive(c_files, include_dirs)
return sorted(c_files), sorted(h_files), sorted(include_dirs), sorted(defines)
def parse_project(project_file_path, project_root=None):
"""
Выбирает парсер в зависимости от расширения project_file_path:
- для *.uvprojx и *.uvproj вызывается парсер Keil
- для остальных - parse_makefile
project_root нужен для parse_makefile, если не передан - берется из project_file_path
"""
ext = os.path.splitext(project_file_path)[1].lower()
if ext in ['.uvprojx', '.uvproj']:
# Парсим Keil проект
return parse_uvprojx(project_file_path)
else:
# Парсим makefile
if project_root is None:
project_root = os.path.dirname(os.path.abspath(project_file_path))
return parse_makefile(project_file_path, project_root)

View File

@@ -1,5 +1,5 @@
import os
import xml.etree.ElementTree as ET
from lxml import etree
def make_absolute_path(path, 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("\\", "/")
def indent_xml(elem, level=0):
indent = " "
i = "\n" + level * indent
# Убираем strip() — они медленные, и текст мы всё равно перезаписываем
i = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + indent
elem.text = elem.text or i + " "
for child in elem:
indent_xml(child, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
elem[-1].tail = elem[-1].tail or i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
elem.tail = elem.tail or i
def fwrite(root, xml_full_path):
indent_xml(root)
ET.ElementTree(root).write(xml_full_path, encoding="utf-8", xml_declaration=True)
#indent_xml(root)
#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):
"""
Безопасно парсит XML-файл.
Возвращает кортеж (root, tree) или (None, None) при ошибках.
"""
if not xml_path or not os.path.isfile(xml_path):
print(f"Файл '{xml_path}' не найден или путь пустой")
return None, None
try:
if os.path.getsize(xml_path) == 0:
return None, None
tree = ET.parse(xml_path)
tree = etree.parse(xml_path)
root = tree.getroot()
return root, tree
except ET.ParseError as e:
except etree .XMLSyntaxError as e:
print(f"Ошибка парсинга XML файла '{xml_path}': {e}")
return None, None
except Exception as e:

View File

@@ -1,154 +0,0 @@
import os
import re
def strip_single_line_comments(code):
# Удалим // ... до конца строки
return re.sub(r'//.*?$', '', code, flags=re.MULTILINE)
def read_file_try_encodings(filepath):
if not os.path.isfile(filepath):
# Файл не существует — просто вернуть пустую строку или None
return "", None
for enc in ['utf-8', 'cp1251']:
try:
with open(filepath, 'r', encoding=enc) as f:
content = f.read()
content = strip_single_line_comments(content)
return content, enc
except UnicodeDecodeError:
continue
raise UnicodeDecodeError(f"Не удалось прочитать файл {filepath} с кодировками utf-8 и cp1251")
def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
"""
Рекурсивно ищет все include-файлы начиная с заданных c_files.
Возвращает множество ПОЛНЫХ ПУТЕЙ к найденным include-файлам.
include_dirs — список директорий, в которых ищем include-файлы.
processed_files — множество уже обработанных файлов (для избежания циклов).
"""
if processed_files is None:
processed_files = set()
include_files = set()
include_pattern = re.compile(r'#include\s+"([^"]+)"')
for cfile in c_files:
norm_path = os.path.normpath(cfile)
if norm_path in processed_files:
continue
processed_files.add(norm_path)
content, _ = read_file_try_encodings(cfile)
if content is None:
continue
includes = include_pattern.findall(content)
for inc in includes:
# Ищем полный путь к include-файлу в include_dirs
inc_full_path = None
for dir_ in include_dirs:
candidate = os.path.normpath(os.path.join(dir_, inc))
if os.path.isfile(candidate):
inc_full_path = os.path.abspath(candidate)
break
if inc_full_path:
include_files.add(inc_full_path)
# Рекурсивный обход вложенных includes
if inc_full_path not in processed_files:
nested_includes = find_all_includes_recursive(
[inc_full_path], include_dirs, processed_files
)
include_files.update(nested_includes)
return include_files
def parse_makefile(makefile_path, proj_path):
makefile_dir = os.path.dirname(makefile_path)
project_root = proj_path
with open(makefile_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
objs_lines = []
collecting = False
for line in lines:
stripped = line.strip()
if stripped.startswith("ORDERED_OBJS") and "+=" in stripped:
parts = stripped.split("\\")
first_part = parts[0]
idx = first_part.find("+=")
tail = first_part[idx+2:].strip()
if tail:
objs_lines.append(tail)
collecting = True
if len(parts) > 1:
for p in parts[1:]:
p = p.strip()
if p:
objs_lines.append(p)
continue
if collecting:
if stripped.endswith("\\"):
objs_lines.append(stripped[:-1].strip())
else:
objs_lines.append(stripped)
collecting = False
objs_str = ' '.join(objs_lines)
objs_str = re.sub(r"\$\([^)]+\)", "", objs_str)
objs = []
for part in objs_str.split():
part = part.strip()
if part.startswith('"') and part.endswith('"'):
part = part[1:-1]
if part:
objs.append(part)
c_files = []
include_dirs = set()
for obj_path in objs:
if "DebugTools" in obj_path:
continue
if "v120" in obj_path:
continue
if "v100" in obj_path:
continue
if obj_path.startswith("Debug\\") or obj_path.startswith("Debug/"):
rel_path = obj_path.replace("Debug\\", "Src\\").replace("Debug/", "Src/")
else:
rel_path = obj_path
abs_path = os.path.normpath(os.path.join(project_root, rel_path))
root, ext = os.path.splitext(abs_path)
if ext.lower() == ".obj":
c_path = root + ".c"
else:
c_path = abs_path
# Проверяем существование файла, если нет — пропускаем
if not os.path.isfile(c_path):
continue
# Сохраняем только .c файлы
if c_path.lower().endswith(".c"):
c_files.append(c_path)
dir_path = os.path.dirname(c_path)
if dir_path and "DebugTools" not in dir_path:
include_dirs.add(dir_path)
h_files = find_all_includes_recursive(c_files, include_dirs)
return sorted(c_files), sorted(h_files), sorted(include_dirs)

319
Src/path_hints.py Normal file
View File

@@ -0,0 +1,319 @@
# path_hints.py
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Tuple
import re
# ---------------------- tokenization helpers ----------------------
def split_path_tokens(path: str) -> List[str]:
"""
Разбивает строку пути на логические части:
'foo[2].bar[1]->baz' -> ['foo', '[2]', 'bar', '[1]', 'baz']
Аналог твоей split_path(), но оставлена как чистая функция.
"""
tokens: List[str] = []
token = ''
i = 0
L = len(path)
while i < L:
c = path[i]
# '->'
if c == '-' and i + 1 < L and path[i:i+2] == '->':
if token:
tokens.append(token)
token = ''
i += 2
continue
# одиночный '-' в конце
if c == '-' and i == L - 1:
i += 1
continue
# '.'
if c == '.':
if token:
tokens.append(token)
token = ''
i += 1
continue
# '[' ... ']'
if c == '[':
if token:
tokens.append(token)
token = ''
idx = ''
while i < L and path[i] != ']':
idx += path[i]
i += 1
if i < L and path[i] == ']':
idx += ']'
i += 1
tokens.append(idx)
continue
# обычный символ
token += c
i += 1
if token:
tokens.append(token)
return tokens
def split_path_tokens_with_spans(path: str) -> List[Tuple[str, int, int]]:
"""
Возвращает список кортежей (токен, start_pos, end_pos)
Токены — так же, как в split_path_tokens, но с позициями в исходной строке.
"""
tokens = []
i = 0
L = len(path)
while i < L:
c = path[i]
start = i
# '->'
if c == '-' and i + 1 < L and path[i:i+2] == '->':
tokens.append(('->', start, start + 2))
i += 2
continue
if c == '.':
tokens.append(('.', start, start + 1))
i += 1
continue
if c == '[':
# захватим весь индекс с ']'
j = i
while j < L and path[j] != ']':
j += 1
if j < L and path[j] == ']':
j += 1
tokens.append((path[i:j], i, j))
i = j
continue
# иначе - обычное имя (до точки, стрелки или скобок)
j = i
while j < L and path[j] not in ['.', '-', '[']:
if path[j] == '-' and j + 1 < L and path[j:j+2] == '->':
break
j += 1
tokens.append((path[i:j], i, j))
i = j
# фильтруем из списка токены-разделители '.' и '->' чтобы оставить только логические части
filtered = [t for t in tokens if t[0] not in ['.', '->']]
return filtered
def canonical_key(path: str) -> str:
"""
Преобразует путь к канонической форме для индекса / поиска:
- '->' -> '.'
- '[' -> '.['
- lower()
"""
p = path.replace('->', '.')
p = p.replace('[', '.[')
return p.lower()
# ---------------------- индекс узлов ----------------------
@dataclass
class PathNode:
"""
Узел в логическом дереве путей.
Храним:
- собственное имя (локальное, напр. 'controller' или '[3]')
- полный путь (оригинальный, как его должен видеть пользователь)
- тип (опционально; widget может хранить отдельно)
- дети
"""
name: str
full_path: str
type_str: str = ''
children: Dict[str, "PathNode"] = field(default_factory=dict)
def add_child(self, child: "PathNode") -> None:
self.children[child.name] = child
def get_children(self) -> List["PathNode"]:
"""
Вернуть список дочерних узлов, отсортированных по имени.
"""
return sorted(self.children.values(), key=lambda n: n.name)
class PathHints:
"""
Движок автоподсказок / completion.
Работает с плоским списком ПОЛНЫХ имён (как показываются пользователю).
Сам восстанавливает иерархию и выдаёт подсказки по текущему вводу.
Qt-независим.
"""
def __init__(self) -> None:
self._paths: List[str] = []
self._types: Dict[str, str] = {} # full_path -> type_str (опционально)
self._index: Dict[str, PathNode] = {} # canonical full path -> node
self._root_children: Dict[str, PathNode] = {} # top-level по первому токену
# ------------ Подаём данные ------------
def set_paths(self,
paths: List[Tuple[str, Optional[str]]]
) -> None:
"""
paths: список кортежей (full_path, type_str|None).
Пример: ('project.controller.read.errors.bit.status_er0', 'unsigned int')
Поля могут содержать '->' и индексы, т.е. строки в пользовательском формате.
NOTE: порядок не важен; дерево строится автоматически.
"""
self._paths = []
self._types.clear()
self._index.clear()
self._root_children.clear()
for p, t in paths:
if t is None:
t = ''
self._add_path(p, t)
def _add_path(self, full_path: str, type_str: str) -> None:
self._paths.append(full_path)
self._types[full_path] = type_str
tokens_spans = split_path_tokens_with_spans(full_path)
if not tokens_spans:
return
cur_dict = self._root_children
cur_full = ''
parent_node: Optional[PathNode] = None
for i, (tok, start, end) in enumerate(tokens_spans):
cur_full = full_path[:end] # подстрока с начала до конца токена включительно
node = cur_dict.get(tok)
if node is None:
node = PathNode(name=tok, full_path=cur_full)
cur_dict[tok] = node
# Регистрируем все узлы, включая промежуточные
self._index[canonical_key(cur_full)] = node
parent_node = node
cur_dict = node.children
# В последний узел добавляем тип
if parent_node:
parent_node.type_str = type_str
# ------------ Поиск узла ------------
def find_node(self, path: str) -> Optional[PathNode]:
return self._index.get(canonical_key(path))
def get_children(self, full_path: str) -> List[PathNode]:
"""
Вернуть список дочерних узлов PathNode для заданного полного пути.
Если узел не найден — вернуть пустой список.
"""
node = self.find_node(full_path)
if node is None:
return []
return node.get_children()
# ------------ Подсказки ------------
def suggest(self,
text: str,
*,
include_partial: bool = True
) -> List[str]:
"""
Вернёт список *полных имён узлов*, подходящих под ввод.
Правила (упрощённо, повторяя твою update_completions()):
- Если текст пуст → top-level.
- Если заканчивается на '.' или '->' или '[' → вернуть детей текущего узла.
- Иначе → фильтр по последнему фрагменту (prefix substring match).
"""
text = text or ''
stripped = text.strip()
# пусто: top-level
if stripped == '':
return sorted(self._root_full_names())
# Завершение по разделителю?
if stripped.endswith('.') or stripped.endswith('->') or stripped.endswith('['):
base = stripped[:-1] if stripped.endswith('[') else stripped.rstrip('.').rstrip('>').rstrip('-')
node = self.find_node(base)
if node:
return self._children_full_names(node)
# не нашли базу — ничего
return []
# иначе: обычный поиск по последней части
toks = split_path_tokens(stripped)
prefix_last = toks[-1].lower() if toks else ''
parent_toks = toks[:-1]
if not parent_toks:
# фильтр top-level
res = []
for name, node in self._root_children.items():
if prefix_last == '' or prefix_last in name.lower():
res.append(node.full_path)
return sorted(res)
# есть родитель
parent_path = self._join_tokens(parent_toks)
parent_node = self.find_node(parent_path)
if not parent_node:
return []
res = []
for child in parent_node.children.values():
if prefix_last == '' or prefix_last in child.name.lower():
res.append(child.full_path)
return sorted(res)
def add_separator(self, full_path: str) -> str:
"""
Возвращает full_path с добавленным разделителем ('.' или '['),
если у узла есть дети и пользователь ещё не поставил разделитель.
Если первый ребёнок — массивный токен ('[0]') → добавляем '['.
Позже можно допилить '->' для указателей.
"""
node = self.find_node(full_path)
text = full_path
if node and node.children and not (
text.endswith('.') or text.endswith('->') or text.endswith('[')
):
first_child = next(iter(node.children.values()))
if first_child.name.startswith('['):
text += '[' # сразу начинаем индекс
else:
text += '.' # обычный переход
return text
# ------------ внутренние вспомогательные ------------
def _root_full_names(self) -> List[str]:
return [node.full_path for node in self._root_children.values()]
def _children_full_names(self, node: PathNode) -> List[str]:
return [ch.full_path for ch in node.children.values()]
@staticmethod
def _join_tokens(tokens: List[str]) -> str:
"""
Собираем путь обратно. Для внутренних нужд (поиск), формат не критичен —
всё равно canonical_key() нормализует.
"""
if not tokens:
return ''
out = tokens[0]
for t in tokens[1:]:
if t.startswith('['):
out += t
else:
out += '.' + t
return out

View File

@@ -6,8 +6,8 @@ import sys
import contextlib
import io
import json
from scanVars import run_scan
from VariableTable import VariableTableWidget, rows
from scan_vars import run_scan
from var_table import VariableTableWidget, rows
from PySide2.QtWidgets import (
QApplication, QWidget, QTableWidget, QTableWidgetItem,
@@ -73,13 +73,13 @@ class EmittingStream(QObject):
self._buffer = ""
class ProcessOutputWindow(QDialog):
def __init__(self, proj_path, makefile_path, xml_path, on_done_callback=None):
super().__init__()
def __init__(self, proj_path, makefile_path, xml_path, on_done_callback=None, parent=None):
super().__init__(parent)
self.setWindowTitle("Поиск переменных...")
self.resize(600, 480)
self.setModal(True)
self.setAttribute(Qt.WA_DeleteOnClose)
self.proj_path = proj_path
self.makefile_path = makefile_path

View File

@@ -1,7 +1,7 @@
# 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
# 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 sys
@@ -9,9 +9,9 @@ import re
import clang.cindex
from clang import cindex
from clang.cindex import Config
import xml.etree.ElementTree as ET
import lxml.etree as ET
from xml.dom import minidom
from parseMakefile import parse_makefile
from makefile_parser import parse_project
from collections import deque
import argparse
import myXML
@@ -118,11 +118,11 @@ def get_canonical_typedef_file(var_type, include_dirs):
break
return None
def analyze_variables_across_files(c_files, h_files, include_dirs):
def analyze_variables_across_files(c_files, h_files, include_dirs, global_defs):
optional_printf(PRINT_STATUS, "Starting analysis of variables across files...")
index = clang.cindex.Index.create()
args = [f"-I{inc}" for inc in include_dirs]
define_args = [f"-D{d}" for d in global_defs]
args = [f"-I{inc}" for inc in include_dirs] + define_args
unique_vars = {} # имя переменной → словарь с инфой
h_files_needed = set()
vars_need_extern = {} # имя переменной → словарь без поля 'extern'
@@ -154,6 +154,7 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
# Проверяем, начинается ли имя с "_" и содержит заглавные буквы или служебные символы
return bool(re.match(r"^_[_A-Z]", var_name))
if node.kind == clang.cindex.CursorKind.VAR_DECL:
if node.semantic_parent.kind == clang.cindex.CursorKind.TRANSLATION_UNIT:
is_extern = (node.storage_class == clang.cindex.StorageClass.EXTERN)
@@ -171,6 +172,11 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
if node.spelling == 'HUGE': # еще одна служеюная, которую хз как выделять
return
if 'Drivers' in node.location.file.name:
return
if 'uint' in node.spelling:
a = 1
# Проверяем, является ли тип указателем на функцию
# Признак: в типе есть '(' и ')' и '*', например: "void (*)(int)"
if "(" in var_type and "*" in var_type and ")" in var_type:
@@ -295,6 +301,8 @@ def strip_ptr_and_array(typename):
return typename
def analyze_typedefs_and_struct(typedefs, structs):
optional_printf(PRINT_STATUS, "Resolving typedefs and expanding struct field types...")
@@ -422,10 +430,28 @@ def contains_anywhere_in_node(node, target: str) -> bool:
return False
def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
def try_guess_std_include():
# Популярные места, где может лежать stdint.h
guesses = [
r"C:\Keil_v5\ARM\ARMCLANG\include",
r"C:\Program Files (x86)\GNU Arm Embedded Toolchain",
r"C:\Program Files (x86)\Arm GNU Toolchain"
]
found = []
for base in guesses:
for root, dirs, files in os.walk(base):
if "stdint.h" in files:
found.append(root)
return found
def analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs):
optional_printf(PRINT_STATUS, "Starting analysis of typedefs and structs across files...")
index = clang.cindex.Index.create()
args = [f"-I{inc}" for inc in include_dirs]
define_args = [f"-D{d}" for d in global_defs]
extra_std_include_dirs = try_guess_std_include()
args = [f"-I{inc}" for inc in include_dirs] + extra_std_include_dirs + define_args
unique_typedefs_raw = {}
unique_structs_raw = {}
@@ -452,7 +478,6 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
raw_name = node.spelling
normalized_name = normalize_type_name(raw_name)
# struct_name всегда с префиксом
if node.spelling and "unnamed" not in normalized_name:
struct_name = f"{prefix}{normalized_name}"
@@ -545,7 +570,7 @@ def read_vars_from_xml(xml_path):
'shortname': var_elem.findtext('shortname', name),
'pt_type': var_elem.findtext('pt_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'),
'file': var_elem.findtext('file', ''),
'extern': get_bool('extern'),
@@ -608,7 +633,7 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
'shortname': info.get('shortname', name),
'pt_type': info.get('pt_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'),
'file': info.get('file', ''),
'extern': info.get('extern', False),
@@ -627,7 +652,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, "pt_type").text = info.get('pt_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')
rel_file = make_relative_if_possible(info.get('file', ''), proj_path).replace("\\", "/")
@@ -855,10 +880,10 @@ Usage example:
print(f"Error: Makefile path '{makefile_path}' does not exist.")
sys.exit(1)
c_files, h_files, include_dirs = parse_makefile(makefile_path, proj_path)
c_files, h_files, include_dirs, global_defs = parse_project(makefile_path, proj_path)
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs)
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs)
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs, global_defs)
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs)
vars = dict(sorted(vars.items()))
includes = get_sorted_headers(c_files, includes, include_dirs)
@@ -898,10 +923,10 @@ def run_scan(proj_path, makefile_path, output_xml, verbose=2):
if not os.path.isfile(makefile_path):
raise FileNotFoundError(f"Makefile path '{makefile_path}' does not exist.")
c_files, h_files, include_dirs = parse_makefile(makefile_path, proj_path)
c_files, h_files, include_dirs, global_defs = parse_project(makefile_path, proj_path)
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs)
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs)
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs, global_defs)
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs)
vars = dict(sorted(vars.items()))
includes = get_sorted_headers(c_files, includes, include_dirs)

View File

@@ -0,0 +1,504 @@
"""
LowLevelSelectorWidget (refactored)
-----------------------------------
Версия, использующая VariableTableWidget вместо самодельной таблицы selected_vars_table.
Ключевые изменения:
* Вместо QTableWidget с 6 колонками теперь встраивается VariableTableWidget (8 колонок: №, En, Name, Origin Type, Base Type, IQ Type, Return Type, Short Name).
* Логика sync <-> self._all_available_vars перенесена в _on_var_table_changed() и _pull_from_var_table().
* Поддержка политики хранения типов:
- ptr_type: строковое имя (без префикса `pt_`).
- ptr_type_enum: числовой индекс (см. PT_ENUM_ORDER).
- Для совместимости с VariableTableWidget: поле `pt_type` = 'pt_<name>'.
- IQ / Return: аналогично (`iq_type` / `iq_type_enum`, `return_type` / `return_type_enum`).
* Функции получения выбранных переменных теперь читают данные из VariableTableWidget.
* Убраны неиспользуемые методы, связанные с прежней таблицей (комбо‑боксы и т.п.).
Как интегрировать:
1. Поместите этот файл рядом с module VariableTableWidget (см. импорт ниже). Если класс VariableTableWidget находится в том же файле — удалите строку импорта и используйте напрямую.
2. Убедитесь, что VariablesXML предоставляет методы get_all_vars_data() (list[dict]) и, при наличии, get_struct_map() -> dict[type_name -> dict[field_name -> field_type]]. Если такого метода нет, передаём пустой {} и автодополнение по структурам будет недоступно.
3. Отметьте переменные в VariableSelectorDialog (как и раньше) — он обновит self._all_available_vars. После закрытия диалога вызывается self._populate_var_table().
4. Для чтения выбранных переменных используйте get_selected_variables_and_addresses(); она вернёт список словарей в унифицированном формате.
Примечание о совместимости: VariableTableWidget работает с ключами `pt_type`, `iq_type`, `return_type` (строки с префиксами). Мы поддерживаем дублирование этих полей с «новыми» полями без префикса и enumзначениями.
"""
from __future__ import annotations
import sys
import re
import datetime
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Tuple, Any
from PySide2 import QtCore, QtGui
from PySide2.QtWidgets import (
QWidget, QVBoxLayout, QPushButton, QLabel, QHBoxLayout, QFileDialog, QMessageBox,
QMainWindow, QApplication, QSizePolicy, QSpinBox, QGroupBox, QSplitter, QFormLayout
)
# Локальные импорты
from path_hints import PathHints
from generate_debug_vars import choose_type_map, type_map
from var_selector_window import VariableSelectorDialog
from allvars_xml_parser import VariablesXML
# Импортируем готовую таблицу
# ЗАМЕТКА: замените на реальное имя файла/модуля, если отличается.
from var_table import VariableTableWidget, rows as VT_ROWS # noqa: F401
# ------------------------------------------------------------ Enumerations --
# Порядок фиксируем на основании предыдущей версии. При необходимости расширьте.
PT_ENUM_ORDER = [
'unknown','int8','int16','int32','int64',
'uint8','uint16','uint32','uint64','float',
'struct','union'
]
IQ_ENUM_ORDER = [
'iq_none','iq','iq1','iq2','iq3','iq4','iq5','iq6',
'iq7','iq8','iq9','iq10','iq11','iq12','iq13','iq14',
'iq15','iq16','iq17','iq18','iq19','iq20','iq21','iq22',
'iq23','iq24','iq25','iq26','iq27','iq28','iq29','iq30'
]
PT_ENUM_VALUE: Dict[str, int] = {name: idx for idx, name in enumerate(PT_ENUM_ORDER)}
IQ_ENUM_VALUE: Dict[str, int] = {name: idx for idx, name in enumerate(IQ_ENUM_ORDER)}
PT_ENUM_NAME_FROM_VAL: Dict[int, str] = {v: k for k, v in PT_ENUM_VALUE.items()}
IQ_ENUM_NAME_FROM_VAL: Dict[int, str] = {v: k for k, v in IQ_ENUM_VALUE.items()}
# ------------------------------------------- Address / validation helpers --
HEX_ADDR_MASK = QtCore.QRegExp(r"0x[0-9A-Fa-f]{0,6}")
class HexAddrValidator(QtGui.QRegExpValidator):
def __init__(self, parent=None):
super().__init__(HEX_ADDR_MASK, parent)
@staticmethod
def normalize(text: str) -> str:
if not text:
return '0x000000'
try:
val = int(text,16)
except ValueError:
return '0x000000'
return f"0x{val & 0xFFFFFF:06X}"
class LowLevelSelectorWidget(QWidget):
variablePrepared = QtCore.Signal(dict)
xmlLoaded = QtCore.Signal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('LowLevel Variable Selector')
self._xml: Optional[VariablesXML] = None
self._paths: List[str] = []
self._path_info: Dict[str, Tuple[int, str]] = {}
self._addr_index: Dict[int, Optional[str]] = {}
self._hints = PathHints()
self._all_available_vars: List[Dict[str, Any]] = []
self.dt = None
self.flat_vars = None
# --- NEW ---
self.btn_read_once = QPushButton("Read Once")
self.btn_start_polling = QPushButton("Start Polling")
self.spin_interval = QSpinBox()
self.spin_interval.setRange(50, 10000)
self.spin_interval.setValue(500)
self.spin_interval.setSuffix(" ms")
self._build_ui()
self._connect()
def _build_ui(self):
tab = QWidget()
main_layout = QVBoxLayout(tab)
# --- Variable Selector ---
g_selector = QGroupBox("Variable Selector")
selector_layout = QVBoxLayout(g_selector)
form_selector = QFormLayout()
# --- XML File chooser ---
file_layout = QHBoxLayout()
self.btn_load = QPushButton('Load XML...')
self.lbl_file = QLabel('<no file>')
self.lbl_file.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
file_layout.addWidget(self.btn_load)
file_layout.addWidget(self.lbl_file, 1)
form_selector.addRow("XML File:", file_layout)
# --- Interval SpinBox ---
self.spin_interval = QSpinBox()
self.spin_interval.setRange(50, 10000)
self.spin_interval.setValue(500)
self.spin_interval.setSuffix(" ms")
form_selector.addRow("Interval:", self.spin_interval)
selector_layout.addLayout(form_selector)
# --- Buttons ---
self.btn_read_once = QPushButton("Read Once")
self.btn_start_polling = QPushButton("Start Polling")
btn_layout = QHBoxLayout()
btn_layout.addWidget(self.btn_read_once)
btn_layout.addWidget(self.btn_start_polling)
selector_layout.addLayout(btn_layout)
# --- Table ---
g_table = QGroupBox("Table")
table_layout = QVBoxLayout(g_table)
self.btn_open_var_selector = QPushButton("Выбрать переменные...")
table_layout.addWidget(self.btn_open_var_selector)
self.var_table = VariableTableWidget(self, show_value_instead_of_shortname=1)
self.var_table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
table_layout.addWidget(self.var_table)
# --- Timestamp (moved here) ---
self.lbl_timestamp = QLabel('Timestamp: -')
table_layout.addWidget(self.lbl_timestamp)
# --- Splitter (Selector + Table) ---
v_split = QSplitter(QtCore.Qt.Vertical)
v_split.addWidget(g_selector)
v_split.addWidget(g_table)
v_split.setStretchFactor(0, 1)
v_split.setStretchFactor(1, 3)
main_layout.addWidget(v_split)
self.setLayout(main_layout)
def _connect(self):
self.btn_load.clicked.connect(self._on_load_xml)
self.btn_open_var_selector.clicked.connect(self._on_open_variable_selector)
# ------------------------------------------------------ XML loading ----
def _on_load_xml(self):
path, _ = QFileDialog.getOpenFileName(
self, 'Select variables XML', '', 'XML Files (*.xml);;All Files (*)')
if not path:
return
try:
self._xml = VariablesXML(path)
self.flat_vars = {v['name']: v for v in self._xml.flattened()}
# Получаем сырые данные по переменным
self._all_available_vars = self._xml.get_all_vars_data()
except Exception as e:
QMessageBox.critical(self, 'Parse error', f'Ошибка парсинга:\n{e}')
return
self.lbl_file.setText(path)
self.lbl_timestamp.setText(f'Timestamp: {self._xml.timestamp or "-"}')
self._populate_internal_maps_from_all_vars()
self._apply_timestamp_to_date()
self.xmlLoaded.emit(path)
self._log(f'Loaded {path}, variables={len(self._all_available_vars)})')
def _apply_timestamp_to_date(self):
if not (self._xml and self._xml.timestamp):
return
try:
# Пример: "Sat Jul 19 15:27:59 2025"
self.dt = datetime.datetime.strptime(self._xml.timestamp, "%a %b %d %H:%M:%S %Y")
except Exception as e:
print(f"Ошибка разбора timestamp '{self._xml.timestamp}': {e}")
# ------------------------------------------ Variable selector dialog ----
def _on_open_variable_selector(self):
if not self._xml:
QMessageBox.warning(self, 'No XML', 'Сначала загрузите XML файл.')
return
dialog = VariableSelectorDialog(
table=None, # не используем встроенную таблицу
all_vars=self._all_available_vars,
structs=None, # при необходимости подайте реальные структуры из XML
typedefs=None, # ...
xml_path=None, # по запросу пользователя xml_path = None
parent=self
)
if dialog.exec_() == dialog.Accepted:
# Диалог обновил self._all_available_vars напрямую
self._populate_internal_maps_from_all_vars()
self._populate_var_table()
self._log("Variable selection updated.")
# ----------------------------------------------------- Populate table ----
def _populate_var_table(self):
"""Отобразить переменные (show_var == 'true') в VariableTableWidget."""
if not self._all_available_vars:
self.var_table.setRowCount(0)
return
# Нормализуем все записи перед передачей таблице.
for var in self._all_available_vars:
self._normalize_var_record(var)
# Карта структур для автодополнения (если VariablesXML предоставляет)
try:
structs_map = self._xml.get_struct_map() if self._xml else {}
except AttributeError:
structs_map = {}
# populate() принимает: (vars_list, structs, on_change_callback)
self.var_table.populate(self._all_available_vars, structs_map, self._on_var_table_changed)
# -------------------------------------------------- Table change slot ----
def _on_var_table_changed(self, *args, **kwargs): # noqa: D401 (неиспользуемые)
"""Вызывается при любом изменении в VariableTableWidget.
Читаем данные из таблицы, мержим в self._all_available_vars (по имени),
пересобираем служебные индексы.
"""
updated = self.var_table.read_data() # list[dict]
# создаём индекс по имени из master списка
idx_by_name = {v.get('name'): v for v in self._all_available_vars if v.get('name')}
for rec in updated:
nm = rec.get('name')
if not nm:
continue
dst = idx_by_name.get(nm)
if not dst:
# Новая запись; добавляем базовые поля
dst = {
'name': nm,
'address': 0,
'file': '', 'extern': 'false', 'static': 'false',
}
self._all_available_vars.append(dst)
idx_by_name[nm] = dst
# перенести видимые поля
dst['show_var'] = str(bool(rec.get('show_var'))).lower()
dst['enable'] = str(bool(rec.get('enable'))).lower()
dst['shortname']= rec.get('shortname', nm)
dst['type'] = rec.get('type', dst.get('type',''))
# типы (строковые, с префиксами) -> нормализуем
pt_pref = rec.get('pt_type','pt_unknown') # 'pt_int16'
iq_pref = rec.get('iq_type','t_iq_none') # 't_iq10' etc.
rt_pref = rec.get('return_type', iq_pref)
self._assign_types_from_prefixed(dst, pt_pref, iq_pref, rt_pref)
# Пересобрать карты путей/адресов
self._populate_internal_maps_from_all_vars()
# --------------------------------- Normalize var record (public-ish) ----
def _normalize_var_record(self, var: Dict[str, Any]):
"""Унифицирует записи переменной.
Требуемые поля после нормализации:
var['ptr_type'] -> str (напр. 'int16')
var['ptr_type_enum'] -> int
var['iq_type'] -> str ('iq10')
var['iq_type_enum'] -> int
var['return_type'] -> str ('iq10')
var['return_type_enum']-> int
var['pt_type'] -> 'pt_<ptr_type>' (для совместимости с VariableTableWidget)
var['return_type_pref']-> 't_<return_type>' (см. ниже) # не обяз.
Дополнительно корректируем show_var/enable и адрес.
"""
# --- show_var / enable
var['show_var'] = str(var.get('show_var', 'false')).lower()
var['enable'] = str(var.get('enable', 'true')).lower()
# --- address
if not var.get('address'):
var_name = var.get('name')
# Ищем в self.flat_vars
if hasattr(self, 'flat_vars') and isinstance(self.flat_vars, dict):
flat_entry = self.flat_vars.get(var_name)
if flat_entry and 'address' in flat_entry:
var['address'] = flat_entry['address']
else:
var['address'] = 0
else:
var['address'] = 0
else:
# Нормализация адреса (если строка типа '0x1234')
try:
if isinstance(var['address'], str):
var['address'] = int(var['address'], 16)
except ValueError:
var['address'] = 0
# --- ptr_type (строка)
name = None
if isinstance(var.get('ptr_type'), str):
name = var['ptr_type']
elif isinstance(var.get('ptr_type_name'), str):
name = var['ptr_type_name']
elif isinstance(var.get('pt_type'), str) and 'pt_' in var.get('pt_type'):
name = var['pt_type'].replace('pt_','')
elif isinstance(var.get('ptr_type'), int):
name = PT_ENUM_NAME_FROM_VAL.get(var['ptr_type'], 'unknown')
else:
name = self._map_type_to_ptr_enum(var.get('type'))
val = PT_ENUM_VALUE.get(name, 0)
var['ptr_type'] = name
var['ptr_type_enum'] = val
var['pt_type'] = f'pt_{name}'
# ---------------------------------------------- prefixed assign helper ----
def _assign_types_from_prefixed(self, dst: Dict[str, Any], pt_pref: str, iq_pref: str, rt_pref: str):
"""Парсит строки вида 'pt_int16', 't_iq10' и записывает нормализованные поля."""
pt_name = pt_pref.replace('pt_','') if pt_pref else 'unknown'
iq_name = iq_pref
if iq_name.startswith('t_'):
iq_name = iq_name[2:]
rt_name = rt_pref
if rt_name.startswith('t_'):
rt_name = rt_name[2:]
dst['ptr_type'] = pt_name
dst['ptr_type_enum'] = PT_ENUM_VALUE.get(pt_name, 0)
dst['pt_type'] = f'pt_{pt_name}'
dst['iq_type'] = iq_name
dst['iq_type_enum'] = IQ_ENUM_VALUE.get(iq_name, 0)
dst['return_type'] = rt_name
dst['return_type_enum'] = IQ_ENUM_VALUE.get(rt_name, dst['iq_type_enum'])
dst['return_type_pref'] = f't_{rt_name}'
# ------------------------------------------ Populate internal maps ----
def _populate_internal_maps_from_all_vars(self):
self._path_info.clear()
self._addr_index.clear()
self._paths.clear()
for var in self._all_available_vars:
nm = var.get('name')
tp = var.get('type')
addr = var.get('address')
if nm is None:
continue
if addr is None:
addr = 0
var['address'] = 0
self._paths.append(nm)
self._path_info[nm] = (addr, tp)
if addr in self._addr_index:
self._addr_index[addr] = None
else:
self._addr_index[addr] = nm
# Обновим подсказки
self._hints.set_paths([(p, self._path_info[p][1]) for p in self._paths])
# -------------------------------------------------- Public helpers ----
def get_selected_variables_and_addresses(self) -> List[Dict[str, Any]]:
"""Возвращает список выбранных переменных (show_var == true) с адресами и типами.
Чтение из VariableTableWidget + подстановка адресов/прочих служебных полей
из master списка.
"""
tbl_data = self.var_table.read_data() # список dict'ов в формате VariableTableWidget
idx_by_name = {v.get('name'): v for v in self._all_available_vars if v.get('name')}
out: List[Dict[str, Any]] = []
for rec in tbl_data:
nm = rec.get('name')
if not nm:
continue
src = idx_by_name.get(nm, {})
addr = src.get('address')
if addr is None or addr == '' or addr == 0:
src['address'] = self.flat_vars.get(nm, {}).get('address', 0)
else:
# если это строка "0x..." — конвертируем в int
if isinstance(addr, str) and addr.startswith('0x'):
try:
src['address'] = int(addr, 16)
except ValueError:
src['address'] = self.flat_vars.get(nm, {}).get('address', 0)
type_str = src.get('type', rec.get('type','N/A'))
# нормализация типов
tmp = dict(src) # copy src to preserve extra fields (file, extern, ...)
self._assign_types_from_prefixed(tmp,
rec.get('pt_type','pt_unknown'),
rec.get('iq_type','t_iq_none'),
rec.get('return_type', rec.get('iq_type','t_iq_none')))
tmp['show_var'] = str(bool(rec.get('show_var'))).lower()
tmp['enable'] = str(bool(rec.get('enable'))).lower()
tmp['name'] = nm
tmp['address'] = addr
tmp['type'] = type_str
out.append(tmp)
return out
def get_datetime(self):
return self.dt
def set_variable_value(self, var_name: str, value: Any):
# 1. Обновляем master-список переменных
found = None
for var in self._all_available_vars:
if var.get('name') == var_name:
var['value'] = value
found = var
break
if not found:
# Если переменной нет в списке, можно либо проигнорировать, либо добавить.
return False
# 2. Обновляем отображение в таблице
#self.var_table.populate(self._all_available_vars, {}, self._on_var_table_changed)
return True
# --------------- Address mapping / type mapping helpers ---------------
def _map_type_to_ptr_enum(self, type_str: Optional[str]) -> str:
if not type_str:
return 'unknown'
low = type_str.lower()
token = low.replace('*',' ').replace('[',' ')
return type_map.get(token, 'unknown').replace('pt_','')
# ----------------------------------------------------------- Logging --
def _log(self, msg: str):
print(f"[LowLevelSelectorWidget Log] {msg}")
# ---------------------------------------------------------------------------
# Тест‑прогоночка (ручной) --------------------------------------------------
# Запускать только вручную: python LowLevelSelectorWidget_refactored.py <xml>
# ---------------------------------------------------------------------------
# ----------------------------------------------------------- Demo window --
class _DemoWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('LowLevel Selector Demo')
self.selector = LowLevelSelectorWidget(self)
self.setCentralWidget(self.selector)
self.selector.variablePrepared.connect(self.on_var)
def on_var(self, data: dict):
print('Variable prepared ->', data)
def closeEvent(self, ev):
self.setCentralWidget(None)
super().closeEvent(ev)
# ----------------------------------------------------------------- main ---
if __name__ == '__main__':
app = QApplication(sys.argv)
w = _DemoWindow()
w.resize(640, 520)
w.show()
sys.exit(app.exec_())

1279
Src/tms_debugvar_term.py Normal file
View File

@@ -0,0 +1,1279 @@
from PySide2 import QtCore, QtWidgets, QtSerialPort, QtGui
from tms_debugvar_lowlevel import LowLevelSelectorWidget
import datetime
import time
import os
from csv_logger import CsvLogger
import auto_updater
# ------------------------------- Константы протокола ------------------------
WATCH_SERVICE_BIT = 0x8000
DEBUG_OK = 0 # ожидаемый код успешного чтения
SIGN_BIT_MASK = 0x80
FRAC_MASK_FULL = 0x7F # если используем 7 бит дробной части
# --- Debug status codes (из прошивки) ---
DEBUG_OK = 0x00
DEBUG_ERR = 0x80 # общий флаг ошибки (старший бит)
DEBUG_ERR_VAR_NUMB = DEBUG_ERR | (1 << 0)
DEBUG_ERR_INVALID_VAR = DEBUG_ERR | (1 << 1)
DEBUG_ERR_ADDR = DEBUG_ERR | (1 << 2)
DEBUG_ERR_ADDR_ALIGN = DEBUG_ERR | (1 << 3)
DEBUG_ERR_INTERNAL = DEBUG_ERR | (1 << 4)
DEBUG_ERR_DATATIME = DEBUG_ERR | (1 << 5)
DEBUG_ERR_RS = DEBUG_ERR | (1 << 5)
# для декодирования по битам
_DEBUG_ERR_BITS = (
(1 << 0, "Invalid Variable Index"),
(1 << 1, "Invalid Variable"),
(1 << 2, "Invalid Address"),
(1 << 3, "Invalid Address Align"),
(1 << 4, "Internal Code Error"),
(1 << 5, "Invalid Data or Time"),
(1 << 6, "Error with RS"),
)
# ---------------------------------------------------------------- CRC util ---
def crc16_ibm(data: bytes, *, init=0xFFFF) -> int:
"""CRC16-IBM (aka CRC-16/ANSI, polynomial 0xA001 reflected)."""
crc = init
for b in data:
crc ^= b
for _ in range(8):
if crc & 1:
crc = (crc >> 1) ^ 0xA001
else:
crc >>= 1
return crc & 0xFFFF
def is_frozen():
# Для Nuitka --onefile
return getattr(sys, 'frozen', False)
def get_base_path():
if is_frozen():
# В Nuitka onefile распаковывается в папку с самим exe во временной директории
return os.path.dirname(sys.executable)
else:
# Режим разработки
return os.path.dirname(os.path.abspath(__file__))
def _decode_debug_status(status: int) -> str:
"""Преобразует код статуса прошивки в строку.
Возвращает 'OK' или перечисление битов через '|'.
Не зависит от того, WATCH или LowLevel.
"""
if status == DEBUG_OK:
return "OK"
parts = []
if status & DEBUG_ERR:
for mask, name in _DEBUG_ERR_BITS:
if status & mask:
parts.append(name)
if not parts: # старший бит есть, но ни один из известных младших не выставлен
parts.append("ERR")
else:
# Неожиданно: статус !=0, но бит DEBUG_ERR не стоит
parts.append(f"0x{status:02X}")
return "|".join(parts)
class Spoiler(QtWidgets.QWidget):
def __init__(self, title="", animationDuration=300, parent=None):
super().__init__(parent)
self._animationDuration = animationDuration
self.state = False
# --- Toggle button ---
self.toggleButton = QtWidgets.QToolButton(self)
self.toggleButton.setStyleSheet("QToolButton { border: none; }")
self.toggleButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.toggleButton.setArrowType(QtCore.Qt.RightArrow)
self.toggleButton.setText(title)
self.toggleButton.setCheckable(True)
# --- Header line ---
self.headerLine = QtWidgets.QFrame(self)
self.headerLine.setFrameShape(QtWidgets.QFrame.HLine)
self.headerLine.setFrameShadow(QtWidgets.QFrame.Sunken)
# --- Content area ---
self.contentArea = QtWidgets.QScrollArea(self)
self.contentArea.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.contentArea.setFrameShape(QtWidgets.QFrame.NoFrame)
self.contentArea.setWidgetResizable(True)
self._contentWidget = QtWidgets.QWidget()
self.contentArea.setWidget(self._contentWidget)
self.contentArea.setMaximumHeight(0)
# --- Анимация только по контенту ---
self._ani_content = QtCore.QPropertyAnimation(self.contentArea, b"maximumHeight")
self._ani_content.setDuration(animationDuration)
self._ani_content.setEasingCurve(QtCore.QEasingCurve.InOutCubic)
# --- Layout ---
self.mainLayout = QtWidgets.QGridLayout(self)
self.mainLayout.setVerticalSpacing(0)
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.mainLayout.addWidget(self.toggleButton, 0, 0, 1, 1)
self.mainLayout.addWidget(self.headerLine, 0, 1, 1, 1)
self.mainLayout.addWidget(self.contentArea, 1, 0, 1, 2)
# --- Signals ---
self.toggleButton.clicked.connect(self._on_toggled)
def setContentLayout(self, contentLayout):
old = self._contentWidget.layout()
if old:
QtWidgets.QWidget().setLayout(old)
self._contentWidget.setLayout(contentLayout)
def getState(self):
return self.state
def _on_toggled(self, checked: bool):
self.state = checked
self.toggleButton.setArrowType(QtCore.Qt.DownArrow if checked else QtCore.Qt.RightArrow)
contentHeight = self._contentWidget.sizeHint().height()
self._ani_content.stop()
self._ani_content.setStartValue(self.contentArea.maximumHeight())
self._ani_content.setEndValue(contentHeight if checked else 0)
self._ani_content.start()
# --------------------------- DebugTerminalWidget ---------------------------
class DebugTerminalWidget(QtWidgets.QWidget):
# Существующие сигналы (Watch)
nameRead = QtCore.Signal(int, int, int, str)
valueRead = QtCore.Signal(int, int, int, int, float)
valuesRead = QtCore.Signal(int, int, list, list, list, list)
# Новые сигналы (LowLevel)
llValueRead = QtCore.Signal(int, int, int, int, float) # addr, status, rettype_raw, raw16_signed, scaled
portOpened = QtCore.Signal(str)
portClosed = QtCore.Signal(str)
txBytes = QtCore.Signal(bytes)
rxBytes = QtCore.Signal(bytes)
def __init__(self, parent=None, *,
start_byte=0x0A,
cmd_byte=0x46,
cmd_lowlevel=0x47,
iq_scaling=None,
read_timeout_ms=250,
auto_crc_check=True,
drop_if_busy=False,
replace_if_busy=True):
super().__init__(parent)
self.device_addr = start_byte
self.cmd_byte = cmd_byte
self.cmd_lowlevel = cmd_lowlevel
self.read_timeout_ms = read_timeout_ms
self.auto_crc_check = auto_crc_check
self._drop_if_busy = drop_if_busy
self._replace_if_busy = replace_if_busy
self._last_txn_timestamp = 0
self._ll_polling_active = False
if iq_scaling is None:
iq_scaling = {n: float(1 << n) for n in range(31)}
iq_scaling[0] = 1.0
self.iq_scaling = iq_scaling
# Serial
self.serial = QtSerialPort.QSerialPort(self)
self.serial.setBaudRate(115200)
self.serial.readyRead.connect(self._on_ready_read)
self.serial.errorOccurred.connect(self._on_serial_error)
# State
self._rx_buf = bytearray()
self._busy = False
self._pending_cmd = None # (frame, meta)
self._txn_meta = None # {'service':bool,'index':int,'varqnt':int,'chain':...,'lowlevel':bool}
self._txn_timer = QtCore.QTimer(self)
self._txn_timer.setSingleShot(True)
self._txn_timer.timeout.connect(self._on_txn_timeout)
# Watch polling
self._poll_timer = QtCore.QTimer(self)
self._poll_timer.timeout.connect(self._on_poll_timeout)
self._polling = False
# LowLevel polling
self._ll_poll_timer = QtCore.QTimer(self)
self._ll_poll_timer.timeout.connect(self._on_ll_poll_timeout)
self._ll_polling = False
self._ll_polling_variables = [] # List of selected variables for polling
self._ll_current_poll_index = -1 # Index of the variable currently being polled in the _ll_polling_variables list
self._ll_current_var_info = []
self.csv_logger = CsvLogger()
self._csv_logging_active = False
self._last_csv_timestamp = 0 # Для отслеживания времени записи
# Кэш: index -> (status, iq, name, is_signed, frac_bits)
self._name_cache = {}
# Очередь service индексов
self._service_queue = []
self._pending_data_after_services = None # (base, count)
self._build_ui()
self._connect_ui()
self.set_available_ports()
# ------------------------------ UI ----------------------------------
def _build_ui(self):
layout = QtWidgets.QVBoxLayout(self)
# --- Serial group ---
g_serial = QtWidgets.QGroupBox("Serial Port")
hs = QtWidgets.QHBoxLayout(g_serial)
self.cmb_port = QtWidgets.QComboBox()
self.btn_refresh = QtWidgets.QPushButton("Refresh")
self.cmb_baud = QtWidgets.QComboBox()
self.cmb_baud.addItems(["9600","19200","38400","57600","115200","230400"])
self.cmb_baud.setCurrentText("115200")
self.btn_open = QtWidgets.QPushButton("Open")
hs.addWidget(QtWidgets.QLabel("Port:"))
hs.addWidget(self.cmb_port, 1)
hs.addWidget(self.btn_refresh)
hs.addSpacing(10)
hs.addWidget(QtWidgets.QLabel("Baud:"))
hs.addWidget(self.cmb_baud)
hs.addWidget(self.btn_open)
# --- TabWidget ---
self.tabs = QtWidgets.QTabWidget()
self._build_watch_tab()
self._build_lowlevel_tab() # <-- Вызываем новый метод
g_control = QtWidgets.QGroupBox("Control / Status")
control_layout = QtWidgets.QHBoxLayout(g_control) # Используем QHBoxLayout
# Форма для статусов слева
form_control = QtWidgets.QFormLayout()
self.lbl_status = QtWidgets.QLabel("Idle")
self.lbl_status.setStyleSheet("font-weight: bold; color: grey;")
form_control.addRow("Status:", self.lbl_status)
self.lbl_actual_interval = QtWidgets.QLabel("-")
form_control.addRow("Actual Interval:", self.lbl_actual_interval)
control_layout.addLayout(form_control, 1) # Растягиваем форму
# Галочка Raw справа
self.chk_raw = QtWidgets.QCheckBox("Raw (no IQ scaling)")
control_layout.addWidget(self.chk_raw)
# Создаем QGroupBox для группировки элементов управления CSV
self.csv_log_groupbox = QtWidgets.QGroupBox("CSV Logging")
csv_log_layout = QtWidgets.QVBoxLayout(self.csv_log_groupbox) # Передаем groupbox как родительский layout
# Элементы управления CSV
h_file_select = QtWidgets.QHBoxLayout()
self.btn_select_csv_file = QtWidgets.QPushButton("Выбрать файл CSV")
# Убедитесь, что self.csv_logger инициализирован где-то до этого момента
self.lbl_csv_filename = QtWidgets.QLabel(self.csv_logger.filename)
h_file_select.addWidget(self.btn_select_csv_file)
h_file_select.addWidget(self.lbl_csv_filename, 1)
csv_log_layout.addLayout(h_file_select)
h_control_buttons = QtWidgets.QHBoxLayout()
self.btn_start_csv_logging = QtWidgets.QPushButton("Начать запись в CSV")
self.btn_stop_csv_logging = QtWidgets.QPushButton("Остановить запись в CSV")
self.btn_save_csv_data = QtWidgets.QPushButton("Сохранить данные в CSV")
self.btn_stop_csv_logging.setEnabled(False) # По умолчанию остановлена
h_control_buttons.addWidget(self.btn_start_csv_logging)
h_control_buttons.addWidget(self.btn_stop_csv_logging)
h_control_buttons.addWidget(self.btn_save_csv_data)
csv_log_layout.addLayout(h_control_buttons)
# Добавляем QGroupBox в основной лейаут
# --- UART Log ---
self.log_spoiler = Spoiler("UART Log", animationDuration=300, parent=self)
self.log_spoiler.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Minimum)
log_layout = QtWidgets.QVBoxLayout()
self.txt_log = QtWidgets.QTextEdit(); self.txt_log.setReadOnly(True)
self.txt_log.setFontFamily("Courier")
log_layout.addWidget(self.txt_log)
self.log_spoiler.setContentLayout(log_layout)
layout.addWidget(g_serial)
layout.addWidget(self.tabs, 1)
layout.addWidget(g_control)
layout.addWidget(self.csv_log_groupbox)
layout.addWidget(self.log_spoiler)
layout.setStretch(layout.indexOf(g_serial), 0)
layout.setStretch(layout.indexOf(self.tabs), 1)
def _build_watch_tab(self):
tab = QtWidgets.QWidget()
main_layout = QtWidgets.QVBoxLayout(tab)
# --- Variable Selector ---
g_selector = QtWidgets.QGroupBox("Variable Selector")
selector_layout = QtWidgets.QVBoxLayout(g_selector)
form_selector = QtWidgets.QFormLayout()
h_layout = QtWidgets.QHBoxLayout()
self.spin_index = QtWidgets.QSpinBox()
self.spin_index.setRange(0, 0x7FFF)
self.spin_index.setAccelerated(True)
self.chk_hex_index = QtWidgets.QCheckBox("Hex")
self.spin_count = QtWidgets.QSpinBox()
self.spin_count.setRange(1, 255)
self.spin_count.setValue(1)
# Первая группа: Base Index + spin + checkbox
base_index_layout = QtWidgets.QHBoxLayout()
base_index_label = QtWidgets.QLabel("Base Index")
base_index_layout.addWidget(base_index_label)
base_index_layout.addWidget(self.spin_index)
base_index_layout.addWidget(self.chk_hex_index)
base_index_layout.setSpacing(5)
# Вторая группа: spin_count + метка справа
count_layout = QtWidgets.QHBoxLayout()
count_layout.setSpacing(2) # минимальный отступ
count_layout.addWidget(self.spin_count)
count_label = QtWidgets.QLabel("Cnt")
count_layout.addWidget(count_label)
# Добавляем обе группы в общий горизонтальный лэйаут
h_layout.addLayout(base_index_layout)
h_layout.addSpacing(20)
h_layout.addLayout(count_layout)
form_selector.addRow(h_layout)
self.spin_interval = QtWidgets.QSpinBox()
self.spin_interval.setRange(50, 10000)
self.spin_interval.setValue(500)
self.spin_interval.setSuffix(" ms")
form_selector.addRow("Interval:", self.spin_interval)
selector_layout.addLayout(form_selector)
btn_layout = QtWidgets.QHBoxLayout()
self.btn_update_service = QtWidgets.QPushButton("Update Service")
self.btn_read_values = QtWidgets.QPushButton("Read Value(s)")
self.btn_poll = QtWidgets.QPushButton("Start Polling")
btn_layout.addWidget(self.btn_update_service)
btn_layout.addWidget(self.btn_read_values)
btn_layout.addWidget(self.btn_poll)
selector_layout.addLayout(btn_layout)
# --- Table ---
g_table = QtWidgets.QGroupBox("Table")
table_layout = QtWidgets.QVBoxLayout(g_table)
self.tbl_values = QtWidgets.QTableWidget(0, 5)
self.tbl_values.setHorizontalHeaderLabels(["Index", "Name", "IQ", "Raw", "Scaled"])
hh = self.tbl_values.horizontalHeader()
for i in range(4):
hh.setSectionResizeMode(i, QtWidgets.QHeaderView.ResizeToContents)
hh.setSectionResizeMode(4, QtWidgets.QHeaderView.Stretch)
self.tbl_values.verticalHeader().setVisible(False)
table_layout.addWidget(self.tbl_values)
# --- Вертикальный сплиттер ---
v_split = QtWidgets.QSplitter(QtCore.Qt.Vertical)
v_split.addWidget(g_selector)
v_split.addWidget(g_table)
v_split.setStretchFactor(0, 1)
v_split.setStretchFactor(1, 3)
v_split.setStretchFactor(2, 1)
main_layout.addWidget(v_split)
self.tabs.addTab(tab, "Watch")
table_layout.addWidget(self.tbl_values)
def _build_lowlevel_tab(self):
# создаём виджет LowLevelSelectorWidget
self.ll_selector = LowLevelSelectorWidget()
# добавляем как корневой виджет вкладки
self.tabs.addTab(self.ll_selector, "LowLevel")
def _connect_ui(self):
# Watch
self.btn_refresh.clicked.connect(self.set_available_ports)
self.btn_open.clicked.connect(self._open_close_port)
self.btn_update_service.clicked.connect(self.request_service_update_for_table)
self.btn_read_values.clicked.connect(self.request_values)
self.btn_poll.clicked.connect(self._toggle_polling)
self.chk_hex_index.stateChanged.connect(self._toggle_index_base)
# LowLevel (новые и переделанные)
self.ll_selector.xmlLoaded.connect(lambda p: self._log(f"[LL] XML loaded: {p}"))
self.ll_selector.btn_read_once.clicked.connect(self._start_ll_cycle)
self.ll_selector.btn_start_polling.clicked.connect(self._toggle_ll_polling)
# --- CSV Logging ---
self.btn_select_csv_file.clicked.connect(self._select_csv_file)
self.btn_start_csv_logging.clicked.connect(self._start_csv_logging)
self.btn_stop_csv_logging.clicked.connect(self._stop_csv_logging)
self.btn_save_csv_data.clicked.connect(self._save_csv_data)
def set_status(self, text: str, mode: str = "idle"):
colors = {
"idle": "gray",
"service": "blue",
"values": "green",
"error": "red"
}
color = colors.get(mode.lower(), "black")
self.lbl_status.setText(text)
self.lbl_status.setStyleSheet(f"font-weight: bold; color: {color};")
# ----------------------------- SERIAL MGMT ----------------------------
def set_available_ports(self):
cur = self.cmb_port.currentText()
self.cmb_port.blockSignals(True)
self.cmb_port.clear()
for info in QtSerialPort.QSerialPortInfo.availablePorts():
self.cmb_port.addItem(info.portName())
if cur:
ix = self.cmb_port.findText(cur)
if ix >= 0:
self.cmb_port.setCurrentIndex(ix)
self.cmb_port.blockSignals(False)
def _open_close_port(self):
if self.serial.isOpen():
name = self.serial.portName()
self.serial.close()
self.btn_open.setText("Open")
self._log(f"[PORT OK] Closed {name}")
self.portClosed.emit(name)
return
port = self.cmb_port.currentText()
if not port:
self._log("[ERR] No port selected")
return
self.serial.setPortName(port)
self.serial.setBaudRate(int(self.cmb_baud.currentText()))
if not self.serial.open(QtCore.QIODevice.ReadWrite):
self._log(f"[ERR] Open fail {port}: {self.serial.errorString()}")
return
self.btn_open.setText("Close")
self._log(f"[PORT OK] Opened {port}")
self.portOpened.emit(port)
# ---------------------------- FRAME BUILD -----------------------------
def _build_request(self, index: int, *, service: bool, varqnt: int) -> bytes:
dbg = index & 0x7FFF
if service:
dbg |= WATCH_SERVICE_BIT
hi = (dbg >> 8) & 0xFF
lo = dbg & 0xFF
q = varqnt & 0xFF
payload = bytes([self.device_addr & 0xFF, self.cmd_byte & 0xFF, hi, lo, q])
crc = crc16_ibm(payload)
return payload + bytes([crc & 0xFF, (crc >> 8) & 0xFF])
def _build_lowlevel_request(self, var_info: dict) -> bytes:
# Формат: [adr][cmd_lowlevel][year_hi][year_lo][month][day][hour][minute][addr2][addr1][addr0][pt_type][iq_type][return_type]
# Пытаемся получить время из переданной информации
dt_info = self.ll_selector.get_datetime()
if dt_info:
# Используем время из var_info
year = dt_info.year
month = dt_info.month
day = dt_info.day
hour = dt_info.hour
minute = dt_info.minute
self._log("[LL] Using time from selector.")
else:
return
addr = var_info.get('address', 0)
addr2 = (addr >> 16) & 0xFF
addr1 = (addr >> 8) & 0xFF
addr0 = addr & 0xFF
# Ensure 'ptr_type' and 'iq_type' from var_info are integers (enum values)
# Use a fallback to 0 if they are not found or not integers
pt_type = var_info.get('ptr_type_enum', 0) & 0xFF
iq_type = var_info.get('iq_type_enum', 0) & 0xFF
ret_type = var_info.get('return_type_enum', 0) & 0xFF
frame_wo_crc = bytes([
self.device_addr & 0xFF, self.cmd_lowlevel & 0xFF,
(year >> 8) & 0xFF, year & 0xFF,
month & 0xFF, day & 0xFF, hour & 0xFF, minute & 0xFF,
addr2, addr1, addr0, pt_type, iq_type, ret_type
])
crc = crc16_ibm(frame_wo_crc)
return frame_wo_crc + bytes([crc & 0xFF, (crc >> 8) & 0xFF])
# ----------------------------- PUBLIC API -----------------------------
def request_service_single(self):
idx = int(self.spin_index.value())
self._enqueue_or_start(idx, service=True, varqnt=0)
def request_service_update_for_table(self):
"""
Очищает кеш имен/типов для всех видимых в таблице переменных
и инициирует их повторное чтение.
"""
indices_to_update = []
for row in range(self.tbl_values.rowCount()):
item = self.tbl_values.item(row, 0)
if item and item.text().isdigit():
indices_to_update.append(int(item.text()))
if not indices_to_update:
self._log("[SERVICE] No variables in table to update.")
return
self._log(f"[SERVICE] Queuing name/type update for {len(indices_to_update)} variables.")
# Очищаем кеш для этих индексов, чтобы принудительно их перечитать
for index in indices_to_update:
if index in self._name_cache:
del self._name_cache[index]
# Запускаем стандартный запрос значений. Он автоматически обработает
# отсутствующую сервисную информацию (имена/типы) перед запросом данных.
if not (self._polling or self._ll_polling):
self.request_values()
def request_values(self):
self._update_interval()
base = int(self.spin_index.value())
count = int(self.spin_count.value())
needed = []
for i in range(base, base+count):
if i not in self._name_cache:
needed.append(i)
if needed:
self._service_queue = needed[:]
self._pending_data_after_services = (base, count)
self._log(f"[AUTO] Need service for {len(needed)} indices: {needed}")
self.set_status("Read service...", "service")
self._kick_service_queue()
else:
self.set_status("Read values...", "values")
self._enqueue_or_start(base, service=False, varqnt=count)
def request_lowlevel_once(self):
"""Запрашивает чтение выбранной LowLevel переменной (однократно)."""
if not self.serial.isOpen():
self._log("[LL] Port is not open.")
return
if self._busy:
self._log("[LL] Busy, request dropped.")
return
# Если переменная не подготовлена, или нет актуальной информации
if not hasattr(self, '_ll_current_var_info') or not self._ll_current_var_info:
self._log("[LL] No variable prepared/selected for single read!")
return
frame = self._build_lowlevel_request(self._ll_current_var_info)
# --- НОВОЕ: Передаем ll_var_info в метаданные транзакции ---
meta = {'lowlevel': True, 'll_polling': False, 'll_var_info': self._ll_current_var_info}
self.set_status("Read lowlevel...", "values")
self._enqueue_raw(frame, meta)
# -------------------------- SERVICE QUEUE FLOW ------------------------
# ... (код без изменений)
def _kick_service_queue(self):
if self._busy:
return
if self._service_queue:
nxt = self._service_queue.pop(0)
self._enqueue_or_start(nxt, service=True, varqnt=0, queue_mode=True)
elif self._pending_data_after_services:
base, count = self._pending_data_after_services
self._pending_data_after_services = None
self._enqueue_or_start(base, service=False, varqnt=count)
# ------------------------ TRANSACTION SCHEDULER -----------------------
# ... (код без изменений)
def _enqueue_raw(self, frame: bytes, meta: dict):
# Добавляем ll_var_info, если это LL запрос
if meta.get('lowlevel', False) and 'll_var_info' not in meta:
# Это должно быть установлено вызывающим кодом, но для безопасности
# или если LL polling не передал var_info явно
meta['ll_var_info'] = self._ll_current_var_info # Используем last prepared var info for single shots
if self._busy:
# ... существующий код ...
if self._replace_if_busy:
self._pending_cmd = (frame, meta)
self._log("[LOCKSTEP] Busy -> replaced pending")
else:
self._log("[LOCKSTEP] Busy -> ignore")
return
self._start_txn(frame, meta)
def _enqueue_or_start(self, index, service: bool, varqnt: int, chain_after=None, queue_mode=False):
frame = self._build_request(index, service=service, varqnt=varqnt)
meta = {'service': service, 'index': index, 'varqnt': varqnt, 'chain': chain_after, 'queue_mode': queue_mode, 'lowlevel': False}
if self._busy:
if self._drop_if_busy and not self._replace_if_busy:
self._log("[LOCKSTEP] Busy -> drop")
return
if self._replace_if_busy:
self._pending_cmd = (frame, meta)
self._log("[LOCKSTEP] Busy -> replaced pending")
else:
self._log("[LOCKSTEP] Busy -> ignore")
return
self._start_txn(frame, meta)
def _start_txn(self, frame: bytes, meta: dict):
if(meta.get('service')):
self._update_interval()
self._busy = True
self._txn_meta = meta
self._rx_buf.clear()
self._set_ui_busy(True)
self._send(frame)
self._txn_timer.start(self.read_timeout_ms)
def _end_txn(self):
self._txn_timer.stop()
queue_mode = False
chain = None
meta = self._txn_meta
if meta:
queue_mode = meta.get('queue_mode', False)
chain = meta.get('chain')
self._txn_meta = None
self._busy = False
self._rx_buf.clear()
self._set_ui_busy(False)
if chain:
base, serv, q = chain
self._enqueue_or_start(base, service=serv, varqnt=q)
return
if self._pending_cmd is not None:
frame, meta = self._pending_cmd
self._pending_cmd = None
QtCore.QTimer.singleShot(0, lambda f=frame, m=meta: self._start_txn(f, m))
return
if queue_mode:
QtCore.QTimer.singleShot(0, self._kick_service_queue)
# !!! Раньше тут было `return`, его убираем
# Если идёт LL polling — переходим сразу к следующей переменной
if self._ll_polling:
self._process_next_ll_variable_in_cycle()
return
def _on_txn_timeout(self):
if not self._busy: return
is_ll = self._txn_meta.get('lowlevel', False) if self._txn_meta else False
log_prefix = "[LL TIMEOUT]" if is_ll else "[TIMEOUT]"
self._log(f"{log_prefix} No response")
if self._rx_buf:
self._log_frame(bytes(self._rx_buf), tx=False)
self._end_txn()
self.set_status("Timeout", "error")
# ------------------------------- TX/RX ---------------------------------
# ... (код без изменений)
def _send(self, data: bytes):
w = self.serial.write(data)
if w != len(data):
self._log(f"[ERR] Write short {w}/{len(data)}")
self.txBytes.emit(data)
self._log_frame(data, tx=True)
def _on_ready_read(self):
self._rx_buf.extend(self.serial.readAll().data())
if not self._busy:
if self._rx_buf:
self._log("[WARN] Data while idle -> drop")
self._log_frame(bytes(self._rx_buf), tx=False)
self._rx_buf.clear()
return
self._try_parse()
if not (self._polling or self._ll_polling):
self.set_status("Idle", "idle")
# ------------------------------- PARSING -------------------------------
def _try_parse(self):
if not self._txn_meta:
return
if self._txn_meta.get('lowlevel', False):
self._try_parse_lowlevel()
else:
self._try_parse_watch()
def _try_parse_watch(self):
# ... (код без изменений)
service = self._txn_meta['service']
buf = self._rx_buf
trailer_len = 4
if service:
if len(buf) < 7 + trailer_len:
return
name_len = buf[6]
expected = 7 + name_len + trailer_len
if len(buf) < expected:
return
frame = bytes(buf[:expected]); del buf[:expected]
self.rxBytes.emit(frame); self._log_frame(frame, tx=False)
self._parse_service_frame(frame)
self._end_txn()
else:
if len(buf) < 6 + trailer_len:
return
varqnt = buf[4]; status = buf[5]
if status != DEBUG_OK:
expected = 8 + trailer_len
if len(buf) < expected: return
frame = bytes(buf[:expected]); del buf[:expected]
self.rxBytes.emit(frame); self._log_frame(frame, tx=False)
self._parse_data_frame(frame, error_mode=True)
self._end_txn()
else:
expected = 6 + varqnt*2 + trailer_len
if len(buf) < expected: return
frame = bytes(buf[:expected]); del buf[:expected]
self.rxBytes.emit(frame); self._log_frame(frame, tx=False)
self._parse_data_frame(frame, error_mode=False)
self._end_txn()
def _try_parse_lowlevel(self):
# Ожидаемая длина: Успех=13, Ошибка=10
buf = self._rx_buf
if len(buf) < 10: # Минимальная длина (ошибка)
return
# Проверяем, что ответ для нас
if buf[1] != self.cmd_lowlevel:
self._log("[LL] Unexpected cmd in lowlevel parser, flushing.")
self._log_frame(bytes(self._rx_buf), tx=False)
self._rx_buf.clear()
# Не завершаем транзакцию, ждём таймаута
return
status = buf[2]
expected_len = 13 if status == DEBUG_OK else 10
if len(buf) >= expected_len:
frame = bytes(buf[:expected_len])
del buf[:expected_len]
self.rxBytes.emit(frame)
self._log_frame(frame, tx=False)
self._parse_lowlevel_frame(frame, success=(status == DEBUG_OK))
self._end_txn()
def _check_crc(self, payload: bytes, crc_lo: int, crc_hi: int):
if not self.auto_crc_check:
return True
crc_rx = (crc_hi << 8) | crc_lo
crc_calc = crc16_ibm(payload)
if crc_calc != crc_rx:
self._log(f"[CRC FAIL] calc=0x{crc_calc:04X} rx=0x{crc_rx:04X}")
return False
self._log("[CRC OK]")
return True
@staticmethod
def _clear_service_bit(vhi, vlo):
return ((vhi & 0x7F) << 8) | vlo
def _parse_service_frame(self, frame: bytes):
# ... (код без изменений)
payload = frame[:-4]; crc_lo, crc_hi = frame[-4], frame[-3]
if len(payload) < 7:
self._log("[ERR] Service frame too short"); return
self._check_crc(payload, crc_lo, crc_hi)
adr, cmd, vhi, vlo, status, iq_raw, name_len = payload[:7]
status_desc = _decode_debug_status(status)
index = self._clear_service_bit(vhi, vlo)
if len(payload) < 7 + name_len:
self._log("[ERR] Service name truncated"); return
name_bytes = payload[7:7+name_len]; name = name_bytes.decode(errors='replace')
is_signed = (iq_raw & SIGN_BIT_MASK) != 0
frac_bits = iq_raw & FRAC_MASK_FULL
if status == DEBUG_OK:
self._name_cache[index] = (status, iq_raw, name, is_signed, frac_bits)
self.nameRead.emit(index, status, iq_raw, name)
self._log(f"[SERVICE] idx={index} status={status} iq_raw=0x{iq_raw:02X} sign={'S' if is_signed else 'U'} frac={frac_bits} name='{name}'")
def _parse_data_frame(self, frame: bytes, *, error_mode: bool):
payload = frame[:-4]; crc_lo, crc_hi = frame[-4], frame[-3]
if len(payload) < 6:
self._log("[ERR] Data frame too short"); return
self._check_crc(payload, crc_lo, crc_hi)
adr, cmd, vhi, vlo, varqnt, status = payload[:6]
base = self._clear_service_bit(vhi, vlo)
if error_mode:
self.set_status("Error", "error")
if len(payload) < 8:
self._log("[ERR] Error frame truncated"); return
err_hi, err_lo = payload[6:8]
bad_index = (err_hi << 8) | err_lo
desc = _decode_debug_status(status)
self._log(f"[DATA] ERROR status=0x{status:02X} ({desc}) bad_index={bad_index}")
# Обновим UI
self._populate_watch_error(bad_index, status)
# Сигналы (оставляем совместимость)
self.valueRead.emit(bad_index, status, 0, 0, float('nan'))
self.valuesRead.emit(base, 0, [], [], [], [])
return
if len(payload) < 6 + varqnt*2:
self._log("[ERR] Data payload truncated"); return
raw_vals = []
pos = 6
for _ in range(varqnt):
hi = payload[pos]; lo = payload[pos+1]; pos += 2
raw16 = (hi << 8) | lo
raw_vals.append(raw16)
idx_list = []; iq_list = []; name_list = []; scaled_list = []; display_raw_list = []
# Получаем текущее время один раз для всех переменных в этом фрейме
current_time = time.time()
for ofs, raw16 in enumerate(raw_vals):
idx = base + ofs
status_i, iq_raw, name_i, is_signed, frac_bits = self._name_cache.get(idx, (DEBUG_OK, 0, '', False, 0))
if is_signed and (raw16 & 0x8000):
value_int = raw16 - 0x10000
else:
value_int = raw16
if self.chk_raw.isChecked():
scale = 1.0
else:
scale = self.iq_scaling.get(frac_bits, 1.0 / (1 << frac_bits))
scaled = float(value_int) / scale if frac_bits > 0 else float(value_int)
idx_list.append(idx); iq_list.append(iq_raw); name_list.append(name_i)
scaled_list.append(scaled); display_raw_list.append(value_int)
# --- Здесь записываем имя и значение в csv_logger ---
self.csv_logger.set_value(current_time, name_i, scaled)
self._populate_table(idx_list, name_list, iq_list, display_raw_list, scaled_list)
if varqnt == 1:
if idx_list[0] == self.spin_index.value():
_, iq_raw0, name0, is_signed0, frac0 = self._name_cache.get(idx_list[0], (DEBUG_OK, 0, '', False, 0))
self.valueRead.emit(idx_list[0], status, iq_list[0], display_raw_list[0], scaled_list[0])
else:
self.valuesRead.emit(base, varqnt, idx_list, iq_list, display_raw_list, scaled_list)
self._log(f"[DATA] base={base} q={varqnt} values={[f'{v:.6g}' for v in scaled_list] if not self.chk_raw.isChecked() else raw_vals}")
def _parse_lowlevel_frame(self, frame: bytes, success: bool):
payload_len = 9 if success else 6
crc_pos = payload_len
payload = frame[:payload_len]
crc_lo, crc_hi = frame[crc_pos], frame[crc_pos+1]
self._check_crc(payload, crc_lo, crc_hi)
status = payload[2]
addr2, addr1, addr0 = payload[3], payload[4], payload[5]
addr24 = (addr2 << 16) | (addr1 << 8) | addr0
status_desc = _decode_debug_status(status)
if not success:
# Ошибка — в ответе нет ReturnType и данных, только статус
self._log(f"[LL] ERROR addr=0x{addr24:06X} status=0x{status:02X} ({status_desc})")
self.llValueRead.emit(addr24, status, None, None, None)
return None
# Если success == True, продолжаем парсить ReturnType и данные
return_type = payload[6]
data_hi, data_lo = payload[7], payload[8]
raw16 = (data_hi << 8) | data_lo
is_signed = (return_type & SIGN_BIT_MASK) != 0
frac_bits = return_type & FRAC_MASK_FULL
if is_signed and (raw16 & 0x8000):
value_int = raw16 - 0x10000
else:
value_int = raw16
if self.chk_raw.isChecked():
scale = 1.0
else:
scale = self.iq_scaling.get(frac_bits, 1.0 / (1 << frac_bits)) # 1 / 2^N
scaled = float(value_int) / scale
self.llValueRead.emit(addr24, status, return_type, value_int, scaled)
var_name = None
if self._ll_current_var_info.get("address") == addr24:
var_name = self._ll_current_var_info.get("name")
display_val = value_int if self.chk_raw.isChecked() else scaled
if var_name:
self.ll_selector.set_variable_value(var_name, display_val)
self._log(f"[LL] OK addr=0x{addr24:06X} type=0x{return_type:02X} raw={value_int} scaled={scaled:.6g}")
current_time = time.time()
self.csv_logger.set_value(current_time, var_name, display_val)
def _populate_watch_error(self, bad_index: int, status: int):
"""Отобразить строку ошибки при неудачном ответе WATCH."""
desc = _decode_debug_status(status)
self.tbl_values.setRowCount(1)
self.tbl_values.setItem(0, 0, QtWidgets.QTableWidgetItem(str(bad_index)))
self.tbl_values.setItem(0, 1, QtWidgets.QTableWidgetItem(f"<ERROR:{desc}>"))
self.tbl_values.setItem(0, 2, QtWidgets.QTableWidgetItem("-"))
self.tbl_values.setItem(0, 3, QtWidgets.QTableWidgetItem("-"))
self.tbl_values.setItem(0, 4, QtWidgets.QTableWidgetItem("<ERROR>"))\
def _populate_table(self, idxs, names, iqs, raws, scaled):
"""
Быстрое массовое обновление таблицы значений.
- Не пересоздаём QTableWidgetItem при каждом вызове: обновляем текст.
- Блокируем сортировку, сигналы и обновления на время заполнения.
- Предвычисляем отображаемые строки (особенно формат scaled).
"""
tbl = self.tbl_values
n = len(idxs)
# Заморозка UI на время массового обновления
prev_sorting = tbl.isSortingEnabled()
tbl.setSortingEnabled(False)
tbl.blockSignals(True)
tbl.setUpdatesEnabled(False)
# Подготовка размера
if tbl.rowCount() != n:
tbl.setRowCount(n)
# Предварительно решаем: показывать сырые или масштабированные значения
show_raw = self.chk_raw.isChecked()
# Готовим строки (ускоряет при больших объёмах)
# str() заранее, чтобы не повторять в цикле
idx_strs = [str(v) for v in idxs]
raw_strs = [str(v) for v in raws]
scaled_strs = raw_strs if show_raw else [f"{v:.6g}" for v in scaled]
# Флаги необновляемых ячеек (только выбор/просмотр)
flags_ro = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
# Локальный шорткат для быстрой установки текста в ячейку
def _set_text(row, col, text):
item = tbl.item(row, col)
if item is None:
item = QtWidgets.QTableWidgetItem(text)
item.setFlags(flags_ro)
tbl.setItem(row, col, item)
else:
# обновим текст только при изменении (немного экономит на больших данных)
if item.text() != text:
item.setText(text)
if item.flags() != flags_ro:
item.setFlags(flags_ro)
# Основной цикл
for row in range(n):
iq_raw = iqs[row]
is_signed = (iq_raw & SIGN_BIT_MASK) != 0
frac_bits = iq_raw & FRAC_MASK_FULL
iq_disp = f"{frac_bits}{'s' if is_signed else 'u'}"
_set_text(row, 0, idx_strs[row])
_set_text(row, 1, names[row])
_set_text(row, 2, iq_disp)
_set_text(row, 3, raw_strs[row])
_set_text(row, 4, scaled_strs[row])
# Разморозка
tbl.blockSignals(False)
tbl.setUpdatesEnabled(True)
tbl.setSortingEnabled(prev_sorting)
tbl.viewport().update()
# ------------------------------ POLLING --------------------------------
def _toggle_polling(self):
if self._polling:
self._poll_timer.stop()
self._polling = False
self.btn_poll.setText("Start Polling")
self.set_status("Idle", "idle")
self._log("[POLL] Stopped")
else:
interval = self.spin_interval.value()
self._poll_timer.start(interval)
self._polling = True
self.btn_poll.setText("Stop Polling")
self.set_status("Idle", "idle")
self._log(f"[POLL] Started interval={interval}ms")
self._set_ui_busy(False) # Обновить доступность кнопок
def _on_poll_timeout(self):
self.request_values()
def _toggle_ll_polling(self):
if self._ll_polling: # If currently polling, stop
self._ll_polling = False
self.ll_selector.btn_start_polling.setText("Start Polling")
self._ll_poll_timer.stop()
self._ll_polling_variables.clear()
self._ll_current_poll_index = -1
self._log("[LL Polling] Stopped.")
else: # If not polling, start
# Get all selected variables from the LowLevelSelectorWidget
self._ll_polling_variables = self.ll_selector.get_selected_variables_and_addresses()
if not self._ll_polling_variables:
self._log("[LL] No variables selected for polling. Aborting.")
self.set_status("Error.", "error")
return
self._ll_polling = True
self.ll_selector.btn_start_polling.setText("Stop Polling")
self._ll_current_poll_index = 0 # Start from the first variable
self._log(f"[LL Polling] Started. Polling {len(self._ll_polling_variables)} variables.")
# Start the timer. It will trigger _on_ll_poll_timeout, which starts the cycle.
# The first cycle starts immediately, subsequent cycles wait for the interval.
self._ll_poll_timer.setInterval(self.ll_selector.spin_interval.value())
self._ll_poll_timer.start() # Start the timer for recurrent cycles
# Immediately kick off the first variable read of the first cycle
self._start_ll_cycle()
self._set_ui_busy(False) # Обновить доступность кнопок
def _on_ll_poll_timeout(self):
"""Вызывается по таймеру для старта нового цикла."""
if self._ll_polling and not self._busy:
self._start_ll_cycle()
elif self._busy:
self._log("[LL Polling] Busy, skip cycle start.")
def _start_ll_cycle(self):
self._update_interval()
"""Запускает новый цикл опроса всех переменных."""
if not self._ll_polling or not self._ll_polling_variables:
return
self._ll_poll_index = 0
self._process_next_ll_variable_in_cycle()
def _on_ll_variable_prepared(self, var_info: dict):
"""Срабатывает при выборе переменной в селекторе."""
self._ll_current_var_info = var_info
def _process_next_ll_variable_in_cycle(self):
if not self._ll_polling: # Добавим проверку, чтобы избежать вызова, если LL polling отключен
return
if self._ll_poll_index < len(self._ll_polling_variables):
var_info = self._ll_polling_variables[self._ll_poll_index]
self._on_ll_variable_prepared(var_info)
self._ll_poll_index += 1
frame = self._build_lowlevel_request(var_info)
# --- НОВОЕ: Передаем var_info в метаданные транзакции для LL polling ---
meta = {'lowlevel': True, 'll_polling': True, 'll_var_info': var_info}
# Получаем адрес переменной, предполагаем что ключ называется 'addr' или 'address'
addr = var_info.get('addr') or var_info.get('address')
if addr is not None:
addr_str = f"0x{addr:06X}"
else:
addr_str = "addr unknown"
self.set_status(f"Polling LL: {addr_str} {var_info.get('name')}", "values")
self._enqueue_raw(frame, meta)
else:
# Цикл завершен, перезапускаем таймер для следующего полного цикла
self.ll_selector._populate_var_table()
# ------------------------------ HELPERS --------------------------------
def _toggle_index_base(self, st):
# ... (код без изменений)
val = self.spin_index.value()
if st == QtCore.Qt.Checked:
self.spin_index.setDisplayIntegerBase(16); self.spin_index.setPrefix("0x")
else:
self.spin_index.setDisplayIntegerBase(10); self.spin_index.setPrefix("")
self.spin_index.setValue(val)
def _set_ui_busy(self, busy: bool):
# Блокируем кнопки в зависимости от состояния 'busy' и 'polling'
# Watch tab
can_use_watch = not busy and not (self._polling or self._ll_polling)
#self.btn_update_service.setEnabled(can_use_watch)
self.btn_read_values.setEnabled(can_use_watch)
# LowLevel tab
can_use_ll = not busy and not (self._ll_polling or self._polling)
self.ll_selector.btn_read_once.setEnabled(can_use_ll)
def _on_serial_error(self, err):
# ... (код без изменений)
if err == QtSerialPort.QSerialPort.NoError: return
self._log(f"[SERIAL ERR] {self.serial.errorString()} ({err})")
if self._busy: self._end_txn()
# ------------------------------ LOGGING --------------------------------
def _select_csv_file(self):
"""Открывает диалог выбора файла для CSV и обновляет UI."""
if self.csv_logger.select_file(self): # Передаем self как parent для диалога
self.lbl_csv_filename.setText(self.csv_logger.filename)
self._log(f"CSV file set to: {self.csv_logger.filename}")
def _start_csv_logging(self):
"""Начинает запись данных в CSV. Устанавливает заголовки в зависимости от активной вкладки."""
if not self.serial.isOpen():
self._log("[CSV] Невозможно начать запись: COM порт не открыт.")
self.set_status("Port closed", "error")
return
# Определяем активную вкладку и устанавливаем заголовки
current_tab_index = self.tabs.currentIndex()
varnames_for_csv = []
if self.tabs.tabText(current_tab_index) == "Watch":
# Для вкладки Watch берем имена из кэша, если они есть, иначе используем Index_X
base_index = self.spin_index.value()
count = self.spin_count.value()
for i in range(base_index, base_index + count):
if i in self._name_cache and self._name_cache[i][2]: # status, iq_raw, name, is_signed, frac_bits
varnames_for_csv.append(self._name_cache[i][2])
else:
varnames_for_csv.append(f"Index_{i}")
self._log(f"[CSV] Начинается запись для Watch переменных: {varnames_for_csv}")
elif self.tabs.tabText(current_tab_index) == "LowLevel":
# Для вкладки LowLevel берем имена из ll_selector
selected_vars = self.ll_selector.get_selected_variables_and_addresses()
varnames_for_csv = [var['name'] for var in selected_vars if 'name' in var]
if not varnames_for_csv:
self._log("[CSV] Внимание: На вкладке LowLevel не выбраны переменные для записи.")
self._log(f"[CSV] Начинается запись для LowLevel переменных: {varnames_for_csv}")
else:
self._log("[CSV] Неизвестная активная вкладка. Невозможно определить заголовки CSV.")
return
if not varnames_for_csv:
self._log("[CSV] Нет переменных для записи в CSV. Запись не начата.")
return
self.csv_logger.set_titles(varnames_for_csv)
self._csv_logging_active = True
self.btn_start_csv_logging.setEnabled(False)
self.btn_stop_csv_logging.setEnabled(True)
self.set_status("CSV Logging ACTIVATED", "service")
self._log("[CSV] Запись данных в CSV началась.")
def _stop_csv_logging(self):
"""Останавливает запись данных в CSV."""
self._csv_logging_active = False
self.btn_start_csv_logging.setEnabled(True)
self.btn_stop_csv_logging.setEnabled(False)
self.set_status("CSV Logging STOPPED", "service")
self._log("[CSV] Запись данных в CSV остановлена.")
def _save_csv_data(self):
"""Сохраняет все собранные данные в CSV файл."""
if self._csv_logging_active:
self._log("[CSV] Запись активна. Сначала остановите запись.")
self.set_status("Stop logging first", "error")
return
self.csv_logger.write_to_csv()
self.set_status("CSV data saved", "service")
def _log(self, msg: str):
# ... (код без изменений)
if 'ERR' in msg:
self.set_status(msg, 'error')
if 'OK' in msg:
self.set_status('Idle', 'idle')
if not self.log_spoiler.getState():
return
ts = datetime.datetime.now().strftime('%H:%M:%S.%f')[:-3]
self.txt_log.append(f"{ts} {msg}")
def _log_frame(self, data: bytes, *, tx: bool):
# ... (код без изменений)
if not self.log_spoiler.getState():
return
tag = 'TX' if tx else 'RX'
hexs = ' '.join(f"{b:02X}" for b in data)
ascii_part = ''.join(chr(b) if 32 <= b < 127 else '.' for b in data)
self._log(f"[{tag}] {hexs} |{ascii_part}|")
def _update_interval(self):
now = time.perf_counter()
if self._last_txn_timestamp is not None:
delta_ms = (now - self._last_txn_timestamp) * 1000
# Обновляем UI только если он уже создан
if hasattr(self, 'lbl_actual_interval'):
self.lbl_actual_interval.setText(f"{delta_ms:.1f} ms")
self._last_txn_timestamp = now
# ---------------------------------------------------------- Demo harness ---
class _DemoWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
base_path = get_base_path()
icon_path = os.path.join(base_path, "icon.ico")
if os.path.exists(icon_path):
self.setWindowIcon(QtGui.QIcon(icon_path))
self.setWindowTitle("DebugVar Terminal")
self.term = DebugTerminalWidget(self)
self.setCentralWidget(self.term)
self.resize(1000, 600)
def closeEvent(self, event):
self.setCentralWidget(None)
if self.term:
self.term.deleteLater(); self.term = None
super().closeEvent(event)
# ------------------------------- Demo --------------------------------------
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
auto_updater.check_and_update(
current_version="1.2.1",
git_releases_url="https://git.arktika.cyou/Razvalyaev/debugVarTool/releases",
exe_name="DebugVarEdit.exe",
zip_name="DebugToolsRelease.rar",
parent_widget=None
)
win = _DemoWindow(); win.show()
sys.exit(app.exec_())

428
Src/var_selector_table.py Normal file
View File

@@ -0,0 +1,428 @@
# variable_select_widget.py
import pickle
import hashlib
from typing import List, Dict, Any, Optional
from PySide2.QtWidgets import (
QWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QLineEdit,
QHeaderView, QCompleter
)
from PySide2.QtGui import QKeyEvent
from PySide2.QtCore import Qt, QStringListModel
from path_hints import PathHints, canonical_key, split_path_tokens
# ------------------------------------------------------------------
# utils
# ------------------------------------------------------------------
def compute_vars_hash(vars_list):
return hashlib.sha1(pickle.dumps(vars_list)).hexdigest()
def is_lazy_item(item: QTreeWidgetItem) -> bool:
return item.childCount() == 1 and item.child(0).text(0) == 'lazy_marker'
# ------------------------------------------------------------------
# VariableSelectWidget
# ------------------------------------------------------------------
class VariableSelectWidget(QWidget):
"""
Виджет выбора переменных с деревом + строкой поиска + автодополнением.
Подсказки полностью через PathHints.
ВАЖНО: ожидается, что в данных (vars_list) каждое var['name'] — ПОЛНЫЙ ПУТЬ
(например: 'project.adc.status'), даже внутри children.
"""
ROLE_NAME = Qt.UserRole # локальный хвост (display)
ROLE_VAR_DICT = Qt.UserRole + 100 # исходный dict
ROLE_FULLPATH = Qt.UserRole + 200 # полный путь
def __init__(self, parent=None):
super().__init__(parent)
# данные
self.expanded_vars: List[Dict[str, Any]] = []
self.is_autocomplete_on = True
self.manual_completion_active = False
self._bckspc_pressed = False
self._vars_hash: Optional[str] = None
# индекс: canonical_full_path -> item
self._item_by_canon: Dict[str, QTreeWidgetItem] = {}
# подсказки
self.hints = PathHints()
# --- 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)
self.completer.activated[str].connect(self.insert_completion)
# layout
lay = QVBoxLayout(self)
lay.setContentsMargins(0, 0, 0, 0)
lay.addWidget(self.search_input)
lay.addWidget(self.tree)
# signals
self.search_input.textChanged.connect(self.on_search_text_changed)
self.search_input.installEventFilter(self)
# ------------------------------------------------------------------
# public api
# ------------------------------------------------------------------
def set_autocomplete(self, enabled: bool):
self.is_autocomplete_on = enabled
def set_data(self, vars_list: List[Dict[str, Any]]):
"""
Загружаем список переменных (формат: см. класс docstring).
"""
# deepcopy
self.expanded_vars = pickle.loads(pickle.dumps(vars_list, protocol=pickle.HIGHEST_PROTOCOL))
# rebuild hints из полного списка узлов (каждый узел уже с full_path)
self._rebuild_hints_from_vars(self.expanded_vars)
# rebuild tree
self.populate_tree(self.expanded_vars)
# ------------------------------------------------------------------
# hints builder: дети уже содержат ПОЛНЫЙ ПУТЬ
# ------------------------------------------------------------------
def _rebuild_hints_from_vars(self, vars_list: List[Dict[str, Any]]):
paths: List[tuple] = []
def walk(node: Dict[str, Any]):
full = node.get('name', '')
if full:
paths.append((full, node.get('type')))
for ch in node.get('children', []) or []:
walk(ch)
for v in vars_list:
walk(v)
self.hints.set_paths(paths)
# ------------------------------------------------------------------
# tree building
# ------------------------------------------------------------------
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._item_by_canon.clear()
# построим top-level из входного списка: определяем по глубине токенов
# (vars_list может содержать и глубокие узлы; выберем корни = те, чей full_path не имеет родителя в списке)
full_to_node = {v['name']: v for v in vars_list}
# но safer: просто добавляем все как top-level, если ты уже передаёшь только корни.
# Если в твоих данных vars_list == корни, просто сделаем:
for v in vars_list:
self._add_tree_item_lazy(None, v)
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: QTreeWidgetItem):
if is_lazy_item(item):
item.removeChild(item.child(0))
var = item.data(0, self.ROLE_VAR_DICT)
if var:
for ch in var.get('children', []) or []:
self._add_tree_item_lazy(item, ch)
# ------------------------------------------------------------------
# item creation (var['name'] — ПОЛНЫЙ ПУТЬ)
# ------------------------------------------------------------------
def _add_tree_item_lazy(self, parent: Optional[QTreeWidgetItem], var: Dict[str, Any]):
full_path = var.get('name', '')
type_str = var.get('type', '')
# здесь оставляем полный путь для отображения
item = QTreeWidgetItem([full_path, type_str])
item.setData(0, self.ROLE_NAME, full_path) # теперь ROLE_NAME = полный путь
item.setData(0, self.ROLE_VAR_DICT, var)
item.setData(0, self.ROLE_FULLPATH, full_path)
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)
# lazy children
if var.get('children'):
dummy = QTreeWidgetItem(["lazy_marker"])
item.addChild(dummy)
# индекс
self._item_by_canon[canonical_key(full_path)] = item
@staticmethod
def _tail_token(full_path: str) -> str:
toks = split_path_tokens(full_path)
return toks[-1] if toks else full_path
# ------------------------------------------------------------------
# filtering
# ------------------------------------------------------------------
def filter_tree(self):
"""
Быстрый фильтр:
- без разделителей → substring по ЛОКАЛЬНОМУ имени top-level
- с разделителями → структурный (по токенам full_path)
"""
text = (self.search_input.text() or '').strip()
low = text.lower()
parts = split_path_tokens(low) if low else []
# простой режим (нет ., ->, [):
if low and all(x not in low for x in ('.', '->', '[')):
for i in range(self.tree.topLevelItemCount()):
it = self.tree.topLevelItem(i)
full = (it.data(0, self.ROLE_FULLPATH) or '').lower()
it.setHidden(low not in full)
return
# структурный
for i in range(self.tree.topLevelItemCount()):
it = self.tree.topLevelItem(i)
self._show_matching_path(it, parts, 0)
def _show_matching_path(self, item: QTreeWidgetItem, path_parts: List[str], level: int = 0):
"""
Сравниваем введённый путь (разбитый на токены) с ПОЛНЫМ ПУТЁМ узла.
Алгоритм: берём полный путь узла, разбиваем в токены, берём уровень level,
и сравниваем с соответствующим токеном path_parts[level].
"""
full = (item.data(0, self.ROLE_FULLPATH) or '').lower()
node_parts = split_path_tokens(full)
if level >= len(path_parts):
item.setHidden(False)
item.setExpanded(False)
return True
if level >= len(node_parts):
item.setHidden(True)
return False
search_part = path_parts[level]
node_part = node_parts[level]
if search_part == node_part:
item.setHidden(False)
matched_any = False
self.on_item_expanded(item)
for i in range(item.childCount()):
ch = item.child(i)
if self._show_matching_path(ch, path_parts, level + 1):
matched_any = True
item.setExpanded(matched_any)
return matched_any or item.childCount() == 0
elif node_part.startswith(search_part):
item.setHidden(False)
item.setExpanded(False)
return True
elif search_part in node_part and (level == len(path_parts) - 1):
item.setHidden(False)
item.setExpanded(False)
return True
else:
item.setHidden(True)
return False
# ------------------------------------------------------------------
# completions (ONLY PathHints)
# ------------------------------------------------------------------
def update_completions(self, text: Optional[str] = None) -> List[str]:
if text is None:
text = self.search_input.text()
suggestions = self.hints.suggest(text)
self.completer.setModel(QStringListModel(suggestions))
if suggestions:
self.completer.complete()
else:
self.completer.popup().hide()
return suggestions
def insert_completion(self, full_path: str):
text = self.hints.add_separator(full_path)
if not self._bckspc_pressed:
self.search_input.setText(text)
self.search_input.setCursorPosition(len(text))
self.run_completions(text)
# ------------------------------------------------------------------
# events
# ------------------------------------------------------------------
def eventFilter(self, obj, event):
if obj == self.search_input and isinstance(event, QKeyEvent):
if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier:
self.manual_completion_active = True
self.run_completions(self.search_input.text())
elif event.key() == Qt.Key_Escape:
if not self.is_autocomplete_on:
self.manual_completion_active = False
self.completer.popup().hide()
return True
if event.key() == Qt.Key_Backspace:
self._bckspc_pressed = True
else:
self._bckspc_pressed = False
return super().eventFilter(obj, event)
def run_completions(self, text: str):
if not self.is_autocomplete_on and not self.manual_completion_active:
self.completer.popup().hide()
return
self.update_completions(text)
def on_search_text_changed(self, text: str):
self.completer.setWidget(self.search_input)
self.filter_tree()
if text is None:
text = self.search_input.text()
if self.is_autocomplete_on:
self.run_completions(text)
else:
if self.manual_completion_active:
self.run_completions(text)
else:
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 closeEvent(self, event):
self.completer.setWidget(None)
self.completer.deleteLater()
super().closeEvent(event)
# ------------------------------------------------------------------
# lookup by full path
# ------------------------------------------------------------------
def find_item_by_fullpath(self, path: str) -> Optional[QTreeWidgetItem]:
return self._item_by_canon.get(canonical_key(path))
# ------------------------------------------------------------------
# tooltips
# ------------------------------------------------------------------
def _set_tool(self, item: QTreeWidgetItem, text: str):
item.setToolTip(0, text)
item.setToolTip(1, text)
# ------------------------------------------------------------------
# selection helpers
# ------------------------------------------------------------------
def get_all_items(self):
"""Все leaf-узлы (подгружаем lazy)."""
def collect_leaf(parent):
leaves = []
for i in range(parent.childCount()):
ch = parent.child(i)
if ch.isHidden():
continue
self.on_item_expanded(ch)
if ch.childCount() == 0:
t = ch.text(1)
if t and 'bitfield' in t.lower():
continue
leaves.append(ch)
else:
leaves.extend(collect_leaf(ch))
return leaves
out = []
for i in range(self.tree.topLevelItemCount()):
top = self.tree.topLevelItem(i)
self.on_item_expanded(top)
if top.childCount() == 0:
t = top.text(1)
if t and 'bitfield' in t.lower():
continue
out.append(top)
else:
out.extend(collect_leaf(top))
return out
def _get_internal_selected_items(self):
selected = self.tree.selectedItems()
all_items = []
def collect(item):
self.on_item_expanded(item)
res = [item]
for i in range(item.childCount()):
res.extend(collect(item.child(i)))
return res
for it in selected:
all_items.extend(collect(it))
return all_items
def get_selected_items(self):
selected = self.tree.selectedItems()
leaves = []
for it in selected:
self.on_item_expanded(it)
if all(it.child(i).isHidden() or not it.child(i).isSelected() for i in range(it.childCount())):
t = it.data(0, self.ROLE_NAME)
if t and isinstance(t, str) and 'bitfield' in t.lower():
continue
leaves.append(it)
return leaves
def get_all_var_names(self):
return [it.data(0, self.ROLE_FULLPATH) for it in self.get_all_items() if it.data(0, self.ROLE_FULLPATH)]
def _get_internal_selected_var_names(self):
return [it.data(0, self.ROLE_FULLPATH) for it in self._get_internal_selected_items() if it.data(0, self.ROLE_FULLPATH)]
def get_selected_var_names(self):
return [it.data(0, self.ROLE_FULLPATH) for it in self.get_selected_items() if it.data(0, self.ROLE_FULLPATH)]

392
Src/var_selector_window.py Normal file
View File

@@ -0,0 +1,392 @@
import re
import lxml.etree as ET
from PySide2.QtWidgets import (
QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout, QSizePolicy
)
from PySide2.QtGui import QKeySequence, QKeyEvent
from PySide2.QtCore import Qt, QStringListModel, QSettings
import var_table
import var_setup
import myXML
import time
import var_selector_table
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
class VariableSelectorDialog(QDialog):
def __init__(self, table, all_vars, structs, typedefs, xml_path=None, parent=None):
super().__init__(parent)
self.setWindowTitle("Выбор переменных")
self.setAttribute(Qt.WA_DeleteOnClose)
self.resize(1200, 500)
self.selected_names = []
self._bckspc_pressed = False # флаг подавления добавления разделителя
self.table = table
self.all_vars = all_vars
self.structs = structs
self.typedefs = typedefs
self.expanded_vars = []
self.var_map = {v['name']: v for v in all_vars}
self.node_index = {}
self.xml_path = xml_path # сохраняем путь к xml
self.manual_completion_active = False
# --- Добавляем чекбокс для автодополнения ---
self.autocomplete_checkbox = QCheckBox("Включить автодополнение")
self.autocomplete_checkbox.setChecked(True)
# Инициализируем QSettings с именем организации и приложения
self.settings = QSettings("SET", "DebugVarEdit_VarsSelector")
# Восстанавливаем сохранённое состояние чекбокса, если есть
checked = self.settings.value("autocomplete_enabled", True, type=bool)
self.autocomplete_checkbox.setChecked(checked)
# При изменении состояния чекбокса сохраняем его
self.autocomplete_checkbox.stateChanged.connect(self.save_checkbox_state)
# Кнопки между таблицами
self.btn_right = QPushButton(">")
self.btn_right.clicked.connect(self.on_move_right)
self.btn_left = QPushButton("<")
self.btn_left.clicked.connect(self.on_move_left)
# Создаем кнопки, они остаются в диалоге
self.btn_accept = QPushButton("Применить")
# Создаем экземпляр вашего готового виджета
self.vars_widget = var_selector_table.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 окна
# Чекбокс автодополнения — первый в главном 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)
tables_layout.addWidget(self.vars_widget)
# Кнопки ">" и "<" между таблицами
middle_buttons_layout = QVBoxLayout()
middle_buttons_layout.addStretch()
middle_buttons_layout.addWidget(self.btn_right)
middle_buttons_layout.addWidget(self.btn_left)
middle_buttons_layout.addStretch()
tables_layout.addLayout(middle_buttons_layout)
# Правая таблица
self.selected_vars_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
tables_layout.addWidget(self.selected_vars_widget)
# Добавляем горизонтальный layout с таблицами в главный вертикальный
main_layout.addLayout(tables_layout)
# Кнопки "Добавить выбранные" и "Удалить выбранные" под таблицами
buttons_layout = QVBoxLayout()
buttons_layout.addWidget(self.btn_accept)
main_layout.addLayout(buttons_layout)
# Важно, если окно — QDialog или QWidget, установи layout
self.setLayout(main_layout)
# Соединяем сигналы кнопок с методами диалога
self.btn_accept.clicked.connect(self.on_apply_clicked)
# Соединяем чекбокс с методом виджета
self.autocomplete_checkbox.stateChanged.connect(self.set_autocomplete_tables)
# Устанавливаем начальное состояние автодополнения в виджете
self.vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
self.selected_vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
# --- Код в конце __init__ ---
self.expanded_vars = var_setup.expand_vars(self.all_vars, self.structs, self.typedefs)
self.update_vars_widget()
def on_move_right(self):
# Устанавливаем show_var=True для всех выбранных переменных из ЛЕВОЙ таблицы
selected = self.vars_widget._get_internal_selected_var_names()
if not selected:
return
def mark_selected_show_var(data):
for var in data:
if var['name'] in selected:
var['show_var'] = 'true'
var['enable'] = 'true'
if 'children' in var:
mark_selected_show_var(var['children'])
mark_selected_show_var(self.expanded_vars)
self.update_vars_widget()
def on_move_left(self):
# Сбрасываем show_var=False для всех выбранных переменных из ПРАВОЙ таблицы
selected = self.selected_vars_widget._get_internal_selected_var_names()
if not selected:
return
def mark_selected_hide_var(data):
for var in data:
if var['name'] in selected:
var['show_var'] = 'false'
if 'children' in var:
mark_selected_hide_var(var['children'])
mark_selected_hide_var(self.expanded_vars)
self.update_vars_widget()
def update_vars_widget(self):
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)
t3 = time.perf_counter()
self.vars_widget.filter_tree()
t4 = time.perf_counter()
self.selected_vars_widget.set_data(self.selected_vars)
t5 = time.perf_counter()
self.selected_vars_widget.filter_tree()
def on_apply_clicked(self):
# Получаем имена всех переменных из правой таблицы (selected_vars_widget)
right_var_names = set(self.selected_vars_widget.get_all_var_names())
all_items = self.selected_vars_widget.get_all_items()
if not all_items:
return
# Устанавливаем show_var=true и enable=true для переменных из правой таблицы
def add_or_update_var(item):
name = item.text(0)
type_str = item.text(1)
if name in self.var_map:
var = self.var_map[name]
var['show_var'] = 'true'
var['enable'] = 'true'
else:
file_val = item.data(0, Qt.UserRole + 1)
extern_val = item.data(0, Qt.UserRole + 2)
static_val = item.data(0, Qt.UserRole + 3)
new_var = {
'name': name,
'type': type_str,
'show_var': 'true',
'enable': 'true',
'shortname': name,
'pt_type': '',
'iq_type': 't_iq_none',
'return_type': 't_iq_none',
'file': file_val,
'extern': str(extern_val).lower() if extern_val else 'false',
'static': str(static_val).lower() if static_val else 'false',
}
self.all_vars.append(new_var)
self.var_map[name] = new_var
for item in all_items:
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()
# Обнови on_left_tree_double_click:
def on_left_tree_double_click(self, item, column):
selected_names = [item.text(0)]
if not selected_names:
return
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)
self.update_vars_widget()
# Добавь обработчик двойного клика справа (если нужно):
def on_rigth_tree_double_click(self, item, column):
selected_names = [item.text(0)]
if not selected_names:
return
def mark_selected_hide_var(data):
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)
self.update_vars_widget()
def keyPressEvent(self, event):
if event.key() == Qt.Key_Delete:
self.delete_selected_vars()
else:
super().keyPressEvent(event)
def delete_selected_vars(self):
selected_names = self._get_selected_var_names()
if not selected_names:
print("nothing selected")
return
# Обновляем var_map и all_vars
for name in selected_names:
if name in self.var_map:
self.var_map[name]['show_var'] = 'false'
self.var_map[name]['enable'] = 'false'
for v in self.all_vars:
if v['name'] == name:
v['show_var'] = 'false'
v['enable'] = 'false'
break
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
#QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
return
root, tree = myXML.safe_parse_xml(self.xml_path)
if root is None:
return
vars_section = root.find('variables')
if vars_section is None:
return
for var_elem in vars_section.findall('var'):
name = var_elem.attrib.get('name')
if name in selected_names:
def set_text(tag, value):
el = var_elem.find(tag)
if el is None:
el = ET.SubElement(var_elem, tag)
el.text = value
set_text('show_var', 'false')
set_text('enable', 'false')
myXML.fwrite(root, self.xml_path)
self.table.populate(self.all_vars, self.structs, None)
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно удалить переменные.")
return
root, tree = myXML.safe_parse_xml(self.xml_path)
if root is None:
return
vars_section = root.find('variables')
if vars_section is None:
return
removed_any = False
for var_elem in list(vars_section.findall('var')):
name = var_elem.attrib.get('name')
if name in selected_names:
vars_section.remove(var_elem)
removed_any = True
self.var_map.pop(name, None)
# Удаляем из all_vars (глобально)
self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names]
# Удаляем из expanded_vars (тоже глобально)
def filter_out_selected(vars_list):
filtered = []
for v in vars_list:
if v['name'] not in selected_names:
# Рекурсивно фильтруем детей, если есть
if 'children' in v:
v = v.copy()
v['children'] = filter_out_selected(v['children'])
filtered.append(v)
return filtered
self.expanded_vars[:] = filter_out_selected(self.expanded_vars)
if removed_any:
myXML.fwrite(root, self.xml_path)
self.update_vars_widget()
def _get_selected_var_names(self):
focused = self.focusWidget()
if focused and focused is self.vars_widget.tree:
return self.vars_widget.get_selected_var_names()
elif focused and focused is self.selected_vars_widget.tree:
return self.selected_vars_widget.get_selected_var_names()
else:
return []
def save_checkbox_state(self):
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)

View File

@@ -1,11 +1,63 @@
import sys
import os
import re
import xml.etree.ElementTree as ET
from generateVars import map_type_to_pt, get_iq_define, type_map
import lxml.etree as ET
from generate_debug_vars import map_type_to_pt, get_iq_define, type_map
from enum import IntEnum
import scanVars
import scan_vars
import myXML
import pickle
# Вспомогательные функции, которые теперь будут использоваться виджетом
def split_path(path):
"""
Разбивает путь на компоненты:
- 'foo[2].bar[1]->baz' → ['foo', '[2]', 'bar', '[1]', 'baz']
Если видит '-' в конце строки (без '>' после) — обрезает этот '-'
"""
tokens = []
token = ''
i = 0
length = len(path)
while i < length:
c = path[i]
# Разделители: '->' и '.'
if c == '-' and i + 1 < length and path[i:i+2] == '->':
if token:
tokens.append(token)
token = ''
i += 2
continue
elif c == '-' and i == length - 1:
# '-' на конце строки без '>' после — просто пропускаем его
i += 1
continue
elif c == '.':
if token:
tokens.append(token)
token = ''
i += 1
continue
elif c == '[':
if token:
tokens.append(token)
token = ''
idx = ''
while i < length and path[i] != ']':
idx += path[i]
i += 1
if i < length and path[i] == ']':
idx += ']'
i += 1
tokens.append(idx)
continue
else:
token += c
i += 1
if token:
tokens.append(token)
return tokens
def make_absolute_path(path, base_path):
@@ -86,7 +138,7 @@ def parse_vars(filename, typedef_map=None):
'shortname': var.findtext('shortname', name),
'pt_type': pt_type,
'iq_type': iq_type,
'return_type': var.findtext('return_type', 'int'),
'return_type': var.findtext('return_type', 't_iq_none'),
'type': var_type,
'file': var.findtext('file', ''),
'extern': var.findtext('extern', 'false') == 'true',
@@ -239,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)
# Ищем структуру по имени типа
base_type = scanVars.strip_ptr_and_array(type_str)
base_type = scan_vars.strip_ptr_and_array(type_str)
fields = structs.get(base_type)
if not isinstance(fields, dict):
# Не структура и не массив — просто возвращаем пустой список
@@ -266,6 +318,12 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
else:
field_type_str = None
if '*' in field_type_str:
full_name_prefix = full_name + '*'
else:
full_name_prefix = full_name
# Обработка, если поле — строка (тип или массив)
if field_type_str:
base_subtype, sub_dims = parse_array_dims(field_type_str)
@@ -311,7 +369,7 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
if isinstance(field_value, dict):
# Это одиночная структура — раскрываем рекурсивно
sub_items = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1)
sub_items = expand_struct_recursively(full_name_prefix, field_value, structs, typedefs, var_attrs, depth + 1)
child = {
'name': full_name,
'type': field_type_str,
@@ -353,7 +411,7 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
'extern': var_attrs.get('extern'),
'static': var_attrs.get('static'),
}
subchildren = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1)
subchildren = expand_struct_recursively(full_name_prefix, field_value, structs, typedefs, var_attrs, depth + 1)
if subchildren:
child['children'] = subchildren
children.append(child)
@@ -399,3 +457,163 @@ def expand_vars(vars_list, structs, typedefs):
return expanded
def build_full_names(parts, full_name):
"""
Восстанавливает вложенные полные имена из списка частей,
ориентируясь на оригинальное полное имя (с '.', '->' и индексами).
Пример:
parts = ['arr', '[0]', '[1]', 'ptr', 'val']
full_name = 'arr[0][1].ptr->val'
→ [
'arr',
'arr[0]',
'arr[0][1]',
'arr[0][1].ptr',
'arr[0][1].ptr->val'
]
"""
names = []
acc = ''
idx = 0
for part in parts:
pos = full_name.find(part, idx)
if pos == -1:
acc += part
else:
acc = full_name[:pos + len(part)]
idx = pos + len(part)
names.append(acc)
return names
def find_var_by_name(tree, name):
for var in tree:
if var.get('name') == name:
return var
if 'children' in var:
found = find_var_by_name(var['children'], name)
if found:
return found
return None
def add_to_nested_tree(tree, var, path_parts, full_names=None, depth=0, source_tree=None):
if not path_parts:
return
if full_names is None:
full_names = build_full_names(path_parts, var['name'])
current_name = full_names[depth]
for child in tree:
if child.get('name') == current_name:
if depth == len(path_parts) - 1:
child.update(var)
return
if 'children' not in child:
child['children'] = []
add_to_nested_tree(child['children'], var, path_parts, full_names, depth + 1, source_tree)
return
# Ищем в source_tree (expanded_vars) родительский узел по current_name
parent_data = {}
if source_tree:
parent_var = find_var_by_name(source_tree, current_name)
if parent_var:
# Копируем все поля кроме детей (children)
parent_data = {k: v for k, v in parent_var.items() if k != 'children'}
new_node = {
'name': current_name,
'children': []
}
# Обновляем new_node данными родителя
new_node.update(parent_data)
if depth == len(path_parts) - 1:
new_node.update(var)
else:
add_to_nested_tree(new_node['children'], var, path_parts, full_names, depth + 1, source_tree)
tree.append(new_node)
def split_vars_by_show_flag(expanded_vars):
unselected_vars = pickle.loads(pickle.dumps(expanded_vars, protocol=pickle.HIGHEST_PROTOCOL))
selected_vars = []
def find_and_remove(var_list, target_name):
"""Удаляет элемент по полному имени и возвращает его"""
for i, var in enumerate(var_list):
if var.get("name") == target_name:
return var_list.pop(i)
if 'children' in var:
found = find_and_remove(var['children'], target_name)
if found:
return found
return None
def collect_selected_nodes(var):
"""Рекурсивно возвращает все show_var=true узлы (включая поддерево)"""
nodes = []
if var.get('show_var', 'false').lower() == 'true':
nodes.append(var)
for child in var.get('children', []):
nodes.extend(collect_selected_nodes(child))
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 = []
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))
for node in selected_nodes:
full_name = node['name']
path_parts = split_path(full_name)
# Вырезать из unselected_vars
removed = find_and_remove(unselected_vars, full_name)
if removed:
add_to_nested_tree(selected_vars, removed, path_parts, source_tree=expanded_vars)
else:
# вдруг удалённый родитель — создаём вручную
add_to_nested_tree(selected_vars, node, path_parts, source_tree=expanded_vars)
return selected_vars, unselected_vars

498
Src/var_table.py Normal file
View File

@@ -0,0 +1,498 @@
from PySide2.QtWidgets import (
QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
QAbstractItemView, QHeaderView, QLabel, QSpacerItem, QSizePolicy, QSpinBox,
QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QScrollArea, QWidget
)
from PySide2.QtGui import QColor, QBrush, QPalette
from PySide2.QtCore import Qt, QSettings
from enum import IntEnum
from generate_debug_vars import type_map
import time
from typing import Dict, List
class rows(IntEnum):
No = 0
include = 1
name = 2
type = 3
pt_type = 4
iq_type = 5
ret_type = 6
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 SetSizeDialog(QDialog):
"""
Диалоговое окно для выбора числового значения (размера).
"""
def __init__(self, parent=None, initial_value=10, min_value=1, max_value=50, title="Укажите размер короткого имени",
label_text="Количество символов:"):
super().__init__(parent)
self.setWindowTitle(title)
self.setFixedSize(320, 120) # Задаем фиксированный размер для аккуратного вида
# Основной вертикальный макет
main_layout = QVBoxLayout(self)
# Макет для ввода значения
input_layout = QHBoxLayout()
label = QLabel(label_text, self)
self.spin_box = QSpinBox(self)
self.spin_box.setRange(min_value, max_value) # Устанавливаем диапазон допустимых значений
initial_value = parent._shortname_size
self.spin_box.setValue(initial_value) # Устанавливаем начальное значение
self.spin_box.setFocus() # Устанавливаем фокус на поле ввода
input_layout.addWidget(label)
input_layout.addWidget(self.spin_box)
main_layout.addLayout(input_layout)
# Добавляем пустое пространство для лучшего разделения
main_layout.addSpacerItem(QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding))
# Макет для кнопок
btn_layout = QHBoxLayout()
btn_layout.addStretch() # Добавляем растягивающийся элемент, чтобы кнопки были справа
btn_ok = QPushButton("OK")
btn_cancel = QPushButton("Отмена")
btn_layout.addWidget(btn_ok)
btn_layout.addWidget(btn_cancel)
main_layout.addLayout(btn_layout)
# Подключение сигналов к слотам
btn_ok.clicked.connect(self.accept) # При нажатии "OK" диалог закроется со статусом "Accepted"
btn_cancel.clicked.connect(self.reject) # При нажатии "Отмена" - со статусом "Rejected"
def get_selected_size(self):
"""
Возвращает значение, выбранное в QSpinBox.
"""
return self.spin_box.value()
class CtrlScrollComboBox(QComboBox):
def wheelEvent(self, event):
if event.modifiers() & Qt.ControlModifier:
super().wheelEvent(event)
else:
event.ignore()
class VariableTableWidget(QTableWidget):
def __init__(self, parent=None, show_value_instead_of_shortname=0):
# Таблица переменных
if show_value_instead_of_shortname:
super().__init__(0, 8, parent)
self.setHorizontalHeaderLabels([
'№',
'En',
'Name',
'Origin Type',
'Base Type',
'IQ Type',
'Return Type',
'Value'
])
self._show_value = True
else:
super().__init__(0, 8, parent)
self.setHorizontalHeaderLabels([
'№',
'En',
'Name',
'Origin Type',
'Base Type',
'IQ Type',
'Return Type',
'Short Name'
])
self._show_value = False
self.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.var_list = []
# QSettings
self.settings = QSettings("SET", "DebugVarEdit_VarTable")
shortsize = self.settings.value("shortname_size", True, type=int)
self._shortname_size = shortsize
if(self._show_value):
self._shortname_size = 3
self.type_options = list(dict.fromkeys(type_map.values()))
self.pt_types_all = [t.replace('pt_', '') for t in self.type_options]
self.iq_types_all = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
self.iq_types = ['iq_none', 'iq', 'iq10', 'iq15', 'iq19', 'iq24']
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]
self.pt_types = [t.replace('pt_', '') for t in type_options]
self._iq_type_filter = list(self.iq_types)
self._pt_type_filter = list(self.pt_types)
self._ret_type_filter = list(self.iq_types)
header = self.horizontalHeader()
for col in range(self.columnCount()):
if col == self.columnCount() - 1:
header.setSectionResizeMode(col, QHeaderView.Stretch)
else:
header.setSectionResizeMode(col, QHeaderView.Interactive)
self.setColumnWidth(rows.No, 30)
self.setColumnWidth(rows.include, 30)
self.setColumnWidth(rows.pt_type, 85)
self.setColumnWidth(rows.iq_type, 85)
self.setColumnWidth(rows.ret_type, 85)
self.setColumnWidth(rows.name, 300)
self.setColumnWidth(rows.type, 100)
self._resizing = False
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):
self.var_list = vars_list
self.setUpdatesEnabled(False)
self.blockSignals(True)
for var in vars_list:
pt_type = var.get('pt_type', '')
if 'struct' in pt_type or 'union' in pt_type:
var['show_var'] = 'false'
var['enable'] = 'false'
filtered_vars = [v for v in vars_list if v.get('show_var', 'false') == 'true']
self.setRowCount(len(filtered_vars))
self.verticalHeader().setVisible(False)
style_with_padding = "padding-left: 5px; padding-right: 5px; font-size: 14pt; font-family: 'Segoe UI';"
for row, var in enumerate(filtered_vars):
# №
no_item = QTableWidgetItem(str(row))
no_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(row, rows.No, no_item)
# Enable
cb = QCheckBox()
cb.setChecked(var.get('enable', 'false') == 'true')
cb.stateChanged.connect(on_change_callback)
cb.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.include, cb)
# Name
name_edit = QLineEdit(var['name'])
name_edit.textChanged.connect(on_change_callback)
name_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.name, name_edit)
# Origin Type
origin_item = QTableWidgetItem(var.get('type', ''))
origin_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
origin_item.setToolTip(var.get('type', ''))
origin_item.setForeground(QBrush(Qt.black))
self.setItem(row, rows.type, origin_item)
# pt_type
pt_combo = CtrlScrollComboBox()
pt_combo.addItems(self.pt_types)
value = var.get('pt_type', 'unknown').replace('pt_', '')
if value not in self.pt_types:
pt_combo.addItem(value)
pt_combo.setCurrentText(value)
pt_combo.currentTextChanged.connect(on_change_callback)
pt_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.pt_type, pt_combo)
# iq_type
iq_combo = CtrlScrollComboBox()
iq_combo.addItems(self.iq_types)
value = var.get('iq_type', 'iq_none').replace('t_', '')
if value not in self.iq_types:
iq_combo.addItem(value)
iq_combo.setCurrentText(value)
iq_combo.currentTextChanged.connect(on_change_callback)
iq_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.iq_type, iq_combo)
# return_type
ret_combo = CtrlScrollComboBox()
ret_combo.addItems(self.iq_types)
value = var.get('return_type', 'iq_none').replace('t_', '')
if value not in self.iq_types:
ret_combo.addItem(value)
ret_combo.setCurrentText(value)
ret_combo.currentTextChanged.connect(on_change_callback)
ret_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.ret_type, ret_combo)
# Последний столбец
if self._show_value:
if self._show_value:
val = var.get('value', '')
if val is None:
val = ''
else:
try:
f_val = float(val)
# Форматируем число с учетом self._shortname_size
if f_val.is_integer():
val = str(int(f_val))
else:
precision = getattr(self, "_shortname_size", 3) # по умолчанию 3
val = f"{f_val:.{precision}f}"
except ValueError:
# Если значение не число (строка и т.п.), оставляем как есть
val = str(val)
val_edit = QLineEdit(val)
val_edit.textChanged.connect(on_change_callback)
val_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.short_name, val_edit)
else:
short_name_val = var.get('shortname', var['name'])
short_name_edit = QLineEdit(short_name_val)
short_name_edit.textChanged.connect(on_change_callback)
short_name_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.short_name, short_name_edit)
self.blockSignals(False)
self.setUpdatesEnabled(True)
self.check()
def check(self):
warning_color = QColor("#FFFACD")
error_color = QColor("#FFB6C1")
tooltip_shortname = "Short Name длиннее 10 символов — будет обрезано при генерации"
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()):
t1 = time.time()
name_widget = self.cellWidget(row, rows.name)
t2 = time.time()
name = name_widget.text() if name_widget else ""
short_name_edit = self.cellWidget(row, rows.short_name)
t3 = time.time()
shortname = short_name_edit.text() if short_name_edit else ""
long_shortname = len(shortname) > self._shortname_size
found = name in var_names_set
color = None
tooltip = ""
if not found:
color = error_color
tooltip = tooltip_missing
elif long_shortname:
if not self._show_value:
color = warning_color
tooltip = tooltip_shortname
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):
result = []
for row in range(self.rowCount()):
cb = self.cellWidget(row, rows.include)
name = self.cellWidget(row, rows.name).text()
pt = self.cellWidget(row, rows.pt_type).currentText()
iq = self.cellWidget(row, rows.iq_type).currentText()
ret = self.cellWidget(row, rows.ret_type).currentText()
shortname = self.cellWidget(row, rows.short_name).text()
origin_type = self.item(row, rows.type).text()
result.append({
'show_var': True,
'enable': cb.isChecked(),
'name': name,
'pt_type': f'pt_{pt}',
'iq_type': f't_{iq}',
'return_type': f't_{ret}',
'shortname': shortname,
'type': origin_type,
})
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})
elif logicalIndex == rows.short_name:
if self._show_value:
dlg = SetSizeDialog(self, title="Укажите точность", label_text="Кол-во знаков после запятой", initial_value=3)
else:
dlg = SetSizeDialog(self)
if dlg.exec_():
self._shortname_size = dlg.get_selected_size()
if not self._show_value:
self.settings.setValue("shortname_size", self._shortname_size)
self.check()
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 not in allowed_items:
combo.addItem(current)
combo.setCurrentText(current)
combo.blockSignals(False)
def on_section_resized(self, logicalIndex, oldSize, newSize):
if self._resizing:
return # предотвращаем рекурсию
min_width = 50
delta = newSize - oldSize
right_index = logicalIndex + 1
if right_index >= self.columnCount():
# Если правая колока - нет соседа, ограничиваем минимальную ширину
if newSize < min_width:
self._resizing = True
self.setColumnWidth(logicalIndex, min_width)
self._resizing = False
return
self._resizing = True
try:
right_width = self.columnWidth(right_index)
new_right_width = right_width - delta
# Если соседняя колонка станет уже минимальной - подкорректируем левую
if new_right_width < min_width:
new_right_width = min_width
newSize = oldSize + (right_width - min_width)
self.setColumnWidth(logicalIndex, newSize)
self.setColumnWidth(right_index, new_right_width)
finally:
self._resizing = False
def highlight_row(self, row: int, color: QColor = None, tooltip: str = ""):
"""
Подсвечивает строку таблицы цветом `color`, не меняя шрифт.
Работает с QLineEdit, QComboBox, QCheckBox (включая обёртки).
Если `color=None`, сбрасывает подсветку.
"""
css_reset = "background-color: none; font: inherit;"
css_color = f"background-color: {color.name()};" if color else css_reset
for col in range(self.columnCount()):
item = self.item(row, col)
widget = self.cellWidget(row, col)
if item is not None:
current_bg = item.background().color() if item.background() else None
if color and current_bg != color:
item.setBackground(QBrush(color))
item.setToolTip(tooltip)
elif not color and current_bg is not None:
item.setBackground(QBrush(Qt.NoBrush))
item.setToolTip("")
elif widget is not None:
if widget.styleSheet() != css_color:
widget.setStyleSheet(css_color)
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):
selected_indexes = self.selectedIndexes()
selected_rows = set(index.row() for index in selected_indexes)
names = []
for row in selected_rows:
name_widget = self.cellWidget(row, rows.name)
if name_widget:
name = name_widget.text()
if name:
names.append(name)
return names

View File

@@ -1,390 +1,416 @@
#include "debug_tools.h"
#include "IQmathLib.h"
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var);
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var);
#if !defined(GLOBAL_Q)
#define GLOBAL_Q 16
#endif
DebugLowLevel_t debug_ll = DEBUG_LOWLEVEL_INIT; ///< Ñòðóêòóðà îòëàäêè íèæíåãî óðîâíÿ (èíèöèàëèçàöèÿ)
static int getDebugVar(DebugVar_t *var, int32_t *int_var, float *float_var);
static int convertDebugVarToIQx(DebugVar_t *var, int32_t *ret_var);
static int iqTypeToQ(DebugVarIQType_t t);
static int is_addr_in_allowed_ranges(uint32_t addr_val, const AddrRange_t *ranges, int count);
/**
* @brief Ìàññèâ äîïóñòèìûõ äèàïàçîíîâ àäðåñîâ äëÿ îòëàäî÷íîãî ÷òåíèÿ
*
* Âêëþ÷àåò â ñåáÿ íàáîð äèàïàçîíîâ ïàìÿòè, ðàçðåø¸ííûõ äëÿ äîñòóïà
* ôóíêöèåé Debug_LowLevel_ReadVar.
*/
static const AddrRange_t debug_allowed_ranges[] = ALLOWED_ADDRESS_RANGES;
/**
* @brief Êîëè÷åñòâî ýëåìåíòîâ â ìàññèâå debug_allowed_ranges
*/
static const int debug_allowed_ranges_count = sizeof(debug_allowed_ranges) / sizeof(debug_allowed_ranges[0]);
int Debug_LowLevel_ReadVar(DebugVar_t *var_ll, long *return_long)
///////////////////////////----EXAPLE-----//////////////////////////////
int var_numb = 1; ///< Ïðèìåð ïåðåìåííîé äëÿ îòëàäêè
DebugVarName_t var_name; ///< Èìÿ ïåðåìåííîé
int32_t return_var; ///< Ïåðåìåííàÿ äëÿ âîçâðàòà ðåçóëüòàòà
int32_t return_ll_var; ///< Âîçâðàùàåìîå çíà÷åíèå ñ íèæíåãî óðîâíÿ
int result; ///< Ïåðåìåííàÿ ðåçóëüòàòà
DateTime_t ext_date = {2025, 11, 07, 16, 50}; ///< Ïðèìåð âíåøíåé äàòû ñáîðêè
/**
* @brief Ïðèìåð èñïîëüçîâàíèÿ ôóíêöèé îòëàäêè.
* @details Äåìîíñòðàöèîííàÿ ôóíêöèÿ äëÿ ðàáîòû ñ ïåðåìåííûìè îòëàäêè.
*/
void Debug_Test_Example(void)
{
if (var_ll == NULL)
return 1;
return;
result = Debug_ReadVar(var_numb, &return_var);
result = Debug_ReadVarName(var_numb, var_name, 0);
char *addr = var_ll->Ptr;
unsigned long addr_val = (unsigned long)addr;
// Ðàçðåø¸ííûå äèàïàçîíû ïàìÿòè íà TMS320F2812
if (!(
(addr_val <= 0x0007FF) || // RAMM0 + RAMM1
(addr_val >= 0x008000 && addr_val <= 0x009FFF) || // L0 + L1 SARAM
(addr_val >= 0x3F8000 && addr_val <= 0x3F9FFF) || // PRAMH0 + DRAMH0
(addr_val >= 0x3D8000 && addr_val <= 0x3EFFFF) || // Flash A-F
(addr_val >= 0x3FF000 && addr_val <= 0x3FFFFF) // Boot ROM / Reset
)) {
return 2; // àäðåñ âíå äîïóñòèìîãî äèàïàçîíà, èãíîðèðóåì
}
convertDebugVarToIQx(var_ll, return_long);
if(Debug_LowLevel_Initialize(&ext_date) == 0)
result = Debug_LowLevel_ReadVar(&return_ll_var);
}
///////////////////////////----PUBLIC-----//////////////////////////////
/**
* @brief ×èòàåò ïåðåìåííóþ ïî èíäåêñó.
* @param var_ind èíäåêñ ïåðåìåííîé.
* @param return_32b óêàçàòåëü äëÿ âîçâðàòà ðåçóëüòàòà.
* @return int 0: óñïåõ, 1: îøèáêà.
* @details Èñïîëüçóåòñÿ äëÿ ÷òåíèÿ çíà÷åíèé ïåðåìåííûõ ïî èõ èíäåêñó.
*/
int Debug_ReadVar(int var_ind, int32_t *return_32b)
{
int32_t tmp_var;
if(return_32b == NULL)
return DEBUG_ERR_INTERNAL;
if (var_ind >= DebugVar_Qnt)
return DEBUG_ERR_VAR_NUMB;
if((dbg_vars[var_ind].ptr_type == pt_struct) || (dbg_vars[var_ind].ptr_type == pt_union) ||
(dbg_vars[var_ind].ptr_type == pt_unknown))
return DEBUG_ERR_INVALID_VAR;
return convertDebugVarToIQx(&dbg_vars[var_ind], return_32b);
}
/**
* @brief ×èòàåò âîçâðàùàåìûé òèï (IQ) ïåðåìåííîé ïî èíäåêñó.
* @param var_ind èíäåêñ ïåðåìåííîé.
* @param vartype óêàçàòåëü äëÿ âîçâðàòà òèïà.
* @return int 0: óñïåõ, 1: îøèáêà.
* @details Èñïîëüçóåòñÿ äëÿ ÷òåíèÿ âîçâðàùàåìîãî òèïà (IQ) ïåðåìåííûõ ïî èõ èíäåêñó.
*/
int Debug_ReadVarReturnType(int var_ind, int *vartype)
{
int rettype;
if(vartype == NULL)
return DEBUG_ERR_INTERNAL;
if (var_ind >= DebugVar_Qnt)
return DEBUG_ERR_VAR_NUMB;
if((dbg_vars[var_ind].ptr_type == pt_struct) || (dbg_vars[var_ind].ptr_type == pt_union) ||
(dbg_vars[var_ind].ptr_type == pt_unknown))
return DEBUG_ERR_INVALID_VAR;
*vartype = iqTypeToQ(dbg_vars[var_ind].return_type);
return 0;
}
int Debug_ReadVar(DebugVar_t *var, long *return_long)
/**
* @brief ×èòàåò òèï ïåðåìåííîé ïî èíäåêñó.
* @param var_ind èíäåêñ ïåðåìåííîé.
* @param vartype óêàçàòåëü äëÿ âîçâðàòà òèïà.
* @return int 0: óñïåõ, 1: îøèáêà.
* @details Èñïîëüçóåòñÿ äëÿ ÷òåíèÿ òèïà ïåðåìåííûõ ïî èõ èíäåêñó.
*/
int Debug_ReadVarType(int var_ind, int *vartype)
{
long tmp_var;
if (var == NULL)
return 1;
if((var->ptr_type == pt_struct) || (var->ptr_type == pt_union) ||
(var->ptr_type == pt_unknown) || (var->return_type == pt_unknown))
return 1;
int rettype;
if(vartype == NULL)
return DEBUG_ERR_INTERNAL;
if (var_ind >= DebugVar_Qnt)
return DEBUG_ERR_VAR_NUMB;
if((dbg_vars[var_ind].ptr_type == pt_struct) || (dbg_vars[var_ind].ptr_type == pt_union) ||
(dbg_vars[var_ind].ptr_type == pt_unknown))
return DEBUG_ERR_INVALID_VAR;
convertDebugVarToIQx(var, return_long);
*vartype = dbg_vars[var_ind].ptr_type;
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++)
switch(dbg_vars[var_ind].ptr_type)
{
name_ptr[i] = var->name[i];
if (var->name[i] == '\0')
case pt_int8:
case pt_int16:
case pt_int32:
case pt_float:
*vartype = dbg_vars[var_ind].ptr_type | DEBUG_SIGNED_VAR;
break;
default:
*vartype = dbg_vars[var_ind].ptr_type;
break;
}
// Ãàðàíòèðîâàííîå çàâåðøåíèå ñòðîêè (íà ñëó÷àé, åñëè â var->name íå áûëî '\0')
name_ptr[sizeof(var->name) - 1] = '\0';
return 0;
}
/**
* @brief ×èòàåò èìÿ ïåðåìåííîé ïî èíäåêñó.
* @param var_ind èíäåêñ ïåðåìåííîé.
* @param name_ptr óêàçàòåëü íà áóôåð èìåíè (DebugVarName_t).
* @return int 0: óñïåõ, 1: îøèáêà.
* @details Êîïèðóåò èìÿ ïåðåìåííîé â ïðåäîñòàâëåííûé áóôåð.
*/
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr, int *length)
{
int i;
if(name_ptr == NULL)
return DEBUG_ERR_INTERNAL;
if (var_ind >= DebugVar_Qnt)
return DEBUG_ERR_VAR_NUMB;
int Debug_LowLevel_Initialize(const uint8_t* external_date)
// Êîïèðîâàíèå ñ çàùèòîé îò ïåðåïîëíåíèÿ è ÿâíîé îñòàíîâêîé ïî '\0'
for (i = 0; i < sizeof(dbg_vars[var_ind].name); i++)
{
name_ptr[i] = dbg_vars[var_ind].name[i];
if (dbg_vars[var_ind].name[i] == '\0')
{
if(length != NULL)
*length = i;
break;
}
}
// Ãàðàíòèðîâàííîå çàâåðøåíèå ñòðîêè (íà ñëó÷àé, åñëè â var->name íå áûëî '\0')
name_ptr[sizeof(dbg_vars[var_ind].name) - 1] = '\0';
return 0;
}
/**
* @brief ×èòàåò çíà÷åíèå ïåðåìåííîé îòëàäêè ñ íèæíåãî óðîâíÿ.
* @param return_32b óêàçàòåëü íà ïåðåìåííóþ, êóäà çàïèñûâàåòñÿ ðåçóëüòàò.
* @return int 0: óñïåõ, 1: îøèáêà, 2: íåäîïóñòèìûé àäðåñ.
* @details Èñïîëüçóåò àäðåññ, ïåðåäàâàåìûé ñ òåðìèíàëêè äëÿ ïîëó÷åíèÿ çíà÷åíèÿ.
*/
int Debug_LowLevel_ReadVar(int32_t *return_32b)
{
uint8_t *addr = debug_ll.dbg_var.Ptr;
uint32_t addr_val = (uint32_t)addr;
if (return_32b == NULL)
return DEBUG_ERR_INTERNAL;
if (debug_ll.isVerified == 0)
return DEBUG_ERR_DATATIME;
if (is_addr_in_allowed_ranges(addr_val, debug_allowed_ranges, debug_allowed_ranges_count) != 0)
{
return DEBUG_ERR_ADDR; // Çàïðåù¸ííûé àäðåñ — íåëüçÿ ÷èòàòü
}
return convertDebugVarToIQx(&debug_ll.dbg_var, return_32b);
}
/**
* @brief Èíèöèàëèçàöèÿ îòëàäêè íà íèæíåì óðîâíå ïî äàòå ñáîðêè.
* @param external_date ñòðóêòóðà ñ äàòîé DateTime_t
* @return int 0: ñîâïàäàåò, 1: íå ñîâïàäàåò, -1: îøèáêà.
* @details Ñðàâíèâàåò äàòó êîìïèëÿöèè ñ çàïðàøèâàåìîé è èíèöèàëèçèðóåò îòëàäî÷íóþ ïåðåìåííóþ.
*/
int Debug_LowLevel_Initialize(DateTime_t* external_date)
{
if (external_date == NULL) {
return -1;
return DEBUG_ERR_INTERNAL;
}
// Ïðåîáðàçóåì external_date â ñòðóêòóðó
DateTimeHex ext;
ext.year = (external_date[0] << 8) | external_date[1];
ext.month = external_date[2];
ext.day = external_date[3];
ext.hour = external_date[4];
ext.minute = external_date[5];
// Ïàðñèì BUILD_FULL_DATE "YYYYMMDD_HHMM"
DateTimeHex build;
char buf[5] = {0};
// Ãîä
memcpy(buf, BUILD_FULL_DATE + 0, 4);
build.year = (uint16_t)atoi(buf);
// Ìåñÿö
memcpy(buf, BUILD_FULL_DATE + 4, 2);
build.month = (uint8_t)atoi(buf);
// Äåíü
memcpy(buf, BUILD_FULL_DATE + 6, 2);
build.day = (uint8_t)atoi(buf);
// ×àñ
memcpy(buf, BUILD_FULL_DATE + 9, 2);
build.hour = (uint8_t)atoi(buf);
// Ìèíóòû
memcpy(buf, BUILD_FULL_DATE + 11, 2);
build.minute = (uint8_t)atoi(buf);
// Ñðàâíåíèå âñåõ ïîëåé
if (ext.year == build.year &&
ext.month == build.month &&
ext.day == build.day &&
ext.hour == build.hour &&
ext.minute == build.minute)
if (external_date->year == debug_ll.build_date.year &&
external_date->month == debug_ll.build_date.month &&
external_date->day == debug_ll.build_date.day &&
external_date->hour == debug_ll.build_date.hour &&
external_date->minute == debug_ll.build_date.minute)
{
debug_ll.isVerified = 1;
return 0; // Ñîâïàëî
}
debug_ll.isVerified = 0;
return 1; // Íå ñîâïàëî
return DEBUG_ERR_DATATIME; // Íå ñîâïàëî
}
/**
* @brief ×èòàåò âîçâðàùàåìûé òèï (IQ) íèçêîóðîâíåíî çàäàííîé ïåðåìåííîé.
* @param var_ind èíäåêñ ïåðåìåííîé.
* @param vartype óêàçàòåëü äëÿ âîçâðàòà òèïà.
* @return int 0: óñïåõ, 1: îøèáêà.
* @details Èñïîëüçóåòñÿ äëÿ ÷òåíèÿ âîçâðàùàåìîãî òèïà (IQ) ïåðåìåííûõ ïî èõ èíäåêñó.
*/
int Debug_LowLevel_ReadVarReturnType(int *vartype)
{
int rettype;
if(vartype == NULL)
return DEBUG_ERR_INTERNAL;
if((debug_ll.dbg_var.ptr_type == pt_struct) || (debug_ll.dbg_var.ptr_type == pt_union) ||
(debug_ll.dbg_var.ptr_type == pt_unknown))
return DEBUG_ERR_INVALID_VAR;
*vartype = iqTypeToQ(debug_ll.dbg_var.return_type);
return 0;
}
/**
* @brief ×èòàåò òèï íèçêîóðîâíåíî çàäàííîé ïåðåìåííîé.
* @param var_ind èíäåêñ ïåðåìåííîé.
* @param vartype óêàçàòåëü äëÿ âîçâðàòà òèïà.
* @return int 0: óñïåõ, 1: îøèáêà.
*/
int Debug_LowLevel_ReadVarType(int *vartype)
{
int rettype;
if(vartype == NULL)
return DEBUG_ERR_INTERNAL;
if((debug_ll.dbg_var.ptr_type == pt_struct) || (debug_ll.dbg_var.ptr_type == pt_union) ||
(debug_ll.dbg_var.ptr_type == pt_unknown))
return DEBUG_ERR_INVALID_VAR;
*vartype = debug_ll.dbg_var.ptr_type;
switch(debug_ll.dbg_var.ptr_type)
{
case pt_int8:
case pt_int16:
case pt_int32:
case pt_float:
*vartype = debug_ll.dbg_var.ptr_type | DEBUG_SIGNED_VAR;
break;
default:
*vartype = debug_ll.dbg_var.ptr_type;
break;
}
return 0;
}
/////////////////////----INTERNAL FUNCTIONS-----////////////////////////
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
/**
* @brief Ïðåîáðàçóåò òèï IQ ïåðåìåííîé â ÷èñëî áèòîâ äëÿ ñäâèãà(Q-ôàêòîð).
* @param t òèï IQ (ïåðå÷èñëåíèå DebugVarIQType_t).
* @return int Q-ôàêòîð (íàïðèìåð, 24), 0: åñëè t_iq_none, -1: îøèáêà.
* @details Ñîïîñòàâëÿåò òèï IQ ïåðåìåííîé ñ ñîîòâåòñòâóþùèì Q-çíà÷åíèåì.
*/
static int iqTypeToQ(DebugVarIQType_t t)
{
long iq_numb, iq_united, iq_final;
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 0; // îøèáêà
}
/**
* @brief Ïðåîáðàçóåò ïåðåìåííóþ îòëàäêè â IQ ôîðìàò.
* @param var óêàçàòåëü íà ïåðåìåííóþ îòëàäêè.
* @param ret_var óêàçàòåëü äëÿ âîçâðàòà çíà÷åíèÿ â ôîðìàòå 32 áèòà.
* @return int 0: óñïåõ, 1: îøèáêà ÷òåíèÿ, 2: íåïðàâèëüíûé ôîðìàò, 3: ïåðåïîëíåíèå.
* @details Îïðåäåëÿåò ôîðìàò IQ ïåðåìåííîé, êîíâåðòèðóåò å¸ â 32b ñ ó÷¸òîì ìàñøòàáà.
*/
static int convertDebugVarToIQx(DebugVar_t *var, int32_t *ret_var)
{
int32_t iq_numb, iq_united, iq_final;
int64_t iq_united64 = 0;
int64_t iq_final64 = 0;
int status;
float float_numb;
if(getDebugVar(var, &iq_numb, &float_numb) != 0)
return 1;
status = getDebugVar(var, &iq_numb, &float_numb);
if(status != 0)
return status;
// ïðèâåäåíèå ê îäíîìó IQ
switch(var->iq_type)
{
case t_iq_none:
if(var->ptr_type == pt_float)
{
iq_united = _IQ(float_numb);
int src_q = iqTypeToQ(var->iq_type);
int dst_q = iqTypeToQ(var->return_type);
// Êîíâåðòàöèÿ ê GLOBAL_Q (64-áèò)
if (var->iq_type == t_iq_none) {
if (var->ptr_type == pt_float) {
// float_numb óìíîæàåì íà 2^GLOBAL_Q
// Ðåçóëüòàò ïðèâîäèì ê 64 áèòà
iq_united64 = (int64_t)(float_numb * ((uint32_t)1 << GLOBAL_Q));
} else {
iq_united64 = ((int64_t)iq_numb) << GLOBAL_Q;
}
} else {
int shift = GLOBAL_Q - src_q;
if (shift >= 0)
iq_united64 = ((int64_t)iq_numb) << shift;
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_united64 = ((int64_t)iq_numb) >> (-shift);
}
// ïðèâåäåíèå îáùåãî IQ ê çàïðàøèâàåìîìó
switch(var->return_type)
{
case t_iq_none:
iq_final = (int)_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;
// Êîíâåðòàöèÿ èç GLOBAL_Q â öåëåâîé IQ (64-áèò)
if (var->return_type == t_iq_none) {
// Âîçâðàùàåì öåëîå, îòáðîñèâ äðîáíóþ ÷àñòü
*ret_var = (uint32_t)(iq_united64 >> GLOBAL_Q);
} else {
int shift = dst_q - GLOBAL_Q;
if (shift >= 0)
iq_final64 = iq_united64 << shift;
else
iq_final64 = iq_united64 >> (-shift);
*ret_var = (int32_t)iq_final64;
}
*ret_var = iq_final;
return 0;
}
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
/**
* @brief Ïðî÷èòàòü çíà÷åíèå ïåðåìåííîé îòëàäêè.
* @param var óêàçàòåëü íà ñòðóêòóðó DebugVar.
* @param int_var óêàçàòåëü íà ïåðåìåííóþ òèïà 32 áèòà äëÿ âîçâðàòà öåëî÷èñëåííîãî çíà÷åíèÿ.
* @param float_var óêàçàòåëü íà ïåðåìåííóþ òèïà float äëÿ âîçâðàòà çíà÷åíèÿ ñ ïëàâàþùåé òî÷êîé.
* @return int 0: óñïåõ, 1: îøèáêà óêàçàòåëåé èëè íåïîääåðæèâàåìûé òèï, 3/4: îøèáêà âûðàâíèâàíèÿ.
* @details  çàâèñèìîñòè îò òèïà ïåðåìåííîé ñ÷èòûâàåò å¸ çíà÷åíèå è ñîõðàíÿåò â ñîîòâåòñòâóþùåì óêàçàòåëå.
*/
static int getDebugVar(DebugVar_t *var, int32_t *int_var, float *float_var)
{
if (!var || !int_var || !float_var || !var->Ptr)
return 1; // îøèáêà: null óêàçàòåëü
uint8_t *addr = var->Ptr;
uint32_t addr_val = (uint32_t)addr;
char *addr = var->Ptr;
unsigned long addr_val = (unsigned long)addr;
if (!var || !int_var || !float_var || !var->Ptr)
return DEBUG_ERR_INTERNAL; // îøèáêà: null óêàçàòåëü
switch (var->ptr_type)
{
case pt_int8: // 8 áèò
if ((addr_val & ALIGN_8BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return DEBUG_ERR_ADDR_ALIGN; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile int8_t *)addr);
break;
case pt_uint8:
// âûðàâíèâàíèå íå íóæíî äëÿ 8 áèò
*int_var = *((volatile char *)addr);
if ((addr_val & ALIGN_8BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return DEBUG_ERR_ADDR_ALIGN; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile uint8_t *)addr);
break;
case pt_int16: // 16 áèò (int)
if ((addr_val & ALIGN_16BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return DEBUG_ERR_ADDR_ALIGN; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile int16_t *)addr);
break;
case pt_uint16:
if (addr_val & 0x1) // ïðîâåðêà âûðàâíèâàíèÿ ïî 2 áàéòàì
return 2; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile int *)addr);
if ((addr_val & ALIGN_16BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return DEBUG_ERR_ADDR_ALIGN; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile uint16_t *)addr);
break;
case pt_int32: // 32 áèò (long)
case pt_int32: // 32 áèò
if ((addr_val & ALIGN_32BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return DEBUG_ERR_ADDR_ALIGN; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile int32_t *)addr);
break;
case pt_uint32:
if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 áàéòàì
return 3; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile long *)addr);
if ((addr_val & ALIGN_32BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return DEBUG_ERR_ADDR_ALIGN; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile uint32_t *)addr);
break;
// case pt_int64: // 64 áèò (long long)
// case pt_uint64:
// if (addr_val & 0x7) // ïðîâåðêà âûðàâíèâàíèÿ ïî 8 áàéòàì
// return 2; // îøèáêà âûðàâíèâàíèÿ
// // Òóò ïðîñòî ÷èòàåì, íî long long ìîæåò íå ïîìåñòèòüñÿ â *int_var
// // Ìîæíî çàìåíèòü ëîãèêó ïîä 64-áèòíîå ÷òåíèå ïðè íåîáõîäèìîñòè
// *int_var = *((volatile long long *)addr);
// break;
case pt_float: // float (4 áàéòà)
if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 áàéòàì
return 4; // îøèáêà âûðàâíèâàíèÿ
if ((addr_val & ALIGN_FLOAT) != 0) // ïðîâåðêà âûðàâíèâàíèÿ
return DEBUG_ERR_ADDR_ALIGN; // îøèáêà âûðàâíèâàíèÿ
*float_var = *((volatile float *)addr);
break;
default:
return 1; // íåïîääåðæèâàåìûé òèï
return DEBUG_ERR_INVALID_VAR; // íåïîääåðæèâàåìûé òèï
// äëÿ óêàçàòåëåé è ìàññèâîâ íå ïîääåðæèâàåòñÿ ÷òåíèå
// case pt_ptr_int8:
// case pt_ptr_int16:
@@ -402,3 +428,24 @@ static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
return 0; // óñïåõ
}
/**
* @brief Ïðîâåðÿåò, âõîäèò ëè àäðåñ â îäèí èç äîïóñòèìûõ äèàïàçîíîâ
*
* @param addr_val - Çíà÷åíèå àäðåñà äëÿ ïðîâåðêè
* @param ranges - Óêàçàòåëü íà ìàññèâ äèàïàçîíîâ AddrRange_t
* @param count - Êîëè÷åñòâî äèàïàçîíîâ â ìàññèâå
* @return 0 åñëè àäðåñ íàõîäèòñÿ â îäíîì èç äèàïàçîíîâ, èíà÷å 1
*/
static int is_addr_in_allowed_ranges(uint32_t addr_val, const AddrRange_t *ranges, int count)
{
int i;
for (i = 0; i < count; i++) {
if (addr_val >= ranges[i].start && addr_val <= ranges[i].end) {
return 0;
}
}
return 1;
}

View File

@@ -1,8 +1,65 @@
#ifndef DEBUG_TOOLS
#define DEBUG_TOOLS
#include "IQmathLib.h"
#include "DSP281x_Device.h"
#include <stdint.h>
#include <limits.h>
#define ALLOWED_ADDRESS_RANGES { \
{0x000000, 0x0007FF}, \
{0x008120, 0x009FFC}, \
{0x3F8000, 0x3F9FFF}, \
{0x3FF000, 0x3FFFFF}, \
{0x080002, 0x09FFFF}, \
{0x0F0000, 0x0FFEFF}, \
{0x100002, 0x103FFF}, \
{0x102000, 0x103FFF} \
}
#if UINT8_MAX // Åñëè åñòü òèï 8 áèò - çí÷à÷èò àäðåñàöèÿ ïî 8 áèò
#define ALIGN_8BIT 0x0 ///< Âûðàâíèâàíèå áåç îãðàíè÷åíèé (ëþáîé àäðåñ)
#define ALIGN_16BIT 0x1 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 2 (addr & 0x1 == 0)
#define ALIGN_32BIT 0x3 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 4 (addr & 0x3 == 0)
#define ALIGN_64BIT 0x7 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 8 (addr & 0x7 == 0)
#define ALIGN_FLOAT ALIGN_32BIT
#else // Åñëè íåò òèïà 8 áèò - çíà÷èò àäðåñàöèÿ ïî 16 áèò
#define ALIGN_8BIT 0x0 ///< Âûðàâíèâàíèå áåç îãðàíè÷åíèé (ëþáîé àäðåñ)
#define ALIGN_16BIT 0x0 ///< Âûðàâíèâàíèå áåç îãðàíè÷åíèé (ëþáîé àäðåñ)
#define ALIGN_32BIT 0x1 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 4 (addr & 0x1 == 0)
#define ALIGN_64BIT 0x3 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 8 (addr & 0x3 == 0)
#define ALIGN_FLOAT ALIGN_32BIT
#endif //STM32/TMS32
#if !UINT8_MAX
typedef unsigned char uint8_t;
typedef signed char int8_t;
#endif
#if !defined(NULL)
#define NULL 0
#endif
#define DEBUG_SIGNED_VAR (1<<7)
#define DEBUG_OK (0)
#define DEBUG_ERR (1<<7)
#define DEBUG_ERR_VAR_NUMB (1<<0) | DEBUG_ERR
#define DEBUG_ERR_INVALID_VAR (1<<1) | DEBUG_ERR
#define DEBUG_ERR_ADDR (1<<2) | DEBUG_ERR
#define DEBUG_ERR_ADDR_ALIGN (1<<3) | DEBUG_ERR
#define DEBUG_ERR_INTERNAL (1<<4) | DEBUG_ERR
#define DEBUG_ERR_DATATIME (1<<5) | DEBUG_ERR
#define DEBUG_ERR_RS (1<<6) | DEBUG_ERR
/**
* @brief Òèï äàííûõ, íà êîòîðûé óêàçûâàåò óêàçàòåëü ïåðåìåííîé îòëàäêè.
*/
typedef enum
{
pt_unknown, // unknown
@@ -14,7 +71,7 @@ typedef enum
pt_uint16, // unsigned int
pt_uint32, // unsigned long
pt_uint64, // unsigned long
pt_float, // float
pt_float, // floatf
pt_struct, // struct
pt_union, // struct
// pt_ptr_int8, // signed char*
@@ -31,6 +88,9 @@ typedef enum
// pt_arr_uint32, // unsigned long[]
}DebugVarPtrType_t;
/**
* @brief Òèïû IQ-ïðåäñòàâëåíèÿ ïåðåìåííîé îòëàäêè.
*/
typedef enum
{
t_iq_none,
@@ -67,30 +127,83 @@ typedef enum
t_iq30
}DebugVarIQType_t;
typedef char DebugVarName_t[11]; ///< Èìÿ ïåðåìåííîé îòëàäêè (äî 10 ñèìâîëîâ + \0)
/**
* @brief Îïèñàíèå ïåðåìåííîé îòëàäêè.
*/
typedef struct
{
char* Ptr;
DebugVarPtrType_t ptr_type;
DebugVarIQType_t iq_type;
DebugVarIQType_t return_type;
char name[11]; // 10 ñèìâîëîâ + '\0'
}DebugVar_t;
uint8_t* Ptr; ///< Óêàçàòåëü íà çíà÷åíèå ïåðåìåííîé
DebugVarPtrType_t ptr_type; ///< Òèï çíà÷åíèÿ
DebugVarIQType_t iq_type; ///< Òèï IQ ïåðåìåííîé (åñëè åñòü)
DebugVarIQType_t return_type;///< Òèï IQ âîçâðàùàåìîãî çíà÷åíèÿ
DebugVarName_t name; ///< Èìÿ ïåðåìåííîé
} DebugVar_t;
typedef long DebugValue_t;
/**
* @brief Ñòðóêòóðà äàòû è âðåìåíè.
*/
typedef struct {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
} DateTimeHex;
uint16_t year; ///< Ãîä (íàïðèìåð, 2025)
uint8_t month; ///< Ìåñÿö (1-12)
uint8_t day; ///< Äåíü (1-31)
uint8_t hour; ///< ×àñû (0-23)
uint8_t minute; ///< Ìèíóòû (0-59)
} DateTime_t;
/**
* @brief Ñòðóêòóðà, îïèñûâàþùàÿ äèàïàçîí àäðåñîâ ïàìÿòè.
*/
typedef struct {
uint32_t start; ///< Íà÷àëüíûé àäðåñ äèàïàçîíà
uint32_t end; ///< Êîíå÷íûé àäðåñ äèàïàçîíà (âêëþ÷èòåëüíî)
} AddrRange_t;
/**
* @brief Ñòðóêòóðà íèæíåãî óðîâíÿ îòëàäêè.
*/
typedef struct
{
DateTime_t build_date; ///< Äàòà ñáîðêè
unsigned int isVerified; ///< Ôëàã èíèöèàëèçàöèè íèçêîóðîâíåíîé îòëàäêè (0 — íåò, 1 — óñïåøíî)
DebugVar_t dbg_var; ///< Ïåðåìåííàÿ äëÿ îòëàäêè
}DebugLowLevel_t;
extern DebugLowLevel_t debug_ll; ///< Ãëîáàëüíûé ýêçåìïëÿð îòëàäêè íèæíåãî óðîâíÿ
extern int DebugVar_Qnt;
extern DebugVar_t dbg_vars[];
/** @brief Ìàêðîñ èíèöèàëèçàöèè äàòû */
#define DATE_INIT {BUILD_YEAR, BUILD_MONTH, BUILD_DATA, BUILD_HOURS, BUILD_MINUTES}
/** @brief Ìàêðîñ èíèöèàëèçàöèè ïåðåìåííîé îòëàäêè */
#define DEBUG_VAR_INIT {0, pt_uint16, t_iq_none, t_iq_none, "\0"}
/** @brief Ìàêðîñ èíèöèàëèçàöèè íèæíåãî óðîâíÿ îòëàäêè */
#define DEBUG_LOWLEVEL_INIT {DATE_INIT, 0, DEBUG_VAR_INIT}
int Debug_LowLevel_ReadVar(DebugVar_t *var_ll, long *return_long);
int Debug_ReadVar(DebugVar_t *var, long *return_long);
int Debug_ReadVarName(DebugVar_t *var, char *name_ptr);
extern int DebugVar_Qnt; ///< Êîëè÷åñòâî ïåðåìåííûõ îòëàäêè
extern DebugVar_t dbg_vars[]; ///< Ìàññèâ ïåðåìåííûõ îòëàäêè
/* Ïðèìåð èñïîëüçîâàíèÿ îòëàäêè */
void Debug_Test_Example(void);
/* ×èòàåò çíà÷åíèå ïåðåìåííîé ïî èíäåêñó */
int Debug_ReadVar(int var_ind, int32_t *return_long);
/* ×èòàåò èìÿ ïåðåìåííîé ïî èíäåêñó */
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr, int *length);
/* ×èòàåò âîçâðàùàåìûé òèï (IQ) ïåðåìåííîé ïî èíäåêñó */
int Debug_ReadVarReturnType(int var_ind, int *vartype);
/* ×èòàåò òèï ïåðåìåííîé ïî èíäåêñó */
int Debug_ReadVarType(int var_ind, int *vartype);
/* ×èòàåò çíà÷åíèå ïåðåìåííîé ñ íèæíåãî óðîâíÿ */
int Debug_LowLevel_ReadVar(int32_t *return_long);
/* Èíèöèàëèçèðóåò îòëàäêó íèæíåãî óðîâíÿ */
int Debug_LowLevel_Initialize(DateTime_t *external_date);
/* ×èòàåò âîçâðàùàåìûé òèï (IQ) íèçêîóðîâíåíî çàäàííîé ïåðåìåííîé */
int Debug_LowLevel_ReadVarReturnType(int *vartype);
/* ×èòàåò òèï íèçêîóðîâíåíî çàäàííîé ïåðåìåííîé.*/
int Debug_LowLevel_ReadVarType(int *vartype);
#endif //DEBUG_TOOLS

View File

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

417
parse_xml/Src/parse_xml.py Normal file
View File

@@ -0,0 +1,417 @@
# pyinstaller --onefile --distpath ./parse_xml --workpath ./parse_xml/build --specpath ./build parse_xml/Src/parse_xml.py
# python -m nuitka --standalone --onefile --output-dir=./parse_xml parse_xml/Src/parse_xml.py
import xml.etree.ElementTree as ET
import xml.dom.minidom
import sys
import os
if len(sys.argv) < 3:
print("Usage: python parse_xml.exe <input.xml> <info.txt> [output.xml]")
sys.exit(1)
input_path = sys.argv[1]
info_path = sys.argv[2]
base_type_sizes = {
"char": 2,
"short": 2,
"int": 2,
"long": 4,
"long long": 8,
"float": 4,
"double": 8,
}
if len(sys.argv) >= 4:
output_path = sys.argv[3]
else:
input_dir = os.path.dirname(os.path.abspath(input_path))
output_path = os.path.join(input_dir, "simplified.xml")
tree = ET.parse(input_path)
root = tree.getroot()
def extract_timestamp(info_path):
with open(info_path, "r", encoding="utf-8") as f:
for line in f:
if "Time Stamp:" in line:
parts = line.split("Time Stamp:")
if len(parts) > 1:
timestamp = parts[1].strip()
return timestamp
die_by_id = {die.attrib.get("id"): die for die in root.iter("die") if "id" in die.attrib}
def get_attr(die, attr_type):
for attr in die.findall("attribute"):
type_elem = attr.find("type")
if type_elem is not None and type_elem.text == attr_type:
return attr.find("value")
return None
def get_die_size(die):
"""Вернуть размер DIE в байтах из атрибута DW_AT_byte_size или по ключевым словам имени типа."""
# Сначала пытаемся получить размер из DW_AT_byte_size
for attr in die.findall("attribute"):
type_elem = attr.find("type")
if type_elem is not None and type_elem.text == "DW_AT_byte_size":
const_elem = attr.find("value/const")
if const_elem is not None:
return int(const_elem.text, 0)
# Если не нашли, пробуем определить размер по ключевым словам в имени типа
name_elem = die.find("attribute[@name='DW_AT_name']/value/const")
if name_elem is not None:
type_name = name_elem.text.lower()
for key, size in base_type_sizes.items():
if key in type_name:
return size
return None
def resolve_type_die(type_id):
"""Получить DIE типа, разрешая typedef, const и volatile."""
visited = set()
while type_id and type_id not in visited:
visited.add(type_id)
die = die_by_id.get(type_id)
if die is None:
return None
tag = die.findtext("tag")
if tag in ("DW_TAG_volatile_type", "DW_TAG_const_type", "DW_TAG_typedef", "DW_TAG_TI_far_type"):
ref = get_attr(die, "DW_AT_type")
if ref is not None and ref.find("ref") is not None:
type_id = ref.find("ref").attrib.get("idref")
else:
return None
else:
return die
return None
# Словарь для простых базовых типов по тегам (пример)
base_types_map = {
"DW_TAG_base_type": lambda die: die.find("attribute[@type='DW_AT_name']/value/string").text if die.find("attribute[@type='DW_AT_name']/value/string") is not None else "unknown",
"DW_TAG_structure_type": lambda die: "struct",
"DW_TAG_union_type": lambda die: "union",
"DW_TAG_pointer_type": lambda die: "pointer",
"DW_TAG_array_type": lambda die: "array",
}
def get_type_name(type_id):
die = resolve_type_die(type_id)
if die is None:
return "unknown"
tag = die.findtext("tag")
if tag == "DW_TAG_pointer_type":
ref = get_attr(die, "DW_AT_type")
if ref is not None and ref.find("ref") is not None:
pointee_id = ref.find("ref").attrib.get("idref")
name = get_type_name(pointee_id)
return name + "*" if name != "unknown" else name
else:
return "void*"
elif tag == "DW_TAG_base_type":
name_attr = get_attr(die, "DW_AT_name")
if name_attr is not None:
return name_attr.findtext("string")
else:
return "base_type_unknown"
elif tag == "DW_TAG_structure_type":
name_attr = get_attr(die, "DW_AT_name")
name = name_attr.findtext("string") if name_attr is not None else "anonymous_struct"
return f"struct {name}"
elif tag == "DW_TAG_union_type":
name_attr = get_attr(die, "DW_AT_name")
name = name_attr.findtext("string") if name_attr is not None else "anonymous_union"
return f"union {name}"
elif tag == "DW_TAG_array_type":
ref = get_attr(die, "DW_AT_type")
if ref is not None and ref.find("ref") is not None:
element_type_id = ref.find("ref").attrib.get("idref")
element_type_name = get_type_name(element_type_id)
return f"{element_type_name}[]"
else:
return "array[]"
# Добавляем поддержку enum
elif tag == "DW_TAG_enumeration_type":
name_attr = get_attr(die, "DW_AT_name")
name = name_attr.findtext("string") if name_attr is not None else "anonymous_enum"
return f"enum {name}"
else:
return "unknown"
def parse_offset(offset_text):
if offset_text and offset_text.startswith("DW_OP_plus_uconst "):
return int(offset_text.split()[-1], 0)
return 0
def get_base_type_die(array_die):
"""Спускаемся по цепочке DW_AT_type, пока не дойдем до не-массива (базового типа)."""
current_die = array_die
while True:
ref = get_attr(current_die, "DW_AT_type")
if ref is None or ref.find("ref") is None:
break
next_die = resolve_type_die(ref.find("ref").attrib.get("idref"))
if next_die is None:
break
if next_die.findtext("tag") == "DW_TAG_array_type":
current_die = next_die
else:
return next_die
return current_die
def get_array_dimensions(array_die):
dims = []
# Итерируем по всем DIE с тегом DW_TAG_subrange_type, потомки текущего массива
for child in array_die.findall("die"):
if child.findtext("tag") != "DW_TAG_subrange_type":
continue
dim_size = None
ub_attr = get_attr(child, "DW_AT_upper_bound")
if ub_attr is not None:
# Попробуем разные варианты получить значение upper_bound
# 1) value/const
val_const = ub_attr.find("const")
if val_const is not None:
try:
dim_size = int(val_const.text, 0) + 1
#print(f"[DEBUG] Found DW_AT_upper_bound const: {val_const.text}, size={dim_size}")
except Exception as e:
a=1#print(f"[WARN] Error parsing upper_bound const: {e}")
else:
# 2) value/block (DW_OP_constu / DW_OP_plus_uconst, etc.)
val_block = ub_attr.find("block")
if val_block is not None:
block_text = val_block.text
# Можно попытаться парсить DWARF expr (например DW_OP_plus_uconst 7)
if block_text and "DW_OP_plus_uconst" in block_text:
try:
parts = block_text.split()
val = int(parts[-1], 0)
dim_size = val + 1
#print(f"[DEBUG] Parsed upper_bound block: {val} + 1 = {dim_size}")
except Exception as e:
a=1#print(f"[WARN] Error parsing upper_bound block: {e}")
else:
a=1#print(f"[WARN] Unexpected DW_AT_upper_bound block content: {block_text}")
else:
a=1#print(f"[WARN] DW_AT_upper_bound has no const or block value")
if dim_size is None:
# fallback по DW_AT_count — редко встречается
ct_attr = get_attr(child, "DW_AT_count")
if ct_attr is not None:
val_const = ct_attr.find("value/const")
if val_const is not None:
try:
dim_size = int(val_const.text, 0)
#print(f"[DEBUG] Found DW_AT_count: {dim_size}")
except Exception as e:
a=1#print(f"[WARN] Error parsing DW_AT_count const: {e}")
if dim_size is None:
print("[DEBUG] No dimension size found for this subrange, defaulting to 0")
dim_size = 0
dims.append(dim_size)
# Если не нашли измерений — пытаемся вычислить размер массива по общему размеру
if not dims:
arr_size = get_die_size(array_die)
elem_size = None
element_type_ref = get_attr(array_die, "DW_AT_type")
if element_type_ref is not None and element_type_ref.find("ref") is not None:
element_type_id = element_type_ref.find("ref").attrib.get("idref")
elem_die = resolve_type_die(element_type_id)
if elem_die is not None:
elem_size = get_die_size(elem_die)
#print(f"[DEBUG] Fallback: arr_size={arr_size}, elem_size={elem_size}")
if arr_size is not None and elem_size:
dim_calc = arr_size // elem_size
dims.append(dim_calc)
#print(f"[DEBUG] Calculated dimension size from total size: {dim_calc}")
else:
dims.append(0)
print("[DEBUG] Could not calculate dimension size, set 0")
# Рекурсивно обрабатываем вложенные массивы
element_type_ref = get_attr(array_die, "DW_AT_type")
if element_type_ref is not None and element_type_ref.find("ref") is not None:
element_type_id = element_type_ref.find("ref").attrib.get("idref")
element_type_die = resolve_type_die(element_type_id)
if element_type_die is not None and element_type_die.findtext("tag") == "DW_TAG_array_type":
dims.extend(get_array_dimensions(element_type_die))
#print(f"[DEBUG] Array dimensions: {dims}")
return dims
def handle_array_type(member_elem, resolved_type, offset=0):
dims = get_array_dimensions(resolved_type)
base_die = get_base_type_die(resolved_type)
base_name = "unknown"
base_size = None
if base_die is not None:
base_id = base_die.attrib.get("id")
if base_id:
base_name = get_type_name(base_id)
base_size = get_die_size(base_die)
else:
base_name = get_type_name(base_die.attrib.get("id", ""))
#print(f"[DEBUG] Base type name: {base_name}, base size: {base_size}")
member_elem.set("type", base_name + "[]" * len(dims))
if base_size is None:
base_size = 0
total_elements = 1
for d in dims:
if d == 0:
total_elements = 0
print(f"[WARN] Dimension size is zero, setting total elements to 0")
break
total_elements *= d
total_size = total_elements * base_size if base_size is not None else 0
if total_size:
member_elem.set("size", str(base_size if base_size is not None else 1))
else:
arr_size = get_die_size(resolved_type)
if arr_size:
member_elem.set("size", str(arr_size))
#print(f"[DEBUG] Used fallback size from resolved_type: {arr_size}")
else:
print(f"[WARN] Could not determine total size for array")
for i, dim in enumerate(dims, 1):
member_elem.set(f"size{i}", str(dim))
#print(f"[DEBUG] Setting size{i} = {dim}")
member_elem.set("kind", "array")
if base_die is not None and base_die.findtext("tag") == "DW_TAG_structure_type":
add_members_recursive(member_elem, base_die, offset)
def add_members_recursive(parent_elem, struct_die, base_offset=0):
is_union = struct_die.findtext("tag") == "DW_TAG_union_type"
size = get_die_size(struct_die)
if size is not None:
parent_elem.set("size", hex(size))
for member in struct_die.findall("die"):
if member.findtext("tag") != "DW_TAG_member":
continue
name_attr = get_attr(member, "DW_AT_name")
offset_attr = get_attr(member, "DW_AT_data_member_location")
type_attr = get_attr(member, "DW_AT_type")
if name_attr is None or offset_attr is None or type_attr is None:
continue
name = name_attr.findtext("string")
offset = parse_offset(offset_attr.findtext("block")) + base_offset
type_id = type_attr.find("ref").attrib.get("idref")
resolved_type = resolve_type_die(type_id)
type_name = get_type_name(type_id)
if type_name == "unknown":
continue
member_elem = ET.SubElement(parent_elem, "member", name=name, offset=hex(offset), type=type_name)
if is_union:
member_elem.set("kind", "union")
if resolved_type is not None:
tag = resolved_type.findtext("tag")
if tag == "DW_TAG_array_type":
handle_array_type(member_elem, resolved_type, offset)
elif tag in ("DW_TAG_structure_type", "DW_TAG_union_type"):
member_elem.set("type", type_name)
add_members_recursive(member_elem, resolved_type, offset)
elif tag == "DW_TAG_pointer_type":
# Проверяем тип, на который указывает указатель
pointee_ref = get_attr(resolved_type, "DW_AT_type")
if pointee_ref is not None and pointee_ref.find("ref") is not None:
pointee_id = pointee_ref.find("ref").attrib.get("idref")
pointee_die = resolve_type_die(pointee_id)
if pointee_die is not None:
pointee_tag = pointee_die.findtext("tag")
if pointee_tag in ("DW_TAG_structure_type", "DW_TAG_union_type"):
# Добавляем подэлементы для структуры, на которую указывает указатель
pointer_elem = ET.SubElement(member_elem, "pointee", type=get_type_name(pointee_id))
add_members_recursive(pointer_elem, pointee_die, 0)
output_root = ET.Element("variables")
for die in root.iter("die"):
if die.findtext("tag") != "DW_TAG_variable":
continue
name_attr = get_attr(die, "DW_AT_name")
addr_attr = get_attr(die, "DW_AT_location")
type_attr = get_attr(die, "DW_AT_type")
if name_attr is None or addr_attr is None or type_attr is None:
continue
name = name_attr.findtext("string")
if "$" in name:
continue
addr_text = addr_attr.findtext("block")
if not addr_text or not addr_text.startswith("DW_OP_addr "):
continue
addr = int(addr_text.split()[-1], 0)
type_id = type_attr.find("ref").attrib.get("idref")
resolved_type = resolve_type_die(type_id)
type_name = get_type_name(type_id)
if 0x800 <= addr < 0x8000 or type_name == "unknown":
continue
var_elem = ET.SubElement(output_root, "variable", name=name, address=hex(addr), type=type_name)
if resolved_type is not None:
tag = resolved_type.findtext("tag")
if tag == "DW_TAG_array_type":
handle_array_type(var_elem, resolved_type)
elif tag in ("DW_TAG_structure_type", "DW_TAG_union_type"):
add_members_recursive(var_elem, resolved_type)
timestamp = extract_timestamp(info_path)
timestamp_elem = ET.Element("timestamp")
timestamp_elem.text = timestamp
output_root.insert(0, timestamp_elem)
rough_string = ET.tostring(output_root, encoding="utf-8")
pretty_xml = xml.dom.minidom.parseString(rough_string).toprettyxml(indent=" ")
with open(output_path, "w", encoding="utf-8") as f:
f.write(pretty_xml)
os.remove(input_path)
os.remove(info_path)
print(f"Simplified and formatted XML saved to: {output_path}")

BIN
parse_xml/parse_xml.exe Normal file

Binary file not shown.

20181
structs.xml

File diff suppressed because it is too large Load Diff

4868
vars.xml
View File

@@ -1,4868 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<analysis makefile_path="Debug/makefile" proj_path="F:/Work/Projects/TMS/TMS_new_bus" structs_path="Src/DebugTools/structs.xml">
<variables>
<var name="ADC1startAddr">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC1StrAdr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC2finishAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ADC2finishAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC2startAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ADC2startAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_f">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ADC_f</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[2][16]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ADC_sf</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[2][16]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADDR_FOR_ALL">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ADDR_FOR_ALL</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="BUSY">
<show_var>false</show_var>
<enable>false</enable>
<shortname>BUSY</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Bender">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Bender</shortname>
<pt_type>pt_arr_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>BENDER[2]</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CAN_answer_wait">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CAN_answer_wait</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CAN_count_cycle_input_units">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CAN_count_cycle_input_units</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[8]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CAN_no_answer">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CAN_no_answer</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CAN_refresh_cicle">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CAN_refresh_cicle</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CAN_request_sent">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CAN_request_sent</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CAN_timeout">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CAN_timeout</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CAN_timeout_cicle">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CAN_timeout_cicle</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CNTRL_ADDR">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CNTRL_ADDR</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CNTRL_ADDR_UNIVERSAL">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CNTRL_ADDR_UNIVERSAL</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>const int</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CONST_15">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CONST_15</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/myLibs/mathlib.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CONST_23">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CONST_23</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/myLibs/mathlib.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CanOpenUnites">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CanOpenUnites</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[30]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="CanTimeOutErrorTR">
<show_var>false</show_var>
<enable>false</enable>
<shortname>CanTimeOutErrorTR</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Controll">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Controll</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>XControll_reg</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Dpwm">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Dpwm</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Dpwm2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Dpwm2</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Dpwm4">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Dpwm4</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="EvaTimer1InterruptCount">
<show_var>false</show_var>
<enable>false</enable>
<shortname>EvaTimer1InterruptCount</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="EvaTimer2InterruptCount">
<show_var>false</show_var>
<enable>false</enable>
<shortname>EvaTimer2InterruptCount</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="EvbTimer3InterruptCount">
<show_var>false</show_var>
<enable>false</enable>
<shortname>EvbTimer3InterruptCount</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="EvbTimer4InterruptCount">
<show_var>false</show_var>
<enable>false</enable>
<shortname>EvbTimer4InterruptCount</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Fpwm">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Fpwm</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Gott">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Gott</shortname>
<pt_type>pt_arr_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char[8][16]</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="IN0finishAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>IN0finishAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="IN0startAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>IN0startAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="IN1finishAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>IN1finishAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="IN1startAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>IN1startAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="IN2finishAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>IN2finishAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="IN2startAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>IN2startAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="IQ_OUT_NOM">
<show_var>false</show_var>
<enable>false</enable>
<shortname>IQ_OUT_NOM</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="I_OUT_1_6_NOMINAL_IQ">
<show_var>false</show_var>
<enable>false</enable>
<shortname>I_OUT_1_6_NOMINAL_IQ</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="I_OUT_1_8_NOMINAL_IQ">
<show_var>false</show_var>
<enable>false</enable>
<shortname>I_OUT_1_8_NOMINAL_IQ</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="I_OUT_NOMINAL">
<show_var>false</show_var>
<enable>false</enable>
<shortname>I_OUT_NOMINAL</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="I_OUT_NOMINAL_IQ">
<show_var>false</show_var>
<enable>false</enable>
<shortname>I_OUT_NOMINAL_IQ</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="I_ZPT_NOMINAL_IQ">
<show_var>false</show_var>
<enable>false</enable>
<shortname>I_ZPT_NOMINAL_IQ</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Id_out_max_full">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Id_out_max_full</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/VectorControl/regul_power.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Id_out_max_low_speed">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Id_out_max_low_speed</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/VectorControl/regul_power.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Iq_out_max">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Iq_out_max</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Iq_out_nom">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Iq_out_nom</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/params_i_out.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="K_LEM_ADC">
<show_var>false</show_var>
<enable>false</enable>
<shortname>K_LEM_ADC</shortname>
<pt_type>pt_arr_uint32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>const unsigned long[20]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="KmodTerm">
<show_var>false</show_var>
<enable>false</enable>
<shortname>KmodTerm</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ROTfinishAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ROTfinishAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="RS_Len">
<show_var>false</show_var>
<enable>false</enable>
<shortname>RS_Len</shortname>
<pt_type>pt_arr_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int[70]</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="R_ADC">
<show_var>false</show_var>
<enable>false</enable>
<shortname>R_ADC</shortname>
<pt_type>pt_arr_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>const unsigned int[20]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="RotPlaneStartAddr">
<show_var>false</show_var>
<enable>false</enable>
<shortname>RotPlaneStartAddr</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="SQRT_32">
<show_var>false</show_var>
<enable>false</enable>
<shortname>SQRT_32</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/myLibs/mathlib.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Unites">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Unites</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[8][128]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="VAR_FREQ_PWM_XTICS">
<show_var>false</show_var>
<enable>false</enable>
<shortname>VAR_FREQ_PWM_XTICS</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="VAR_PERIOD_MAX_XTICS">
<show_var>false</show_var>
<enable>false</enable>
<shortname>VAR_PERIOD_MAX_XTICS</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="VAR_PERIOD_MIN_BR_XTICS">
<show_var>false</show_var>
<enable>false</enable>
<shortname>VAR_PERIOD_MIN_BR_XTICS</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="VAR_PERIOD_MIN_XTICS">
<show_var>false</show_var>
<enable>false</enable>
<shortname>VAR_PERIOD_MIN_XTICS</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="Zpwm">
<show_var>false</show_var>
<enable>false</enable>
<shortname>Zpwm</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="a">
<show_var>false</show_var>
<enable>false</enable>
<shortname>a</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>WINDING</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="addrToSent">
<show_var>false</show_var>
<enable>false</enable>
<shortname>addrToSent</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>volatile AddrToSent</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="adr_read_from_modbus3">
<show_var>false</show_var>
<enable>false</enable>
<shortname>adr_read_from_modbus3</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="alarm_log_can">
<show_var>false</show_var>
<enable>false</enable>
<shortname>alarm_log_can</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ALARM_LOG_CAN</type>
<file>Src/myLibs/alarm_log_can.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="alarm_log_can_setup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>alarm_log_can_setup</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ALARM_LOG_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="analog">
<show_var>false</show_var>
<enable>false</enable>
<shortname>analog</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ANALOG_VALUE</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ar_sa_all">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ar_sa_all</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[3][6][4][7]</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ar_tph">
<show_var>false</show_var>
<enable>false</enable>
<shortname>ar_tph</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq[7]</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="biTemperatureLimits">
<show_var>false</show_var>
<enable>false</enable>
<shortname>biTemperatureLimits</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[12]</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="biTemperatureWarnings">
<show_var>false</show_var>
<enable>false</enable>
<shortname>biTemperatureWarnings</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[12]</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="block_size_counter_fast">
<show_var>false</show_var>
<enable>false</enable>
<shortname>block_size_counter_fast</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="block_size_counter_slow">
<show_var>false</show_var>
<enable>false</enable>
<shortname>block_size_counter_slow</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="break_result_1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>break_result_1</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="break_result_2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>break_result_2</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="break_result_3">
<show_var>false</show_var>
<enable>false</enable>
<shortname>break_result_3</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="break_result_4">
<show_var>false</show_var>
<enable>false</enable>
<shortname>break_result_4</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="bvTemperatureLimits">
<show_var>false</show_var>
<enable>false</enable>
<shortname>bvTemperatureLimits</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[12]</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="bvTemperatureWarnings">
<show_var>false</show_var>
<enable>false</enable>
<shortname>bvTemperatureWarnings</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[12]</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="byte">
<show_var>false</show_var>
<enable>false</enable>
<shortname>byte</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>Byte</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="c_s">
<show_var>false</show_var>
<enable>false</enable>
<shortname>c_s</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/main/rotation_speed.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="calibration1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>calibration1</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/isolation.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="calibration2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>calibration2</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/isolation.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="callfunc">
<show_var>false</show_var>
<enable>false</enable>
<shortname>callfunc</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>test_functions</type>
<file>Src/main/Main.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="canopen_can_setup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>canopen_can_setup</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>CANOPEN_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="capnum0">
<show_var>false</show_var>
<enable>false</enable>
<shortname>capnum0</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="capnum1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>capnum1</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="capnum2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>capnum2</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="capnum3">
<show_var>false</show_var>
<enable>false</enable>
<shortname>capnum3</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="chNum">
<show_var>false</show_var>
<enable>false</enable>
<shortname>chNum</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/x_example_all.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="chanell1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>chanell1</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>BREAK_PHASE_I</type>
<file>Src/main/detect_phase.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="chanell2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>chanell2</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>BREAK_PHASE_I</type>
<file>Src/main/detect_phase.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="cmd_3_or_16">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cmd_3_or_16</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="cmd_crc">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cmd_crc</shortname>
<pt_type>pt_arr_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char[4]</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="cmd_finish1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cmd_finish1</shortname>
<pt_type>pt_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="cmd_finish2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cmd_finish2</shortname>
<pt_type>pt_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="cmd_start">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cmd_start</shortname>
<pt_type>pt_arr_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char[5]</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="cmd_txt">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cmd_txt</shortname>
<pt_type>pt_arr_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char[4][8]</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="compress_size">
<show_var>false</show_var>
<enable>false</enable>
<shortname>compress_size</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/alarm_log_can.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="controlReg">
<show_var>false</show_var>
<enable>false</enable>
<shortname>controlReg</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ControlReg</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="cos_fi">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cos_fi</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>COS_FI_STRUCT</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="count_error_sync">
<show_var>false</show_var>
<enable>false</enable>
<shortname>count_error_sync</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="count_modbus_table_changed">
<show_var>false</show_var>
<enable>false</enable>
<shortname>count_modbus_table_changed</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_fill_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="count_run_pch">
<show_var>false</show_var>
<enable>false</enable>
<shortname>count_run_pch</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="counterSBWriteErrors">
<show_var>false</show_var>
<enable>false</enable>
<shortname>counterSBWriteErrors</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/x_serial_bus.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="crc_16_tab">
<show_var>false</show_var>
<enable>false</enable>
<shortname>crc_16_tab</shortname>
<pt_type>pt_arr_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>WORD[256]</type>
<file>Src/myXilinx/CRC_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="crypt">
<show_var>false</show_var>
<enable>false</enable>
<shortname>crypt</shortname>
<pt_type>pt_arr_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char[34]</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="cur_position_buf_modbus16">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cur_position_buf_modbus16</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/message_modbus.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="cur_position_buf_modbus16_can">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cur_position_buf_modbus16_can</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/message_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="cur_position_buf_modbus3">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cur_position_buf_modbus3</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/message_modbus.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="cycle">
<show_var>false</show_var>
<enable>false</enable>
<shortname>cycle</shortname>
<pt_type>pt_arr_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>CYCLE[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="data_to_umu1_7f">
<show_var>false</show_var>
<enable>false</enable>
<shortname>data_to_umu1_7f</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="data_to_umu1_8">
<show_var>false</show_var>
<enable>false</enable>
<shortname>data_to_umu1_8</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="data_to_umu2_7f">
<show_var>false</show_var>
<enable>false</enable>
<shortname>data_to_umu2_7f</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="data_to_umu2_8">
<show_var>false</show_var>
<enable>false</enable>
<shortname>data_to_umu2_8</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/init_protect_levels.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="delta_capnum">
<show_var>false</show_var>
<enable>false</enable>
<shortname>delta_capnum</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="delta_error">
<show_var>false</show_var>
<enable>false</enable>
<shortname>delta_error</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="doors">
<show_var>false</show_var>
<enable>false</enable>
<shortname>doors</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>volatile DOORS_STATUS</type>
<file>Src/main/doors_control.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="dq_to_ab">
<show_var>false</show_var>
<enable>false</enable>
<shortname>dq_to_ab</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>DQ_TO_ALPHABETA</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="enable_can">
<show_var>false</show_var>
<enable>false</enable>
<shortname>enable_can</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/message_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="enable_can_recive_after_units_box">
<show_var>false</show_var>
<enable>false</enable>
<shortname>enable_can_recive_after_units_box</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="err_level_adc">
<show_var>false</show_var>
<enable>false</enable>
<shortname>err_level_adc</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="err_level_adc_on_go">
<show_var>false</show_var>
<enable>false</enable>
<shortname>err_level_adc_on_go</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="err_main">
<show_var>false</show_var>
<enable>false</enable>
<shortname>err_main</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/Main.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="err_modbus16">
<show_var>false</show_var>
<enable>false</enable>
<shortname>err_modbus16</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="err_modbus3">
<show_var>false</show_var>
<enable>false</enable>
<shortname>err_modbus3</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="errors">
<show_var>false</show_var>
<enable>false</enable>
<shortname>errors</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ERRORS</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="f">
<show_var>false</show_var>
<enable>false</enable>
<shortname>f</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>FLAG</type>
<file>Src/main/Main.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="fail">
<show_var>false</show_var>
<enable>false</enable>
<shortname>fail</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>volatile int</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="faults">
<show_var>false</show_var>
<enable>false</enable>
<shortname>faults</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>FAULTS</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="fifo">
<show_var>false</show_var>
<enable>false</enable>
<shortname>fifo</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>FIFO</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>filter</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ANALOG_VALUE</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_buf">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_buf</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/rotation_speed.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_enable_can_from_mpu">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_enable_can_from_mpu</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_enable_can_from_terminal">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_enable_can_from_terminal</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_on_off_pch">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_on_off_pch</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_received_first_mess_from_MPU">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_received_first_mess_from_MPU</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_reverse">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_reverse</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_send_answer_rs">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_send_answer_rs</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_test_tabe_filled">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_test_tabe_filled</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_fill_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="flag_we_int_pwm_on">
<show_var>false</show_var>
<enable>false</enable>
<shortname>flag_we_int_pwm_on</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="freq1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>freq1</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="freqTerm">
<show_var>false</show_var>
<enable>false</enable>
<shortname>freqTerm</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="global_time">
<show_var>false</show_var>
<enable>false</enable>
<shortname>global_time</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>GLOBAL_TIME</type>
<file>Src/main/global_time.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="hb_logs_data">
<show_var>false</show_var>
<enable>false</enable>
<shortname>hb_logs_data</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="i">
<show_var>false</show_var>
<enable>false</enable>
<shortname>i</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="i1_out">
<show_var>false</show_var>
<enable>false</enable>
<shortname>i1_out</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>BREAK2_PHASE</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="i2_out">
<show_var>false</show_var>
<enable>false</enable>
<shortname>i2_out</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>BREAK2_PHASE</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="init_log">
<show_var>false</show_var>
<enable>false</enable>
<shortname>init_log</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[3]</type>
<file>Src/myLibs/log_can.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="iq19_k_norm_ADC">
<show_var>false</show_var>
<enable>false</enable>
<shortname>iq19_k_norm_ADC</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq19</iq_type>
<return_type>int</return_type>
<type>_iq19[20]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="iq19_zero_ADC">
<show_var>false</show_var>
<enable>false</enable>
<shortname>iq19_zero_ADC</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq19</iq_type>
<return_type>int</return_type>
<type>_iq19[20]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="iq_alfa_coef">
<show_var>false</show_var>
<enable>false</enable>
<shortname>iq_alfa_coef</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="iq_k_norm_ADC">
<show_var>false</show_var>
<enable>false</enable>
<shortname>iq_k_norm_ADC</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq[20]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="iq_logpar">
<show_var>false</show_var>
<enable>false</enable>
<shortname>iq_logpar</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>IQ_LOGSPARAMS</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="iq_max">
<show_var>false</show_var>
<enable>false</enable>
<shortname>iq_max</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/myLibs/svgen_dq_v2.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="iq_norm_ADC">
<show_var>false</show_var>
<enable>false</enable>
<shortname>iq_norm_ADC</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq[20]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="isolation1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>isolation1</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ISOLATION</type>
<file>Src/main/isolation.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="isolation2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>isolation2</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ISOLATION</type>
<file>Src/main/isolation.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="k1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>k1</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kI_D">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kI_D</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kI_D_Inv31">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kI_D_Inv31</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kI_Q">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kI_Q</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kI_Q_Inv31">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kI_Q_Inv31</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kP_D">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kP_D</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kP_D_Inv31">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kP_D_Inv31</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kP_Q">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kP_Q</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kP_Q_Inv31">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kP_Q_Inv31</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kan">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kan</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="koef_Base_stop_run">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Base_stop_run</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Iabc_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Iabc_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Im_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Im_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Im_filter_long">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Im_filter_long</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_K_stop_run">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_K_stop_run</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Krecup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Krecup</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Min_recup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Min_recup</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/break_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_TemperBSU_long_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_TemperBSU_long_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Ud_fast_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Ud_fast_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Ud_long_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Ud_long_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Wlong">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Wlong</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Wout_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Wout_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/rotation_speed.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koef_Wout_filter_long">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koef_Wout_filter_long</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/rotation_speed.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koeff_Fs_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koeff_Fs_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koeff_Idq_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koeff_Idq_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koeff_Iq_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koeff_Iq_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/VectorControl/regul_power.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koeff_Iq_filter_slow">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koeff_Iq_filter_slow</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koeff_Ud_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koeff_Ud_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="koeff_Uq_filter">
<show_var>false</show_var>
<enable>false</enable>
<shortname>koeff_Uq_filter</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="kom">
<show_var>false</show_var>
<enable>false</enable>
<shortname>kom</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/bender.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="length">
<show_var>false</show_var>
<enable>false</enable>
<shortname>length</shortname>
<pt_type>pt_uint32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>volatile unsigned long</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="level_on_off_break">
<show_var>false</show_var>
<enable>false</enable>
<shortname>level_on_off_break</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq[13][2]</type>
<file>Src/main/break_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="log_can">
<show_var>false</show_var>
<enable>false</enable>
<shortname>log_can</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>logcan_TypeDef</type>
<file>Src/myLibs/log_can.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="log_can_setup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>log_can_setup</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>LOG_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="log_params">
<show_var>false</show_var>
<enable>false</enable>
<shortname>log_params</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>TYPE_LOG_PARAMS</type>
<file>Src/myLibs/log_params.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="logbuf_sync1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>logbuf_sync1</shortname>
<pt_type>pt_arr_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long[10]</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="logpar">
<show_var>false</show_var>
<enable>false</enable>
<shortname>logpar</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>LOGSPARAMS</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="mPWM_a">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mPWM_a</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mPWM_b">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mPWM_b</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="m_PWM">
<show_var>false</show_var>
<enable>false</enable>
<shortname>m_PWM</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="mailboxs_can_setup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mailboxs_can_setup</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MAILBOXS_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="manufactorerAndProductID">
<show_var>false</show_var>
<enable>false</enable>
<shortname>manufactorerAndProductID</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="modbus_table_can_in">
<show_var>false</show_var>
<enable>false</enable>
<shortname>modbus_table_can_in</shortname>
<pt_type>pt_ptr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="modbus_table_can_out">
<show_var>false</show_var>
<enable>false</enable>
<shortname>modbus_table_can_out</shortname>
<pt_type>pt_ptr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="modbus_table_in">
<show_var>false</show_var>
<enable>false</enable>
<shortname>modbus_table_in</shortname>
<pt_type>pt_arr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT[450]</type>
<file>Src/myLibs/modbus_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="modbus_table_out">
<show_var>false</show_var>
<enable>false</enable>
<shortname>modbus_table_out</shortname>
<pt_type>pt_arr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT[450]</type>
<file>Src/myLibs/modbus_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="modbus_table_rs_in">
<show_var>false</show_var>
<enable>false</enable>
<shortname>modbus_table_rs_in</shortname>
<pt_type>pt_ptr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="modbus_table_rs_out">
<show_var>false</show_var>
<enable>false</enable>
<shortname>modbus_table_rs_out</shortname>
<pt_type>pt_ptr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="modbus_table_test">
<show_var>false</show_var>
<enable>false</enable>
<shortname>modbus_table_test</shortname>
<pt_type>pt_arr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT[450]</type>
<file>Src/myLibs/modbus_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="mpu_can_setup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mpu_can_setup</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MPU_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="mzz_limit_100">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_100</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mzz_limit_1000">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_1000</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mzz_limit_1100">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_1100</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mzz_limit_1200">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_1200</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mzz_limit_1400">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_1400</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mzz_limit_1500">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_1500</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mzz_limit_2000">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_2000</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="mzz_limit_500">
<show_var>false</show_var>
<enable>false</enable>
<shortname>mzz_limit_500</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="new_cycle_fifo">
<show_var>false</show_var>
<enable>false</enable>
<shortname>new_cycle_fifo</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>NEW_CYCLE_FIFO</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="no_write">
<show_var>false</show_var>
<enable>false</enable>
<shortname>no_write</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="no_write_slow">
<show_var>false</show_var>
<enable>false</enable>
<shortname>no_write_slow</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="number_modbus_table_changed">
<show_var>false</show_var>
<enable>false</enable>
<shortname>number_modbus_table_changed</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/modbus_fill_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="optical_read_data">
<show_var>false</show_var>
<enable>false</enable>
<shortname>optical_read_data</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>OPTICAL_BUS_DATA</type>
<file>Src/main/optical_bus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="optical_write_data">
<show_var>false</show_var>
<enable>false</enable>
<shortname>optical_write_data</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>OPTICAL_BUS_DATA</type>
<file>Src/main/optical_bus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="options_controller">
<show_var>false</show_var>
<enable>false</enable>
<shortname>options_controller</shortname>
<pt_type>pt_arr_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>MODBUS_REG_STRUCT[200]</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidCur_Ki">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidCur_Ki</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidD">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidD</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidD2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidD2</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidFvect">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidFvect</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG3</type>
<file>Src/VectorControl/regul_turns.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidFvectKi_test">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidFvectKi_test</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/message2.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidFvectKp_test">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidFvectKp_test</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/message2.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidPvect">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidPvect</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG3</type>
<file>Src/VectorControl/regul_power.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidQ">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidQ</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidQ2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidQ2</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidReg_koeffs">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidReg_koeffs</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG_KOEFFICIENTS</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pidTetta">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pidTetta</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PIDREG3</type>
<file>Src/VectorControl/teta_calc.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="power_ratio">
<show_var>false</show_var>
<enable>false</enable>
<shortname>power_ratio</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>POWER_RATIO</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="prev_flag_buf">
<show_var>false</show_var>
<enable>false</enable>
<shortname>prev_flag_buf</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/main/rotation_speed.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="prev_status_received">
<show_var>false</show_var>
<enable>false</enable>
<shortname>prev_status_received</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myLibs/log_can.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="project">
<show_var>false</show_var>
<enable>false</enable>
<shortname>project</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>T_project</type>
<file>Src/myXilinx/xp_project.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="pwmd">
<show_var>false</show_var>
<enable>false</enable>
<shortname>pwmd</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>PWMGEND</type>
<file>Src/main/PWMTMSHandle.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="r_c_sbus">
<show_var>false</show_var>
<enable>false</enable>
<shortname>r_c_sbus</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>T_controller_read</type>
<file>Src/myXilinx/x_serial_bus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="r_controller">
<show_var>false</show_var>
<enable>false</enable>
<shortname>r_controller</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>T_controller_read</type>
<file>Src/myXilinx/xp_hwp.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="refo">
<show_var>false</show_var>
<enable>false</enable>
<shortname>refo</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>FIFO</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="reply">
<show_var>false</show_var>
<enable>false</enable>
<shortname>reply</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>TMS_TO_TERMINAL_STRUCT</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="reply_test_all">
<show_var>false</show_var>
<enable>false</enable>
<shortname>reply_test_all</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>TMS_TO_TERMINAL_TEST_ALL_STRUCT</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="return_var">
<show_var>false</show_var>
<enable>false</enable>
<shortname>return_var</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/main/Main.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="rmp_freq">
<show_var>false</show_var>
<enable>false</enable>
<shortname>rmp_freq</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>RMP_MY1</type>
<file>Src/main/PWMTools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="rmp_wrot">
<show_var>false</show_var>
<enable>false</enable>
<shortname>rmp_wrot</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>RMP_MY1</type>
<file>Src/main/rotation_speed.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="rotation_sensor">
<show_var>false</show_var>
<enable>false</enable>
<shortname>rotation_sensor</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>T_rotation_sensor</type>
<file>Src/myXilinx/xp_rotation_sensor.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="rotor">
<show_var>false</show_var>
<enable>false</enable>
<shortname>rotor</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>ROTOR_VALUE</type>
<file>Src/main/rotation_speed.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="rs_a">
<show_var>false</show_var>
<enable>false</enable>
<shortname>rs_a</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>RS_DATA_STRUCT</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="rs_b">
<show_var>false</show_var>
<enable>false</enable>
<shortname>rs_b</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>RS_DATA_STRUCT</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="sincronisationFault">
<show_var>false</show_var>
<enable>false</enable>
<shortname>sincronisationFault</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myLibs/modbus_read_table.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="size_cmd15">
<show_var>false</show_var>
<enable>false</enable>
<shortname>size_cmd15</shortname>
<pt_type>pt_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="size_cmd16">
<show_var>false</show_var>
<enable>false</enable>
<shortname>size_cmd16</shortname>
<pt_type>pt_int8</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>char</type>
<file>Src/myXilinx/RS_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="size_fast_done">
<show_var>false</show_var>
<enable>false</enable>
<shortname>size_fast_done</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="size_slow_done">
<show_var>false</show_var>
<enable>false</enable>
<shortname>size_slow_done</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="stop_log">
<show_var>false</show_var>
<enable>false</enable>
<shortname>stop_log</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="stop_log_slow">
<show_var>false</show_var>
<enable>false</enable>
<shortname>stop_log_slow</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="svgen_dq_1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>svgen_dq_1</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>SVGENDQ</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="svgen_dq_2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>svgen_dq_2</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>SVGENDQ</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="svgen_pwm24_1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>svgen_pwm24_1</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>SVGEN_PWM24</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="svgen_pwm24_2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>svgen_pwm24_2</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>SVGEN_PWM24</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="temp">
<show_var>false</show_var>
<enable>false</enable>
<shortname>temp</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="temperature_limit_koeff">
<show_var>false</show_var>
<enable>false</enable>
<shortname>temperature_limit_koeff</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/errors_temperature.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="temperature_warning_BI1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>temperature_warning_BI1</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>INVERTER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="temperature_warning_BI2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>temperature_warning_BI2</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>INVERTER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="temperature_warning_BV1">
<show_var>false</show_var>
<enable>false</enable>
<shortname>temperature_warning_BV1</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>RECTIFIER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="temperature_warning_BV2">
<show_var>false</show_var>
<enable>false</enable>
<shortname>temperature_warning_BV2</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>RECTIFIER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="terminal_can_setup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>terminal_can_setup</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>TERMINAL_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="tetta_calc">
<show_var>false</show_var>
<enable>false</enable>
<shortname>tetta_calc</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>TETTA_CALC</type>
<file>Src/VectorControl/teta_calc.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="timCNT_alg">
<show_var>false</show_var>
<enable>false</enable>
<shortname>timCNT_alg</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="timCNT_prev">
<show_var>false</show_var>
<enable>false</enable>
<shortname>timCNT_prev</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="time">
<show_var>false</show_var>
<enable>false</enable>
<shortname>time</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="timePauseBENDER_Messages">
<show_var>false</show_var>
<enable>false</enable>
<shortname>timePauseBENDER_Messages</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/main22220.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="timePauseCAN_Messages">
<show_var>false</show_var>
<enable>false</enable>
<shortname>timePauseCAN_Messages</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/main/main22220.c</file>
<extern>false</extern>
<static>True</static>
</var>
<var name="time_alg">
<show_var>false</show_var>
<enable>false</enable>
<shortname>time_alg</shortname>
<pt_type>pt_float</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>float</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="time_pause_enable_can_from_mpu">
<show_var>false</show_var>
<enable>false</enable>
<shortname>time_pause_enable_can_from_mpu</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="time_pause_enable_can_from_terminal">
<show_var>false</show_var>
<enable>false</enable>
<shortname>time_pause_enable_can_from_terminal</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="time_pause_logs">
<show_var>false</show_var>
<enable>false</enable>
<shortname>time_pause_logs</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_can.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="time_pause_titles">
<show_var>false</show_var>
<enable>false</enable>
<shortname>time_pause_titles</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int</type>
<file>Src/myLibs/log_can.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="tryNumb">
<show_var>false</show_var>
<enable>false</enable>
<shortname>tryNumb</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>volatile int</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="unites_can_setup">
<show_var>false</show_var>
<enable>false</enable>
<shortname>unites_can_setup</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>UNITES_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="var_numb">
<show_var>false</show_var>
<enable>false</enable>
<shortname>var_numb</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>long</type>
<file>Src/main/Main.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="vect_control">
<show_var>false</show_var>
<enable>false</enable>
<shortname>vect_control</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>VECTOR_CONTROL</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="water_cooler">
<show_var>false</show_var>
<enable>false</enable>
<shortname>water_cooler</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>WaterCooler</type>
<file>Src/myLibs/can_watercool.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="winding_displacement">
<show_var>false</show_var>
<enable>false</enable>
<shortname>winding_displacement</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/main/v_pwm24.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="word">
<show_var>false</show_var>
<enable>false</enable>
<shortname>word</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>Word</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="wordReversed">
<show_var>false</show_var>
<enable>false</enable>
<shortname>wordReversed</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>WordReversed</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="wordToReverse">
<show_var>false</show_var>
<enable>false</enable>
<shortname>wordToReverse</shortname>
<pt_type>pt_union</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>WordToReverse</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="x_parallel_bus_project">
<show_var>false</show_var>
<enable>false</enable>
<shortname>x_parallel_bus_project</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>X_PARALLEL_BUS</type>
<file>Src/myXilinx/x_parallel_bus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="x_serial_bus_project">
<show_var>false</show_var>
<enable>false</enable>
<shortname>x_serial_bus_project</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>X_SERIAL_BUS</type>
<file>Src/myXilinx/x_serial_bus.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="xeeprom_controll_fast">
<show_var>false</show_var>
<enable>false</enable>
<shortname>xeeprom_controll_fast</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="xeeprom_controll_store">
<show_var>false</show_var>
<enable>false</enable>
<shortname>xeeprom_controll_store</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>unsigned int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="xpwm_time">
<show_var>false</show_var>
<enable>false</enable>
<shortname>xpwm_time</shortname>
<pt_type>pt_struct</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>XPWM_TIME</type>
<file>Src/myXilinx/xp_write_xpwm_time.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="zadan_Id_min">
<show_var>false</show_var>
<enable>false</enable>
<shortname>zadan_Id_min</shortname>
<pt_type>pt_int32</pt_type>
<iq_type>t_iq</iq_type>
<return_type>int</return_type>
<type>_iq</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="zero_ADC">
<show_var>false</show_var>
<enable>false</enable>
<shortname>zero_ADC</shortname>
<pt_type>pt_arr_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>int</return_type>
<type>int[20]</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="project.cds_tk[0].plane_address">
<show_var>true</show_var>
<enable>true</enable>
<shortname>tk0_Adr</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>UInt16</type>
<file>Src/myXilinx/xp_project.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][0]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf00</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][1]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf01</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][2]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf02</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][3]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf03</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][4]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf04</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][5]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf05</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][6]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf06</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][7]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf07</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][8]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf08</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][9]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf09</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][10]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf010</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][11]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf011</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][12]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf012</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][13]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf013</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][14]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf014</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="ADC_sf[0][15]">
<show_var>true</show_var>
<enable>true</enable>
<shortname>ADC_sf015</shortname>
<pt_type>pt_int16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>t_iq_none</return_type>
<type>int</type>
<file>Src/main/adc_tools.c</file>
<extern>false</extern>
<static>false</static>
</var>
<var name="project.cds_tk[0].read.sbus.mask_protect_tk.all">
<show_var>true</show_var>
<enable>true</enable>
<shortname>project.cds_tk[0].read.sbus.mask_protect_tk.all</shortname>
<pt_type>pt_uint16</pt_type>
<iq_type>t_iq_none</iq_type>
<return_type>iq_none</return_type>
<type>UInt16</type>
<file>Src/myXilinx/xp_project.c</file>
<extern>false</extern>
<static>false</static>
</var>
</variables>
<includes>
<file>Src/main/vector.h</file>
<file>Src/main/f281xpwm.h</file>
<file>Src/myLibs/log_can.h</file>
<file>Src/myXilinx/RS_Functions_modbus.h</file>
<file>Src/main/errors.h</file>
<file>Src/VectorControl/pwm_vector_regul.h</file>
<file>Src/myXilinx/xp_project.h</file>
<file>Src/myXilinx/xp_write_xpwm_time.h</file>
<file>Src/main/v_pwm24.h</file>
<file>Src/main/adc_tools.h</file>
<file>Src/main/rotation_speed.h</file>
<file>Src/VectorControl/dq_to_alphabeta_cos.h</file>
<file>Src/VectorControl/teta_calc.h</file>
<file>Src/myLibs/CAN_Setup.h</file>
<file>Src/myLibs/log_to_memory.h</file>
<file>Src/myLibs/log_params.h</file>
<file>Src/myXilinx/CRC_Functions.h</file>
<file>Src/main/global_time.h</file>
<file>Src/myXilinx/RS_Functions.h</file>
<file>Src/myLibs/detect_phase_break2.h</file>
<file>Src/myXilinx/x_parallel_bus.h</file>
<file>Src/myXilinx/x_serial_bus.h</file>
<file>Src/myXilinx/Spartan2E_Functions.h</file>
<file>Src/myXilinx/xp_controller.h</file>
<file>Src/myXilinx/xPeriphSP6_loader.h</file>
<file>Src/myXilinx/xp_rotation_sensor.h</file>
<file>Src/myLibs/svgen_dq.h</file>
<file>Src/myLibs/pid_reg3.h</file>
<file>Src/myLibs/IQmathLib.h</file>
<file>Src/main/doors_control.h</file>
<file>Src/main/isolation.h</file>
<file>Src/main/main22220.h</file>
<file>Src/main/optical_bus.h</file>
<file>Src/myLibs/alarm_log_can.h</file>
<file>Src/myLibs/bender.h</file>
<file>Src/myLibs/can_watercool.h</file>
<file>Src/myLibs/detect_phase_break.h</file>
<file>Src/myLibs/modbus_read_table.h</file>
<file>Src/myLibs/rmp_cntl_my1.h</file>
</includes>
<externs>
<var name="ADC0finishAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="ADC0startAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="ADC1finishAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="ADC1startAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="ADC2finishAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="ADC2startAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="ADC_f">
<type>int[2][16]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="ADC_sf">
<type>int[2][16]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="ADDR_FOR_ALL">
<type>int</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="BUSY">
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="Bender">
<type>BENDER[2]</type>
<file>Src/myLibs/bender.c</file>
</var>
<var name="CAN_answer_wait">
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CAN_count_cycle_input_units">
<type>int[8]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CAN_no_answer">
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CAN_refresh_cicle">
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CAN_request_sent">
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CAN_timeout">
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CAN_timeout_cicle">
<type>int[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CNTRL_ADDR">
<type>int</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="CNTRL_ADDR_UNIVERSAL">
<type>const int</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="CONST_15">
<type>_iq</type>
<file>Src/myLibs/mathlib.c</file>
</var>
<var name="CONST_23">
<type>_iq</type>
<file>Src/myLibs/mathlib.c</file>
</var>
<var name="CanOpenUnites">
<type>int[30]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="CanTimeOutErrorTR">
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="Controll">
<type>XControll_reg</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
</var>
<var name="Dpwm">
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
</var>
<var name="Dpwm2">
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
</var>
<var name="Dpwm4">
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
</var>
<var name="EvaTimer1InterruptCount">
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
</var>
<var name="EvaTimer2InterruptCount">
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
</var>
<var name="EvbTimer3InterruptCount">
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
</var>
<var name="EvbTimer4InterruptCount">
<type>int</type>
<file>Src/main/281xEvTimersInit.c</file>
</var>
<var name="Fpwm">
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
</var>
<var name="IN0finishAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="IN0startAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="IN1finishAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="IN1startAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="IN2finishAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="IN2startAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="IQ_OUT_NOM">
<type>float</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="I_OUT_1_6_NOMINAL_IQ">
<type>long</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="I_OUT_1_8_NOMINAL_IQ">
<type>long</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="I_OUT_NOMINAL">
<type>float</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="I_OUT_NOMINAL_IQ">
<type>long</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="I_ZPT_NOMINAL_IQ">
<type>long</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="Id_out_max_full">
<type>_iq</type>
<file>Src/VectorControl/regul_power.c</file>
</var>
<var name="Id_out_max_low_speed">
<type>_iq</type>
<file>Src/VectorControl/regul_power.c</file>
</var>
<var name="Iq_out_max">
<type>_iq</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="Iq_out_nom">
<type>_iq</type>
<file>Src/main/params_i_out.c</file>
</var>
<var name="K_LEM_ADC">
<type>const unsigned long[20]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="KmodTerm">
<type>float</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="ROTfinishAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="RS_Len">
<type>unsigned int[70]</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="R_ADC">
<type>const unsigned int[20]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="RotPlaneStartAddr">
<type>int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="SQRT_32">
<type>_iq</type>
<file>Src/myLibs/mathlib.c</file>
</var>
<var name="Unites">
<type>int[8][128]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="VAR_FREQ_PWM_XTICS">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="VAR_PERIOD_MAX_XTICS">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="VAR_PERIOD_MIN_BR_XTICS">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="VAR_PERIOD_MIN_XTICS">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="Zpwm">
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
</var>
<var name="a">
<type>WINDING</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="addrToSent">
<type>volatile AddrToSent</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="adr_read_from_modbus3">
<type>unsigned int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="alarm_log_can">
<type>ALARM_LOG_CAN</type>
<file>Src/myLibs/alarm_log_can.c</file>
</var>
<var name="alarm_log_can_setup">
<type>ALARM_LOG_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="analog">
<type>ANALOG_VALUE</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="ar_sa_all">
<type>int[3][6][4][7]</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="ar_tph">
<type>_iq[7]</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="block_size_counter_fast">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="block_size_counter_slow">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="break_result_1">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="break_result_2">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="break_result_3">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="break_result_4">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="byte">
<type>Byte</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="c_s">
<type>long</type>
<file>Src/main/rotation_speed.c</file>
</var>
<var name="calibration1">
<type>int</type>
<file>Src/main/isolation.c</file>
</var>
<var name="calibration2">
<type>int</type>
<file>Src/main/isolation.c</file>
</var>
<var name="callfunc">
<type>test_functions</type>
<file>Src/main/Main.c</file>
</var>
<var name="canopen_can_setup">
<type>CANOPEN_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="capnum0">
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="capnum1">
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="capnum2">
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="capnum3">
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="chNum">
<type>unsigned int</type>
<file>Src/myXilinx/x_example_all.c</file>
</var>
<var name="chanell1">
<type>BREAK_PHASE_I</type>
<file>Src/main/detect_phase.c</file>
</var>
<var name="chanell2">
<type>BREAK_PHASE_I</type>
<file>Src/main/detect_phase.c</file>
</var>
<var name="cmd_3_or_16">
<type>int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="compress_size">
<type>int</type>
<file>Src/myLibs/alarm_log_can.c</file>
</var>
<var name="controlReg">
<type>ControlReg</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="cos_fi">
<type>COS_FI_STRUCT</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="count_error_sync">
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="count_modbus_table_changed">
<type>int</type>
<file>Src/myLibs/modbus_fill_table.c</file>
</var>
<var name="count_run_pch">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="crc_16_tab">
<type>WORD[256]</type>
<file>Src/myXilinx/CRC_Functions.c</file>
</var>
<var name="crypt">
<type>char[34]</type>
<file>Src/myLibs/bender.c</file>
</var>
<var name="cur_position_buf_modbus16_can">
<type>int</type>
<file>Src/myLibs/message_modbus.c</file>
</var>
<var name="cycle">
<type>CYCLE[32]</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="delta_capnum">
<type>int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="delta_error">
<type>int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="doors">
<type>volatile DOORS_STATUS</type>
<file>Src/main/doors_control.c</file>
</var>
<var name="enable_can">
<type>int</type>
<file>Src/myLibs/message_modbus.c</file>
</var>
<var name="enable_can_recive_after_units_box">
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="err_level_adc">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="err_level_adc_on_go">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="err_main">
<type>unsigned int</type>
<file>Src/main/Main.c</file>
</var>
<var name="err_modbus16">
<type>int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="err_modbus3">
<type>int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="errors">
<type>ERRORS</type>
<file>Src/main/errors.c</file>
</var>
<var name="f">
<type>FLAG</type>
<file>Src/main/Main.c</file>
</var>
<var name="fail">
<type>volatile int</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="faults">
<type>FAULTS</type>
<file>Src/main/errors.c</file>
</var>
<var name="fifo">
<type>FIFO</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="filter">
<type>ANALOG_VALUE</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="flag_buf">
<type>int</type>
<file>Src/main/rotation_speed.c</file>
</var>
<var name="flag_enable_can_from_mpu">
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="flag_enable_can_from_terminal">
<type>int</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="flag_on_off_pch">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="flag_received_first_mess_from_MPU">
<type>unsigned int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="flag_reverse">
<type>unsigned int</type>
<file>Src/myLibs/modbus_read_table.c</file>
</var>
<var name="flag_send_answer_rs">
<type>unsigned int</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="flag_test_tabe_filled">
<type>int</type>
<file>Src/myLibs/modbus_fill_table.c</file>
</var>
<var name="flag_we_int_pwm_on">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="freq1">
<type>_iq</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="freqTerm">
<type>float</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="global_time">
<type>GLOBAL_TIME</type>
<file>Src/main/global_time.c</file>
</var>
<var name="hb_logs_data">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="i">
<type>int</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="i1_out">
<type>BREAK2_PHASE</type>
<file>Src/main/errors.c</file>
</var>
<var name="i2_out">
<type>BREAK2_PHASE</type>
<file>Src/main/errors.c</file>
</var>
<var name="init_log">
<type>int[3]</type>
<file>Src/myLibs/log_can.c</file>
</var>
<var name="iq19_k_norm_ADC">
<type>_iq19[20]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="iq19_zero_ADC">
<type>_iq19[20]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="iq_alfa_coef">
<type>_iq</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="iq_k_norm_ADC">
<type>_iq[20]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="iq_logpar">
<type>IQ_LOGSPARAMS</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="iq_max">
<type>_iq</type>
<file>Src/myLibs/svgen_dq_v2.c</file>
</var>
<var name="iq_norm_ADC">
<type>_iq[20]</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="isolation1">
<type>ISOLATION</type>
<file>Src/main/isolation.c</file>
</var>
<var name="isolation2">
<type>ISOLATION</type>
<file>Src/main/isolation.c</file>
</var>
<var name="k1">
<type>_iq</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="kI_D">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="kI_D_Inv31">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="kI_Q">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="kI_Q_Inv31">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="kP_D">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="kP_D_Inv31">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="kP_Q">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="kP_Q_Inv31">
<type>float</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="koef_Base_stop_run">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="koef_Iabc_filter">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="koef_Im_filter">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="koef_Im_filter_long">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="koef_K_stop_run">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="koef_Krecup">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="koef_Min_recup">
<type>_iq</type>
<file>Src/main/break_regul.c</file>
</var>
<var name="koef_TemperBSU_long_filter">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="koef_Ud_fast_filter">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="koef_Ud_long_filter">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="koef_Wlong">
<type>_iq</type>
<file>Src/main/adc_tools.c</file>
</var>
<var name="koef_Wout_filter">
<type>_iq</type>
<file>Src/main/rotation_speed.c</file>
</var>
<var name="koef_Wout_filter_long">
<type>_iq</type>
<file>Src/main/rotation_speed.c</file>
</var>
<var name="koeff_Fs_filter">
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="koeff_Idq_filter">
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="koeff_Iq_filter">
<type>_iq</type>
<file>Src/VectorControl/regul_power.c</file>
</var>
<var name="koeff_Iq_filter_slow">
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="koeff_Ud_filter">
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="koeff_Uq_filter">
<type>long</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="length">
<type>volatile unsigned long</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="level_on_off_break">
<type>_iq[13][2]</type>
<file>Src/main/break_tools.c</file>
</var>
<var name="log_can">
<type>logcan_TypeDef</type>
<file>Src/myLibs/log_can.c</file>
</var>
<var name="log_can_setup">
<type>LOG_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="log_params">
<type>TYPE_LOG_PARAMS</type>
<file>Src/myLibs/log_params.c</file>
</var>
<var name="logbuf_sync1">
<type>long[10]</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="logpar">
<type>LOGSPARAMS</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="m_PWM">
<type>int</type>
<file>Src/main/PWMTMSHandle.c</file>
</var>
<var name="mailboxs_can_setup">
<type>MAILBOXS_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="manufactorerAndProductID">
<type>int</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="modbus_table_can_in">
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
</var>
<var name="modbus_table_can_out">
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
</var>
<var name="modbus_table_in">
<type>MODBUS_REG_STRUCT[450]</type>
<file>Src/myLibs/modbus_table.c</file>
</var>
<var name="modbus_table_out">
<type>MODBUS_REG_STRUCT[450]</type>
<file>Src/myLibs/modbus_table.c</file>
</var>
<var name="modbus_table_rs_in">
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
</var>
<var name="modbus_table_rs_out">
<type>MODBUS_REG_STRUCT *</type>
<file>Src/myLibs/modbus_table.c</file>
</var>
<var name="modbus_table_test">
<type>MODBUS_REG_STRUCT[450]</type>
<file>Src/myLibs/modbus_table.c</file>
</var>
<var name="mpu_can_setup">
<type>MPU_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="new_cycle_fifo">
<type>NEW_CYCLE_FIFO</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="no_write">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="no_write_slow">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="number_modbus_table_changed">
<type>int</type>
<file>Src/myLibs/modbus_fill_table.c</file>
</var>
<var name="optical_read_data">
<type>OPTICAL_BUS_DATA</type>
<file>Src/main/optical_bus.c</file>
</var>
<var name="optical_write_data">
<type>OPTICAL_BUS_DATA</type>
<file>Src/main/optical_bus.c</file>
</var>
<var name="options_controller">
<type>MODBUS_REG_STRUCT[200]</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="pidCur_Ki">
<type>_iq</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="pidD">
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="pidD2">
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="pidFvect">
<type>PIDREG3</type>
<file>Src/VectorControl/regul_turns.c</file>
</var>
<var name="pidFvectKi_test">
<type>int</type>
<file>Src/main/message2.c</file>
</var>
<var name="pidFvectKp_test">
<type>int</type>
<file>Src/main/message2.c</file>
</var>
<var name="pidPvect">
<type>PIDREG3</type>
<file>Src/VectorControl/regul_power.c</file>
</var>
<var name="pidQ">
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="pidQ2">
<type>PIDREG3</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="pidReg_koeffs">
<type>PIDREG_KOEFFICIENTS</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="pidTetta">
<type>PIDREG3</type>
<file>Src/VectorControl/teta_calc.c</file>
</var>
<var name="power_ratio">
<type>POWER_RATIO</type>
<file>Src/myLibs/modbus_read_table.c</file>
</var>
<var name="prev_flag_buf">
<type>int</type>
<file>Src/main/rotation_speed.c</file>
</var>
<var name="prev_status_received">
<type>unsigned int</type>
<file>Src/myLibs/log_can.c</file>
</var>
<var name="project">
<type>T_project</type>
<file>Src/myXilinx/xp_project.c</file>
</var>
<var name="pwmd">
<type>PWMGEND</type>
<file>Src/main/PWMTMSHandle.c</file>
</var>
<var name="r_c_sbus">
<type>T_controller_read</type>
<file>Src/myXilinx/x_serial_bus.c</file>
</var>
<var name="r_controller">
<type>T_controller_read</type>
<file>Src/myXilinx/xp_hwp.c</file>
</var>
<var name="refo">
<type>FIFO</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="reply">
<type>TMS_TO_TERMINAL_STRUCT</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="reply_test_all">
<type>TMS_TO_TERMINAL_TEST_ALL_STRUCT</type>
<file>Src/myXilinx/RS_Functions_modbus.c</file>
</var>
<var name="return_var">
<type>long</type>
<file>Src/main/Main.c</file>
</var>
<var name="rmp_freq">
<type>RMP_MY1</type>
<file>Src/main/PWMTools.c</file>
</var>
<var name="rmp_wrot">
<type>RMP_MY1</type>
<file>Src/main/rotation_speed.c</file>
</var>
<var name="rotation_sensor">
<type>T_rotation_sensor</type>
<file>Src/myXilinx/xp_rotation_sensor.c</file>
</var>
<var name="rotor">
<type>ROTOR_VALUE</type>
<file>Src/main/rotation_speed.c</file>
</var>
<var name="rs_a">
<type>RS_DATA_STRUCT</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="rs_b">
<type>RS_DATA_STRUCT</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="sincronisationFault">
<type>unsigned int</type>
<file>Src/myLibs/modbus_read_table.c</file>
</var>
<var name="size_cmd15">
<type>char</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="size_cmd16">
<type>char</type>
<file>Src/myXilinx/RS_Functions.c</file>
</var>
<var name="size_fast_done">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="size_slow_done">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="stop_log">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="stop_log_slow">
<type>int</type>
<file>Src/myLibs/log_to_memory.c</file>
</var>
<var name="svgen_dq_1">
<type>SVGENDQ</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="svgen_dq_2">
<type>SVGENDQ</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="svgen_pwm24_1">
<type>SVGEN_PWM24</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="svgen_pwm24_2">
<type>SVGEN_PWM24</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="temp">
<type>unsigned int</type>
<file>Src/main/sync_tools.c</file>
</var>
<var name="temperature_limit_koeff">
<type>_iq</type>
<file>Src/main/errors_temperature.c</file>
</var>
<var name="temperature_warning_BI1">
<type>INVERTER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
</var>
<var name="temperature_warning_BI2">
<type>INVERTER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
</var>
<var name="temperature_warning_BV1">
<type>RECTIFIER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
</var>
<var name="temperature_warning_BV2">
<type>RECTIFIER_TEMPERATURES</type>
<file>Src/main/errors.c</file>
</var>
<var name="terminal_can_setup">
<type>TERMINAL_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="tetta_calc">
<type>TETTA_CALC</type>
<file>Src/VectorControl/teta_calc.c</file>
</var>
<var name="timCNT_alg">
<type>int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
</var>
<var name="timCNT_prev">
<type>int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
</var>
<var name="time">
<type>unsigned int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
</var>
<var name="time_alg">
<type>float</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
</var>
<var name="time_pause_enable_can_from_mpu">
<type>long</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="time_pause_enable_can_from_terminal">
<type>long</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="time_pause_logs">
<type>int</type>
<file>Src/myLibs/log_can.c</file>
</var>
<var name="time_pause_titles">
<type>int</type>
<file>Src/myLibs/log_can.c</file>
</var>
<var name="tryNumb">
<type>volatile int</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="unites_can_setup">
<type>UNITES_CAN_SETUP</type>
<file>Src/myLibs/CAN_Setup.c</file>
</var>
<var name="var_numb">
<type>long</type>
<file>Src/main/Main.c</file>
</var>
<var name="vect_control">
<type>VECTOR_CONTROL</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="water_cooler">
<type>WaterCooler</type>
<file>Src/myLibs/can_watercool.c</file>
</var>
<var name="winding_displacement">
<type>_iq</type>
<file>Src/main/v_pwm24.c</file>
</var>
<var name="word">
<type>Word</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="wordReversed">
<type>WordReversed</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="wordToReverse">
<type>WordToReverse</type>
<file>Src/myXilinx/xPeriphSP6_loader.c</file>
</var>
<var name="x_parallel_bus_project">
<type>X_PARALLEL_BUS</type>
<file>Src/myXilinx/x_parallel_bus.c</file>
</var>
<var name="x_serial_bus_project">
<type>X_SERIAL_BUS</type>
<file>Src/myXilinx/x_serial_bus.c</file>
</var>
<var name="xeeprom_controll_fast">
<type>unsigned int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
</var>
<var name="xeeprom_controll_store">
<type>unsigned int</type>
<file>Src/myXilinx/Spartan2E_Functions.c</file>
</var>
<var name="xpwm_time">
<type>XPWM_TIME</type>
<file>Src/myXilinx/xp_write_xpwm_time.c</file>
</var>
<var name="zadan_Id_min">
<type>_iq</type>
<file>Src/VectorControl/pwm_vector_regul.c</file>
</var>
<var name="zero_ADC">
<type>int[20]</type>
<file>Src/main/adc_tools.c</file>
</var>
</externs>
</analysis>