5 Commits

Author SHA1 Message Date
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
10 changed files with 783 additions and 421 deletions

Binary file not shown.

View File

@@ -1,23 +1,56 @@
# DebugVarEdit — Утилита для генерации переменных для отладки # 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);
```
Переменные доступные для чтения определяются в **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" }, \
};
```
# DebugVarEdit - Настройка переменных
**DebugVarEdit** — графическое приложение для Windows, предназначенное для настройки и генерации отладочных переменных (`debug_vars.c`) на основе исходного C-проекта. Работает с `makefile` проекта, сохраняет изменения в XML и позволяет удобно редактировать переменные и их типы через интерфейс. **DebugVarEdit** — графическое приложение для Windows, предназначенное для настройки и генерации отладочных переменных (`debug_vars.c`) на основе исходного C-проекта. Работает с `makefile` проекта, сохраняет изменения в XML и позволяет удобно редактировать переменные и их типы через интерфейс.
Программа — один исполняемый файл `DebugVarEdit.exe`, не требующий установки и дополнительных зависимостей. Программа — один исполняемый файл `DebugVarEdit.exe`, не требующий установки и дополнительных зависимостей.
> Требуется Windows 7 или новее. > Требуется Windows 7 или новее.
> [Для разработчиков](#для-разработчиков)
--- ---
## Как использовать ## Как использовать приложение
1. Запустите **DebugVarEdit.exe.** 1. Запустите **DebugVarEdit.exe.**
2. Укажите пути: 2. Укажите пути и контроллер:
- **Путь к XML** — новый или существующий файл настроек переменных; - **Путь к XML** — новый или существующий файл настроек переменных;
- **Путь к проекту** — путь к корню проека (папка, которая является корнем для проекта в Code Composer); - **Путь к проекту** — путь к корню проека (папка, которая является корнем для проекта в Code Composer);
- **Путь к makefile** — путь к `makefile` относительно корня проекта; - **Путь к makefile** — путь к `makefile` относительно корня проекта;
- **Путь для debug_vars.c** — папка, куда будет сгенерирован файл `debug_vars.c` с переменными. - **Путь для debug_vars.c** — папка, куда будет сгенерирован файл `debug_vars.c` с переменными.
- **МК** — TMS или STM. Они отличаются размером int, и также принятыми кодировками файлов (utf-8/cp1251)
3. Нажмите **Сканировать переменные**: 3. Нажмите **Сканировать переменные**:
- Программа проанализирует исходники, указанные в makefile, и найдёт все переменные. - Программа проанализирует исходники, указанные в makefile, и найдёт все переменные.
@@ -61,7 +94,7 @@
## Пример XML-файла ## Пример XML-файла
```xml ```xml
<project proj_path="C:/myproj" makefile_path="Debug/Makefile" structs_path="debugVars/structs.xml"> <project proj_path="C:/myproj" makefile_path="Debug/Makefile" structs_path="Src/DebugTools/structs.xml">
<variables> <variables>
<var name="g_myvar"> <var name="g_myvar">
<enable>true</enable> <enable>true</enable>
@@ -79,6 +112,7 @@
</project> </project>
``` ```
---
--- ---
# Для разработчиков # Для разработчиков
@@ -107,14 +141,14 @@ Src
Для запуска приложения: Для запуска приложения:
- **Python 3.7+** - **Python 3.7+**
- **clang** — используется для парсинга C-кода (требуется `libclang.dll`) - **clang** — используется для парсинга C-кода (требуется `libclang.dll`, лежит в папке Src)
- **PySide2** — GUI-фреймворк - **PySide2** — GUI-фреймворк
- **lxml** — работа с XML - **lxml** — работа с XML
> Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7 > Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7
Для сборки `.exe`: Для сборки `.exe`:
- **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей - **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей
- **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен) - **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен для запуска `.exe`)
### Сборка: ### Сборка:
@@ -134,5 +168,5 @@ Src
### Установка зависимостей ### Установка зависимостей
```bash ```bash
pip install PySide2 lxml nuitka pyinstaller pip install clang PySide2 lxml nuitka pyinstaller
``` ```

View File

@@ -5,7 +5,7 @@ import sys
import os import os
import subprocess import subprocess
import lxml.etree as ET import lxml.etree as ET
from generate_debug_vars import type_map from generate_debug_vars import type_map, choose_type_map
from enum import IntEnum from enum import IntEnum
import threading import threading
from generate_debug_vars import run_generate from generate_debug_vars import run_generate
@@ -21,8 +21,9 @@ from PySide2.QtWidgets import (
QApplication, QWidget, QTableWidget, QTableWidgetItem, QApplication, QWidget, QTableWidget, QTableWidgetItem,
QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton, QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton,
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit, 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.QtGui import QTextCursor, QKeyEvent, QIcon, QFont
from PySide2.QtCore import Qt, QProcess, QObject, Signal, QSettings from PySide2.QtCore import Qt, QProcess, QObject, Signal, QSettings
@@ -58,6 +59,7 @@ class VarEditor(QWidget):
self.output_path = None self.output_path = None
self._updating = False # Флаг блокировки рекурсии self._updating = False # Флаг блокировки рекурсии
self._resizing = False # флаг блокировки повторного вызова self._resizing = False # флаг блокировки повторного вызова
self.target = 'TMS'
self.initUI() self.initUI()
def initUI(self): def initUI(self):
@@ -122,6 +124,32 @@ class VarEditor(QWidget):
self.btn_update_vars = QPushButton(scan_title) self.btn_update_vars = QPushButton(scan_title)
self.btn_update_vars.clicked.connect(self.update_vars_data) 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)
menubar.addMenu(self.target_menu)
# Кнопка сохранения # Кнопка сохранения
btn_save = QPushButton(build_title) btn_save = QPushButton(build_title)
btn_save.clicked.connect(self.save_build) btn_save.clicked.connect(self.save_build)
@@ -137,6 +165,7 @@ class VarEditor(QWidget):
self.table = VariableTableWidget() self.table = VariableTableWidget()
# Основной layout # Основной layout
layout = QVBoxLayout() layout = QVBoxLayout()
layout.setMenuBar(menubar) # прикрепляем menubar в layout сверху
layout.addLayout(xml_layout) layout.addLayout(xml_layout)
layout.addLayout(proj_layout) layout.addLayout(proj_layout)
layout.addLayout(makefile_layout) layout.addLayout(makefile_layout)
@@ -150,7 +179,20 @@ class VarEditor(QWidget):
self.setLayout(layout) self.setLayout(layout)
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): def get_xml_path(self):
xml_path = self.xml_output_edit.text().strip() xml_path = self.xml_output_edit.text().strip()
return xml_path return xml_path
@@ -241,7 +283,7 @@ class VarEditor(QWidget):
return return
try: 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 успешно сгенерирован.") QMessageBox.information(self, "Готово", "Файл debug_vars.c успешно сгенерирован.")
self.update() self.update()
except Exception as e: except Exception as e:
@@ -358,15 +400,25 @@ class VarEditor(QWidget):
super().keyPressEvent(event) super().keyPressEvent(event)
def __browse_makefile(self): 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( 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:
path = myXML.make_relative_path(file_path, self.proj_path) if self.proj_path:
else: path = myXML.make_relative_path(file_path, self.proj_path)
path = file_path else:
self.makefile_edit.setText(path) path = file_path
self.makefile_path = path self.makefile_edit.setText(path)
self.makefile_path = path
def __browse_source_output(self): def __browse_source_output(self):
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку для debug_vars.c") dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку для debug_vars.c")
@@ -438,12 +490,12 @@ class VarEditor(QWidget):
self.write_to_xml() self.write_to_xml()
def __open_variable_selector(self): def __open_variable_selector(self):
self.update()
if not self.vars_list: if not self.vars_list:
QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).") QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).")
return return
self.update()
dlg = VariableSelectorDialog(self.table, self.vars_list, self.structs, self.typedef_map, self.xml_path, self) dlg = VariableSelectorDialog(self.table, self.vars_list, self.structs, self.typedef_map, self.xml_path, self)
if dlg.exec_(): if dlg.exec_():
self.write_to_xml() self.write_to_xml()

View File

@@ -12,9 +12,10 @@ from xml.dom import minidom
import myXML import myXML
import argparse import argparse
shortnameSize = 10
# === Словарь соответствия типов XML → DebugVarType_t === # === Словарь соответствия типов XML → DebugVarType_t ===
type_map = dict([ type_map_tms = dict([
*[(k, 'pt_int8') for k in ('signed char', 'char')], *[(k, 'pt_int8') for k in ('signed char', 'char')],
*[(k, 'pt_int16') for k in ('int', 'int16', 'short')], *[(k, 'pt_int16') for k in ('int', 'int16', 'short')],
*[(k, 'pt_int32') for k in ('long', 'int32', '_iqx')], *[(k, 'pt_int32') for k in ('long', 'int32', '_iqx')],
@@ -52,6 +53,150 @@ type_map = dict([
('struct[]', 'pt_arr_struct'), ('struct[]', 'pt_arr_struct'),
('union[]', 'pt_arr_union'), ('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): def map_type_to_pt(typename, varname=None, typedef_map=None):
typename_orig = typename.strip() typename_orig = typename.strip()
@@ -140,15 +285,20 @@ def add_new_vars_to_xml(proj_path, xml_rel_path, output_path):
Возвращает True если что-то добавлено и XML перезаписан, иначе False. Возвращает 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 = {} parsed_vars = {}
if os.path.isfile(output_path): if os.path.isfile(output_path):
with open(output_path, 'r', encoding='utf-8', errors='ignore') as f: with open(output_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f: for line in f:
# {(char *)&some.deep.var.name , pt_uint16 , t_iq15 , "ShortName"}, # {(uint8_t *)&some.deep.var.name , pt_uint16 , t_iq15 , t_iq10, "ShortName"},
m = re.match( m = pattern.search(line)
r'{\s*\(char\s*\*\)\s*&([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\s*,\s*(pt_\w+)\s*,\s*(t?iq_\w+)\s*,\s*"([^"]+)"',
line)
if m: if m:
full_varname = m.group(1) # e.g., some.deep.var.name full_varname = m.group(1) # e.g., some.deep.var.name
pt_type = m.group(2) pt_type = m.group(2)
@@ -285,12 +435,27 @@ def read_vars_from_xml(proj_path, xml_rel_path):
return unique_vars, include_files, vars_need_extern 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): def generate_vars_file(proj_path, xml_path, output_dir):
output_dir = os.path.join(proj_path, output_dir) output_dir = os.path.join(proj_path, output_dir)
os.makedirs(output_dir, exist_ok=True) os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, 'debug_vars.c') 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 # Запись новых переменных для в XML
@@ -338,7 +503,7 @@ def generate_vars_file(proj_path, xml_path, output_dir):
# Дополнительные поля, например комментарий # Дополнительные поля, например комментарий
comment = info.get("comment", "") comment = info.get("comment", "")
short_name = info.get("shortname", f'"{vname}"') 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'): if pt_type not in ('pt_struct', 'pt_union'):
f_name = f'{vname},' f_name = f'{vname},'
@@ -348,7 +513,7 @@ def generate_vars_file(proj_path, xml_path, output_dir):
f_short_name = f'"{short_trimmed}"' # оборачиваем в кавычки f_short_name = f'"{short_trimmed}"' # оборачиваем в кавычки
# Добавим комментарий после записи, если он есть # Добавим комментарий после записи, если он есть
comment_str = f' // {comment}' if comment else '' comment_str = f' // {comment}' if comment else ''
line = f'{{(char *)&{f_name:<57} {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 new_debug_vars[vname] = line
else: 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'\n\n// Определение массива с указателями на переменные для отладки')
out_lines.append(f'int DebugVar_Qnt = {len(all_debug_lines)};') out_lines.append(f'int DebugVar_Qnt = {len(all_debug_lines)};')
out_lines.append('#pragma DATA_SECTION(dbg_vars,".dbgvar_info")') 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.append('DebugVar_t dbg_vars[] = {\\')
out_lines.extend(all_debug_lines) out_lines.extend(all_debug_lines)
out_lines.append('};') out_lines.append('};')
out_lines.append('') out_lines.append('')
# Выберем кодировку для записи файла # Выберем кодировку для записи файла
# Если встречается несколько, возьмем первую из set # Если встречается несколько, возьмем первую из set
enc_to_write = 'cp1251' if stm_flag_global == 0:
enc_to_write = 'cp1251'
else:
enc_to_write = 'utf-8'
#print("== GLOBAL VARS FOUND ==") #print("== GLOBAL VARS FOUND ==")
#for vname, (vtype, path) in vars_in_c.items(): #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: with open(output_path, 'w', encoding=enc_to_write) as f:
f.write('\n'.join(out_lines)) 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)}') print(f'Файл debug_vars.c сгенерирован в кодировке, переменных: {len(all_debug_lines)}')
@@ -472,16 +652,17 @@ Usage example:
print(f"Error: Project path '{proj_path}' не является директорией или не существует.") print(f"Error: Project path '{proj_path}' не является директорией или не существует.")
sys.exit(1) 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__": if __name__ == "__main__":
main() main()
def run_generate(proj_path, xml_path, output_dir): def run_generate(proj_path, xml_path, output_dir, shortname_size):
import os import os
global shortnameSize
shortnameSize = shortname_size
# Normalize absolute paths # Normalize absolute paths
proj_path = os.path.abspath(proj_path) proj_path = os.path.abspath(proj_path)
xml_path_abs = os.path.abspath(xml_path) xml_path_abs = os.path.abspath(xml_path)

View File

@@ -1,5 +1,6 @@
import os import os
import re import re
from lxml import etree as ET
def strip_single_line_comments(code): def strip_single_line_comments(code):
@@ -66,89 +67,176 @@ def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
return include_files 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): def parse_makefile(makefile_path, proj_path):
makefile_dir = os.path.dirname(makefile_path) import os
project_root = proj_path 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: with open(makefile_path, 'r', encoding='utf-8') as f:
lines = f.readlines() lines = f.readlines()
objs_lines = [] raw_entries = []
collecting = False collecting = False
for line in lines: for line in lines:
stripped = line.strip() stripped = line.strip()
if stripped.startswith("ORDERED_OBJS") and "+=" in stripped:
parts = stripped.split("\\") if (("ORDERED_OBJS" in stripped or "C_SOURCES" in stripped) and ("+=" in stripped or "=" in stripped)):
first_part = parts[0]
idx = first_part.find("+=")
tail = first_part[idx+2:].strip()
if tail:
objs_lines.append(tail)
collecting = True collecting = True
if len(parts) > 1:
for p in parts[1:]:
p = p.strip()
if p:
objs_lines.append(p)
continue
if collecting: if collecting:
if stripped.endswith("\\"): line_clean = stripped.rstrip("\\").strip()
objs_lines.append(stripped[:-1].strip()) if line_clean:
else: line_clean = re.sub(r"\$\([^)]+\)", "", line_clean)
objs_lines.append(stripped) line_clean = re.sub(r"\$\{[^}]+\}", "", line_clean)
raw_entries.append(line_clean)
if not stripped.endswith("\\"):
collecting = False collecting = False
objs_str = ' '.join(objs_lines) for entry in raw_entries:
for token in entry.split():
token = token.strip('"')
if not token:
continue
objs_str = re.sub(r"\$\([^)]+\)", "", objs_str) token = token.replace("\\", "/")
objs = [] if token.endswith(".obj"):
for part in objs_str.split(): token = re.sub(r"\.obj$", ".c", token)
part = part.strip() elif token.endswith(".o"):
if part.startswith('"') and part.endswith('"'): token = re.sub(r"\.o$", ".c", token)
part = part[1:-1]
if part:
objs.append(part)
c_files = [] if token.endswith(".c"):
include_dirs = set() 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))
for obj_path in objs: if not c_files:
if "DebugTools" in obj_path: makefile_dir = os.path.dirname(os.path.abspath(makefile_path))
continue objects_list_path = os.path.join(makefile_dir, "objects.list")
if "v120" in obj_path: c_from_objects, inc_from_objects = parse_objects_list(objects_list_path, project_root)
continue c_files.extend(c_from_objects)
if "v100" in obj_path: include_dirs.update(inc_from_objects)
continue
if obj_path.startswith("Debug\\") or obj_path.startswith("Debug/"): for line in lines:
rel_path = obj_path.replace("Debug\\", "Src\\").replace("Debug/", "Src/") if "-I" in line or "C_INCLUDES" in line:
else: matches = re.findall(r"-I\s*([^\s\\]+)", line)
rel_path = obj_path 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)
abs_path = os.path.normpath(os.path.join(project_root, rel_path)) # Добавляем пути с заменой 'Src' на 'Inc', если путь заканчивается на 'Src'
additional_includes = set()
root, ext = os.path.splitext(abs_path) for inc in include_dirs:
if ext.lower() == ".obj": if inc.endswith(os.sep + "Src") or inc.endswith("/Src"):
c_path = root + ".c" inc_inc = inc[:-3] + "Inc" # заменяем 'Src' на 'Inc'
else: if os.path.isdir(inc_inc):
c_path = abs_path additional_includes.add(inc_inc)
# Проверяем существование файла, если нет — пропускаем
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)
include_dirs.update(additional_includes)
h_files = find_all_includes_recursive(c_files, include_dirs) h_files = find_all_includes_recursive(c_files, include_dirs)
return sorted(c_files), sorted(h_files), sorted(include_dirs), sorted(defines)
return sorted(c_files), sorted(h_files), sorted(include_dirs)
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

@@ -11,7 +11,7 @@ from clang import cindex
from clang.cindex import Config from clang.cindex import Config
import lxml.etree as ET import lxml.etree as ET
from xml.dom import minidom from xml.dom import minidom
from makefile_parser import parse_makefile from makefile_parser import parse_project
from collections import deque from collections import deque
import argparse import argparse
import myXML import myXML
@@ -118,11 +118,11 @@ def get_canonical_typedef_file(var_type, include_dirs):
break break
return None 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...") optional_printf(PRINT_STATUS, "Starting analysis of variables across files...")
index = clang.cindex.Index.create() 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 = {} # имя переменной → словарь с инфой unique_vars = {} # имя переменной → словарь с инфой
h_files_needed = set() h_files_needed = set()
vars_need_extern = {} # имя переменной → словарь без поля 'extern' 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)) return bool(re.match(r"^_[_A-Z]", var_name))
if node.kind == clang.cindex.CursorKind.VAR_DECL: if node.kind == clang.cindex.CursorKind.VAR_DECL:
if node.semantic_parent.kind == clang.cindex.CursorKind.TRANSLATION_UNIT: if node.semantic_parent.kind == clang.cindex.CursorKind.TRANSLATION_UNIT:
is_extern = (node.storage_class == clang.cindex.StorageClass.EXTERN) is_extern = (node.storage_class == clang.cindex.StorageClass.EXTERN)
@@ -170,7 +171,12 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
return # игнорируем только явно известные служебные переменные return # игнорируем только явно известные служебные переменные
if node.spelling == 'HUGE': # еще одна служеюная, которую хз как выделять if node.spelling == 'HUGE': # еще одна служеюная, которую хз как выделять
return return
if 'Drivers' in node.location.file.name:
return
if 'uint' in node.spelling:
a = 1
# Проверяем, является ли тип указателем на функцию # Проверяем, является ли тип указателем на функцию
# Признак: в типе есть '(' и ')' и '*', например: "void (*)(int)" # Признак: в типе есть '(' и ')' и '*', например: "void (*)(int)"
if "(" in var_type and "*" in var_type and ")" in var_type: if "(" in var_type and "*" in var_type and ")" in var_type:
@@ -295,6 +301,8 @@ def strip_ptr_and_array(typename):
return typename return typename
def analyze_typedefs_and_struct(typedefs, structs): def analyze_typedefs_and_struct(typedefs, structs):
optional_printf(PRINT_STATUS, "Resolving typedefs and expanding struct field types...") 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 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...") optional_printf(PRINT_STATUS, "Starting analysis of typedefs and structs across files...")
index = clang.cindex.Index.create() 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_typedefs_raw = {}
unique_structs_raw = {} unique_structs_raw = {}
@@ -452,7 +478,6 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
raw_name = node.spelling raw_name = node.spelling
normalized_name = normalize_type_name(raw_name) normalized_name = normalize_type_name(raw_name)
# struct_name всегда с префиксом # struct_name всегда с префиксом
if node.spelling and "unnamed" not in normalized_name: if node.spelling and "unnamed" not in normalized_name:
struct_name = f"{prefix}{normalized_name}" struct_name = f"{prefix}{normalized_name}"
@@ -855,10 +880,10 @@ Usage example:
print(f"Error: Makefile path '{makefile_path}' does not exist.") print(f"Error: Makefile path '{makefile_path}' does not exist.")
sys.exit(1) 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) 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) typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs)
vars = dict(sorted(vars.items())) vars = dict(sorted(vars.items()))
includes = get_sorted_headers(c_files, includes, include_dirs) 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): if not os.path.isfile(makefile_path):
raise FileNotFoundError(f"Makefile path '{makefile_path}' does not exist.") 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) 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) typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs)
vars = dict(sorted(vars.items())) vars = dict(sorted(vars.items()))
includes = get_sorted_headers(c_files, includes, include_dirs) includes = get_sorted_headers(c_files, includes, include_dirs)

View File

@@ -1,10 +1,10 @@
from PySide2.QtWidgets import ( from PySide2.QtWidgets import (
QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter, QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
QAbstractItemView, QHeaderView, QLabel, QAbstractItemView, QHeaderView, QLabel, QSpacerItem, QSizePolicy, QSpinBox,
QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QScrollArea, QWidget QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QScrollArea, QWidget
) )
from PySide2.QtGui import QColor, QBrush, QPalette from PySide2.QtGui import QColor, QBrush, QPalette
from PySide2.QtCore import Qt from PySide2.QtCore import Qt, QSettings
from enum import IntEnum from enum import IntEnum
from generate_debug_vars import type_map from generate_debug_vars import type_map
import time import time
@@ -60,6 +60,57 @@ class FilterDialog(QDialog):
return [cb.text() for cb in self.checkboxes if cb.isChecked()] 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="Укажите размер короткого имени"):
super().__init__(parent)
self.setWindowTitle(title)
self.setFixedSize(320, 120) # Задаем фиксированный размер для аккуратного вида
# Основной вертикальный макет
main_layout = QVBoxLayout(self)
# Макет для ввода значения
input_layout = QHBoxLayout()
label = QLabel("Количество символов:", 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): class CtrlScrollComboBox(QComboBox):
def wheelEvent(self, event): def wheelEvent(self, event):
if event.modifiers() & Qt.ControlModifier: if event.modifiers() & Qt.ControlModifier:
@@ -83,6 +134,11 @@ class VariableTableWidget(QTableWidget):
]) ])
self.setEditTriggers(QAbstractItemView.AllEditTriggers) self.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.var_list = [] self.var_list = []
# Инициализируем QSettings с именем организации и приложения
self.settings = QSettings("SET", "DebugVarEdit_VarTable")
# Восстанавливаем сохранённое состояние, если есть
shortsize = self.settings.value("shortname_size", True, type=int)
self._shortname_size = shortsize
self.type_options = list(dict.fromkeys(type_map.values())) self.type_options = list(dict.fromkeys(type_map.values()))
self.pt_types_all = [t.replace('pt_', '') for t in self.type_options] self.pt_types_all = [t.replace('pt_', '') for t in self.type_options]
@@ -231,7 +287,7 @@ class VariableTableWidget(QTableWidget):
t3 = time.time() t3 = time.time()
shortname = short_name_edit.text() if short_name_edit else "" shortname = short_name_edit.text() if short_name_edit else ""
long_shortname = len(shortname) > 10 long_shortname = len(shortname) > self._shortname_size
found = name in var_names_set found = name in var_names_set
color = None color = None
@@ -293,6 +349,13 @@ class VariableTableWidget(QTableWidget):
if dlg.exec_(): if dlg.exec_():
self._ret_type_filter = dlg.get_selected() self._ret_type_filter = dlg.get_selected()
self.update_comboboxes({rows.ret_type: self._ret_type_filter}) self.update_comboboxes({rows.ret_type: self._ret_type_filter})
elif logicalIndex == rows.short_name:
dlg = SetSizeDialog(self)
if dlg.exec_():
self._shortname_size = dlg.get_selected_size()
self.settings.setValue("shortname_size", self._shortname_size)
self.check()

View File

@@ -1,46 +1,68 @@
#include "debug_tools.h" #include "debug_tools.h"
#include "IQmathLib.h"
DebugLowLevel_t debug_ll = DEBUG_LOWLEVEL_INIT; #if !defined(GLOBAL_Q)
#define GLOBAL_Q 16
#endif
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var);
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var); 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);
///////////////////////////----EXAPLE-----////////////////////////////// ///////////////////////////----EXAPLE-----//////////////////////////////
long var_numb = 1; int var_numb = 1; ///< Ïðèìåð ïåðåìåííîé äëÿ îòëàäêè
DebugVarName_t var_name; DebugVarName_t var_name; ///< Èìÿ ïåðåìåííîé
long return_var; int32_t return_var; ///< Ïåðåìåííàÿ äëÿ âîçâðàòà ðåçóëüòàòà
long return_ll_var; int32_t return_ll_var; ///< Âîçâðàùàåìîå çíà÷åíèå ñ íèæíåãî óðîâíÿ
int result; int result; ///< Ïåðåìåííàÿ ðåçóëüòàòà
char ext_date[] = {7, 233, 11, 07, 16, 50}; DateTime_t ext_date = {2025, 11, 07, 16, 50}; ///< Ïðèìåð âíåøíåé äàòû ñáîðêè
/**
* @brief Ïðèìåð èñïîëüçîâàíèÿ ôóíêöèé îòëàäêè.
* @details Äåìîíñòðàöèîííàÿ ôóíêöèÿ äëÿ ðàáîòû ñ ïåðåìåííûìè îòëàäêè.
*/
void Debug_Test_Example(void) void Debug_Test_Example(void)
{ {
result = Debug_ReadVar(var_numb, &return_var); result = Debug_ReadVar(var_numb, &return_var);
result = Debug_ReadVarName(var_numb, var_name); result = Debug_ReadVarName(var_numb, var_name);
if(Debug_LowLevel_Initialize(ext_date) == 0) if(Debug_LowLevel_Initialize(&ext_date) == 0)
result = Debug_LowLevel_ReadVar(&return_ll_var); result = Debug_LowLevel_ReadVar(&return_ll_var);
} }
///////////////////////////----PUBLIC-----////////////////////////////// ///////////////////////////----PUBLIC-----//////////////////////////////
int Debug_ReadVar(int var_ind, long *return_long)
/**
* @brief ×èòàåò ïåðåìåííóþ ïî èíäåêñó.
* @param var_ind èíäåêñ ïåðåìåííîé.
* @param return_32b óêàçàòåëü äëÿ âîçâðàòà ðåçóëüòàòà.
* @return int 0: óñïåõ, 1: îøèáêà.
* @details Èñïîëüçóåòñÿ äëÿ ÷òåíèÿ çíà÷åíèé ïåðåìåííûõ ïî èõ èíäåêñó.
*/
int Debug_ReadVar(int var_ind, int32_t *return_32b)
{ {
if(return_long == NULL) if(return_32b == NULL)
return 1; return 1;
long tmp_var; int32_t tmp_var;
if (var_ind >= DebugVar_Qnt) if (var_ind >= DebugVar_Qnt)
return 1; return 1;
if((dbg_vars[var_numb].ptr_type == pt_struct) || (dbg_vars[var_numb].ptr_type == pt_union) || if((dbg_vars[var_ind].ptr_type == pt_struct) || (dbg_vars[var_ind].ptr_type == pt_union) ||
(dbg_vars[var_numb].ptr_type == pt_unknown)) (dbg_vars[var_ind].ptr_type == pt_unknown))
return 1; return 1;
return convertDebugVarToIQx(&dbg_vars[var_ind], return_32b);
return convertDebugVarToIQx(&dbg_vars[var_numb], return_long);
} }
/**
* @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 Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr)
{ {
if(name_ptr == NULL) if(name_ptr == NULL)
@@ -51,29 +73,34 @@ int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr)
int i; int i;
// Êîïèðîâàíèå ñ çàùèòîé îò ïåðåïîëíåíèÿ è ÿâíîé îñòàíîâêîé ïî '\0' // Êîïèðîâàíèå ñ çàùèòîé îò ïåðåïîëíåíèÿ è ÿâíîé îñòàíîâêîé ïî '\0'
for (i = 0; i < sizeof(dbg_vars[var_numb].name); i++) for (i = 0; i < sizeof(dbg_vars[var_ind].name); i++)
{ {
name_ptr[i] = dbg_vars[var_numb].name[i]; name_ptr[i] = dbg_vars[var_ind].name[i];
if (dbg_vars[var_numb].name[i] == '\0') if (dbg_vars[var_ind].name[i] == '\0')
break; break;
} }
// Ãàðàíòèðîâàííîå çàâåðøåíèå ñòðîêè (íà ñëó÷àé, åñëè â var->name íå áûëî '\0') // Ãàðàíòèðîâàííîå çàâåðøåíèå ñòðîêè (íà ñëó÷àé, åñëè â var->name íå áûëî '\0')
name_ptr[sizeof(dbg_vars[var_numb].name) - 1] = '\0'; name_ptr[sizeof(dbg_vars[var_ind].name) - 1] = '\0';
return 0; return 0;
} }
/**
int Debug_LowLevel_ReadVar(long *return_long) * @brief ×èòàåò çíà÷åíèå ïåðåìåííîé îòëàäêè ñ íèæíåãî óðîâíÿ.
* @param return_32b óêàçàòåëü íà ïåðåìåííóþ, êóäà çàïèñûâàåòñÿ ðåçóëüòàò.
* @return int 0: óñïåõ, 1: îøèáêà, 2: íåäîïóñòèìûé àäðåñ.
* @details Èñïîëüçóåò àäðåññ, ïåðåäàâàåìûé ñ òåðìèíàëêè äëÿ ïîëó÷åíèÿ çíà÷åíèÿ.
*/
int Debug_LowLevel_ReadVar(int32_t *return_32b)
{ {
if (return_long == NULL) if (return_32b == NULL)
return 1; return 1;
if (debug_ll.isVerified == 0) if (debug_ll.isVerified == 0)
return 1; return 1;
char *addr = debug_ll.dbg_var.Ptr; uint8_t *addr = debug_ll.dbg_var.Ptr;
unsigned long addr_val = (unsigned long)addr; uint32_t addr_val = (uint32_t)addr;
// Ðàçðåø¸ííûå äèàïàçîíû ïàìÿòè (èç .cmd ôàéëà) // Ðàçðåø¸ííûå äèàïàçîíû ïàìÿòè (èç .cmd ôàéëà)
if (!( if (!(
@@ -89,32 +116,28 @@ int Debug_LowLevel_ReadVar(long *return_long)
return 2; // Çàïðåù¸ííûé àäðåñ — íåëüçÿ ÷èòàòü return 2; // Çàïðåù¸ííûé àäðåñ — íåëüçÿ ÷èòàòü
} }
return convertDebugVarToIQx(&debug_ll.dbg_var, return_long); return convertDebugVarToIQx(&debug_ll.dbg_var, return_32b);
;
} }
/**
int Debug_LowLevel_Initialize(const char* external_date) * @brief Èíèöèàëèçàöèÿ îòëàäêè íà íèæíåì óðîâíå ïî äàòå ñáîðêè.
* @param external_date ñòðóêòóðà ñ äàòîé DateTime_t
* @return int 0: ñîâïàäàåò, 1: íå ñîâïàäàåò, -1: îøèáêà.
* @details Ñðàâíèâàåò äàòó êîìïèëÿöèè ñ çàïðàøèâàåìîé è èíèöèàëèçèðóåò îòëàäî÷íóþ ïåðåìåííóþ.
*/
int Debug_LowLevel_Initialize(DateTime_t* external_date)
{ {
if (external_date == NULL) { if (external_date == NULL) {
return -1; return -1;
} }
// Ïðåîáðàçóåì external_date â ñòðóêòóðó
DateTime_t ext;
ext.year = (external_date[0] << 8) | external_date[1];
ext.day = external_date[2];
ext.month = external_date[3];
ext.hour = external_date[4];
ext.minute = external_date[5];
// Ñðàâíåíèå âñåõ ïîëåé // Ñðàâíåíèå âñåõ ïîëåé
if (ext.year == debug_ll.build_date.year && if (external_date->year == debug_ll.build_date.year &&
ext.month == debug_ll.build_date.month && external_date->month == debug_ll.build_date.month &&
ext.day == debug_ll.build_date.day && external_date->day == debug_ll.build_date.day &&
ext.hour == debug_ll.build_date.hour && external_date->hour == debug_ll.build_date.hour &&
ext.minute == debug_ll.build_date.minute) external_date->minute == debug_ll.build_date.minute)
{ {
debug_ll.isVerified = 1; debug_ll.isVerified = 1;
return 0; // Ñîâïàëî return 0; // Ñîâïàëî
@@ -129,6 +152,12 @@ int Debug_LowLevel_Initialize(const char* external_date)
/////////////////////----INTERNAL FUNCTIONS-----//////////////////////// /////////////////////----INTERNAL FUNCTIONS-----////////////////////////
/**
* @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) static int iqTypeToQ(DebugVarIQType_t t)
{ {
if (t == t_iq_none) if (t == t_iq_none)
@@ -141,9 +170,16 @@ static int iqTypeToQ(DebugVarIQType_t t)
return -1; // îøèáêà return -1; // îøèáêà
} }
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var) /**
* @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)
{ {
long iq_numb, iq_united, iq_final; int32_t iq_numb, iq_united, iq_final;
float float_numb; float float_numb;
if(getDebugVar(var, &iq_numb, &float_numb) != 0) if(getDebugVar(var, &iq_numb, &float_numb) != 0)
@@ -155,30 +191,30 @@ static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
if (src_q < 0 || dst_q < 0) if (src_q < 0 || dst_q < 0)
return 2; // íåïðàâèëüíûé ôîðìàò return 2; // íåïðàâèëüíûé ôîðìàò
long long iq_united64 = 0; int64_t iq_united64 = 0;
long long iq_final64 = 0; int64_t iq_final64 = 0;
// Êîíâåðòàöèÿ ê GLOBAL_Q (64-áèò) // Êîíâåðòàöèÿ ê GLOBAL_Q (64-áèò)
if (var->iq_type == t_iq_none) { if (var->iq_type == t_iq_none) {
if (var->ptr_type == pt_float) { if (var->ptr_type == pt_float) {
// float_numb óìíîæàåì íà 2^GLOBAL_Q (2^24=16777216) // float_numb óìíîæàåì íà 2^GLOBAL_Q
// Ðåçóëüòàò ïðèâîäèì ê long long // Ðåçóëüòàò ïðèâîäèì ê 64 áèòà
iq_united64 = (long long)(float_numb * 16777216.0f); iq_united64 = (int64_t)(float_numb * (1 << GLOBAL_Q));
} else { } else {
iq_united64 = ((long long)iq_numb) << GLOBAL_Q; iq_united64 = ((int64_t)iq_numb) << GLOBAL_Q;
} }
} else { } else {
int shift = GLOBAL_Q - src_q; int shift = GLOBAL_Q - src_q;
if (shift >= 0) if (shift >= 0)
iq_united64 = ((long long)iq_numb) << shift; iq_united64 = ((int64_t)iq_numb) << shift;
else else
iq_united64 = ((long long)iq_numb) >> (-shift); iq_united64 = ((int64_t)iq_numb) >> (-shift);
} }
// Êîíâåðòàöèÿ èç GLOBAL_Q â öåëåâîé IQ (64-áèò) // Êîíâåðòàöèÿ èç GLOBAL_Q â öåëåâîé IQ (64-áèò)
if (var->return_type == t_iq_none) { if (var->return_type == t_iq_none) {
// Âîçâðàùàåì öåëîå, îòáðîñèâ äðîáíóþ ÷àñòü // Âîçâðàùàåì öåëîå, îòáðîñèâ äðîáíóþ ÷àñòü
*ret_var = (long)(iq_united64 >> GLOBAL_Q); *ret_var = (uint32_t)(iq_united64 >> GLOBAL_Q);
} else { } else {
int shift = dst_q - GLOBAL_Q; int shift = dst_q - GLOBAL_Q;
if (shift >= 0) if (shift >= 0)
@@ -187,54 +223,65 @@ static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
iq_final64 = iq_united64 >> (-shift); iq_final64 = iq_united64 >> (-shift);
// Ïðîâåðÿåì ïåðåïîëíåíèå int32_t // Ïðîâåðÿåì ïåðåïîëíåíèå int32_t
if (iq_final64 > LONG_MAX || iq_final64 < LONG_MIN) if (iq_final64 > 2147483647 || iq_final64 < -2147483648)
return 3; // ïåðåïîëíåíèå return 3; // ïåðåïîëíåíèå
*ret_var = (long)iq_final64; *ret_var = (uint32_t)iq_final64;
} }
return 0; 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) if (!var || !int_var || !float_var || !var->Ptr)
return 1; // îøèáêà: null óêàçàòåëü return 1; // îøèáêà: null óêàçàòåëü
char *addr = var->Ptr; uint8_t *addr = var->Ptr;
unsigned long addr_val = (unsigned long)addr; uint32_t addr_val = (uint32_t)addr;
switch (var->ptr_type) switch (var->ptr_type)
{ {
case pt_int8: // 8 áèò case pt_int8: // 8 áèò
if ((addr_val & ALIGN_8BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return 1; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile int8_t *)addr);
case pt_uint8: case pt_uint8:
// âûðàâíèâàíèå íå íóæíî äëÿ 8 áèò if ((addr_val & ALIGN_8BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
*int_var = *((volatile char *)addr); return 1; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile uint8_t *)addr);
break; break;
case pt_int16: // 16 áèò (int) case pt_int16: // 16 áèò (int)
if ((addr_val & ALIGN_16BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return 2; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile int16_t *)addr);
case pt_uint16: case pt_uint16:
*int_var = *((volatile int *)addr); if ((addr_val & ALIGN_16BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return 2; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile uint16_t *)addr);
break; break;
case pt_int32: // 32 áèò (long) case pt_int32: // 32 áèò
case pt_uint32: if ((addr_val & ALIGN_32BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
if (addr_val & 0x1) // ïðîâåðÿåì âûðàâíèâàíèå ïî 2 ñëîâàì (4 áàéòà)
return 3; // îøèáêà âûðàâíèâàíèÿ return 3; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile long *)addr); *int_var = *((volatile int32_t *)addr);
case pt_uint32:
if ((addr_val & ALIGN_32BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
return 3; // îøèáêà âûðàâíèâàíèÿ
*int_var = *((volatile uint32_t *)addr);
break; break;
// case pt_int64: // 64 áèò (long long)
// case pt_uint64:
// if (addr_val & 0x3) // ïðîâåðêà âûðàâíèâàíèÿ ïî 4 ñëîâàì (8 áàéòàì)
// return 2; // îøèáêà âûðàâíèâàíèÿ
// // Òóò ïðîñòî ÷èòàåì, íî long long ìîæåò íå ïîìåñòèòüñÿ â *int_var
// // Ìîæíî çàìåíèòü ëîãèêó ïîä 64-áèòíîå ÷òåíèå ïðè íåîáõîäèìîñòè
// *int_var = *((volatile long long *)addr);
// break;
case pt_float: // float (4 áàéòà) case pt_float: // float (4 áàéòà)
if (addr_val & 0x1) // ïðîâåðêà âûðàâíèâàíèÿ ïî 2 ñëîâàì if ((addr_val & ALIGN_FLOAT) != 0) // ïðîâåðêà âûðàâíèâàíèÿ
return 4; // îøèáêà âûðàâíèâàíèÿ return 4; // îøèáêà âûðàâíèâàíèÿ
*float_var = *((volatile float *)addr); *float_var = *((volatile float *)addr);
break; break;
@@ -259,211 +306,3 @@ static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
return 0; // óñïåõ return 0; // óñïåõ
} }
///////////// OUTDATE ////////////////
//
// // ïðèâåäåíèå ê îäíîìó IQ
// switch(var->iq_type)
// {
// case t_iq_none:
// if(var->ptr_type == pt_float)
// {
// iq_united = _IQ(float_numb);
// }
// else
// {
// iq_united = _IQ(iq_numb);
// }
// break;
// case t_iq1:
// iq_united = _IQ1toIQ(iq_numb);
// break;
// case t_iq2:
// iq_united = _IQ2toIQ(iq_numb);
// break;
// case t_iq3:
// iq_united = _IQ3toIQ(iq_numb);
// break;
// case t_iq4:
// iq_united = _IQ4toIQ(iq_numb);
// break;
// case t_iq5:
// iq_united = _IQ5toIQ(iq_numb);
// break;
// case t_iq6:
// iq_united = _IQ6toIQ(iq_numb);
// break;
// case t_iq7:
// iq_united = _IQ7toIQ(iq_numb);
// break;
// case t_iq8:
// iq_united = _IQ8toIQ(iq_numb);
// break;
// case t_iq9:
// iq_united = _IQ9toIQ(iq_numb);
// break;
// case t_iq10:
// iq_united = _IQ10toIQ(iq_numb);
// break;
// case t_iq11:
// iq_united = _IQ11toIQ(iq_numb);
// break;
// case t_iq12:
// iq_united = _IQ12toIQ(iq_numb);
// break;
// case t_iq13:
// iq_united = _IQ13toIQ(iq_numb);
// break;
// case t_iq14:
// iq_united = _IQ14toIQ(iq_numb);
// break;
// case t_iq15:
// iq_united = _IQ15toIQ(iq_numb);
// break;
// case t_iq16:
// iq_united = _IQ16toIQ(iq_numb);
// break;
// case t_iq17:
// iq_united = _IQ17toIQ(iq_numb);
// break;
// case t_iq18:
// iq_united = _IQ18toIQ(iq_numb);
// break;
// case t_iq19:
// iq_united = _IQ19toIQ(iq_numb);
// break;
// case t_iq20:
// iq_united = _IQ20toIQ(iq_numb);
// break;
// case t_iq21:
// iq_united = _IQ21toIQ(iq_numb);
// break;
// case t_iq22:
// iq_united = _IQ22toIQ(iq_numb);
// break;
// case t_iq23:
// iq_united = _IQ23toIQ(iq_numb);
// break;
// case t_iq24:
// iq_united = _IQ24toIQ(iq_numb);
// break;
// case t_iq25:
// iq_united = _IQ25toIQ(iq_numb);
// break;
// case t_iq26:
// iq_united = _IQ26toIQ(iq_numb);
// break;
// case t_iq27:
// iq_united = _IQ27toIQ(iq_numb);
// break;
// case t_iq28:
// iq_united = _IQ28toIQ(iq_numb);
// break;
// case t_iq29:
// iq_united = _IQ29toIQ(iq_numb);
// break;
// case t_iq30:
// iq_united = _IQ30toIQ(iq_numb);
// break;
// }
//
// // ïðèâåäåíèå îáùåãî IQ ê çàïðàøèâàåìîìó
// switch(var->return_type)
// {
// case t_iq_none:
// iq_final = (long)_IQtoF(iq_united);
// break;
// case t_iq1:
// iq_final = _IQtoIQ1(iq_united);
// break;
// case t_iq2:
// iq_final = _IQtoIQ2(iq_united);
// break;
// case t_iq3:
// iq_final = _IQtoIQ3(iq_united);
// break;
// case t_iq4:
// iq_final = _IQtoIQ4(iq_united);
// break;
// case t_iq5:
// iq_final = _IQtoIQ5(iq_united);
// break;
// case t_iq6:
// iq_final = _IQtoIQ6(iq_united);
// break;
// case t_iq7:
// iq_final = _IQtoIQ7(iq_united);
// break;
// case t_iq8:
// iq_final = _IQtoIQ8(iq_united);
// break;
// case t_iq9:
// iq_final = _IQtoIQ9(iq_united);
// break;
// case t_iq10:
// iq_final = _IQtoIQ10(iq_united);
// break;
// case t_iq11:
// iq_final = _IQtoIQ11(iq_united);
// break;
// case t_iq12:
// iq_final = _IQtoIQ12(iq_united);
// break;
// case t_iq13:
// iq_final = _IQtoIQ13(iq_united);
// break;
// case t_iq14:
// iq_final = _IQtoIQ14(iq_united);
// break;
// case t_iq15:
// iq_final = _IQtoIQ15(iq_united);
// break;
// case t_iq16:
// iq_final = _IQtoIQ16(iq_united);
// break;
// case t_iq17:
// iq_final = _IQtoIQ17(iq_united);
// break;
// case t_iq18:
// iq_final = _IQtoIQ18(iq_united);
// break;
// case t_iq19:
// iq_final = _IQtoIQ19(iq_united);
// break;
// case t_iq20:
// iq_final = _IQtoIQ20(iq_united);
// break;
// case t_iq21:
// iq_final = _IQtoIQ21(iq_united);
// break;
// case t_iq22:
// iq_final = _IQtoIQ22(iq_united);
// break;
// case t_iq23:
// iq_final = _IQtoIQ23(iq_united);
// break;
// case t_iq24:
// iq_final = _IQtoIQ24(iq_united);
// break;
// case t_iq25:
// iq_final = _IQtoIQ25(iq_united);
// break;
// case t_iq26:
// iq_final = _IQtoIQ26(iq_united);
// break;
// case t_iq27:
// iq_final = _IQtoIQ27(iq_united);
// break;
// case t_iq28:
// iq_final = _IQtoIQ28(iq_united);
// break;
// case t_iq29:
// iq_final = _IQtoIQ29(iq_united);
// break;
// case t_iq30:
// iq_final = _IQtoIQ30(iq_united);
// break;
// }
// *ret_var = iq_final;

View File

@@ -1,8 +1,40 @@
#ifndef DEBUG_TOOLS #ifndef DEBUG_TOOLS
#define DEBUG_TOOLS #define DEBUG_TOOLS
#include "IQmathLib.h" #include <stdint.h>
#include "DSP281x_Device.h" #include <limits.h>
#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
/**
* @brief Òèï äàííûõ, íà êîòîðûé óêàçûâàåò óêàçàòåëü ïåðåìåííîé îòëàäêè.
*/
typedef enum typedef enum
{ {
pt_unknown, // unknown pt_unknown, // unknown
@@ -14,7 +46,7 @@ typedef enum
pt_uint16, // unsigned int pt_uint16, // unsigned int
pt_uint32, // unsigned long pt_uint32, // unsigned long
pt_uint64, // unsigned long pt_uint64, // unsigned long
pt_float, // float pt_float, // floatf
pt_struct, // struct pt_struct, // struct
pt_union, // struct pt_union, // struct
// pt_ptr_int8, // signed char* // pt_ptr_int8, // signed char*
@@ -31,6 +63,9 @@ typedef enum
// pt_arr_uint32, // unsigned long[] // pt_arr_uint32, // unsigned long[]
}DebugVarPtrType_t; }DebugVarPtrType_t;
/**
* @brief Òèïû IQ-ïðåäñòàâëåíèÿ ïåðåìåííîé îòëàäêè.
*/
typedef enum typedef enum
{ {
t_iq_none, t_iq_none,
@@ -67,45 +102,67 @@ typedef enum
t_iq30 t_iq30
}DebugVarIQType_t; }DebugVarIQType_t;
typedef char DebugVarName_t[11]; typedef char DebugVarName_t[11]; ///< Èìÿ ïåðåìåííîé îòëàäêè (äî 10 ñèìâîëîâ + \0)
/**
* @brief Îïèñàíèå ïåðåìåííîé îòëàäêè.
*/
typedef struct typedef struct
{ {
char* Ptr; uint8_t* Ptr; ///< Óêàçàòåëü íà çíà÷åíèå ïåðåìåííîé
DebugVarPtrType_t ptr_type; DebugVarPtrType_t ptr_type; ///< Òèï çíà÷åíèÿ
DebugVarIQType_t iq_type; DebugVarIQType_t iq_type; ///< Òèï IQ ïåðåìåííîé (åñëè åñòü)
DebugVarIQType_t return_type; DebugVarIQType_t return_type;///< Òèï IQ âîçâðàùàåìîãî çíà÷åíèÿ
DebugVarName_t name; DebugVarName_t name; ///< Èìÿ ïåðåìåííîé
}DebugVar_t; } DebugVar_t;
typedef long DebugValue_t;
/**
* @brief Ñòðóêòóðà äàòû è âðåìåíè.
*/
typedef struct { typedef struct {
int year; uint16_t year; ///< Ãîä (íàïðèìåð, 2025)
char month; uint8_t month; ///< Ìåñÿö (1-12)
char day; uint8_t day; ///< Äåíü (1-31)
char hour; uint8_t hour; ///< ×àñû (0-23)
char minute; uint8_t minute; ///< Ìèíóòû (0-59)
} DateTime_t; } DateTime_t;
/**
* @brief Ñòðóêòóðà íèæíåãî óðîâíÿ îòëàäêè.
*/
typedef struct typedef struct
{ {
DateTime_t build_date; DateTime_t build_date; ///< Äàòà ñáîðêè
unsigned int isVerified; unsigned int isVerified; ///< Ôëàã èíèöèàëèçàöèè íèçêîóðîâíåíîé îòëàäêè (0 — íåò, 1 — óñïåøíî)
DebugVar_t dbg_var; DebugVar_t dbg_var; ///< Ïåðåìåííàÿ äëÿ îòëàäêè
}DebugLowLevel_t; }DebugLowLevel_t;
extern DebugLowLevel_t debug_ll; extern DebugLowLevel_t debug_ll; ///< Ãëîáàëüíûé ýêçåìïëÿð îòëàäêè íèæíåãî óðîâíÿ
/** @brief Ìàêðîñ èíèöèàëèçàöèè äàòû */
#define DATE_INIT {BUILD_YEAR, BUILD_MONTH, BUILD_DATA, BUILD_HOURS, BUILD_MINUTES} #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"} #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} #define DEBUG_LOWLEVEL_INIT {DATE_INIT, 0, DEBUG_VAR_INIT}
extern int DebugVar_Qnt; extern int DebugVar_Qnt; ///< Êîëè÷åñòâî ïåðåìåííûõ îòëàäêè
extern DebugVar_t dbg_vars[]; extern DebugVar_t dbg_vars[]; ///< Ìàññèâ ïåðåìåííûõ îòëàäêè
/* Ïðèìåð èñïîëüçîâàíèÿ îòëàäêè */
void Debug_Test_Example(void); void Debug_Test_Example(void);
int Debug_ReadVar(int var_ind, long *return_long); /* ×èòàåò çíà÷åíèå ïåðåìåííîé ïî èíäåêñó */
int Debug_ReadVar(int var_ind, int32_t *return_long);
/* ×èòàåò èìÿ ïåðåìåííîé ïî èíäåêñó */
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr); int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr);
int Debug_LowLevel_ReadVar(long *return_long); /* ×èòàåò çíà÷åíèå ïåðåìåííîé ñ íèæíåãî óðîâíÿ */
int Debug_LowLevel_Initialize(const char* external_date); int Debug_LowLevel_ReadVar(int32_t *return_long);
/* Èíèöèàëèçèðóåò îòëàäêó íèæíåãî óðîâíÿ */
int Debug_LowLevel_Initialize(DateTime_t *external_date);
#endif //DEBUG_TOOLS #endif //DEBUG_TOOLS

23
debug_vars_example.c Normal file
View File

@@ -0,0 +1,23 @@
#include "debug_tools.h"
// Инклюды для доступа к переменным
#include "bender.h"
// Экстерны для доступа к переменным
extern int ADC0finishAddr;
// Определение массива с указателями на переменные для отладки
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" }, \
};