добавлены комменты к debug_tools.c/.h
начата работа над поддержкой stm32 и кейл проектов
This commit is contained in:
		
							parent
							
								
									742c4e9e1b
								
							
						
					
					
						commit
						4de53090a1
					
				
							
								
								
									
										
											BIN
										
									
								
								DebugVarEdit.exe
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								DebugVarEdit.exe
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							@ -5,7 +5,7 @@ import sys
 | 
			
		||||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
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
 | 
			
		||||
import threading
 | 
			
		||||
from generate_debug_vars import run_generate
 | 
			
		||||
@ -21,8 +21,9 @@ 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
 | 
			
		||||
 | 
			
		||||
@ -58,6 +59,7 @@ class VarEditor(QWidget):
 | 
			
		||||
        self.output_path = None
 | 
			
		||||
        self._updating = False  # Флаг блокировки рекурсии
 | 
			
		||||
        self._resizing = False  # флаг блокировки повторного вызова
 | 
			
		||||
        self.target = 'TMS'
 | 
			
		||||
        self.initUI()
 | 
			
		||||
 | 
			
		||||
    def initUI(self):
 | 
			
		||||
@ -122,6 +124,23 @@ class VarEditor(QWidget):
 | 
			
		||||
        self.btn_update_vars = QPushButton(scan_title)
 | 
			
		||||
        self.btn_update_vars.clicked.connect(self.update_vars_data)
 | 
			
		||||
 | 
			
		||||
        # Добавляем чекбокс для выбора типовой карты
 | 
			
		||||
        # --- Создаем верхнее меню ---
 | 
			
		||||
        menubar = QMenuBar(self)
 | 
			
		||||
        target_menu = QMenu("Target", menubar)
 | 
			
		||||
        # Создаем действия для выбора Target
 | 
			
		||||
        self.action_tms = QAction("TMS", self, checkable=True)
 | 
			
		||||
        self.action_stm = QAction("STM", self, checkable=True)
 | 
			
		||||
        # Группируем действия чтобы выбирался только один
 | 
			
		||||
        self.action_tms.setChecked(True)  # по умолчанию TMS
 | 
			
		||||
        self.action_tms.triggered.connect(lambda: self.on_target_selected("tms"))
 | 
			
		||||
        self.action_stm.triggered.connect(lambda: self.on_target_selected("stm"))
 | 
			
		||||
 | 
			
		||||
        target_menu.addAction(self.action_tms)
 | 
			
		||||
        target_menu.addAction(self.action_stm)
 | 
			
		||||
 | 
			
		||||
        menubar.addMenu(target_menu)
 | 
			
		||||
 | 
			
		||||
        # Кнопка сохранения
 | 
			
		||||
        btn_save = QPushButton(build_title)
 | 
			
		||||
        btn_save.clicked.connect(self.save_build)
 | 
			
		||||
@ -137,6 +156,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)
 | 
			
		||||
@ -150,7 +170,18 @@ class VarEditor(QWidget):
 | 
			
		||||
        self.setLayout(layout)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    def on_target_selected(self, target):
 | 
			
		||||
        self.target = target.lower()
 | 
			
		||||
        if 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()
 | 
			
		||||
        return xml_path
 | 
			
		||||
@ -358,15 +389,25 @@ 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:
 | 
			
		||||
            path = myXML.make_relative_path(file_path, self.proj_path)
 | 
			
		||||
        else:
 | 
			
		||||
            path = file_path
 | 
			
		||||
        self.makefile_edit.setText(path)
 | 
			
		||||
        self.makefile_path = path
 | 
			
		||||
        if file_path:
 | 
			
		||||
            if self.proj_path:
 | 
			
		||||
                path = myXML.make_relative_path(file_path, self.proj_path)
 | 
			
		||||
            else:
 | 
			
		||||
                path = file_path
 | 
			
		||||
            self.makefile_edit.setText(path)
 | 
			
		||||
            self.makefile_path = path
 | 
			
		||||
 | 
			
		||||
    def __browse_source_output(self):
 | 
			
		||||
        dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку для debug_vars.c")
 | 
			
		||||
@ -438,12 +479,12 @@ class VarEditor(QWidget):
 | 
			
		||||
        self.write_to_xml()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __open_variable_selector(self):
 | 
			
		||||
    def __open_variable_selector(self):        
 | 
			
		||||
        self.update()
 | 
			
		||||
        if not self.vars_list:
 | 
			
		||||
            QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).")
 | 
			
		||||
            return
 | 
			
		||||
        
 | 
			
		||||
        self.update()
 | 
			
		||||
        dlg = VariableSelectorDialog(self.table, self.vars_list, self.structs, self.typedef_map, self.xml_path, self)
 | 
			
		||||
        if dlg.exec_():
 | 
			
		||||
            self.write_to_xml()
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ import argparse
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# === Словарь соответствия типов 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 +52,147 @@ 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
 | 
			
		||||
 | 
			
		||||
def choose_type_map(stm_flag):
 | 
			
		||||
    global type_map  # объявляем, что будем менять глобальную переменную
 | 
			
		||||
    if stm_flag:
 | 
			
		||||
        type_map = type_map_stm32
 | 
			
		||||
    else:
 | 
			
		||||
        type_map = type_map_tms
 | 
			
		||||
 | 
			
		||||
def map_type_to_pt(typename, varname=None, typedef_map=None):
 | 
			
		||||
    typename_orig = typename.strip()
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
from lxml import etree as ET
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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):
 | 
			
		||||
    makefile_dir = os.path.dirname(makefile_path)
 | 
			
		||||
    project_root = 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()
 | 
			
		||||
 | 
			
		||||
    objs_lines = []
 | 
			
		||||
    raw_entries = []
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
        if (("ORDERED_OBJS" in stripped or "C_SOURCES" in stripped) and ("+=" in stripped or "=" in stripped)):
 | 
			
		||||
            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)
 | 
			
		||||
            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
 | 
			
		||||
 | 
			
		||||
    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 = []
 | 
			
		||||
    for part in objs_str.split():
 | 
			
		||||
        part = part.strip()
 | 
			
		||||
        if part.startswith('"') and part.endswith('"'):
 | 
			
		||||
            part = part[1:-1]
 | 
			
		||||
        if part:
 | 
			
		||||
            objs.append(part)
 | 
			
		||||
            if token.endswith(".obj"):
 | 
			
		||||
                token = re.sub(r"\.obj$", ".c", token)
 | 
			
		||||
            elif token.endswith(".o"):
 | 
			
		||||
                token = re.sub(r"\.o$", ".c", token)
 | 
			
		||||
 | 
			
		||||
    c_files = []
 | 
			
		||||
    include_dirs = set()
 | 
			
		||||
            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))
 | 
			
		||||
 | 
			
		||||
    for obj_path in objs:
 | 
			
		||||
        if "DebugTools" in obj_path:
 | 
			
		||||
            continue
 | 
			
		||||
        if "v120" in obj_path:
 | 
			
		||||
            continue
 | 
			
		||||
        if "v100" in obj_path:
 | 
			
		||||
            continue
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
    # Добавляем пути с заменой '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)
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
@ -11,7 +11,7 @@ from clang import cindex
 | 
			
		||||
from clang.cindex import Config
 | 
			
		||||
import lxml.etree as ET
 | 
			
		||||
from xml.dom import minidom
 | 
			
		||||
from makefile_parser 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'
 | 
			
		||||
@ -295,6 +295,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 +424,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 = {}
 | 
			
		||||
@ -444,6 +464,8 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
 | 
			
		||||
        def visit(node):
 | 
			
		||||
            if node.kind == clang.cindex.CursorKind.TYPEDEF_DECL:
 | 
			
		||||
                name = node.spelling
 | 
			
		||||
                if 'ADC_HandleTypeDef' in name:
 | 
			
		||||
                    a =1 
 | 
			
		||||
                underlying = node.underlying_typedef_type.spelling
 | 
			
		||||
                typedefs[name] = underlying
 | 
			
		||||
 | 
			
		||||
@ -451,6 +473,8 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
 | 
			
		||||
                prefix = "struct " if node.kind == clang.cindex.CursorKind.STRUCT_DECL else "union "
 | 
			
		||||
 | 
			
		||||
                raw_name = node.spelling
 | 
			
		||||
                if 'struct (unnamed struct at F:\\Work\\Projects\\NIIET\\MZKT\\MZKT\\Drivers\\STM32F4xx_HAL_Driver\\Inc\\stm32f4xx_hal_adc.h:195:9)' in raw_name:
 | 
			
		||||
                    a =1 
 | 
			
		||||
                normalized_name = normalize_type_name(raw_name)
 | 
			
		||||
 | 
			
		||||
                # struct_name всегда с префиксом
 | 
			
		||||
@ -855,10 +879,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 +922,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)
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,23 @@
 | 
			
		||||
#include "debug_tools.h"
 | 
			
		||||
#include "IQmathLib.h"
 | 
			
		||||
 | 
			
		||||
DebugLowLevel_t debug_ll = DEBUG_LOWLEVEL_INIT;
 | 
			
		||||
DebugLowLevel_t debug_ll = DEBUG_LOWLEVEL_INIT; ///< Структура отладки нижнего уровня (инициализация)
 | 
			
		||||
 | 
			
		||||
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var);
 | 
			
		||||
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var);
 | 
			
		||||
 | 
			
		||||
///////////////////////////----EXAPLE-----//////////////////////////////
 | 
			
		||||
long var_numb = 1;
 | 
			
		||||
DebugVarName_t var_name;
 | 
			
		||||
long return_var;
 | 
			
		||||
long return_ll_var;
 | 
			
		||||
int result;
 | 
			
		||||
char ext_date[] = {7, 233, 11, 07, 16, 50};
 | 
			
		||||
long var_numb = 1;          ///< Пример переменной для отладки
 | 
			
		||||
DebugVarName_t var_name;    ///< Имя переменной
 | 
			
		||||
long return_var;            ///< Переменная для возврата результата
 | 
			
		||||
long return_ll_var;         ///< Возвращаемое значение с нижнего уровня
 | 
			
		||||
int result;                 ///< Переменная результата
 | 
			
		||||
char ext_date[] = {7, 233, 11, 07, 16, 50}; ///< Пример внешней даты сборки
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief    Пример использования функций отладки.
 | 
			
		||||
  * @details  Демонстрационная функция для работы с переменными отладки.
 | 
			
		||||
  */
 | 
			
		||||
void Debug_Test_Example(void)
 | 
			
		||||
{
 | 
			
		||||
    result = Debug_ReadVar(var_numb, &return_var);
 | 
			
		||||
@ -24,6 +29,14 @@ void Debug_Test_Example(void)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///////////////////////////----PUBLIC-----//////////////////////////////
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief    Читает переменную по индексу.
 | 
			
		||||
  * @param    var_ind      – индекс переменной.
 | 
			
		||||
  * @param    return_long  – указатель для возврата результата.
 | 
			
		||||
  * @return   int          – 0: успех, 1: ошибка.
 | 
			
		||||
  * @details  Используется для чтения значений переменных по их индексу.
 | 
			
		||||
  */
 | 
			
		||||
int Debug_ReadVar(int var_ind, long *return_long)
 | 
			
		||||
{
 | 
			
		||||
    if(return_long == NULL)
 | 
			
		||||
@ -41,6 +54,13 @@ int Debug_ReadVar(int var_ind, long *return_long)
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    if(name_ptr == NULL)
 | 
			
		||||
@ -64,7 +84,12 @@ int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief    Читает значение переменной отладки с нижнего уровня.
 | 
			
		||||
  * @param    return_long – указатель на переменную, куда записывается результат.
 | 
			
		||||
  * @return   int         – 0: успех, 1: ошибка, 2: недопустимый адрес.
 | 
			
		||||
  * @details  Использует адресс, передаваемый с терминалки для получения значения.
 | 
			
		||||
  */
 | 
			
		||||
int Debug_LowLevel_ReadVar(long *return_long)
 | 
			
		||||
{
 | 
			
		||||
    if (return_long == NULL)
 | 
			
		||||
@ -93,7 +118,12 @@ int Debug_LowLevel_ReadVar(long *return_long)
 | 
			
		||||
;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief    Инициализация отладки на нижнем уровне по дате сборки.
 | 
			
		||||
  * @param    external_date – указатель на массив из 6 байт: {year_hi, year_lo, day, month, hour, minute}.
 | 
			
		||||
  * @return   int           – 0: совпадает, 1: не совпадает, -1: ошибка.
 | 
			
		||||
  * @details  Сравнивает дату компиляции с запрашиваемой и инициализирует отладочную переменную.
 | 
			
		||||
  */
 | 
			
		||||
int Debug_LowLevel_Initialize(const char* external_date)
 | 
			
		||||
{
 | 
			
		||||
    if (external_date == NULL) {
 | 
			
		||||
@ -129,6 +159,12 @@ int Debug_LowLevel_Initialize(const char* external_date)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/////////////////////----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)
 | 
			
		||||
{
 | 
			
		||||
    if (t == t_iq_none)
 | 
			
		||||
@ -141,6 +177,13 @@ static int iqTypeToQ(DebugVarIQType_t t)
 | 
			
		||||
        return -1;      // îøèáêà
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief    Преобразует переменную отладки в IQ формат.
 | 
			
		||||
  * @param    var      – указатель на переменную отладки.
 | 
			
		||||
  * @param    ret_var  – указатель для возврата значения в формате long.
 | 
			
		||||
  * @return   int      – 0: успех, 1: ошибка чтения, 2: неправильный формат, 3: переполнение.
 | 
			
		||||
  * @details  Определяет формат IQ переменной, конвертирует её в long с учётом масштаба.
 | 
			
		||||
  */
 | 
			
		||||
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
 | 
			
		||||
{
 | 
			
		||||
    long iq_numb, iq_united, iq_final;
 | 
			
		||||
@ -196,6 +239,14 @@ static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief    Прочитать значение переменной отладки.
 | 
			
		||||
  * @param    var        – указатель на структуру DebugVar.
 | 
			
		||||
  * @param    int_var    – указатель на переменную типа long для возврата целочисленного значения.
 | 
			
		||||
  * @param    float_var  – указатель на переменную типа float для возврата значения с плавающей точкой.
 | 
			
		||||
  * @return   int        – 0: успех, 1: ошибка указателей или неподдерживаемый тип, 3/4: ошибка выравнивания.
 | 
			
		||||
  * @details  В зависимости от типа переменной считывает её значение и сохраняет в соответствующем указателе.
 | 
			
		||||
  */
 | 
			
		||||
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
 | 
			
		||||
{
 | 
			
		||||
    if (!var || !int_var || !float_var || !var->Ptr)
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,9 @@
 | 
			
		||||
#include "IQmathLib.h"
 | 
			
		||||
#include "DSP281x_Device.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Тип данных, на который указывает указатель переменной отладки.
 | 
			
		||||
  */
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
    pt_unknown,             // unknown
 | 
			
		||||
@ -31,6 +34,9 @@ typedef enum
 | 
			
		||||
//    pt_arr_uint32,          // unsigned long[]
 | 
			
		||||
}DebugVarPtrType_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Типы IQ-представления переменной отладки.
 | 
			
		||||
  */
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
    t_iq_none,
 | 
			
		||||
@ -67,45 +73,65 @@ typedef enum
 | 
			
		||||
    t_iq30
 | 
			
		||||
}DebugVarIQType_t;
 | 
			
		||||
 | 
			
		||||
typedef char DebugVarName_t[11];
 | 
			
		||||
typedef char DebugVarName_t[11];  ///< Имя переменной отладки (до 10 символов + \0)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Описание переменной отладки.
 | 
			
		||||
  */
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
    char*               Ptr;
 | 
			
		||||
    DebugVarPtrType_t   ptr_type;
 | 
			
		||||
    DebugVarIQType_t    iq_type;
 | 
			
		||||
    DebugVarIQType_t    return_type;
 | 
			
		||||
    DebugVarName_t      name;
 | 
			
		||||
}DebugVar_t;
 | 
			
		||||
    char*               Ptr;        ///< Указатель на значение переменной
 | 
			
		||||
    DebugVarPtrType_t   ptr_type;   ///< Тип значения
 | 
			
		||||
    DebugVarIQType_t    iq_type;    ///< Тип IQ переменной (если есть)
 | 
			
		||||
    DebugVarIQType_t    return_type;///< Тип IQ возвращаемого значения
 | 
			
		||||
    DebugVarName_t      name;       ///< Имя переменной
 | 
			
		||||
} DebugVar_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Структура даты и времени.
 | 
			
		||||
  */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int year;
 | 
			
		||||
    char  month;
 | 
			
		||||
    char  day;
 | 
			
		||||
    char  hour;
 | 
			
		||||
    char  minute;
 | 
			
		||||
    int   year;     ///< Год (например, 2025)
 | 
			
		||||
    char  month;    ///< Месяц (1-12)
 | 
			
		||||
    char  day;      ///< День (1-31)
 | 
			
		||||
    char  hour;     ///< Часы (0-23)
 | 
			
		||||
    char  minute;   ///< Минуты (0-59)
 | 
			
		||||
} DateTime_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Структура нижнего уровня отладки.
 | 
			
		||||
  */
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
    DateTime_t      build_date;
 | 
			
		||||
    unsigned int    isVerified;
 | 
			
		||||
    DebugVar_t      dbg_var;
 | 
			
		||||
    DateTime_t      build_date; ///< Дата сборки
 | 
			
		||||
    unsigned int    isVerified; ///< Флаг инициализации низкоуровненой отладки (0 — нет, 1 — успешно)
 | 
			
		||||
    DebugVar_t      dbg_var;    ///< Переменная для отладки
 | 
			
		||||
}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}
 | 
			
		||||
/** @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}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern int DebugVar_Qnt;
 | 
			
		||||
extern DebugVar_t dbg_vars[];
 | 
			
		||||
extern int DebugVar_Qnt;          ///< Количество переменных отладки
 | 
			
		||||
extern DebugVar_t dbg_vars[];     ///< Массив переменных отладки
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Пример использования отладки */
 | 
			
		||||
void Debug_Test_Example(void);
 | 
			
		||||
 | 
			
		||||
/* Читает значение переменной по индексу */
 | 
			
		||||
int Debug_ReadVar(int var_ind, long *return_long);
 | 
			
		||||
/* Читает имя переменной по индексу */
 | 
			
		||||
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr);
 | 
			
		||||
/* Читает значение переменной с нижнего уровня */
 | 
			
		||||
int Debug_LowLevel_ReadVar(long *return_long);
 | 
			
		||||
/* Инициализирует отладку нижнего уровня */
 | 
			
		||||
int Debug_LowLevel_Initialize(const char* external_date);
 | 
			
		||||
 | 
			
		||||
#endif //DEBUG_TOOLS
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user