# Общее ядро 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. ## Android/JVM: настройки и локальный стенд `DeifSettings` хранит профиль SLAVE, независимые параметры MASTER, выбор пяти отправляемых объектов, калибровки управления, единицу POWER и ручные привязки. Сериализация не сохраняет запуск симуляции или таймеров. `readdressed` переносит связанные SAM/DAM-адреса через C, сохраняя отдельные ручные источники, индексы объектов и масштабы. `DeifWorkspace` объединяет пассивное наблюдение, физический CAN-SLAVE и автономный стенд. Он получает монотонное время от приложения и возвращает готовые кадры раздельными маршрутами MASTER и SLAVE. Локальная симуляция не возвращает физические кадры; остановленный локальный SLAVE отклоняет MASTER и команды экрана вместо переключения на адаптер. NMT разрешён только работающему локальному SLAVE. Физический сервер отклоняет запуск встроенного MASTER. `DeifXdi.master/make/service/selector/bind/binding/selectorInfo/readdress/validate` являются тонкими вызовами существующего C ABI. Порты не строят COB-ID, индексы, little-endian I16, NMT или диммер повторно. Перевод касания в заданный пользователем масштаб относится к управлению интерфейсом; интерактивная отрисовка, отдельное подтверждение яркости и палитры, хранилище настроек, USB и жизненный цикл остаются у приложения. `DeifWorkspaceTest` проверяет точные builders, автономный приём интерактивных заданий, отсутствие физического TX на локальном стенде, ограничения NMT, независимые периоды MASTER/heartbeat, ошибки JNI, сохранение профиля и перенос адресов без потери ручных привязок. ## Проверки `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.