Добавлен регистратор запуска и отключения УМП для стендовой проверки

Реализованы кольцевая запись CAN-команд, дискретных сигналов, уставок и состояния ЦАП, а также отдельный архив отключения с секундой постинтервала.
Добавлено расширение Modbus для онлайн-графиков и чтения архива через SetGUI. Сохранены управляющая логика и существующая область технологических регистров.

Добавлены русские комментарии, описание протокола и тест регистратора. Проверка алгоритма и синтаксиса C пройдена; сборка TI/CCS и испытания на плате ещё требуются.
This commit is contained in:
2026-09-21 00:15:27 +03:00
parent 799e6ba46d
commit df719229b7
21 changed files with 628 additions and 9 deletions

View File

@@ -0,0 +1,71 @@
#include "../../Source/Internal/log_to_mem.c"
struct mock_gpio GpioDataRegs;
int READY = 1, Desk = 6, Mode = 5;
int modbus[128];
int CanTimeOutErrorTR;
unsigned long IMPowse, WAKEpowse;
unsigned int ADC_table[4];
#define CHECK(x) if (!(x)) return __LINE__
/* Возвращаем номер строки при ошибке, ноль при успехе; CRT не требуется. */
__declspec(dllexport) int run_tests(void)
{
unsigned int i, generation, archived;
unsigned long sequence;
CHECK(!ump_log_write(UMP_LOG_BASE+1, 0));
CHECK(!ump_log_write(UMP_LOG_BASE+1, 1001));
CHECK(ump_log_write(UMP_LOG_BASE+1, 1));
modbus[127] = 0x80;
modbus[0x50] = 6; modbus[0x51] = 16;
modbus[0x7B] = 1234; modbus[0x1C] = 160;
CHECK(ump_log_write(UMP_LOG_BASE, 1));
CHECK(!ump_log_write(UMP_LOG_BASE, 1));
CHECK(!ump_log_write(UMP_LOG_BASE+1, 20));
for (i=0; i<900; i++) ump_log_tick();
CHECK(ump_count == UMP_LOG_CAPACITY);
CHECK(ump_word(0, 0, 0) == 101);
CHECK(ump_word(0, UMP_LOG_CAPACITY-1, 0) == 900);
CHECK(ump_word(0, 0, 8) == 1234);
CHECK(ump_word(0, 0, 24) == 6);
/* Короткая CAN-команда должна остаться отдельным событием. */
modbus[127] = 0x40;
ump_log_can(0x807F, 0x40, 0, 0);
CHECK(ump_post == 1000);
CHECK(ump_word(0, ump_count-1, 2) == 0x102);
CHECK(ump_word(0, ump_count-1, 18) == 0x807F);
for (i=0; i<999; i++) ump_log_tick();
CHECK(ump_generation == 0);
ump_log_tick();
CHECK(ump_generation == 1);
CHECK(ump_archive_count == UMP_LOG_CAPACITY);
CHECK(ump_word(1, UMP_LOG_CAPACITY/2-1, 2) == 0x102);
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 2) == 0x205);
CHECK(ump_count == 0 && ump_state == 1);
generation = ump_generation;
archived = ump_word(1, UMP_LOG_CAPACITY-1, 0);
sequence = ump_sequence;
for (i=0; i<200; i++) ump_log_tick();
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 0) == archived);
CHECK(ump_generation == generation);
CHECK(ump_sequence == sequence + 200);
CHECK(ump_log_read(UMP_LOG_LIVE+2) == 3);
CHECK(ump_log_read(UMP_LOG_LIVE+4) == ump_time-2);
CHECK(ump_log_write(UMP_LOG_BASE+3, 1));
CHECK(ump_log_write(UMP_LOG_BASE+2, UMP_LOG_CAPACITY-1));
CHECK(ump_log_read(UMP_LOG_DATA) == archived);
CHECK(ump_log_read(UMP_LOG_DATA+UMP_LOG_WORDS) == 0);
CHECK(!ump_log_write(UMP_LOG_BASE+2, UMP_LOG_CAPACITY));
CHECK(ump_log_write(UMP_LOG_BASE, 0));
sequence = ump_sequence;
ump_log_tick(); ump_log_io(); ump_log_can(1,2,3,4);
CHECK(sequence == ump_sequence);
CHECK(ump_log_write(UMP_LOG_BASE, 1));
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 0) == archived);
/* Новый пуск и спад start без reset также фиксируют отключение. */
modbus[127] = 0x80; ump_log_rs();
modbus[127] = 0; ump_log_rs();
CHECK(ump_post == 1000);
for (i=0; i<1000; i++) ump_log_tick();
CHECK(ump_generation == generation+1);
return 0;
}

View File

@@ -0,0 +1,27 @@
"""Сборка и запуск исходного регистратора с подменой GPIO/IRQ на Windows.
Нужны Clang и lld-link в PATH. Проверяется алгоритм, но не ABI и тайминги TI.
DLL создаётся во временной папке; исходные .out/.hex прошивки не затрагиваются.
"""
import ctypes
import os
from pathlib import Path
import subprocess
import tempfile
root = Path(__file__).resolve().parents[2]
with tempfile.TemporaryDirectory(prefix='ump-recorder-') as directory:
library = Path(directory) / 'recorder_test.dll'
subprocess.run([
'clang', '-shared', '-nostdlib', '-fuse-ld=lld',
'-Wl,/noentry,/nodefaultlib', '-Wno-unknown-pragmas', '-Wno-int-to-pointer-cast',
'-Itests/ump_logger/stubs', '-ISource/Internal/Include',
'tests/ump_logger/recorder_test.c', '-o', str(library),
], cwd=root, check=True)
# Отдельный процесс освобождает DLL до удаления временной папки Windows.
subprocess.run([
os.sys.executable, '-c',
'import ctypes,sys; r=ctypes.CDLL(sys.argv[1]).run_tests(); '
'print("PASS" if r==0 else f"FAIL: C line {r}"); sys.exit(bool(r))',
str(library),
], check=True)

View File

@@ -0,0 +1 @@
extern unsigned int ADC_table[4];

View File

@@ -0,0 +1 @@
extern unsigned long IMPowse, WAKEpowse;

View File

@@ -0,0 +1,9 @@
#ifndef UMP_TEST_DEVICE_H
#define UMP_TEST_DEVICE_H
struct mock_bits { unsigned int GPIO3, GPIO6, GPIO8, GPIO11, GPIO58, GPIO62; };
struct mock_reg { struct mock_bits bit; };
struct mock_gpio { struct mock_reg GPADAT, GPBDAT; };
extern struct mock_gpio GpioDataRegs;
static unsigned int __disable_interrupts(void) { return 0; }
static void __restore_interrupts(unsigned int saved) { (void)saved; }
#endif

View File

@@ -0,0 +1 @@
/* Подмена зависимостей для проверки регистратора без платы. */

View File

@@ -0,0 +1 @@
/* Подмена зависимостей для проверки регистратора без платы. */

View File

@@ -0,0 +1,2 @@
extern int READY, Desk, Mode;
#define READY_FREQ 1000

View File

@@ -0,0 +1 @@
/* Подмена зависимостей для проверки регистратора без платы. */

View File

@@ -0,0 +1,11 @@
extern int modbus[128];
#define dsk_LOAD 6
#define Commands modbus[127]
#define sens_data (modbus+24)
#define DAC_go modbus[0x50]
#define DAC_stop modbus[0x51]
#define DAC_min() modbus[0x79]
#define DAC_max() modbus[0x78]
#define DAC_cal() modbus[0x7A]
#define DAC_04 modbus[0x6F]
#define DAC_20 modbus[0x6E]

View File

@@ -0,0 +1 @@
/* Подмена зависимостей для проверки регистратора без платы. */

View File

@@ -0,0 +1,3 @@
/* Декларации TI-интринсиков только для проверки синтаксиса на компьютере. */
unsigned int __disable_interrupts(void);
void __restore_interrupts(unsigned int saved);