Сохрани адресацию отдельных регистров GAS 0x3 и выдели слотам тип 0x4 с маской Word0. Добавь единое C-ядро GAS_WATCH2, тонкие Python/JNI-порты и проверки общих эталонных байтов. Совместимость: тип 0x4 больше не обслуживает Modbus Coil. Потребителям PCAN_MSG_MODBUS_COIL и ProtoCanMsgToModbusCoil нужно перейти на GAS_SLOT и отдельный API слотов; регистровый GAS остаётся на 0x3.
66 lines
9.9 KiB
C
66 lines
9.9 KiB
C
/* GAS_WATCH2: проверяемый список GAS-слов и независимые от транспорта выборки; формат описан в docs/GAS_WATCH2.md. */
|
|
#ifndef SET_GAS_WATCH_H /* Исключает повторные объявления при подключении ядра несколькими компонентами прошивки. */
|
|
#define SET_GAS_WATCH_H /* Отмечает загрузку публичного контракта расширенной подписки. */
|
|
#include <stdbool.h> /* Даёт булевы результаты операций без платформенной зависимости. */
|
|
#include "pcan_abi.h" /* Предоставляет фиксированные типы, size_t и экспорт стабильных функций для ctypes/JNI. */
|
|
#include "pcan_gas.h" /* Предоставляет карту 16-битных GAS-регистров и проверяемые операции чтения. */
|
|
#ifdef __cplusplus /* Открывает C ABI для проектов, компилирующих публичный заголовок как C++. */
|
|
extern "C" { /* Запрещает изменение имён экспортируемых функций компилятором C++. */
|
|
#endif /* Завершает условие входа в совместимую с C область объявлений. */
|
|
|
|
#define SET_GAS_WATCH_VERSION 2U /* Версия payload; отличается от версии внешнего кадрирования GUI. */
|
|
#define SET_GAS_WATCH_MAX 64U /* Максимум 16-битных слов в одном списке; многословный параметр занимает несколько позиций. */
|
|
#define SET_GAS_WATCH_CONFIG_HEADER 12U /* Байты version:u16, period:u16, config_id:u32, count:u16, reserved:u16. */
|
|
#define SET_GAS_WATCH_SAMPLE_HEADER 16U /* Байты version:u16, count:u16, config_id:u32, sequence:u32, timestamp_ms:u32. */
|
|
#define SET_GAS_WATCH_CONFIG_MAX (SET_GAS_WATCH_CONFIG_HEADER + 2U * SET_GAS_WATCH_MAX) /* 140 байт с адресами 64 слов. */
|
|
#define SET_GAS_WATCH_SAMPLE_MAX (SET_GAS_WATCH_SAMPLE_HEADER + 8U + 2U * SET_GAS_WATCH_MAX) /* 152 байта: заголовок, 64 бита достоверности и значения. */
|
|
|
|
typedef enum { /* Разделяет неверный payload, ошибки карты и конфликт поколений без строк или исключений. */
|
|
SET_GAS_WATCH_OK = 0, /* Весь список применён либо подтверждён точный повтор действующей конфигурации. */
|
|
SET_GAS_WATCH_INVALID = 1, /* Нарушены версия, длина, указатели, период, уникальность адресов или структура карты. */
|
|
SET_GAS_WATCH_NO_REG = 2, /* Хотя бы один адрес отсутствует в корректной карте; действующий список сохранён. */
|
|
SET_GAS_WATCH_ACCESS = 3, /* Хотя бы один регистр запрещён для чтения либо не имеет источника чтения. */
|
|
SET_GAS_WATCH_CONFLICT = 4 /* Идентификатор устарел либо повторно использован с другим содержимым. */
|
|
} set_gas_watch_result_t; /* Завершает публичный набор детерминированных результатов настройки. */
|
|
|
|
typedef struct { /* Состояние одного прибора и одного управляющего клиента; память принадлежит приложению. */
|
|
uint32_t config_id; /* Ненулевое поколение; новые поколения сравниваются по модульной разности меньше 2^31. */
|
|
uint32_t sequence; /* Номер следующей выборки; первая имеет номер 0, переполнение происходит по модулю 2^32. */
|
|
uint32_t next_ms; /* Срок следующего захвата в миллисекундах локального 32-битного счётчика устройства. */
|
|
uint16_t period_ms; /* Период захвата в миллисекундах; ноль вместе с пустым списком останавливает поток. */
|
|
uint16_t count; /* Число выбранных 16-битных GAS-слов, от 0 до SET_GAS_WATCH_MAX. */
|
|
uint16_t address[SET_GAS_WATCH_MAX]; /* Упорядоченные уникальные GAS-индексы, а не указатели на память MCU. */
|
|
uint8_t scheduled; /* Ноль разрешает первую выборку сразу, единица включает проверку next_ms с переполнением. */
|
|
} set_gas_watch_t; /* Внутренняя структура прошивки не передаётся через wire или языковую границу. */
|
|
|
|
typedef struct { /* Самодостаточная копия одного захвата, пригодная для графика, архива и повторной передачи. */
|
|
uint32_t config_id; /* Связывает позиции значений с подтверждённым списком адресов. */
|
|
uint32_t sequence; /* Номер захвата, позволяющий обнаружить потерю пакета при занятой линии. */
|
|
uint32_t timestamp_ms; /* Время захвата на устройстве; задержка USB/UART не меняет эту метку. */
|
|
uint16_t count; /* Число значений и признаков достоверности в используемой части массивов. */
|
|
uint16_t values[SET_GAS_WATCH_MAX]; /* Сырые слова; при ошибке соответствующего источника сохраняется ноль. */
|
|
uint8_t valid[SET_GAS_WATCH_MAX]; /* Единица означает успешное чтение слова, ноль отличает ошибку от реального нулевого значения. */
|
|
} set_gas_watch_sample_t; /* Приложение хранит выборку до завершения её использования всеми потребителями. */
|
|
|
|
/* Все обращения к состоянию и захвату RAM приложение сериализует своим lock/IRQ-портом; ядро не управляет прерываниями. */
|
|
void set_gas_watch_init(set_gas_watch_t *watch); /* Обнуляет состояние до первой команды; NULL допустим как пустая операция. */
|
|
/* Проверяет весь payload и карту без вызовов источников; ошибка оставляет состояние неизменным. Повтор id+содержимое идемпотентен. */
|
|
int set_gas_watch_apply(set_gas_watch_t *watch, const pcan_gas_map_t *map, const uint8_t *payload, size_t size); /* Пустой stop не требует карты. */
|
|
size_t set_gas_watch_encode_ack(const set_gas_watch_t *watch, uint8_t *out, size_t capacity); /* Возвращает полное эхо применённой конфигурации или 0. */
|
|
bool set_gas_watch_due(const set_gas_watch_t *watch, uint32_t now_ms); /* Проверяет срок с переполнением; период проверок должен быть меньше 2^31 мс. */
|
|
/* Захватывает RAM по явному вызову, без проверки due; источники обязаны быть быстрыми и не выполнять I/O или ожидания. */
|
|
bool set_gas_watch_capture(set_gas_watch_t *watch, const pcan_gas_map_t *map, uint32_t now_ms, set_gas_watch_sample_t *sample); /* Отказ источника отражается valid=0. */
|
|
/* Кодирует только готовую выборку, без обращений к карте и без блокировки источников; приложение вызывает после снятия lock. */
|
|
size_t set_gas_watch_encode_sample(const set_gas_watch_sample_t *sample, uint8_t *out, size_t capacity); /* Неверный аргумент не меняет выходной буфер. */
|
|
|
|
/* Экспортируемый ABI использует скаляры и буферы: ни один клиент не повторяет кодек payload на своём языке. */
|
|
PCAN_ABI_API size_t set_gas_watch_request(uint32_t config_id, uint16_t period_ms, const uint16_t *addresses, size_t count, uint8_t *out, size_t capacity); /* 0 означает отказ без записи. */
|
|
PCAN_ABI_API int set_gas_watch_ack(const uint8_t *payload, size_t size, uint32_t config_id, uint16_t period_ms, const uint16_t *addresses, size_t count); /* 1 подтверждает точное эхо всех адресов. */
|
|
/* Возвращает число слов или -1; до полной проверки payload и ожидаемого поколения не меняет ни один выходной аргумент. */
|
|
PCAN_ABI_API int set_gas_watch_decode(const uint8_t *payload, size_t size, uint32_t expected_config_id, size_t expected_count, uint32_t *sequence, uint32_t *timestamp_ms, uint16_t *values, uint8_t *valid, size_t capacity); /* Метаданные sequence/time могут быть NULL. */
|
|
|
|
#ifdef __cplusplus /* Закрывает только ту область linkage, которую открывали для C++ потребителя. */
|
|
} /* Завершает объявления с C-именами функций. */
|
|
#endif /* Завершает условное закрытие C++ linkage. */
|
|
#endif /* SET_GAS_WATCH_H: завершает защиту публичного заголовка. */
|