.. _module_description: Описание модуля для протокола ECPP ================================== Протокол ECPP используется для обмена данными между основным и подчиненными модулями контроллера. Обмен выполняется небольшими пакетами (не более 16 байт), каждый из которых имеет фиксированный числовой идентификатор. Данные передаются только при их изменении. Координатором передачи выступает основной модуль. Чтобы основной модуль мог опрашивать подчиненные модули, ему необходимо описание внутренней структуры объектов, реализованных в подчиненных модулях. Это описание оформляется в JSON-файле в формате, описанном ниже. Общие параметры --------------- .. list-table:: Общие параметры модуля :header-rows: 1 :widths: 20 30 50 * - Параметр - Тип - Описание * - ``type`` - string - Строковый тип контроллера, для которого предназначен модуль. Например ``"M245A"`` * - ``version`` - number - Версия формата описания, пока всегда ``1`` * - ``moduleID`` - number - Числовой идентификатор модуля, например ``2561`` (``0xA01``) * - ``moduleVer`` - number - Числовая версия модуля * - ``pubName`` - string - Пользовательское имя модуля * - ``shortName`` - string - Краткое пользовательское имя. Если параметр отсутствует, то используется ``moduleID`` в HEX формате, например ``A01`` * - ``floor`` - number - Позиция модуля в многослойной конструкции. Нумерация идет сверху вниз. Обычно базовый модуль сверху и нумеруется ``0``, средний - ``1``, нижний - ``2`` * - ``package`` - number - Идентификатор пакета плат для проверки совместимости. Для всех плат одного пакета он должен иметь одинаковое значение Массив ``interface`` -------------------- Массив ``interface`` описывает различные интерфейсы, которые могут быть реализованы в модулях. Пока используется только для определения количества портов, которые физически проброшены с основной платы в модуль. **Параметры объекта интерфейса:** .. list-table:: Параметры интерфейса :header-rows: 1 :widths: 20 30 50 * - Параметр - Тип - Описание * - ``name`` - string - Имя порта * - ``id`` - string - Идентификатор порта (обычно это порядковый номер интерфейса начиная с ``0``) * - ``mode`` - string - Режим порта, пока не используется * - ``type`` - string - Тип порта, пока не используется **Пример:** .. code-block:: json "interface": [ { "name": "COM0", "id": "0", "mode": "connector", "type": "uart" }, { "name": "COM1", "id": "1", "mode": "connector", "type": "uart" } ] Массив ``rxobjects`` -------------------- Массив ``rxobjects`` содержит объекты протокола ECPP для чтения. **Параметры объекта:** .. list-table:: Параметры rxobjects :header-rows: 1 :widths: 20 30 50 * - Параметр - Тип - Описание * - ``ecppID`` - number - Числовой идентификатор объекта * - ``size`` - number - Размер объекта в байтах, не может быть больше ``16`` * - ``comment`` - string (опционально) - Комментарий к объекту с описанием его структуры **Пример:** .. code-block:: json "rxobjects": [ { "ecppID": 32, "size": 4 }, // Показания АЦП AIN1:ADC и AIN2:ADC { "ecppID": 56, "size": 16, "comment": "AIN1:Напряжение, AIN2:Напряжение, AIN1:Сопротивление, AIN2:Сопротивление" } ] Массив ``txobjects`` -------------------- Массив ``txobjects`` содержит объекты протокола ECPP для записи. Аналогичен ``rxobjects``. **Пример:** .. code-block:: json "txobjects": [ { "ecppID": 40, "size": 2 } // Значения AIN1:Mode и AIN2:Mode ] Массив ``groups`` - группы переменных ------------------------------------- Массив ``groups`` объединяет переменные в логические группы для отображения в визуальном интерфейсе. Каждый объект в этом массиве описывает одну группу и содержит массив ``vars``. **Параметры группы:** .. list-table:: Параметры группы :header-rows: 1 :widths: 20 30 50 * - Параметр - Тип - Описание * - ``intName`` - string - Внутреннее имя группы (только латиница и цифры) * - ``pubName`` - string - Пользовательское имя группы для отображения в интерфейсе * - ``vars`` - array - Массив переменных, входящих в группу Секция описания переменных ``vars`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Массив ``vars`` описывает переменные для входов/выходов. **Параметры переменной:** .. list-table:: Параметры переменной :header-rows: 1 :widths: 20 20 60 * - Параметр - Тип - Описание * - ``datatype`` - string - Тип данных (``"UInt16"``, ``"Bool"``, ``"Float32"`` и т.д.) * - ``vdef`` - number - Значение по умолчанию (если отсутствует, то ``0``) * - ``pubname`` - string - Пользовательское название переменной * - ``intname`` - string - Внутреннее имя переменной (только латинские буквы и цифры). Используется как идентификатор * - ``shortname`` - string (опционально) - Краткое наименование, отображаемое на блоке. Если не указано, используется ``intname`` с добавлением адреса модуля * - ``description`` - string - Описание переменной для пользователя * - ``ecppID`` - number - Идентификатор объекта ECPP, в котором находится значение. Должен быть описан в ``txobjects`` или ``rxobjects`` * - ``ecppOffsetAddr`` - number - Смещение от начала объекта в байтах (или в битах для булевых значений) * - ``groupID`` - string - Имя группы для объединения переменных в универсальные каналы * - ``groupMode`` - number - Режим работы универсальной переменной (см. таблицу режимов) * - ``writable`` - boolean - Доступность для записи (размещена в объекте ``tx``) * - ``readable`` - boolean - Доступность для чтения (размещена в объекте ``rx``) .. important:: В параметре ``intname`` допускается использовать только латинские буквы и цифры. Никаких знаков препинания и служебных символов добавлять нельзя! Режимы работы ``groupMode`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. list-table:: Значения groupMode :header-rows: 1 :widths: 20 20 60 * - Режим - Значение - Описание * - ``ext_none`` - 0x00 - Вход не сконфигурирован * - ``ext_in_a`` - 0x10 - Аналоговый вход - данные в АЦП * - ``ext_volt3_3`` - 0x20 - Аналоговый вход - данные в float 0-3.3V * - ``ext_volt10`` - 0x30 - Аналоговый вход - данные в float 0-10V * - ``ext_cur`` - 0x40 - Аналоговый вход - данные в float 4-20mA * - ``ext_res`` - 0x50 - Аналоговый вход - данные в float в Омах * - ``ext_din`` - 0x60 - Дискретный вход - есть/нет сигнала * - ``ext_cntr`` - 0x70 - Счетный вход - количество импульсов * - ``ext_frec`` - 0x80 - Частотный вход - частота в целых Гц * - ``ext_out_d`` - 0x90 - Цифровой выход - реле или дискретный сигнал * - ``ext_out_a`` - 0xA0 - Аналоговый выход - 0-10В значение от 0 до 1000 * - ``ext_out_a_5`` - 0xA1 - Аналоговый выход - 0-5В значение от 0 до 1000 * - ``ext_out_a_24`` - 0xA2 - Аналоговый выход - 0-24В значение от 0 до 1000 * - ``ext_out_v24`` - 0x11 - Дискретный выход 0-24 В * - ``ext_out_spwm`` - 0x13 - Медленный ШИМ * - ``ext_out_fpwm`` - 0x14 - Быстрый ШИМ * - ``ext_ref`` - 0xB0 - Источники опорного напряжения Пример простых переменных (без группировки в каналы) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Если переменные не требуется объединять в универсальные каналы, параметры ``groupID`` и ``groupMode`` можно оставить пустыми (или ``0``). Переменные при этом будут сгруппированы только визуально в интерфейсе. .. code-block:: json "groups": [ { "intName": "F00", "pubName": "Модуль F00", "vars": [ {"datatype": "UInt16", "vdef": 500, "pubname": "Частота сигнала", "description": "Частота звука в Гц, минимальное значение 184Гц", "intname": "SpeakerFreq", "writable": true, "readable": true, "groupID": "", "groupMode": 0, "ecppID": 3584, "ecppOffsetAddr": 0}, {"datatype": "UInt16", "vdef": 50, "pubname": "Громкость сигнала", "description": "Громкость звука от 0 до 100%", "intname": "Volume", "writable": true, "readable": true, "groupID": "", "groupMode": 0, "ecppID": 3584, "ecppOffsetAddr": 2}, {"datatype": "UInt16", "vdef": 0, "pubname": "Включить звук", "description": "Включить звук на заданное время, мс", "intname": "Speaker", "writable": true, "readable": true, "groupID": "", "groupMode": 0, "ecppID": 3584, "ecppOffsetAddr": 4}, {"datatype": "UInt16", "vdef": 2, "pubname": "Время фильтрации", "description": "Время фильтрации для цифровых входов на включение, мс", "intname": "TimeFilter", "writable": true, "readable": true, "groupID": "", "groupMode": 0, "ecppID": 40, "ecppOffsetAddr": 2}, {"datatype": "UInt16", "vdef": 1000, "pubname": "Время подсчета частоты", "description": "Время подсчета частоты цифрового сигнала, мс", "intname": "TimeFreq", "writable": true, "readable": true, "groupID": "", "groupMode": 0, "ecppID": 40, "ecppOffsetAddr": 4}, {"datatype": "UInt8", "vdef": 0, "pubname": "Код ошибки", "intname": "ErrCode", "shortname": "ErrCode", "writable": false, "readable": true, "groupID": "", "groupMode": 0, "ecppID": 208, "ecppOffsetAddr": 0} ] } ] Принцип группировки переменных в универсальные каналы ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Параметры ``groupID`` и ``groupMode`` объединяют переменные в логические группы (универсальные каналы). Это нужно, когда несколько переменных относятся к одному физическому каналу (например, АЦП, напряжение, сопротивление — всё с одного входа). **Основные правила:** 1. Один физический канал = один ``groupID`` 2. ``groupMode = 0`` — управляющая переменная (задает режим работы канала) 3. Остальные ``groupMode`` — типы данных (напряжение, сопротивление, АЦП и т.д.) 4. Программа использует ту переменную, чей ``groupMode`` совпадает со значением управляющей переменной **Пример группировки для канала AIN1:** .. code-block:: json "groups": [ { "intName": "AIN", "pubName": "Аналоговые входы", "vars": [ // Управляющая переменная {"datatype": "UInt8", "vdef": "48", "pubname": "AIN1", "intname": "AIN1:Mode", "writable": true, "readable": false, "groupID": "AIN1", "groupMode": 0, "ecppID": 40, "ecppOffsetAddr": 0}, // Переменные данных {"datatype": "UInt16", "vdef": "0", "pubname": "AIN1:АЦП", "intname": "AIN1:ADC", "description": "Значение АЦП", "writable": false, "readable": true, "groupID": "AIN1", "groupMode": 16, "ecppID": 32, "ecppOffsetAddr": 0}, {"datatype": "Float32", "vdef": "0", "pubname": "AIN1:Напряжение", "intname": "AIN1:Volt", "description": "Значение напряжения", "writable": false, "readable": true, "groupID": "AIN1", "groupMode": 48, "ecppID": 56, "ecppOffsetAddr": 0}, {"datatype": "Float32", "vdef": "0", "pubname": "AIN1:Сопротивление", "intname": "AIN1:Res", "description": "Значение сопротивления", "writable": false, "readable": true, "groupID": "AIN1", "groupMode": 80, "ecppID": 56, "ecppOffsetAddr": 8} ] } ] **Как это работает:** - Программа читает ``AIN1:Mode`` (groupMode = 0) - Если ``Mode = 48`` (напряжение) → использует ``AIN1:Volt`` - Если ``Mode = 80`` (сопротивление) → использует ``AIN1:Res`` - Если ``Mode = 16`` (АЦП) → использует ``AIN1:ADC`` **Визуальное представление:** :: Группа "Аналоговые входы" ├── Канал AIN1 (режим = напряжение): │ ├── AIN1:Mode = 48 │ └── AIN1:Volt = 5.23 V ← активно └── Канал AIN2 (режим = сопротивление): ├── AIN2:Mode = 80 └── AIN2:Res = 1200 Ω ← активно .. important:: В каждой группе (по ``groupID``) должна быть только одна переменная с ``groupMode = 0``. Полный пример описания модуля ----------------------------- .. code-block:: json { "type": "M245A", "version": 1, "moduleID": 2561, "moduleVer": 1, "pubName": "Модуль аналоговых входов", "shortName": "AIN", "floor": 0, "package": 1, "interface": [ {"name": "COM0", "id": "0", "mode": "connector", "type": "uart"} ], "rxobjects": [ {"ecppID": 32, "size": 4}, {"ecppID": 56, "size": 16} ], "txobjects": [ {"ecppID": 40, "size": 2} ], "groups": [ { "intName": "AIN", "pubName": "Аналоговые входы", "vars": [ {"datatype": "UInt16", "vdef": "0", "pubname": "AIN1:АЦП", "intname": "AIN1:ADC", "description": "Значение АЦП", "writable": false, "readable": true, "groupID": "AIN1", "groupMode": 16, "ecppID": 32, "ecppOffsetAddr": 0}, {"datatype": "UInt16", "vdef": "0", "pubname": "AIN2:АЦП", "intname": "AIN2:ADC", "description": "Значение АЦП", "writable": false, "readable": true, "groupID": "AIN2", "groupMode": 16, "ecppID": 32, "ecppOffsetAddr": 2}, {"datatype": "Float32", "vdef": "0", "pubname": "AIN1:Напряжение", "intname": "AIN1:Volt", "description": "Значение напряжения", "writable": false, "readable": true, "groupID": "AIN1", "groupMode": 48, "ecppID": 56, "ecppOffsetAddr": 0}, {"datatype": "Float32", "vdef": "0", "pubname": "AIN2:Напряжение", "intname": "AIN2:Volt", "description": "Значение напряжения", "writable": false, "readable": true, "groupID": "AIN2", "groupMode": 48, "ecppID": 56, "ecppOffsetAddr": 4}, {"datatype": "Float32", "vdef": "0", "pubname": "AIN1:Сопротивление", "intname": "AIN1:Res", "description": "Значение сопротивления", "writable": false, "readable": true, "groupID": "AIN1", "groupMode": 80, "ecppID": 56, "ecppOffsetAddr": 8}, {"datatype": "Float32", "vdef": "0", "pubname": "AIN2:Сопротивление", "intname": "AIN2:Res", "description": "Значение сопротивления", "writable": false, "readable": true, "groupID": "AIN2", "groupMode": 80, "ecppID": 56, "ecppOffsetAddr": 12}, {"datatype": "UInt8", "vdef": "48", "pubname": "AIN1", "intname": "AIN1:Mode", "writable": true, "readable": false, "groupID": "AIN1", "groupMode": 0, "ecppID": 40, "ecppOffsetAddr": 0}, {"datatype": "UInt8", "vdef": "48", "pubname": "AIN2", "intname": "AIN2:Mode", "writable": true, "readable": false, "groupID": "AIN2", "groupMode": 0, "ecppID": 40, "ecppOffsetAddr": 1} ] } ] }