Расширить DEIF, загрузку CAN и общую обработку сигналов

Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt.
Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor.
Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов.
Обновить справочники устройств, проекты CCS и регрессионные проверки.
This commit is contained in:
2026-10-24 15:40:51 +03:00
parent a5e46d4627
commit 41e24629ce
170 changed files with 43762 additions and 281 deletions
+104
View File
@@ -0,0 +1,104 @@
# Общее ядро DEIF XDi / CANopen
Единственная реализация профиля DEIF находится в `include/deif_xdi.h` и
`src/deif_xdi.c`. Desktop использует её через `python/set_devices/deif_native.py`,
Android — через `ports/android/set_deif_jni.c` и `deif/DeifXdi.kt`.
Кодеки, адресация, числовой каталог, NMT, сроки, SDO и выбор азимута
не реализуются повторно в Python или Kotlin.
Основание профиля: DEIF XDi-net/CANopen reference manual 4189350066D,
§§1–3, §9.11, Appendix 3 и Appendix 5. Набор переменных соответствует
наблюдаемой библиотеке: азимут, RPM, RPM%, мощность AC2 и POWER%.
Абсолютная мощность остаётся RAW до подтверждения её физической единицы.
## Два режима
- **Пассивный наблюдатель** принимает данные без включения симуляции,
ничего не отправляет, скрывает устаревшее показание через пять секунд.
- **CAN-SLAVE** принимает данные от внешнего MASTER и производит Boot-up,
heartbeat, EMCY и ответы на явно поддерживаемые SDO. После 3000 мс без
обновления поля сохраняет последнее валидное число и сообщает Data lost;
мигание выполняет GUI по готовой маске устаревших входов.
Пассивный режим предназначен в том числе для обычного приёма показаний
без занятия собственного Node-ID в сети. На MPDO в активном режиме
также нет ответного PDO. В нормальном обмене SLAVE передаёт heartbeat.
## Азимут
Фактическое значение `0x3001:02` и сетевое задание `0x3001:07` хранятся
независимо. `setp_deif_angle` возвращает значение и его тип:
- `0` — пригодного показания нет;
- `1` — фактический угол;
- `2` — принятое задание, которое GUI обязан подписывать как задание.
При исходной привязке фактического угла до первого кадра `0x02` допускается
показывать принятое `0x07`. После первого фактического кадра задание его
не подменяет. Ошибочный фактический I16 также не заменяется старым заданием.
Явная ручная привязка к `0x07` остаётся индикатором задания.
Локальный черновик MASTER не входит в состояние C-модели.
Эталонный кадр `STD 0x201 / 01 01 30 07 84 03 00 00` должен показывать
**90° · задание** и при выключенной симуляции. Node-ID физического SLAVE
не является источником этой SAM-рассылки: источник здесь Node 1.
## Адресация и сервисы
SAM согласует источник с COB-ID и поддерживает legacy broadcast `0x27F`.
DAM проверяет собственный Node-ID и выбранный RPDO. XDi-net резервирует
RPDO1 для SAM и Node 127 для сервисного прибора. Чистый CANopen допускает
DAM RPDO1. Все кадры профиля являются Classic CAN STD data frames.
После Boot-up выдаётся Pre-operational; стандартный self-start занимает
1000 мс. Исходный период heartbeat — 500 мс. NMT Start/Stop/Pre-operational,
Reset node и Reset communication принимаются только для собственного узла
либо broadcast 0. Reset communication сохраняет прикладные значения и
возвращает несохранённые коммуникационные параметры к исходным значениям.
SDO обслуживается в Operational и Pre-operational, в Stopped не отвечает.
Чтение: `0x1000:00`, `0x1001:00`, `0x1017:00`, `0x1018:00/01` и привязанные
I16-переменные. До обновления переменной возвращается `0x7FFF`.
Запись: U16 `0x1017:00`. Ноль отключает HB только вне XDi-net.
Неизвестный индекс, подиндекс, неподдерживаемая запись или команда дают
стандартный SDO abort. Серийный номер и код конкретного изделия не выдумываются.
Это явный поднабор профиля индикации, а не полный EDS прошивки. LSS,
segmented SDO, EEPROM, произвольные конфигурационные записи, TPDO mapping,
двухканальное резервирование и механика привода не моделируются.
## Контракт портов
Память состояния выделяет вызывающий через `setp_deif_state_size`.
Буфер должен иметь выравнивание не слабее `uint64_t`; ctypes использует
массив `uint64`, JNI — direct ByteBuffer. Private-layout состояния не
передаётся между языками и не сериализуется.
Все часы передаются как монотонные миллисекунды. C не вызывает ОС,
не использует Qt/JVM и не выделяет динамическую память. Каждый прибор
имеет отдельный контекст. JNI-порт сериализует операции экземпляра.
`setp_deif_poll` выдаёт готовые кадры однократно. Порт обслуживает его
регулярно и после запросов SDO; очередь ограничена 16 событиями. Экранная
пауза CAN-журнала не должна останавливать протокол. Потеря подключения,
ошибка TX и закрытие владельца останавливают активный сервер.
`setp_deif_make/master/service/angle_command` создают готовые сообщения.
`setp_deif_selector_info/readdress/route` обслуживают редакторы профиля:
UI не извлекает endian, смещения или адресные маски самостоятельно.
Локализованные тексты и мигание готовых показаний остаются в GUI.
При отсутствии нативного ядра порт выдаёт явную ошибку. Python/Kotlin
fallback протокола отсутствует. Windows source build может использовать
дополнительную сборку того же C-ядра `setprotocol_deif.dll`; путь задаёт
приложение либо стандартный загрузчик находит компонент рядом с основной
DLL. Новый автономный EXE использует собственную основную DLL с DEIF.
## Проверки
`tests/fixtures/deif-xdi-v1.tsv` — единые эталонные байты для C, Python и JNI.
Их используют `tests/test_deif_xdi.c`, `python/tests/test_deif_shared.py` и
`ports/android/tests/.../deif/DeifXdiTest.kt`. Отдельно проверяются пассивные
90°, независимый фактический угол, Boot-up, NMT, heartbeat и отсутствие
выдуманного ответного PDO. Desktop дополнительно проверяет миграцию старой
пустой привязки без включения симуляции и без физического TX.
+26
View File
@@ -1,5 +1,31 @@
# Универсальное адресное пространство эмуляторов
## Подключение панелей к конкретному MCU
Каталог `python/set_devices/mcu_profiles.py` связывает платы с общими сервисами,
моделью `DEVICE_INFO`, настройками подключения и аппаратным таймером.
`python/set_devices/qt_ports/emulator_workspace.py` принимает готовые панели
потребителя по ключам `settings`, `ump`, `tms2812`, `igbt`, `wavegen` и выбирает
их состав методом `select_mcu`. Общие алгоритмы УМП, 2812, IGBT и ЦАП остаются
в описанном ниже C-ядре; новая панель не создаёт вторую модель или соединение.
SETGUI подключает эти инструменты из страниц «Терминал → STM32 → MCU».
Поддержаны эмулятор STM32F407VET6 с TIM6 72 МГц и порт STM32G474RB с TIM6
160 МГц. Параметры COM хранятся отдельно; расчёт частот ЦАП, подписи Vin
и проверяемая модель SET v2 соответствуют выбранной плате. Профиль MCU
нельзя переключать во время обмена. Сам выбор профиля не отправляет команды.
Общий автомат обнаружения находится в `python/set_devices/emulator_protocol.py`,
COM-адаптер и клиент IGBT — в `python/set_devices/qt_ports/emulator_serial.py`
и `igbt_client.py`. Они не импортируют SETGUI. Старые пути SETGUI только
реэкспортируют эти реализации для совместимости.
STM32G474VET6 с прошивкой CANdle имеет отдельный профиль BOOT: приложение
`0x08008000`, размер до 480 КиБ, CAN 500 кбит/с, Type 7 / Device 15 /
Product 0, либо USART1 PA9/PA10 на 512000 бод, 8N1. Это другая прошивка,
чем эмулятор STM32G474RB. Профиль BOOT готовит форму обновления и проверяет
векторы приложения до начала CAN-передачи.
Общий код находится в `templates/c/set-protocol`. Прошивка платы задаёт память,
GPIO и аппаратные callbacks; протокол и модели не включают STM32/HAL/USB/ОС,
не выделяют heap и не читают системное время. Все вызовы одного экземпляра