From 3cf85a278eaed0cff21722c0e96e57aa94a08d6f Mon Sep 17 00:00:00 2001 From: Claude Code Assistant Date: Thu, 20 Aug 2026 17:24:34 +0300 Subject: [PATCH 01/11] init commit --- Inc/protocan.h | 320 ++++++++++ Src/protocan.c | 1517 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1837 insertions(+) create mode 100644 Inc/protocan.h create mode 100644 Src/protocan.c diff --git a/Inc/protocan.h b/Inc/protocan.h new file mode 100644 index 0000000..99fa270 --- /dev/null +++ b/Inc/protocan.h @@ -0,0 +1,320 @@ +#ifndef _protocan +#define _protocan +#include "main.h" +#include "can.h" + +#define _DEMO + +#define ONLINE 1; +#define OFFLINE 0; + +#define ID_MAIN_DEVICE 0x000 +#define CURRENT_TYPE_DEVICE 0b001 +#define CURRENT_ID_DEVICE 0b0010 + +#define PROTOCAN_RX_BUFFER_SIZE 128 + +#define SensorToModbusRegister(SensorType, SensorID) SensorType << 11 | SensorID +#define HighByteOfWord(WORD) (WORD>>8)&0xFF +#define LowByteOfWord(WORD) WORD&0xFF + +/** + * @brief Статус инициализации протокола CAN. + * + * Это перечисление описывает возможные статусы после попытки инициализации. + */ +typedef enum +{ + PROTOCAN_INIT_OK = 0x00U, /**< Инициализация прошла успешно. */ + PROTOCAN_INIT_HCAN_ERROR = 0x01U, /**< Ошибка при инициализации модуля CAN. */ + PROTOCAN_INIT_HRTC_ERROR = 0x02U, /**< Ошибка при инициализации модуля RTC. */ + PROTOCAN_INIT_TIM_ERROR = 0x04U /**< Ошибка при инициализации таймера. */ +} PROTOCAN_INIT_StatusTypeDef; + +/** + * @brief Статус выполнения операции протокола CAN. + * + * Это перечисление описывает возможные результаты выполнения функций протокола. + */ +typedef enum +{ + PROTOCAN_OK = 0x00U, /**< Операция прошла успешно. */ + PROTOCAN_ERROR = 0x01U, /**< Обнаружена ошибка во время выполнения. */ + PROTOCAN_BUSY = 0x02U, /**< Канал занят, выполнение невозможно в данный момент. */ + PROTOCAN_TIMEOUT = 0x03U /**< Истек таймаут ожидания. */ +} PROTOCAN_StatusTypeDef; + +/** + * @brief Уровень приоритета CAN-сообщения. + * + * Это перечисление определяет важность и приоритет обработки сообщения. + */ +typedef enum { + PROTOCAN_PRIORITY_CRITICAL = 0, /**< Критический приоритет, рекомендуется обработка без задержек. */ + PROTOCAN_PRIORITY_STANDARD = 1 /**< Стандартный приоритет, менее важный. */ +} ProtoCanPriorityType; + +/** + * @brief Маршрут CAN-сообщения. + * + * Это перечисление задает направление маршрута отправки сообщения. + */ +typedef enum { + PROTOCAN_ROUTE_FROM_PM = 0, /**< Сообщение отправляется от управляющего модуля (PM). */ + PROTOCAN_ROUTE_FROM_DEVICE = 1 /**< Сообщение отправляется от устройства (Device). */ +} ProtoCanRouteType; + +/** + * @brief Типы сообщений CAN. + * + * Перечисление определяет различные типы сообщений, используемые в протоколе. + */ +typedef enum { + PROTOCAN_MSGTYPE_BROADCAST = 0b0000, /**< Широковещательное сообщение. */ + PROTOCAN_MSGTYPE_DISCRETE = 0b0001, /**< Дискретное цифровое сообщение. */ + PROTOCAN_MSGTYPE_ANALOG = 0b0010, /**< Аналоговое сообщение. */ + PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE = 0b0011, /**< Сообщение общего адресного пространства. */ + PROTOCAN_MSGTYPE_MODBUS_COIL = 0b0100, /**< Сообщение Modbus - Coil. */ + PROTOCAN_MSGTYPE_MODBUS_DISCRETE = 0b0101, /**< Сообщение Modbus - Discrete. */ + PROTOCAN_MSGTYPE_MODBUS_HOLDING = 0b0110, /**< Сообщение Modbus - Holding. */ + PROTOCAN_MSGTYPE_MODBUS_INPUT = 0b0111, /**< Сообщение Modbus - Input. */ + PROTOCAN_MSGTYPE_ERROR = 0b1000, /**< Сообщение об ошибке. */ + PROTOCAN_MSGTYPE_PULSE = 0b1111, /**< Импульсное сообщение. */ +}ProtoCanMsgType; + +/** + * @brief Типы широковещательных сообщений CAN. + * + * Перечисление задает различные типы широковещательных команд, используемых в протоколе. + */ +typedef enum { + PROTOCAN_BROADCAST_STATUS = 0b000000000000, /**< Статус устройства. */ + PROTOCAN_BROADCAST_ONOFF = 0b000000000001, /**< Включение/выключение устройства. */ + PROTOCAN_BROADCAST_RESTARTDEVICE = 0b000000000010, /**< Перезагрузка устройства. */ + PROTOCAN_BROADCAST_RTCSETUP = 0b000000000011, /**< Настройка RTC (часы реального времени). */ + PROTOCAN_BROADCAST_END = 0b111111111111 /**< Конец диапазона широковещательных сообщений. */ +}ProtoCanBroadcastType; + +/** + * @brief Структура и представление широковещательного сообщения CAN. + * + * Объединение позволяет обращаться к данным сообщения либо как к отдельным полям, либо как к целому 16-битному значению. + */ +typedef union{ + struct msgBody_Broadcast{ + unsigned Body:4; /**< Поле для дополнительных данных или кода задачи (4 бита). */ + ProtoCanBroadcastType Type:12; /**< Тип широковещательного сообщения (12 бит). */ + } Fields; /**< Структура с разбивкой по полям. */ + unsigned Body; /**< Общее 16-битное представление сообщения. */ +} msgBodyBroadcastType; + +/** + * @brief Типы дискретных сообщений CAN. + * + * Перечисление задает различные виды дискретных команд или событий. + */ +typedef enum { + PROTOCAN_DISCRETE_ACCIDENT = 0b0000, /**< Аварийное состояние. */ + PROTOCAN_DISCRETE_WARNING = 0b0001, /**< Предупредительный сигнал. */ + PROTOCAN_DISCRETE_CONTROL_SIGNALS = 0b0010, /**< Управляющие сигналы. */ + PROTOCAN_DISCRETE_FLAGS = 0b0011, /**< Флаги состояния. */ + PROTOCAN_DISCRETE_RESET = 0b0100, /**< Сброс устройства. */ + PROTOCAN_DISCRETE_CHANGE_MODE = 0b0101, /**< Смена режима работы. */ + PROTOCAN_DISCRETE_REQUEST_LIST_OF_PARAMETERS = 0b0110, /**< Запрос списка параметров. */ + PROTOCAN_DISCRETE_END = 0b1111 /**< Конец диапазона дискретных сообщений. */ +}ProtoCanDiscreteType; + +/** + * @brief Структура и представление дискретного сообщения CAN. + * + * Объединение позволяет обращаться к данным сообщения как к отдельным полям или как к целому 16-битному значению. + */ +typedef union{ + struct msgBody_Discrete{ + unsigned Body:12; /**< Поле данных или кода (12 бит). */ + ProtoCanDiscreteType Type:4; /**< Тип дискретного сообщения (4 бита). */ + } Fields; /**< Структура с разбивкой по полям. */ + unsigned Body; /**< Общее 16-битное представление сообщения. */ +} msgBodyDiscreteType; + +/** + * @brief Типы аналоговых сообщений CAN. + * + * Перечисление определяет различные типы аналоговых данных или команд. + */ +typedef enum { + PROTOCAN_ANALOG_UNIVERSAL = 0b0000, /**< Универсальный тип. */ + PROTOCAN_ANALOG_SETTINGS = 0b0001, /**< Настройки. */ + PROTOCAN_ANALOG_U = 0b0010, /**< Напряжение (U). */ + PROTOCAN_ANALOG_I = 0b0011, /**< Ток (I). */ + PROTOCAN_ANALOG_T = 0b0100, /**< Температура (T). */ + PROTOCAN_ANALOG_END = 0b1111 /**< Конец диапазона типов. */ +}ProtoCanAnalogType; + +/** + * @brief Структура и представление аналогового сообщения CAN. + * + * Объединение позволяет обращаться к данным сообщения как к отдельным полям или как к целому 16-битному значению. + */ +typedef union{ + struct msgBody_Analog{ + unsigned SensorID:12; /**< Идентификатор датчика (12 бит). */ + ProtoCanAnalogType Type:4; /**< Тип аналоговых данных (4 бита). */ + } Fields; /**< Структура с разбивкой по полям. */ + unsigned Body; /**< Общее 16-битное представление сообщения. */ +}msgBodyAnalogType; + +/** + * @brief Структура и представление сообщения Modbus CAN. + * + * Объединение позволяет обращаться к данным как к отдельным полям или как к целому 16-битному значению. + */ +typedef union{ + struct msgBody_Modbus{ + unsigned RegCount:4; /**< Количество регистров (4 бита). */ + unsigned StrAdr:12; /**< Адрес строки или регистра (12 бит). */ + } Fields; /**< Поля структуры сообщения Modbus. */ + unsigned Body; /**< Общее 16-битное представление сообщения. */ +} msgBodyModbusType; + +/** + * @brief Структура и представление сообщения об ошибке CAN. + * + * Объединение позволяет обращаться к данным как к отдельным полям или как к целому 16-битному значению. + */ +typedef union{ + struct msgBody_Error{ + unsigned ErrorCode:8; /**< Код ошибки (8 бит). */ + unsigned Info:8; /**< Дополнительная информация (8 бит). */ + } Fields; /**< Поля ошибки. */ + unsigned Body; /**< Общее 16-битное представление сообщения об ошибке. */ +} msgBodyErrorType; + +struct controlflags{ + unsigned IsPulse:1; + unsigned IsRtrMode:1; +}; + +/** + * @brief Поля идентификатора протокола CAN. + * + * Объединение позволяет обращаться к различным полям идентификатора, а также как к 29-битному целому числу. + */ +typedef union{ + struct protoCanIdFields{ + unsigned MsgBody:16; /**< Поле сообщения (16 бит). */ + ProtoCanMsgType MsgType:4; /**< Тип сообщения (4 бита). */ + unsigned DeviceID:4; /**< Идентификатор устройства (4 бита). */ + unsigned DeviceType:3; /**< Тип устройства (3 бита). */ + ProtoCanRouteType Route:1; /**< Маршрут (1 бит). */ + ProtoCanPriorityType Priority:1; /**< Приоритет (1 бит). */ + } Fields; /**< Структура с разбивкой по полям. */ + unsigned int BitAll:29; /**< Общее представление 29-битного идентификатора. */ +} ProtoCanId_t; + +/** + * @brief Структура для общего адресного пространства CAN. + * + * Используется для хранения данных о регистре и его содержимом. + */ +typedef struct{ + struct ProtoCanCoreData{ + uint16_t Type; + uint16_t Body; + uint8_t *Data; + unsigned DataCount; + } CoreData; + struct ProtoCanGeneralAddressSpaceData{ + uint16_t RegStartAdr; /**< Начальный адрес регистров. */ + uint16_t *Data; /**< Указатель на массив данных. */ + unsigned RegCount; /**< Количество регистров. */ + } GeneralAddressSpaceData; + struct ProtoCanModbusData{ + uint16_t StrAdr; + uint16_t *Data; + unsigned RegCount:4; + } ModbusData; + struct ProtoCanErrorData{ + uint16_t Info; + uint16_t Code; + } ErrorData; +} ProtoCanData_t; + +/** + * @brief Структура данных устройства CAN. + * + * Включает статус, идентификатор, таймер последнего импульса и шаг последнего импульса. + */ +typedef struct{ + unsigned Status:1; /**< Статус устройства (флаг). */ + ProtoCanId_t Id; /**< Идентификатор CAN. */ + unsigned TimeFromLastPulse; /**< Время с последнего импульса (мс). */ + unsigned LastPulseStep; /**< Шаг последнего импульса. */ +} ProtoCanDevice_t; + +/** + * @brief Структура для хранения сообщения RXCAN. + */ +struct RXMsg { + /** + * @brief Структура, содержащая флаги информации. + */ + struct INFO { + unsigned EXT : 1; /**< Бит расширенного идентификатора (EXT). */ + unsigned RTR : 1; /**< Бит запроса на передачу (RTR). */ + } info; /**< Информационные флаги сообщения. */ + ProtoCanId_t eID; /**< Идентификатор CAN-сообщения. */ + uint16_t DLC; /**< Длина данных (Data Length Code). */ + uint8_t Data[8]; /**< Массив данных (до 8 байт). */ +}; + +uint16_t AvailableCanRxMsg(void); + +PROTOCAN_INIT_StatusTypeDef PROTOCAN_INIT(CAN_HandleTypeDef *tmp_hcan, + RTC_HandleTypeDef *tmp_hrtc, + TIM_HandleTypeDef *tmp_tim); +void PROTOCAN_DEINIT(uint8_t stage); +void PROTOCAN_FILTERS(void); +void PROTOCAN_LoopProcessRxMsgs(void); +PROTOCAN_StatusTypeDef PROTOCAN_ProcessAllRxMsgs(void); +PROTOCAN_StatusTypeDef PROTOCAN_ProcessSingleRxMsg(void); +PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data); + +void ProtoCanPulseCallback(TIM_HandleTypeDef *htim); +void ProtoCanRxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan); + +PROTOCAN_StatusTypeDef PROTOCAN_BroadcastProcessing(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastStatus(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastOnOff(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastRestart(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastRtcSetup(struct RXMsg _rxMsg); + +PROTOCAN_StatusTypeDef PROTOCAN_DiscreticProcessing(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteAccident(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteWarning(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteControlSignals(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteFlags(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteReset(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteChangeMode(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteRequestListOfParameters(struct RXMsg _rxMsg); + +PROTOCAN_StatusTypeDef PROTOCAN_AnalogProcessing(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogUniversal(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogSettings(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogUSens(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogISens(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg _rxMsg); + +PROTOCAN_StatusTypeDef ProtoCanMsgToGeneralAddressSpace(struct RXMsg _rxMsg); + +PROTOCAN_StatusTypeDef PROTOCAN_RequestError(struct RXMsg _rxMsg); + +PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToModbusCoil(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToModbusDiscrete(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToModbusHolding(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToModbusInput(struct RXMsg _rxMsg); + +void PROTOCAN_RTC_SYNC(uint8_t *data); + +#endif diff --git a/Src/protocan.c b/Src/protocan.c new file mode 100644 index 0000000..16f6033 --- /dev/null +++ b/Src/protocan.c @@ -0,0 +1,1517 @@ +#include "protocan.h" + +ProtoCanDevice_t CurrentDevice; +ProtoCanDevice_t Device_on_the_Network[8][16]; +struct controlflags ControlFlags; + +CAN_HandleTypeDef *_HCAN = 0; +RTC_HandleTypeDef *_HRTC = 0; +TIM_HandleTypeDef *_HTIM = 0; + +/* CurrentStep - индекс следующего сообщения на обработку (пишет основной код). + LastStep - индекс последнего записанного сообщения (пишет ISR). + Оба индекса volatile: без этого компилятор вправе закэшировать значение в + регистре, т.к. в его модели исполнения прерывание в код не входит. + Сам массив rxMsg volatile НЕ объявлен - это ухудшило бы кодогенерацию и + мешало бы копированию структуры по значению. Порядок "заполнить слот, затем + опубликовать индекс" обеспечивается барьерами __DMB() в точках публикации и + чтения. */ +volatile uint16_t CurrentStep = 1; +volatile uint16_t LastStep = 0; +struct RXMsg rxMsg[PROTOCAN_RX_BUFFER_SIZE]; + +/** +* @brief Проверяет, является ли год високосным. +* В системе год хранится как смещение от 2000. Например, значение 24 соответствует 2024. +* Эта функция добавляет 2000 к значению и проверяет, високосный ли получившийся год. +* @param year Смещение от 2000, тип uint8_t (от 0 до 255). +* @return _Bool true, если год високосный; false — иначе. +*/ +_Bool IsLeapYear(uint8_t year) +{ + year += 2000; + return (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)); +} + +/** +* @brief Возвращает количество доступных сообщений в буфере приёма CAN. +* Используется кольцевой буфер. +* Возвращаемое значение — количество элементов между указателями LastStep и CurrentStep. +* @return uint16_t Количество доступных сообщений, ожидающих обработки, в буфере. +*/ +uint16_t AvailableCanRxMsg(void) +{ + /* Однократное чтение индекса, обновляемого из ISR. */ + uint16_t last = LastStep; + uint16_t current = CurrentStep; + /* Индекс прочитан до обращения к данным слота. */ + __DMB(); + return (uint16_t)(((unsigned)PROTOCAN_RX_BUFFER_SIZE + last - current + 1u) % PROTOCAN_RX_BUFFER_SIZE); +} + +void PROTOCAN_DEINIT(uint8_t stage) +{ + switch(stage) + { + case 3: + #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) + HAL_TIM_UnRegisterCallback(_HTIM, HAL_TIM_PERIOD_ELAPSED_CB_ID); + #endif + case 2: + case 1: + #if (USE_HAL_CAN_REGISTER_CALLBACKS == 1) + HAL_CAN_UnRegisterCallback(_HCAN, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID); + #endif + } + return; +} + +/** +* @brief Инициализация переферии +* @details Инициализация указателей на HCAN, HRTC, установка фильтров CAN. +* @note Фильтры CAN описаны в разделе PROTOCAN_CAN_FILTERS(). +*/ +PROTOCAN_INIT_StatusTypeDef PROTOCAN_INIT(CAN_HandleTypeDef *tmp_hcan, RTC_HandleTypeDef *tmp_hrtc, TIM_HandleTypeDef *tmp_tim) +{ + unsigned initStage = 0; + if(tmp_hcan) + { + _HCAN = tmp_hcan; + #if (USE_HAL_CAN_REGISTER_CALLBACKS == 1) + HAL_StatusTypeDef CAN_RC_RESULT = HAL_CAN_RegisterCallback(_HCAN, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID, ProtoCanRxFifo0MsgPendingCallback); + if(CAN_RC_RESULT != HAL_OK) + { + PROTOCAN_DEINIT(initStage); + return PROTOCAN_INIT_HCAN_ERROR; + } + #endif + } else { + PROTOCAN_DEINIT(initStage); + return PROTOCAN_INIT_HCAN_ERROR; + } + initStage++; + if(tmp_hrtc) + { + _HRTC = tmp_hrtc; + } + else + { + PROTOCAN_DEINIT(initStage); + return PROTOCAN_INIT_HRTC_ERROR; + } + initStage++; + if(tmp_tim) + { + _HTIM = tmp_tim; + #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) + HAL_StatusTypeDef TIM_RC_RESULT = HAL_TIM_RegisterCallback(_HTIM, HAL_TIM_PERIOD_ELAPSED_CB_ID, ProtoCanPulseCallback); + if(TIM_RC_RESULT != HAL_OK) + { + PROTOCAN_DEINIT(initStage); + return PROTOCAN_INIT_TIM_ERROR; + } + #endif + } + else + { + PROTOCAN_DEINIT(initStage); + return PROTOCAN_INIT_TIM_ERROR; + } + initStage++; + PROTOCAN_FILTERS(); + ControlFlags.IsPulse = 1; + return PROTOCAN_INIT_OK; +} + +/** + * @brief Бесконечный цикл обработки входящих CAN-сообщений. + * + * Эта функция постоянно проверяет наличие доступных сообщений в буфере CAN и + * вызывает соответствующие обработчики в зависимости от типа полученного сообщения. + * Обрабатываемые типы сообщений: + * - Аналоговые данные + * - Широковещательные сообщения + * - Дискретные данные + * - Общее адресное пространство + * - Модбас сообщения + * - Ошибки + * + * Обработка сообщений осуществляется внутри бесконечного цикла с использованием + * функции AvailableCanRxMsg() для определения наличия новых сообщений. + * + * В конце каждого обработанного сообщения индекс текущего элемента буфера инкрементируется + * с учетом размера буфера через операцию по модулю. + */ +void PROTOCAN_LoopProcessRxMsgs(void) +{ + while(1) + { + if(AvailableCanRxMsg()) + { + if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_ANALOG) + { + PROTOCAN_AnalogProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_BROADCAST) + { + PROTOCAN_BroadcastProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_DISCRETE) + { + PROTOCAN_DiscreticProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE) + { + ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) + { + PROTOCAN_ModbusProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_ERROR) + { + PROTOCAN_RequestError(rxMsg[CurrentStep]); + } + // Обновление индекса текущего сообщения с циклическим масштабированием + CurrentStep = (uint16_t)(CurrentStep + 1) % PROTOCAN_RX_BUFFER_SIZE; + } + } +} + +/** + * @brief Обрабатывает все доступные входящие CAN-сообщения. + * + * Эта функция последовательно обрабатывает все сообщения, доступные в буфере, + * вызывая соответствующие функции обработчики в зависимости от типа сообщения. + * После обработки каждого сообщения индекс текущего элемента буфера обновляется + * циклически. + * + * @return PROTOCAN_OK, если все сообщения были обработаны успешно. + * В противном случае возвращается код ошибки, полученный при обработке сообщения. + * + * Обработка происходит до тех пор, пока есть доступные сообщения, полученные функцией + * AvailableCanRxMsg(). + */ +PROTOCAN_StatusTypeDef PROTOCAN_ProcessAllRxMsgs(void) +{ + PROTOCAN_StatusTypeDef result = PROTOCAN_TIMEOUT; + while(AvailableCanRxMsg()) + { + if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_ANALOG) + { + result = PROTOCAN_AnalogProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_BROADCAST) + { + result = PROTOCAN_BroadcastProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_DISCRETE) + { + result = PROTOCAN_DiscreticProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE) + { + result = ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) + { + result = PROTOCAN_ModbusProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_ERROR) + { + result = PROTOCAN_RequestError(rxMsg[CurrentStep]); + } + CurrentStep = (uint16_t)(CurrentStep + 1) % PROTOCAN_RX_BUFFER_SIZE; + if(result != PROTOCAN_OK) + { + return result; + } + } + return result; +} + +/** + * @brief Обрабатывает одно доступное CAN-сообщение. + * + * Эта функция проверяет наличие доступных сообщений в буфере и, если таковое есть, + * выполняет обработку текущего сообщения в зависимости от его типа. После обработки + * индекс текущего сообщения обновляется циклически. + * + * @return Прошедший статус обработки: + * - PROTOCAN_OK, если сообщение успешно обработано, + * - PROTOCAN_TIMEOUT, если сообщений не было, + * - или код ошибки, возвращенный функцией обработки. + */ +PROTOCAN_StatusTypeDef PROTOCAN_ProcessSingleRxMsg(void) +{ + PROTOCAN_StatusTypeDef result = PROTOCAN_TIMEOUT; + if(AvailableCanRxMsg()) + { + if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_ANALOG) + { + result = PROTOCAN_AnalogProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_BROADCAST) + { + result = PROTOCAN_BroadcastProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_DISCRETE) + { + result = PROTOCAN_DiscreticProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE) + { + result = ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || + rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) + { + result = PROTOCAN_ModbusProcessing(rxMsg[CurrentStep]); + } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_ERROR) + { + result = PROTOCAN_RequestError(rxMsg[CurrentStep]); + } + CurrentStep = (uint16_t)(CurrentStep + 1) % PROTOCAN_RX_BUFFER_SIZE; + } + return result; +} + +/** +* @brief Функция обработки широковещательных запросов. +* @param struct RXMsg _rxMsg - структура для полученного сообщения. +* @details Функция, выполняющая команды, переданные в широковещательном формате с головного (master) устройства. Типы команд: Запрос статуса, запрос на включение или выключение, рестарт устройств, установка времени. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +PROTOCAN_StatusTypeDef PROTOCAN_BroadcastProcessing(struct RXMsg _rxMsg) +{ + msgBodyBroadcastType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + switch(msg.Fields.Type) + { + case PROTOCAN_BROADCAST_STATUS: + { + //Обработка запроса статуса устройства + return ProtoCanMsgToBroadcastStatus(_rxMsg); + } + case PROTOCAN_BROADCAST_ONOFF: + { + //Обработка запроса на вкл/выкл + ProtoCanMsgToBroadcastOnOff(_rxMsg); + break; + } + case PROTOCAN_BROADCAST_RESTARTDEVICE: + { + ProtoCanMsgToBroadcastRestart(_rxMsg); + break; + } + case PROTOCAN_BROADCAST_RTCSETUP: + { + //Обработка запроса на синхронизацию времени + //С головным устройством + ProtoCanMsgToBroadcastRtcSetup(_rxMsg); + break;; + } + default: + //RESERVE SENSOR TYPE. + return PROTOCAN_ERROR; + break; + } + return PROTOCAN_OK; +} + +/** +* @brief Формирует и отправляет широковещательное CAN-сообщение для ответа на запрос статуса. +* Устанавливает идентификатор, собирает текущие параметры времени и даты, и отправляет сообщение. +* @param _rxMsg Структура полученного по CAN запроса. +* @return HAL_StatusTypeDef Статус операции HAL, например HAL_OK при успехе. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastStatus(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.DLC = 7; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + tmp_eID.Fields.DeviceType = CURRENT_TYPE_DEVICE; + tmp_eID.Fields.DeviceID = CURRENT_ID_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + RTC_TimeTypeDef sTime = {0}; + HAL_RTC_GetTime(_HRTC, &sTime, RTC_FORMAT_BIN); + data[0] = sTime.Hours; + data[1] = sTime.Minutes; + data[2] = sTime.Seconds; + RTC_DateTypeDef DateToUpdate = {0}; + HAL_RTC_GetDate(_HRTC, &DateToUpdate, RTC_FORMAT_BIN); + data[3] = DateToUpdate.Year; + data[4] = DateToUpdate.Month; + data[5] = DateToUpdate.Date; + data[6] = DateToUpdate.WeekDay; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief Виртуальная слабая функция для переключения режима пульсации ON/OFF. +* Меняет состояние флага IsPulse в структуре ControlFlags. +* В данном случае — просто инвертирует его логическое значение. +* @param _rxMsg Структура полученного CAN-сообщения (Пока не используется в функции). +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastOnOff(struct RXMsg _rxMsg) +{ + ControlFlags.IsPulse = !ControlFlags.IsPulse; + return PROTOCAN_OK; +} + +/** +* @brief __weak функция для обработки широковещательного сообщения перезапуска устройства. +* Проверяет длину сообщения, извлекает ID из данных и, если она совпадает с текущим устройством, +* вызывает системный перезапуск. +* @param _rxMsg Структура полученного CAN-сообщения с командой перезапуска. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastRestart(struct RXMsg _rxMsg) +{ + if(_rxMsg.DLC == 0) + { + return PROTOCAN_ERROR; + } + msgBodyBroadcastType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + if(msg.Fields.Body == (CURRENT_ID_DEVICE / (_rxMsg.DLC*8))) + { + uint64_t page = 0; + for(uint32_t i = 0; i < _rxMsg.DLC; i++) + { + /* Приведение обязательно: Data[i] продвигается до int, и сдвиг на + 32..56 бит без него - неопределённое поведение. */ + page |= (uint64_t)_rxMsg.Data[i] << (i * 8u); + } + if((page >> CURRENT_ID_DEVICE) & 1u) + { + NVIC_SystemReset(); + } + } + return PROTOCAN_OK; +} + +/** +* @brief __weak функция для обработки запроса на синхронизацию RTC через широковещательное сообщение. +* Проверяет длину сообщения и корректность данных (время и дата). Если все проверки пройдены, +* вызывает функцию синхронизации RTC. +* @param _rxMsg Структура полученного CAN-сообщения с данными для установки времени и даты. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToBroadcastRtcSetup(struct RXMsg _rxMsg) +{ + /* Нужны все 7 полей: чч, мм, сс, год, месяц, число, день недели. + Прежняя проверка (DLC > 7) пропускала в том числе пустой кадр, и время + устанавливалось из неинициализированных байт. */ + if(_rxMsg.DLC != 7) + { + return PROTOCAN_ERROR; + } + else + { + static const uint8_t DaysCount_Normal[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + /* Месяц нумеруется с 1, индекс массива - с 0. */ + if( _rxMsg.Data[0] > 23 || + _rxMsg.Data[1] > 59 || + _rxMsg.Data[2] > 59 || + _rxMsg.Data[3] > 99 || + _rxMsg.Data[4] == 0 || _rxMsg.Data[4] > 12 || + _rxMsg.Data[5] == 0 || + _rxMsg.Data[5] > DaysCount_Normal[IsLeapYear(_rxMsg.Data[3])][_rxMsg.Data[4] - 1] || + _rxMsg.Data[6] > 6) + { + return PROTOCAN_ERROR; + } + else + { + PROTOCAN_RTC_SYNC(_rxMsg.Data); + } + } + return PROTOCAN_OK; +} + +/** +* @brief Функция обработки дискретных запросов. +* @param struct RXMsg _rxMsg - структура для полученного сообщения. +* @details Функция, формирующая и отправляющая ответ на запросы. Типы запросов: Аварии, Предупреждения, Управляющие сигналы, Флаги, Рестарт устройства, Изменение режима работы устройства, Запрос на устройство. +* @note Запрос на устройство. Головное (master) устройство запрашивает некоторое колличество параметров. В Data - 64 битовых адресса параметров, тип которых задаётся в Sensor ID. Имеется возможность запрашивать непоследовательные параметры. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +PROTOCAN_StatusTypeDef PROTOCAN_DiscreticProcessing(struct RXMsg _rxMsg) +{ + msgBodyDiscreteType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + switch(msg.Fields.Type) + { + case PROTOCAN_DISCRETE_ACCIDENT: + { + ProtoCanMsgToDiscreteAccident(_rxMsg); + break; + } + case PROTOCAN_DISCRETE_WARNING: + { + ProtoCanMsgToDiscreteWarning(_rxMsg); + break; + } + case PROTOCAN_DISCRETE_CONTROL_SIGNALS: + { + ProtoCanMsgToDiscreteControlSignals(_rxMsg); + break; + } + case PROTOCAN_DISCRETE_FLAGS: + { + ProtoCanMsgToDiscreteFlags(_rxMsg); + break; + } + case PROTOCAN_DISCRETE_RESET: + { + ProtoCanMsgToDiscreteReset(_rxMsg); + break; + } + case PROTOCAN_DISCRETE_CHANGE_MODE: + { + ProtoCanMsgToDiscreteChangeMode(_rxMsg); + break; + } + case PROTOCAN_DISCRETE_REQUEST_LIST_OF_PARAMETERS: + { + ProtoCanMsgToDiscreteRequestListOfParameters(_rxMsg); + break; + } + default: + //RESERVE SENSOR TYPE. + return PROTOCAN_ERROR; + break; + } + return PROTOCAN_OK; +} + +/** +* @brief Обработка запроса аварийных ситуаций. +* В текущей реализации — заглушка, ничего не выполняет. +* Можно реализовать отправку или обработку аварийных данных. +* @param _rxMsg Входящее сообщение с данными запроса. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteAccident(struct RXMsg _rxMsg) +{ + return PROTOCAN_OK; +} + +/** +* @brief Обработка запроса предупреждений. +* В текущей реализации — заглушка. +* Можно реализовать обработку или ответ на предупреждения. +* @param _rxMsg Входящее сообщение. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteWarning(struct RXMsg _rxMsg) +{ + return PROTOCAN_OK; +} + +/** +* @brief Обработка запроса управляющих сигналов. +* В текущей реализации — заглушка. +* Можно реализовать управление сигналами. +* @param _rxMsg Входящее сообщение. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteControlSignals(struct RXMsg _rxMsg) +{ + return PROTOCAN_OK; +} + +/** +* @brief Обработка запроса флагов. +* В текущей реализации — заглушка. +* Можно реализовать работу с флагами. +* @param _rxMsg Входящее сообщение. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteFlags(struct RXMsg _rxMsg) +{ + return PROTOCAN_OK; +} + +/** +* @brief Обработка рестарта системы по CAN-запросу. +* Выполняет программный рестарт системы. +* @param _rxMsg Входящее сообщение. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteReset(struct RXMsg _rxMsg) +{ + NVIC_SystemReset(); + return PROTOCAN_ERROR; +} + +/** +* @brief Обработка запроса на изменение режима. +* В текущей реализации — заглушка. +* Можно реализовать изменение режима работы. +* @param _rxMsg Входящее сообщение. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteChangeMode(struct RXMsg _rxMsg) +{ + return PROTOCAN_OK; +} + +/** +* @brief Обработка запроса на получение списка параметров. +* В текущей реализации — заглушка. +* Можно реализовать отправку списка параметров. +* @param _rxMsg Входящее сообщение. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToDiscreteRequestListOfParameters(struct RXMsg _rxMsg) +{ + return PROTOCAN_OK; +} + +/** +* @brief Функция обработки аналоговых запросов. +* @param struct RXMsg _rxMsg - структура для полученного сообщения. +* @details Функция, сортирующая запросы по типам и вызывающая соответствующие функции. Типы запросов: Универсальный, Уставки, Напряжение, Ток, Температура. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +PROTOCAN_StatusTypeDef PROTOCAN_AnalogProcessing(struct RXMsg _rxMsg) +{ + msgBodyAnalogType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + switch (msg.Fields.Type) + { + case PROTOCAN_ANALOG_UNIVERSAL: + { + return ProtoCanMsgToAnalogUniversal(_rxMsg); + break; + } + case PROTOCAN_ANALOG_SETTINGS: + { + return ProtoCanMsgToAnalogSettings(_rxMsg); + break; + } + case PROTOCAN_ANALOG_U: + { + return ProtoCanMsgToAnalogUSens(_rxMsg); + break; + } + case PROTOCAN_ANALOG_I: + { + return ProtoCanMsgToAnalogISens(_rxMsg); + break; + } + case PROTOCAN_ANALOG_T: + { + return ProtoCanMsgToAnalogTSens(_rxMsg); + break; + } + default: + //RESERVE SENSOR TYPE + return PROTOCAN_ERROR; + break; + } + return PROTOCAN_ERROR; +} + +/** +* @brief Функция ответа на запрос данных со всех датчиков. +* Создает сообщение с определенными данными и отправляет его через CAN-шину. +* @param _rxMsg Структура входящего сообщения, используется для формирования ID. +* @return HAL_StatusTypeDef Статус выполнения операции HAL, например HAL_OK. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogUniversal(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 6; + data[0] = 'U'; + data[1] = 'N'; + data[2] = 'I'; + data[3] = 'V'; + data[4] = 'E'; + data[5] = 'R'; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief Функция ответа на запрос уставок по CAN. +* Создает сообщение с определенными данными и отправляет его через CAN-шину. +* @param _rxMsg Структура входящего сообщения, используется только для формирования ID. +* @return HAL_StatusTypeDef Статус выполнения операции HAL, например HAL_OK. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogSettings(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 7; + data[0] = 'U'; + data[1] = 'S'; + data[2] = 'T'; + data[3] = 'A'; + data[4] = 'V'; + data[5] = 'K'; + data[6] = 'I'; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief Функция ответа на запрос данных с датчиков напряжения. +* Создает сообщение с указанными параметрами и отправляет его через CAN-шину. +* @param _rxMsg Структура входящего сообщения, используемая для формирования идентификатора и данных. +* @return HAL_StatusTypeDef Статус выполнения операции HAL, например HAL_OK при успешной отправке. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogUSens(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 6; + msgBodyAnalogType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + data[0] = 'U'; + data[1] = 'S'; + data[2] = '0' + msg.Fields.SensorID / 1000; + data[3] = '0' + msg.Fields.SensorID / 100 % 10; + data[4] = '0' + msg.Fields.SensorID / 10 % 10; + data[5] = '0' + msg.Fields.SensorID % 10; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief Функция ответа на запрос данных с датчиков тока. +* Создает сообщение с определенными параметрами и отправляет его через CAN-шину. +* @param _rxMsg Структура входящего сообщения, используется для формирования идентификатора и данных. +* @return HAL_StatusTypeDef Статус операции HAL, например HAL_OK при успешной отправке. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogISens(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 6; + msgBodyAnalogType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + data[0] = 'I'; + data[1] = 'S'; + data[2] = '0' + msg.Fields.SensorID / 1000; + data[3] = '0' + msg.Fields.SensorID / 100 % 10; + data[4] = '0' + msg.Fields.SensorID / 10 % 10; + data[5] = '0' + msg.Fields.SensorID % 10; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief Функция ответа на запрос данных с датчиков температуры. +* Создает сообщение с определенным заголовком, формирует данные по ID сенсора и отправляет его через CAN. +* @param _rxMsg Структура полученного сообщения, которая используется для формирования идентификатора. +* @return HAL_StatusTypeDef Статус выполнения функции HAL, например HAL_OK при успехе. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 6; + msgBodyAnalogType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + data[0] = 'T'; + data[1] = 'S'; + data[2] = '0' + msg.Fields.SensorID / 1000; + data[3] = '0' + msg.Fields.SensorID / 100 % 10; + data[4] = '0' + msg.Fields.SensorID / 10 % 10; + data[5] = '0' + msg.Fields.SensorID % 10; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** + * @brief Отправляет сообщение по CAN-шине в соответствии с типом протокола. + * Эта функция формирует и отправляет сообщение через CAN-шину, основываясь на типе + * переданного ID и данных. Поддерживаются типы сообщений: широковещательные, дискретные + * и аналоговые. + * @param id Идентификатор сообщения, содержащий тип сообщения и другую информацию. + * @param coreData Структура данных, включающая тип, тело и данные для передачи. + * @return PROTOCAN_StatusTypeDef Статус операции. + * @details + * В зависимости от типа сообщения (панель broadcast, discrete или analog), + * формируется соответствующий пакет данных и отправляется на шину CAN. + * Для сообщений, превышающих длину 8 байт, передача выполняется пакетами. + * В случае ошибок при добавлении сообщения в очередь передачи, возвращается ошибка. + */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_CORE(const ProtoCanId_t id, const struct ProtoCanCoreData coreData) +{ + ProtoCanId_t localId = id; + CAN_TxHeaderTypeDef TxHeader; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.RTR = CAN_RTR_DATA; + TxHeader.TransmitGlobalTime = DISABLE; + uint32_t TxMailBox = 0; + uint8_t canData[8]; + switch(id.Fields.MsgType) + { + case PROTOCAN_MSGTYPE_BROADCAST: + { + msgBodyBroadcastType body; + body.Fields.Type = coreData.Type; + body.Fields.Body = coreData.Body; + localId.Fields.MsgBody = body.Body; + TxHeader.ExtId = localId.BitAll; + TxHeader.DLC = 0; + if(HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK) + { + return PROTOCAN_ERROR; + } + break; + } + case PROTOCAN_MSGTYPE_DISCRETE: + { + msgBodyDiscreteType body; + body.Fields.Type = coreData.Type; + uint8_t regsRemaining = coreData.DataCount; + uint8_t currentIndex = 0; + while(regsRemaining > 0) + { + uint8_t regsInPacket = (regsRemaining > 8) ? 8 : regsRemaining; + body.Fields.Body = coreData.Body + currentIndex; + localId.Fields.MsgBody = body.Body; + TxHeader.ExtId = localId.BitAll; + TxHeader.DLC = regsInPacket; + for(int i = 0; i < regsInPacket; i++) + { + canData[i] = coreData.Data[currentIndex + i]; + } + HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox); + if(status != HAL_OK) + { + return (PROTOCAN_StatusTypeDef)status; + } + regsRemaining -= regsInPacket; + currentIndex += regsInPacket; + } + break; + } + case PROTOCAN_MSGTYPE_ANALOG: + { + msgBodyAnalogType body; + body.Fields.Type = coreData.Type; + uint8_t regsRemaining = coreData.DataCount; + uint8_t currentIndex = 0; + while(regsRemaining > 0) + { + uint8_t regsInPacket = (regsRemaining > 8) ? 8 : regsRemaining; + body.Fields.SensorID = coreData.Body + currentIndex; + localId.Fields.MsgBody = body.Body; + TxHeader.ExtId = localId.BitAll; + TxHeader.DLC = regsInPacket; + for(int i = 0; i < regsInPacket; i++) + { + canData[i] = coreData.Data[currentIndex + i]; + } + HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox); + if(status != HAL_OK) + { + return (PROTOCAN_StatusTypeDef)status; + } + regsRemaining -= regsInPacket; + currentIndex += regsInPacket; + } + break; + } + default: + { + return PROTOCAN_ERROR; + } + } + return PROTOCAN_OK; +} + +/** +* @brief Обработка и ответ на запрос общего адресного пространства. +* Формирует и передает сообщение с данными о статусе "GAS-XXXX", где XXXX — значение из сообщения _rxMsg. +* @param _rxMsg Структура входящего сообщения, содержит идентификатор и тело сообщения. +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToGeneralAddressSpace(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 8; + data[0] = 'G'; + data[1] = 'A'; + data[2] = 'S'; + data[3] = '-'; + for(int i = 0; i < 4; i++) + { + unsigned sym = (_rxMsg.eID.Fields.MsgBody >> (12 - (i * 4))) & 0xF; + if(sym >= 10) + { + data[4 + i] = sym % 10 + 'A'; + } + else + { + data[4 + i] = sym + '0'; + } + } + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** + * @brief Отправляет произвольный диапазон регистров в пакетах по, максимум, 4 регистра за раз через CAN. + * Функция разбивает передаваемый массив регистров на пакеты по 4 или меньше и отправляет их по отдельности. + * Для каждого пакета формируется уникальный MsgBody, равный адресу первого регистра в пакете. + * @param priority Приоритет сообщения CAN. ProtoCan_Priority_TypeDef + * @param regStartAdr Адрес первого регистра из всего массива. + * @param data Указатель на массив регистров для отправки. + * @param regCount Общее количество регистров для отправки. + * @return Возвращает статус отправки: HAL_OK при успехе, или код ошибки HAL_StatusTypeDef при сбое. + */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_GENERAL_ADDRESS_SPACE(ProtoCanId_t id, uint16_t regStartAdr, uint16_t *data, uint8_t regCount) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t canData[8]; + + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = id.BitAll; + + uint8_t regsRemaining = regCount; + uint8_t currentIndex = 0; + + while(regsRemaining > 0) + { + uint8_t regsInPacket = (regsRemaining > 4) ? 4 : regsRemaining; + + tmp_eID.Fields.MsgBody = regStartAdr + currentIndex; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = regsInPacket*2; + + for(int i = 0; i < regsInPacket; i++) + { + canData[(i * 2)] = LowByteOfWord(data[currentIndex + i]); + canData[(i * 2) + 1] = HighByteOfWord(data[currentIndex + i]); + } + + HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox); + + if(status != HAL_OK) + { + return (PROTOCAN_StatusTypeDef)status; + } + + regsRemaining -= regsInPacket; + currentIndex += regsInPacket; + } + return (PROTOCAN_StatusTypeDef)HAL_OK; +} + +/** +* @brief Обработка запроса на основе типа Modbus. +* В зависимости от типа сообщения, вызывает соответствующую функцию +* для отправки Modbus-запроса по CAN-шине. +* @param _rxMsg Структура входящего сообщения RXMsg. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg _rxMsg) +{ + switch(_rxMsg.eID.Fields.MsgType) + { + case PROTOCAN_MSGTYPE_MODBUS_COIL: + { + return ProtoCanMsgToModbusCoil(_rxMsg); + break; + } + case PROTOCAN_MSGTYPE_MODBUS_DISCRETE: + { + return ProtoCanMsgToModbusDiscrete(_rxMsg); + break; + } + case PROTOCAN_MSGTYPE_MODBUS_HOLDING: + { + return ProtoCanMsgToModbusHolding(_rxMsg); + break; + } + case PROTOCAN_MSGTYPE_MODBUS_INPUT: + { + return ProtoCanMsgToModbusInput(_rxMsg); + break; + } + default: + //ERROR + return PROTOCAN_ERROR; + break; + } + return PROTOCAN_ERROR; +} + +/** +* @brief __weak Функция отправки ответа на запрос Coil Modbus по CAN. +* Формирует CAN ответ на запрос Coil Modbus и отправляет его. +* @param _rxMsg Структура входящего сообщения RXMsg. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusCoil(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 8; + msgBodyModbusType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + data[0] = 'M'; + data[1] = 'C'; + data[2] = ' '; + data[3] = 'S'; + data[4] = msg.Fields.StrAdr; + data[5] = ' '; + data[6] = 'C'; + data[7] = msg.Fields.RegCount; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief __weak Функция отправки ответа на запрос Discrete Modbus по CAN. +* Формирует CAN ответ на запрос Discrete Modbus и отправляет его. +* @param _rxMsg Структура входящего сообщения RXMsg. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusDiscrete(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 8; + msgBodyModbusType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + data[0] = 'M'; + data[1] = 'D'; + data[2] = ' '; + data[3] = 'S'; + data[4] = msg.Fields.StrAdr; + data[5] = ' '; + data[6] = 'C'; + data[7] = msg.Fields.RegCount; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief __weak Функция отправки ответа на запрос Holding Modbus по CAN. +* Формирует CAN ответ на запрос Holding Modbus и отправляет его. +* @param _rxMsg Структура входящего сообщения RXMsg. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusHolding(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 8; + msgBodyModbusType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + data[0] = 'M'; + data[1] = 'H'; + data[2] = ' '; + data[3] = 'S'; + data[4] = msg.Fields.StrAdr; + data[5] = ' '; + data[6] = 'C'; + data[7] = msg.Fields.RegCount; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** +* @brief __weak Функция отправки ответа на запрос Input Modbus по CAN. +* Формирует CAN ответ на запрос Input Modbus и отправляет его. +* @param _rxMsg Структура входящего сообщения RXMsg. +* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). +*/ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusInput(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 8; + msgBodyModbusType msg; + msg.Body = _rxMsg.eID.Fields.MsgBody; + data[0] = 'M'; + data[1] = 'I'; + data[2] = ' '; + data[3] = 'S'; + data[4] = msg.Fields.StrAdr; + data[5] = ' '; + data[6] = 'C'; + data[7] = msg.Fields.RegCount; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** + * @brief Отправляет данные Modbus через CAN-шину в соответствии с типом сообщения. + * Эта функция формирует и отправляет Modbus-данные по CAN-шине, поддерживая + * различные типы сообщений: Coil, Discrete, Holding Register и Input Register. + * Для сообщений, превышающих 4 регистров, данные отправляются пакетами. + * @param id Идентификатор сообщения, содержащий тип сообщения и другую информацию. + * @param modbusData Структура с данными Modbus: адрес, количество регистров и сами данные. + * @return PROTOCAN_StatusTypeDef Статус операции. + * @details + * В зависимости от типа Modbus (coil/discrete или holding/input), формируется + * соответствующий CAN-пакет. Для coil/discrete отправляется один пакет, для holding/input — + * несколько, по 4 регистра в пакете. В случае ошибок при добавлении сообщения API HAL возвращается ошибка. + */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_MODBUS(const ProtoCanId_t id, const struct ProtoCanModbusData modbusData) +{ + ProtoCanId_t localId = id; + uint8_t msgType = localId.Fields.MsgType; + // Структура для отправки + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t canData[8]; + if(msgType == PROTOCAN_MSGTYPE_MODBUS_COIL || msgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE) + { + // Формируем body + msgBodyModbusType body; + body.Fields.StrAdr = modbusData.StrAdr; + body.Fields.RegCount = modbusData.RegCount; + // Устанавливаем коллизию ExtId с body.Body + localId.Fields.MsgBody = (body.Body & 0xFFFF); + // Обновляем ExtId + TxHeader.ExtId = localId.BitAll; + // Остальные настройки + TxHeader.IDE = CAN_ID_EXT; + TxHeader.RTR = CAN_RTR_DATA; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.DLC = modbusData.RegCount % 8 + 1; + // Формируем CAN данные + canData[0] = LowByteOfWord(modbusData.Data[0]); + canData[1] = HighByteOfWord(modbusData.Data[0]); + if (HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK) + { + return PROTOCAN_ERROR; + } + } + else if(msgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || msgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) + { + uint16_t* dataPtr = modbusData.Data; + unsigned totalRegs = modbusData.RegCount; + unsigned regsProcessed = 0; + unsigned startAddress = modbusData.StrAdr; + while (regsProcessed < totalRegs) + { + uint8_t regsInPacket = (totalRegs - regsProcessed) > 4 ? 4 : (totalRegs - regsProcessed); + // Формируем body + msgBodyModbusType body; + body.Fields.StrAdr = startAddress; + body.Fields.RegCount = regsInPacket; + // Обновляем ExtId + localId.Fields.MsgBody = (body.Body & 0xFFFF); + TxHeader.ExtId = localId.BitAll; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.RTR = CAN_RTR_DATA; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.DLC = regsInPacket * 2; + // Добавляем регистры + for (int i = 0; i < regsInPacket; i++) + { + canData[i * 2] = LowByteOfWord(dataPtr[regsProcessed + i]); + canData[i * 2 + 1] = HighByteOfWord(dataPtr[regsProcessed + i]); + } + // Отправляем сообщение + if(HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK) + { + return PROTOCAN_ERROR; + } + regsProcessed += regsInPacket; + startAddress += regsInPacket; + } + } + else + { + return PROTOCAN_ERROR; // Неверный тип сообщения + } + return PROTOCAN_OK; +} + +/** +* @brief __weak Функция отправки сообщения об ошибке. +* Посылает CAN сообщение с кодом ошибки. Используется, когда необходимо оповестить о неуспешной операции. +* @param _rxMsg Структура входящего сообщения RXMsg, данными которого формируется ответ-ошибка. +* @return HAL_StatusTypeDef Статус выполнения команды CAN. +*/ +__weak PROTOCAN_StatusTypeDef PROTOCAN_RequestError(struct RXMsg _rxMsg) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = _rxMsg.eID.BitAll; + tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + tmp_eID.Fields.MsgType = PROTOCAN_MSGTYPE_ERROR; + msgBodyErrorType msg; + msg.Fields.ErrorCode = 0xFF; + msg.Fields.Info = 0; + tmp_eID.Fields.MsgBody = msg.Body; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = 0; + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); +} + +/** + * @brief Отправляет сообщение об ошибке по CAN-шине. + * Эта функция формирует и отправляет сообщение об ошибке с кодом и информацией, + * объединёнными в поле MsgBody идентификатора сообщения, и передаёт его через CAN. + * @param id Идентификатор сообщения, содержащий базовую информацию. + * @param errorData Структура с данными ошибки: код и дополнительная информация. + * @return PROTOCAN_StatusTypeDef Статус операции. + * @details + * В качестве данных передаётся 2 байта: старшие биты — информация об ошибке, младшие — код ошибки. + * Размер данных в CANFrames устанавливается нулевым, так как все данные инкапсулированы в MsgBody. + */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_ERROR(const ProtoCanId_t id, const struct ProtoCanErrorData errorData) +{ + ProtoCanId_t localId = id; + // Структура для отправки + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t canData[8]; + localId.Fields.MsgBody = ((errorData.Info << 8) | errorData.Code); + // Обновляем ExtId + TxHeader.ExtId = localId.BitAll; + // Остальные настройки + TxHeader.IDE = CAN_ID_EXT; + TxHeader.RTR = CAN_RTR_DATA; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.DLC = 0; + if(HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK) + { + return PROTOCAN_ERROR; + } + return PROTOCAN_OK; +} + +/** +* @brief Записывает полученное сообщение CAN в буфер rxMsg. +* Копирует параметры расширенного ID, типы, длину данных и сам данные в указанный элемент буфера. +* @param tmp_eID Расширенный ID сообщения. +* @param tmp_IDE Тип идентификатора (например, CAN_ID_EXT). +* @param tmp_RTR Тип запроса (например, CAN_RTR_DATA). +* @param tmp_DLC Длина данных в сообщении. +* @param tmp_DATA Указатель на массив данных, полученных из CAN. +* @param tmp_LastStep Индекс позиции в буфере, куда записывать сообщение. +*/ +void TakeRxMsgToBuffer(ProtoCanId_t tmp_eID, uint32_t tmp_IDE, uint32_t tmp_RTR, uint32_t tmp_DLC, uint8_t *tmp_DATA, uint16_t tmp_LastStep) +{ + if(tmp_DLC > 8u) + { + tmp_DLC = 8u; + } + rxMsg[tmp_LastStep].eID.BitAll = tmp_eID.BitAll; + rxMsg[tmp_LastStep].info.EXT = tmp_IDE; + rxMsg[tmp_LastStep].info.RTR = tmp_RTR; + rxMsg[tmp_LastStep].DLC = tmp_DLC; + for(uint32_t i = 0; i < tmp_DLC; i++) + { + rxMsg[tmp_LastStep].Data[i] = tmp_DATA[i]; + } + /* Слот заполнен - только теперь публикуем его. Без барьера компилятору + разрешено поднять запись LastStep выше записей в rxMsg, и обработчик + увидит наполовину заполненное сообщение. */ + __DMB(); + LastStep = tmp_LastStep; +} + +/** +* @brief Обработка сообщений, ожидающих в FIFO, по прерыванию HAL_CAN_RxFifo0MsgPendingCallback. +* Читает все сообщения из FIFO, проверяет их тип, обновляет статус устройств сети или сохраняет сообщение в буфер. +* @param hcan Указатель на структуру управления CAN-Hardware. +*/ +void ProtoCanRxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) +{ + //Обработка всех сообщений в FIFO + CAN_RxHeaderTypeDef RxHeader; + uint8_t RCAN_Data[8]; + while(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RCAN_Data) == HAL_OK) + { + //Расширенный ID + if(RxHeader.IDE == CAN_ID_EXT) + { + ProtoCanId_t ExtID_Of_RX_MSG; + ExtID_Of_RX_MSG.BitAll = RxHeader.ExtId; + //Полученное сообщение - пульс устройств в сети. + //Место в буфере не занимает, поэтому проверяется до проверки переполнения. + if(ExtID_Of_RX_MSG.Fields.MsgType == PROTOCAN_MSGTYPE_PULSE) + { + Device_on_the_Network[ExtID_Of_RX_MSG.Fields.DeviceType][ExtID_Of_RX_MSG.Fields.DeviceID].Status = 1u; + Device_on_the_Network[ExtID_Of_RX_MSG.Fields.DeviceType][ExtID_Of_RX_MSG.Fields.DeviceID].TimeFromLastPulse = 0; + //continue, а не return: остаток FIFO нужно вычитать в этом же вызове, + //иначе прерывание по непустому FIFO сработает повторно. + continue; + } + //Полезная ёмкость буфера - (PROTOCAN_RX_BUFFER_SIZE - 1): при большем + //заполнении счётчик AvailableCanRxMsg() переполняется и даёт 0 ("пусто"). + if(AvailableCanRxMsg() >= (PROTOCAN_RX_BUFFER_SIZE - 1u)) + { + //Буфер переполнен, кадр отбрасывается. Кадр уже извлечён из + //аппаратного FIFO, поэтому продолжаем вычитывать остаток. + continue; + } + uint16_t tmp_LastStep = (uint16_t)((LastStep + 1u) % PROTOCAN_RX_BUFFER_SIZE); + TakeRxMsgToBuffer(ExtID_Of_RX_MSG, RxHeader.IDE, RxHeader.RTR, RxHeader.DLC, RCAN_Data, tmp_LastStep); + } + } +} + +/** +* @brief Функция отправки пульса устройства. +* @details Пульс устройства. Есть возможность отключить пульс по запросу. +*/ +void ProtoCanPulseCallback(TIM_HandleTypeDef *htim) +{ + if(ControlFlags.IsPulse) + { + static unsigned PulseStage = 0; + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + ProtoCanId_t currentID; + currentID.BitAll = 0; + currentID.Fields.Priority = PROTOCAN_PRIORITY_STANDARD; + currentID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + currentID.Fields.DeviceType = CURRENT_TYPE_DEVICE; + currentID.Fields.DeviceID = CURRENT_ID_DEVICE; + currentID.Fields.MsgType = PROTOCAN_MSGTYPE_PULSE; + currentID.Fields.MsgBody = 0; + TxHeader.ExtId = currentID.BitAll; + uint8_t data[8]; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + TxHeader.DLC = 1; + PulseStage++; + if(PulseStage > 0xFF) + { + PulseStage = 0; + } + data[0] = PulseStage; + HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); + } +} + +/** +* @brief Функция установки в RTC полученной даты/время из запроса. +* @param uint8_t *data - Байтовый массив, 7 элементов. [0] - Часы. [1] - Минуты. [2] - Секунды. [3] - Год. [4] - Месяц. [5] - Дата. [6] - День недели. +*/ +void PROTOCAN_RTC_SYNC(uint8_t *data) +{ + __HAL_RTC_WRITEPROTECTION_DISABLE(_HRTC); + RTC_TimeTypeDef sTime = {0}; + RTC_DateTypeDef DateToUpdate = {0}; + sTime.Hours = data[0]; + sTime.Minutes = data[1]; + sTime.Seconds = data[2]; + if(HAL_RTC_SetTime(_HRTC, &sTime, RTC_FORMAT_BIN) != HAL_OK) + { + Error_Handler(); + } + DateToUpdate.Year = data[3]; + DateToUpdate.Month = data[4]; + DateToUpdate.Date = data[5]; + DateToUpdate.WeekDay = data[6]; + if(HAL_RTC_SetDate(_HRTC, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK) + { + Error_Handler(); + } + __HAL_RTC_WRITEPROTECTION_ENABLE(_HRTC); +} + +/** +* @brief Настройка CAN-Фильтра. +* На основе переданных ID и маски настраивает фильтр CAN для приема только определённых сообщений. +* @param filterBank Номер фильтра (обычно 0..27). +* @param idFilter 32-битный идентификатор, используемый для фильтрации. +* @param idMask 32-битная маска, определяющая биты, проверяемые фильтром. +*/ +void PROTOCAN_CONFIG_FILTER(uint8_t filterBank, uint32_t idFilter, uint32_t idMask) +{ + CAN_FilterTypeDef canFilterConfig; + canFilterConfig.FilterBank = filterBank; + canFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; + canFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; + canFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; + canFilterConfig.FilterActivation = ENABLE; + canFilterConfig.SlaveStartFilterBank = 14; + #define CAN_IDE_32 0b00000100 // Для 32-х битного масштаба + // Разбиваем 32-битный ID и маску для фильтрации на High и Low 16 бит + canFilterConfig.FilterIdHigh = (uint16_t)(((idFilter) >> 13)); // верхние 16 бит + canFilterConfig.FilterIdLow = (uint16_t)((((idFilter) << 3)) | CAN_IDE_32); // низкие 16 бит, + canFilterConfig.FilterMaskIdHigh = (uint16_t)(((idMask) >> 13)); + canFilterConfig.FilterMaskIdLow = (uint16_t)((((idMask) << 3)) | CAN_IDE_32); + if(HAL_CAN_ConfigFilter(_HCAN, &canFilterConfig) != HAL_OK) + { + Error_Handler(); + } +} + +/** +* @brief Конфигурирует три фильтра CAN для различных типов сообщений. +*/ +void PROTOCAN_FILTERS() +{ + #define BIT27 (1UL << 27) + #define BITS_20_23_MASK (0xFUL << 20) // 4 бита (20..23) + #define BITS_24_26_MASK (0x7UL << 24) // 3 бита (24..26) + + uint32_t filter1_id = BIT27 | (CURRENT_TYPE_DEVICE << 24) | (CURRENT_ID_DEVICE << 20); + uint32_t filter1_mask = BIT27 | BITS_24_26_MASK | BITS_20_23_MASK; // все проверяемые биты + + #define BITS_16_19_MASK (0xFUL << 16) + + uint32_t filter2_id = PROTOCAN_MSGTYPE_BROADCAST << 16; + uint32_t filter2_mask = BITS_16_19_MASK; + + uint32_t filter3_id = PROTOCAN_MSGTYPE_PULSE << 16; + uint32_t filter3_mask = BITS_16_19_MASK; + + // Первый фильтр: проверяем 20-27 биты, где 27-й всегда 1 + PROTOCAN_CONFIG_FILTER(0, filter1_id, filter1_mask); + + // Второй фильтр: проверяем 16-19 биты, равны PROTOCAN_MSGTYPE_BROADCASTE + PROTOCAN_CONFIG_FILTER(1, filter2_id, filter2_mask); + + // Третий фильтр: проверяем 16-19 биты, равны PROTOCAN_MSGTYPE_PULSE + PROTOCAN_CONFIG_FILTER(2, filter3_id, filter3_mask); +} + +/** + * @brief Отправляет CAN-сообщение в зависимости от типа сообщения. + * Эта функция анализирует тип сообщения в идентификаторе и вызывает + * соответствующую функцию отправки. В текущей реализации поддерживается только + * тип PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE. + * @param id Идентификатор CAN-сообщения, содержащий информацию о типе. + * @param data Структура с данными, которые необходимо отправить. Зависит от типа сообщения. + * @return Статус выполнения операции. + */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data) +{ + switch(id.Fields.MsgType) + { + case PROTOCAN_MSGTYPE_BROADCAST: + case PROTOCAN_MSGTYPE_DISCRETE: + case PROTOCAN_MSGTYPE_ANALOG: + { + return PROTOCAN_SEND_CORE(id, data.CoreData); + break; + } + case PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE: + { + /* Если есть регистры для отправки, указатель data должен быть валиден. */ + if((data.GeneralAddressSpaceData.RegCount > 0U) && data.GeneralAddressSpaceData.Data == 0) + { + return PROTOCAN_ERROR; + } + return PROTOCAN_SEND_GENERAL_ADDRESS_SPACE(id, data.GeneralAddressSpaceData.RegStartAdr, + data.GeneralAddressSpaceData.Data, + data.GeneralAddressSpaceData.RegCount); + } + case PROTOCAN_MSGTYPE_MODBUS_COIL: + case PROTOCAN_MSGTYPE_MODBUS_DISCRETE: + case PROTOCAN_MSGTYPE_MODBUS_HOLDING: + case PROTOCAN_MSGTYPE_MODBUS_INPUT: + { + return PROTOCAN_SEND_MODBUS(id, data.ModbusData); + break; + } + case PROTOCAN_MSGTYPE_ERROR: + { + return PROTOCAN_SEND_ERROR(id, data.ErrorData); + break; + } + default: + return PROTOCAN_ERROR; + } + return PROTOCAN_ERROR; +} \ No newline at end of file From ce6c4327a484723dd5238d71c16455eebefa2009 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 25 Aug 2026 18:55:43 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8E=20SETCAN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..d17c1d0 --- /dev/null +++ b/README.md @@ -0,0 +1,310 @@ +# SETCAN + +`SETCAN` — небольшой модуль прикладного протокола поверх классического CAN для микроконтроллеров STM32 и библиотеки STM32 HAL. Модуль принимает только кадры с расширенным 29-битным идентификатором, складывает их в кольцевой буфер и передаёт обработчикам по типу сообщения. Также он умеет отправлять широковещательные, дискретные, аналоговые, адресные, Modbus-подобные сообщения, ошибки и периодический «пульс» устройства. + +Это не самостоятельный проект STM32CubeIDE: здесь нет `.ioc`, startup-файлов, linker script или настроек тактирования. Каталоги `Inc` и `Src` нужно добавить в существующую прошивку STM32. + +## Состав + +```text +SETCAN/ +├── Inc/ +│ └── protocan.h # типы протокола, настройки устройства и публичный API +└── Src/ + └── protocan.c # приём, буферизация, разбор и отправка CAN-кадров +``` + +Модуль зависит от файлов `main.h` и `can.h`, сгенерированных STM32CubeMX, а также от HAL-драйверов CAN, RTC и TIM. + +## Формат расширенного CAN ID + +Протокол размещает служебные поля в 29-битном Extended ID: + +| Биты | Поле | Размер | Назначение | +|---:|---|---:|---| +| 28 | `Priority` | 1 | `0` — критический, `1` — стандартный приоритет | +| 27 | `Route` | 1 | `0` — от управляющего модуля, `1` — от устройства | +| 26..24 | `DeviceType` | 3 | тип устройства, `0..7` | +| 23..20 | `DeviceID` | 4 | номер устройства, `0..15` | +| 19..16 | `MsgType` | 4 | тип сообщения | +| 15..0 | `MsgBody` | 16 | тип команды, адрес, ID датчика или код ошибки | + +Типы сообщений: + +| Значение | Тип | +|---:|---| +| `0x0` | широковещательное (`BROADCAST`) | +| `0x1` | дискретное (`DISCRETE`) | +| `0x2` | аналоговое (`ANALOG`) | +| `0x3` | общее адресное пространство | +| `0x4` | Modbus Coil | +| `0x5` | Modbus Discrete | +| `0x6` | Modbus Holding | +| `0x7` | Modbus Input | +| `0x8` | ошибка | +| `0xF` | пульс присутствия устройства | + +Разметка `MsgBody` зависит от типа сообщения: + +- broadcast: младшие 4 бита — дополнительное поле, старшие 12 бит — команда; +- discrete: младшие 12 бит — данные/адрес, старшие 4 бита — подтип; +- analog: младшие 12 бит — ID датчика, старшие 4 бита — тип величины; +- Modbus: младшие 4 бита — количество регистров, старшие 12 бит — начальный адрес; +- error: младший байт — код ошибки, старший байт — дополнительная информация. + +Для регистров `uint16_t` в CAN payload используется порядок байтов little-endian: сначала младший байт, затем старший. + +> Разметка ID реализована C-битовыми полями. Она соответствует используемому STM32 GCC ABI, но не является переносимой между произвольными компиляторами без проверки фактического расположения битов. + +## Подключение к STM32-проекту + +### 1. Добавить файлы + +Скопировать или подключить к сборке: + +- `Inc/protocan.h`; +- `Src/protocan.c`. + +Каталог `Inc` добавить в include paths компилятора. + +### 2. Настроить устройство + +В `Inc/protocan.h` задать значения конкретного узла: + +```c +#define CURRENT_TYPE_DEVICE 0b001 /* 3 бита: 0..7 */ +#define CURRENT_ID_DEVICE 0b0010 /* 4 бита: 0..15 */ +``` + +При необходимости изменить размер программного RX-буфера: + +```c +#define PROTOCAN_RX_BUFFER_SIZE 128 +``` + +Полезная ёмкость кольцевого буфера на один элемент меньше заданного размера, то есть при значении `128` в нём помещается 127 ожидающих кадров. + +### 3. Настроить CubeMX + +В проекте должны быть инициализированы: + +- CAN с поддержкой Extended ID; +- RTC; +- базовый таймер, задающий период отправки пульса. + +Модуль использует CAN FIFO0 и фильтры с номерами `0`, `1`, `2`. В `PROTOCAN_CONFIG_FILTER()` также жёстко задано `SlaveStartFilterBank = 14`. Если приложение уже использует фильтры, номера и границу банков нужно согласовать. + +### 4. Инициализировать и запустить периферию + +Пример для `main.c`: + +```c +#include "protocan.h" + +int main(void) +{ + HAL_Init(); + SystemClock_Config(); + + MX_GPIO_Init(); + MX_CAN_Init(); + MX_RTC_Init(); + MX_TIM2_Init(); + + PROTOCAN_INIT_StatusTypeDef init_status = + PROTOCAN_INIT(&hcan, &hrtc, &htim2); + + if (init_status != PROTOCAN_INIT_OK) { + Error_Handler(); + } + + /* PROTOCAN_INIT() этого не делает. */ + if (HAL_CAN_Start(&hcan) != HAL_OK) { + Error_Handler(); + } + if (HAL_CAN_ActivateNotification( + &hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) { + Error_Handler(); + } + if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) { + Error_Handler(); + } + + while (1) { + (void)PROTOCAN_ProcessAllRxMsgs(); + } +} +``` + +`PROTOCAN_INIT()` требует ненулевые указатели на CAN, RTC и TIM, настраивает CAN-фильтры и включает отправку пульса. Функцию следует вызвать после `MX_CAN_Init()`, `MX_RTC_Init()` и `MX_TIMx_Init()`, но до запуска CAN. + +### 5. Подключить callback’и HAL + +Если в HAL включены `USE_HAL_CAN_REGISTER_CALLBACKS == 1` и `USE_HAL_TIM_REGISTER_CALLBACKS == 1`, `PROTOCAN_INIT()` зарегистрирует callback’и автоматически. + +Если регистрация callback’ов отключена, добавить перенаправление из стандартных HAL-callback’ов: + +```c +void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan_ptr) +{ + if (hcan_ptr == &hcan) { + ProtoCanRxFifo0MsgPendingCallback(hcan_ptr); + } +} + +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim_ptr) +{ + if (htim_ptr == &htim2) { + ProtoCanPulseCallback(htim_ptr); + } +} +``` + +Не следует одновременно регистрировать callback через HAL и вручную вызывать его из стандартного callback — иначе один кадр или событие таймера может быть обработано дважды. + +## Приём сообщений + +В прерывании `ProtoCanRxFifo0MsgPendingCallback()` модуль вычитывает все кадры из FIFO0: + +- стандартные CAN ID игнорируются; +- `PULSE` не занимает место в RX-буфере, а сразу обновляет внутреннюю таблицу присутствующих устройств; +- остальные Extended-кадры помещаются в кольцевой буфер; +- при переполнении новые кадры молча отбрасываются. + +Обработку прикладной логики следует выполнять вне прерывания одним из трёх способов: + +```c +PROTOCAN_ProcessSingleRxMsg(); /* обработать не более одного кадра */ +PROTOCAN_ProcessAllRxMsgs(); /* обработать все накопленные кадры */ +PROTOCAN_LoopProcessRxMsgs(); /* бесконечный блокирующий цикл */ +``` + +Для обычного `while (1)` удобнее `PROTOCAN_ProcessAllRxMsgs()`. Она возвращает `PROTOCAN_TIMEOUT`, если очередь была пуста, `PROTOCAN_OK` после успешной обработки или код первой ошибки. + +## Свои обработчики входящих команд + +Большинство обработчиков объявлены как `__weak`. Приложение может определить функцию с тем же именем и заменить демонстрационную реализацию своей логикой. + +Пример обработки запроса температуры: + +```c +PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg msg) +{ + msgBodyAnalogType body = {0}; + body.Body = msg.eID.Fields.MsgBody; + + uint16_t sensor_id = body.Fields.SensorID; + /* Прочитать датчик sensor_id и сформировать нужный ответ. */ + + return PROTOCAN_OK; +} +``` + +Доступные точки переопределения находятся в `protocan.h`: + +- `ProtoCanMsgToBroadcast...()` — статус, включение/выключение, restart, RTC; +- `ProtoCanMsgToDiscrete...()` — аварии, предупреждения, флаги и команды; +- `ProtoCanMsgToAnalog...()` — универсальные данные, настройки, U/I/T; +- `ProtoCanMsgToGeneralAddressSpace()`; +- `ProtoCanMsgToModbus...()`; +- `PROTOCAN_RequestError()`. + +Стандартные слабые обработчики в основном являются демонстрационными: часть возвращает `PROTOCAN_OK` без действий, часть отправляет текстовые ответы вроде `TS0001` или `GAS-0001`. Для рабочего изделия их обычно нужно переопределить. + +## Отправка + +Публичная точка отправки — `PROTOCAN_SEND(id, data)`. Сначала заполняется общий Extended ID, затем соответствующая часть `ProtoCanData_t`. + +Пример отправки диапазона 16-битных регистров общего адресного пространства: + +```c +uint16_t registers[] = { 0x1234, 0x5678, 0x9ABC }; + +ProtoCanId_t id = {0}; +id.Fields.Priority = PROTOCAN_PRIORITY_STANDARD; +id.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; +id.Fields.DeviceType = CURRENT_TYPE_DEVICE; +id.Fields.DeviceID = CURRENT_ID_DEVICE; +id.Fields.MsgType = PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE; + +ProtoCanData_t tx = {0}; +tx.GeneralAddressSpaceData.RegStartAdr = 100; +tx.GeneralAddressSpaceData.Data = registers; +tx.GeneralAddressSpaceData.RegCount = 3; + +if (PROTOCAN_SEND(id, tx) != PROTOCAN_OK) { + /* Очередь CAN занята или произошла ошибка HAL. */ +} +``` + +Массив автоматически разбивается на кадры максимум по четыре регистра (8 байт) с увеличением адреса в `MsgBody`. + +Пример сообщения об ошибке без payload: + +```c +ProtoCanId_t id = {0}; +id.Fields.Priority = PROTOCAN_PRIORITY_CRITICAL; +id.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; +id.Fields.DeviceType = CURRENT_TYPE_DEVICE; +id.Fields.DeviceID = CURRENT_ID_DEVICE; +id.Fields.MsgType = PROTOCAN_MSGTYPE_ERROR; + +ProtoCanData_t tx = {0}; +tx.ErrorData.Code = 0x12; +tx.ErrorData.Info = 0x34; + +(void)PROTOCAN_SEND(id, tx); +``` + +Для `BROADCAST`, `DISCRETE` и `ANALOG` используется `tx.CoreData`; для Modbus-типов — `tx.ModbusData`. Если количество передаваемых элементов больше нуля, соответствующий указатель `Data` должен быть валиден до завершения вызова. + +## Пульс устройства + +Каждое прерывание переданного в `PROTOCAN_INIT()` таймера вызывает `ProtoCanPulseCallback()` и отправляет кадр: + +- `MsgType = PROTOCAN_MSGTYPE_PULSE`; +- `DLC = 1`; +- `Data[0]` — циклический счётчик `0..255`. + +Период пульса полностью определяется настройками таймера. Broadcast-команда `PROTOCAN_BROADCAST_ONOFF` в стандартной реализации переключает его отправку. + +Полученный пульс помечает удалённое устройство как активное и обнуляет `TimeFromLastPulse`. Увеличение этого времени и перевод устройства в offline в текущем модуле не реализованы — если это требуется, контроль таймаута нужно добавить в приложение. + +## Синхронизация RTC + +Broadcast-команда `PROTOCAN_BROADCAST_RTCSETUP` ожидает ровно 7 байт: + +| Индекс | Значение | +|---:|---| +| 0 | часы, `0..23` | +| 1 | минуты, `0..59` | +| 2 | секунды, `0..59` | +| 3 | год как смещение от 2000, `0..99` | +| 4 | месяц, `1..12` | +| 5 | число месяца | +| 6 | день недели в формате, ожидаемом данной прошивкой | + +Перед записью проверяются диапазоны и количество дней с учётом високосного года. + +## Важные ограничения текущей реализации + +- Модуль рассчитан на classic CAN с payload до 8 байт, не на CAN FD. +- `PROTOCAN_INIT()` не запускает CAN/таймер и не включает CAN notification. +- Все три аппаратных фильтра и номера банков заданы внутри библиотеки. +- Адресованные сообщения фильтруются с установленным битом `Route` (бит 27). Это стоит сверить с принятой в системе трактовкой `PROTOCAN_ROUTE_FROM_PM`/`PROTOCAN_ROUTE_FROM_DEVICE`. +- Таблица присутствующих устройств обновляется при пульсе, но автоматического offline-таймаута нет. +- Буфер переполнения не ведёт счётчик потерь и не сообщает ошибку приложению. +- В репозитории нет тестов, примера полного STM32-проекта и системы сборки. +- Несколько внутренних функций отправки реализованы только в `protocan.c` и не входят в публичный заголовок; для прикладного кода следует использовать `PROTOCAN_SEND()`. + +## Краткий порядок запуска + +1. Добавить `protocan.c/.h` в STM32-проект. +2. Задать `CURRENT_TYPE_DEVICE` и `CURRENT_ID_DEVICE`. +3. Настроить CAN, RTC и периодический TIM в CubeMX. +4. Вызвать `PROTOCAN_INIT()` после `MX_..._Init()`. +5. Запустить CAN, активировать `CAN_IT_RX_FIFO0_MSG_PENDING` и запустить таймер с прерыванием. +6. При необходимости подключить HAL-callback’и вручную. +7. Переопределить нужные `__weak`-обработчики. +8. Вызывать `PROTOCAN_ProcessAllRxMsgs()` в основном цикле. + From bb7c94f1b77b926b7663c181d0b4b367675fb585 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 26 Aug 2026 20:13:06 +0300 Subject: [PATCH 03/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D1=8B=20SETTINGS?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=B8=D0=B2=D1=8F=D0=B7?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B4=D0=B0=D1=82=D1=87=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Inc/protocan.h | 71 +++++++++++++++++++++- README.md | 78 +++++++++++++++++++++--- Src/protocan.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 295 insertions(+), 16 deletions(-) diff --git a/Inc/protocan.h b/Inc/protocan.h index 99fa270..e7b4a1e 100644 --- a/Inc/protocan.h +++ b/Inc/protocan.h @@ -9,8 +9,8 @@ #define OFFLINE 0; #define ID_MAIN_DEVICE 0x000 -#define CURRENT_TYPE_DEVICE 0b001 -#define CURRENT_ID_DEVICE 0b0010 +#define CURRENT_TYPE_DEVICE 0b111 +#define CURRENT_ID_DEVICE 0b1111 #define PROTOCAN_RX_BUFFER_SIZE 128 @@ -79,9 +79,49 @@ typedef enum { PROTOCAN_MSGTYPE_MODBUS_HOLDING = 0b0110, /**< Сообщение Modbus - Holding. */ PROTOCAN_MSGTYPE_MODBUS_INPUT = 0b0111, /**< Сообщение Modbus - Input. */ PROTOCAN_MSGTYPE_ERROR = 0b1000, /**< Сообщение об ошибке. */ + PROTOCAN_MSGTYPE_SETTINGS = 0b1110, /**< Привязка датчика к локации. */ PROTOCAN_MSGTYPE_PULSE = 0b1111, /**< Импульсное сообщение. */ }ProtoCanMsgType; +/** Длина ROM-кода 1-Wire и payload успешного ответа SETTINGS. */ +#define PROTOCAN_SETTINGS_ROM_SIZE 8U + +/** Фиксированные базы выбранного DeviceType=0x7, DeviceID=0xF, MsgType=0xE. */ +#define PROTOCAN_SETTINGS_REQUEST_BASE_ID 0x17FE0000UL +#define PROTOCAN_SETTINGS_RESPONSE_BASE_ID 0x1FFE0000UL +#define PROTOCAN_SETTINGS_HEADER_MASK 0x1FFF0000UL + +/** Операции SETTINGS, определяемые по направлению, DLC и payload. */ +typedef enum { + PROTOCAN_SETTINGS_GET = 0, + PROTOCAN_SETTINGS_WRITE = 1, + PROTOCAN_SETTINGS_CLEAR = 2, + PROTOCAN_SETTINGS_RESPONSE = 3, + PROTOCAN_SETTINGS_ERROR = 4, + PROTOCAN_SETTINGS_INVALID = 5 +} ProtoCanSettingsOperationType; + +/** Коды результата SETTINGS в ответе с DLC=1. */ +typedef enum { + PROTOCAN_SETTINGS_RESULT_OK = 0x00U, + PROTOCAN_SETTINGS_RESULT_INVALID_DLC = 0x01U, + PROTOCAN_SETTINGS_RESULT_INVALID_ROM_CRC = 0x02U, + PROTOCAN_SETTINGS_RESULT_NOT_FOUND = 0x03U, + PROTOCAN_SETTINGS_RESULT_ALREADY_ASSIGNED = 0x04U, + PROTOCAN_SETTINGS_RESULT_EEPROM_ERROR = 0x05U, + PROTOCAN_SETTINGS_RESULT_INVALID_LOCATION = 0x06U, + PROTOCAN_SETTINGS_RESULT_BUSY = 0x07U +} ProtoCanSettingsResultType; + +/** Разобранная команда SETTINGS с локацией и ROM. */ +typedef struct { + ProtoCanSettingsOperationType Operation; + uint8_t AssemblySerial; /**< Body[15:8], номер сборки Z. */ + uint8_t Position; /**< Body[7:0], позиция Y. */ + ProtoCanSettingsResultType Result; + uint8_t Rom[PROTOCAN_SETTINGS_ROM_SIZE]; +} ProtoCanSettingsMsg_t; + /** * @brief Типы широковещательных сообщений CAN. * @@ -238,6 +278,10 @@ typedef struct{ uint16_t Info; uint16_t Code; } ErrorData; + struct ProtoCanSettingsData{ + const uint8_t *Data; + uint8_t DataCount; + } SettingsData; } ProtoCanData_t; /** @@ -305,6 +349,29 @@ PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogUSens(struct RXMsg _rxMsg); PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogISens(struct RXMsg _rxMsg); PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg _rxMsg); +/** Разбирает запрос SETTINGS и вызывает прикладной обработчик. */ +PROTOCAN_StatusTypeDef PROTOCAN_SettingsProcessing(struct RXMsg _rxMsg); + +/** + * Прикладной обработчик GET/WRITE/CLEAR. Приложение должно переопределить + * слабую реализацию и после проверки датчика/EEPROM отправить ответ или ошибку. + */ +PROTOCAN_StatusTypeDef ProtoCanMsgToSettings(const ProtoCanSettingsMsg_t *message); + +/** Отправляет произвольный SETTINGS-кадр с уже заполненным Body. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_SETTINGS(ProtoCanId_t id, + const struct ProtoCanSettingsData data); + +/** Отправляет успешный ответ 0x1FFEZZYY, DLC=8, с текущим ROM локации. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_SETTINGS_RESPONSE(uint8_t assemblySerial, + uint8_t position, + const uint8_t *rom); + +/** Отправляет ошибку 0x1FFEZZYY, DLC=1, Data[0]=result. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_SETTINGS_ERROR(uint8_t assemblySerial, + uint8_t position, + ProtoCanSettingsResultType result); + PROTOCAN_StatusTypeDef ProtoCanMsgToGeneralAddressSpace(struct RXMsg _rxMsg); PROTOCAN_StatusTypeDef PROTOCAN_RequestError(struct RXMsg _rxMsg); diff --git a/README.md b/README.md index d17c1d0..96b179e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SETCAN -`SETCAN` — небольшой модуль прикладного протокола поверх классического CAN для микроконтроллеров STM32 и библиотеки STM32 HAL. Модуль принимает только кадры с расширенным 29-битным идентификатором, складывает их в кольцевой буфер и передаёт обработчикам по типу сообщения. Также он умеет отправлять широковещательные, дискретные, аналоговые, адресные, Modbus-подобные сообщения, ошибки и периодический «пульс» устройства. +`SETCAN` — небольшой модуль прикладного протокола поверх классического CAN для микроконтроллеров STM32 и библиотеки STM32 HAL. Модуль принимает только кадры с расширенным 29-битным идентификатором, складывает их в кольцевой буфер и передаёт обработчикам по типу сообщения. Также он умеет отправлять широковещательные, дискретные, аналоговые, адресные, Modbus-подобные сообщения, команды привязки датчиков `SETTINGS`, ошибки и периодический «пульс» устройства. Это не самостоятельный проект STM32CubeIDE: здесь нет `.ioc`, startup-файлов, linker script или настроек тактирования. Каталоги `Inc` и `Src` нужно добавить в существующую прошивку STM32. @@ -42,6 +42,7 @@ SETCAN/ | `0x6` | Modbus Holding | | `0x7` | Modbus Input | | `0x8` | ошибка | +| `0xE` | настройка привязки датчика (`SETTINGS`) | | `0xF` | пульс присутствия устройства | Разметка `MsgBody` зависит от типа сообщения: @@ -50,6 +51,7 @@ SETCAN/ - discrete: младшие 12 бит — данные/адрес, старшие 4 бита — подтип; - analog: младшие 12 бит — ID датчика, старшие 4 бита — тип величины; - Modbus: младшие 4 бита — количество регистров, старшие 12 бит — начальный адрес; +- SETTINGS: старший байт — номер сборки `Z`, младший байт — позиция `Y`; - error: младший байт — код ошибки, старший байт — дополнительная информация. Для регистров `uint16_t` в CAN payload используется порядок байтов little-endian: сначала младший байт, затем старший. @@ -69,11 +71,11 @@ SETCAN/ ### 2. Настроить устройство -В `Inc/protocan.h` задать значения конкретного узла: +В `Inc/protocan.h` для прибора привязки DS18B20 заданы выбранные значения: ```c -#define CURRENT_TYPE_DEVICE 0b001 /* 3 бита: 0..7 */ -#define CURRENT_ID_DEVICE 0b0010 /* 4 бита: 0..15 */ +#define CURRENT_TYPE_DEVICE 0b111 /* DeviceType = 0x7 */ +#define CURRENT_ID_DEVICE 0b1111 /* DeviceID = 0xF */ ``` При необходимости изменить размер программного RX-буфера: @@ -92,7 +94,7 @@ SETCAN/ - RTC; - базовый таймер, задающий период отправки пульса. -Модуль использует CAN FIFO0 и фильтры с номерами `0`, `1`, `2`. В `PROTOCAN_CONFIG_FILTER()` также жёстко задано `SlaveStartFilterBank = 14`. Если приложение уже использует фильтры, номера и границу банков нужно согласовать. +Модуль использует CAN FIFO0 и фильтры с номерами `0`, `1`, `2`. Адресованный фильтр принимает Route=0 (запрос от ПМ) для текущих `DeviceType/DeviceID`; отдельные фильтры принимают broadcast и pulse. В `PROTOCAN_CONFIG_FILTER()` также жёстко задано `SlaveStartFilterBank = 14`. Если приложение уже использует фильтры, номера и границу банков нужно согласовать. ### 4. Инициализировать и запустить периферию @@ -205,12 +207,72 @@ PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg msg) - `ProtoCanMsgToBroadcast...()` — статус, включение/выключение, restart, RTC; - `ProtoCanMsgToDiscrete...()` — аварии, предупреждения, флаги и команды; - `ProtoCanMsgToAnalog...()` — универсальные данные, настройки, U/I/T; +- `ProtoCanMsgToSettings()` — GET/WRITE/CLEAR привязки ROM к локации; - `ProtoCanMsgToGeneralAddressSpace()`; - `ProtoCanMsgToModbus...()`; - `PROTOCAN_RequestError()`. Стандартные слабые обработчики в основном являются демонстрационными: часть возвращает `PROTOCAN_OK` без действий, часть отправляет текстовые ответы вроде `TS0001` или `GAS-0001`. Для рабочего изделия их обычно нужно переопределить. +## SETTINGS: привязка DS18B20 к локации + +Для прибора `DeviceType=0x7`, `DeviceID=0xF` используется `MsgType=0xE`: + +```text +Body = (Z << 8) | Y + +запрос от ПМ = 0x17FEZZYY +ответ прибора = 0x1FFEZZYY +``` + +| Запрос | Операция | +|---|---| +| `DLC=0` | `GET`: прочитать ROM локации | +| `DLC=8`, ROM не нулевой | `WRITE/REPLACE`: записать или заменить датчик | +| `DLC=8`, восемь нулей | `CLEAR`: очистить локацию | +| другой DLC или RTR | автоматический ответ `INVALID_DLC` | + +Успешный ответ имеет DLC=8 и содержит текущее состояние локации: ROM после +GET/WRITE либо восемь нулей после CLEAR. Ошибка сохраняет тот же Body, имеет +DLC=1 и передаёт `ProtoCanSettingsResultType` в `Data[0]`. + +`PROTOCAN_SettingsProcessing()` выполняет транспортный разбор и вызывает +слабую функцию `ProtoCanMsgToSettings()`. Приложение переопределяет её и +выполняет проверку family code/CRC8, поиск ROM на 1-Wire и запись EEPROM: + +```c +PROTOCAN_StatusTypeDef ProtoCanMsgToSettings( + const ProtoCanSettingsMsg_t *message) +{ + uint8_t current_rom[PROTOCAN_SETTINGS_ROM_SIZE] = {0}; + + switch (message->Operation) { + case PROTOCAN_SETTINGS_GET: + /* Загрузить ROM локации в current_rom; свободная локация = нули. */ + return PROTOCAN_SEND_SETTINGS_RESPONSE( + message->AssemblySerial, message->Position, current_rom); + + case PROTOCAN_SETTINGS_WRITE: + /* Проверить ROM и атомарно записать его в каталог/EEPROM. */ + return PROTOCAN_SEND_SETTINGS_RESPONSE( + message->AssemblySerial, message->Position, message->Rom); + + case PROTOCAN_SETTINGS_CLEAR: + /* Удалить локацию из каталога/EEPROM. */ + return PROTOCAN_SEND_SETTINGS_RESPONSE( + message->AssemblySerial, message->Position, current_rom); + + default: + return PROTOCAN_SEND_SETTINGS_ERROR( + message->AssemblySerial, message->Position, + PROTOCAN_SETTINGS_RESULT_INVALID_DLC); + } +} +``` + +Слабая реализация специально не подтверждает операцию: без прикладного +каталога библиотека не должна сообщать, что ROM был сохранён. + ## Отправка Публичная точка отправки — `PROTOCAN_SEND(id, data)`. Сначала заполняется общий Extended ID, затем соответствующая часть `ProtoCanData_t`. @@ -256,7 +318,7 @@ tx.ErrorData.Info = 0x34; (void)PROTOCAN_SEND(id, tx); ``` -Для `BROADCAST`, `DISCRETE` и `ANALOG` используется `tx.CoreData`; для Modbus-типов — `tx.ModbusData`. Если количество передаваемых элементов больше нуля, соответствующий указатель `Data` должен быть валиден до завершения вызова. +Для `BROADCAST`, `DISCRETE` и `ANALOG` используется `tx.CoreData`; для Modbus-типов — `tx.ModbusData`, для `SETTINGS` — `tx.SettingsData`. Для успешных ответов и ошибок SETTINGS удобнее использовать готовые функции `PROTOCAN_SEND_SETTINGS_RESPONSE()` и `PROTOCAN_SEND_SETTINGS_ERROR()`. Если количество передаваемых элементов больше нуля, соответствующий указатель `Data` должен быть валиден до завершения вызова. ## Пульс устройства @@ -291,7 +353,8 @@ Broadcast-команда `PROTOCAN_BROADCAST_RTCSETUP` ожидает ровно - Модуль рассчитан на classic CAN с payload до 8 байт, не на CAN FD. - `PROTOCAN_INIT()` не запускает CAN/таймер и не включает CAN notification. - Все три аппаратных фильтра и номера банков заданы внутри библиотеки. -- Адресованные сообщения фильтруются с установленным битом `Route` (бит 27). Это стоит сверить с принятой в системе трактовкой `PROTOCAN_ROUTE_FROM_PM`/`PROTOCAN_ROUTE_FROM_DEVICE`. +- Фильтр адресованных сообщений рассчитан на устройство: он принимает Route=0 от ПМ. Для использования библиотеки на стороне ПМ потребуется отдельная конфигурация фильтров Route=1. +- Проверку ROM, физического датчика и EEPROM выполняет приложение в переопределённом `ProtoCanMsgToSettings()`. - Таблица присутствующих устройств обновляется при пульсе, но автоматического offline-таймаута нет. - Буфер переполнения не ведёт счётчик потерь и не сообщает ошибку приложению. - В репозитории нет тестов, примера полного STM32-проекта и системы сборки. @@ -307,4 +370,3 @@ Broadcast-команда `PROTOCAN_BROADCAST_RTCSETUP` ожидает ровно 6. При необходимости подключить HAL-callback’и вручную. 7. Переопределить нужные `__weak`-обработчики. 8. Вызывать `PROTOCAN_ProcessAllRxMsgs()` в основном цикле. - diff --git a/Src/protocan.c b/Src/protocan.c index 16f6033..731444c 100644 --- a/Src/protocan.c +++ b/Src/protocan.c @@ -164,6 +164,10 @@ void PROTOCAN_LoopProcessRxMsgs(void) { ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_SETTINGS) + { + PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); + } else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || @@ -216,6 +220,10 @@ PROTOCAN_StatusTypeDef PROTOCAN_ProcessAllRxMsgs(void) { result = ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_SETTINGS) + { + result = PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); + } else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || @@ -269,6 +277,10 @@ PROTOCAN_StatusTypeDef PROTOCAN_ProcessSingleRxMsg(void) { result = ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_SETTINGS) + { + result = PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); + } else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || @@ -868,7 +880,140 @@ PROTOCAN_StatusTypeDef PROTOCAN_SEND_CORE(const ProtoCanId_t id, const struct Pr return PROTOCAN_ERROR; } } - return PROTOCAN_OK; + return PROTOCAN_OK; +} + +/** + * @brief Разбирает однокадровый запрос SETTINGS для текущего устройства. + * + * Body[15:8] содержит номер сборки, Body[7:0] — позицию. DLC=0 означает + * GET, DLC=8 с ненулевым ROM — WRITE/REPLACE, DLC=8 с нулями — CLEAR. + * Проверка физического датчика и сохранение EEPROM выполняются приложением в + * переопределённой функции ProtoCanMsgToSettings(). + */ +PROTOCAN_StatusTypeDef PROTOCAN_SettingsProcessing(struct RXMsg _rxMsg) +{ + ProtoCanSettingsMsg_t message; + uint8_t index; + uint8_t romIsZero = 1U; + + if((_rxMsg.eID.BitAll & PROTOCAN_SETTINGS_HEADER_MASK) + != PROTOCAN_SETTINGS_REQUEST_BASE_ID) + { + return PROTOCAN_ERROR; + } + + message.AssemblySerial = (uint8_t)((_rxMsg.eID.Fields.MsgBody >> 8U) & 0xFFU); + message.Position = (uint8_t)(_rxMsg.eID.Fields.MsgBody & 0xFFU); + message.Result = PROTOCAN_SETTINGS_RESULT_OK; + for(index = 0U; index < PROTOCAN_SETTINGS_ROM_SIZE; index++) + { + message.Rom[index] = 0U; + } + + if((_rxMsg.info.RTR != 0U) + || ((_rxMsg.DLC != 0U) && (_rxMsg.DLC != PROTOCAN_SETTINGS_ROM_SIZE))) + { + message.Operation = PROTOCAN_SETTINGS_INVALID; + message.Result = PROTOCAN_SETTINGS_RESULT_INVALID_DLC; + return PROTOCAN_SEND_SETTINGS_ERROR(message.AssemblySerial, message.Position, + message.Result); + } + if(_rxMsg.DLC == 0U) + { + message.Operation = PROTOCAN_SETTINGS_GET; + return ProtoCanMsgToSettings(&message); + } + + for(index = 0U; index < PROTOCAN_SETTINGS_ROM_SIZE; index++) + { + message.Rom[index] = _rxMsg.Data[index]; + if(message.Rom[index] != 0U) + { + romIsZero = 0U; + } + } + message.Operation = (romIsZero != 0U) ? PROTOCAN_SETTINGS_CLEAR + : PROTOCAN_SETTINGS_WRITE; + return ProtoCanMsgToSettings(&message); +} + +/** + * @brief Слабая точка подключения каталога датчиков приложения. + */ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToSettings( + const ProtoCanSettingsMsg_t *message) +{ + (void)message; + return PROTOCAN_ERROR; +} + +/** Отправляет один SETTINGS-кадр с Body из id и payload длиной 0..8. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_SETTINGS( + ProtoCanId_t id, const struct ProtoCanSettingsData data) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0U; + uint8_t canData[PROTOCAN_SETTINGS_ROM_SIZE] = {0U}; + uint8_t index; + + if((id.Fields.MsgType != PROTOCAN_MSGTYPE_SETTINGS) + || (data.DataCount > PROTOCAN_SETTINGS_ROM_SIZE) + || ((data.DataCount != 0U) && (data.Data == 0))) + { + return PROTOCAN_ERROR; + } + for(index = 0U; index < data.DataCount; index++) + { + canData[index] = data.Data[index]; + } + TxHeader.ExtId = id.BitAll; + TxHeader.IDE = CAN_ID_EXT; + TxHeader.RTR = CAN_RTR_DATA; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.DLC = data.DataCount; + if(HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK) + { + return PROTOCAN_ERROR; + } + return PROTOCAN_OK; +} + +/** Отправляет успешный ответ SETTINGS с текущим ROM целевой локации. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_SETTINGS_RESPONSE(uint8_t assemblySerial, + uint8_t position, const uint8_t *rom) +{ + ProtoCanId_t id; + ProtoCanData_t data; + + if(rom == 0) + { + return PROTOCAN_ERROR; + } + id.BitAll = PROTOCAN_SETTINGS_RESPONSE_BASE_ID + | ((uint32_t)assemblySerial << 8U) | position; + data.SettingsData.Data = rom; + data.SettingsData.DataCount = PROTOCAN_SETTINGS_ROM_SIZE; + return PROTOCAN_SEND_SETTINGS(id, data.SettingsData); +} + +/** Отправляет однобайтовую ошибку SETTINGS с сохранением Body запроса. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_SETTINGS_ERROR(uint8_t assemblySerial, + uint8_t position, ProtoCanSettingsResultType result) +{ + ProtoCanId_t id; + ProtoCanData_t data; + const uint8_t error = (uint8_t)result; + + if(result == PROTOCAN_SETTINGS_RESULT_OK) + { + return PROTOCAN_ERROR; + } + id.BitAll = PROTOCAN_SETTINGS_RESPONSE_BASE_ID + | ((uint32_t)assemblySerial << 8U) | position; + data.SettingsData.Data = &error; + data.SettingsData.DataCount = 1U; + return PROTOCAN_SEND_SETTINGS(id, data.SettingsData); } /** @@ -1291,8 +1436,8 @@ void TakeRxMsgToBuffer(ProtoCanId_t tmp_eID, uint32_t tmp_IDE, uint32_t tmp_RTR, tmp_DLC = 8u; } rxMsg[tmp_LastStep].eID.BitAll = tmp_eID.BitAll; - rxMsg[tmp_LastStep].info.EXT = tmp_IDE; - rxMsg[tmp_LastStep].info.RTR = tmp_RTR; + rxMsg[tmp_LastStep].info.EXT = (tmp_IDE == CAN_ID_EXT) ? 1U : 0U; + rxMsg[tmp_LastStep].info.RTR = (tmp_RTR == CAN_RTR_REMOTE) ? 1U : 0U; rxMsg[tmp_LastStep].DLC = tmp_DLC; for(uint32_t i = 0; i < tmp_DLC; i++) { @@ -1445,7 +1590,8 @@ void PROTOCAN_FILTERS() #define BITS_20_23_MASK (0xFUL << 20) // 4 бита (20..23) #define BITS_24_26_MASK (0x7UL << 24) // 3 бита (24..26) - uint32_t filter1_id = BIT27 | (CURRENT_TYPE_DEVICE << 24) | (CURRENT_ID_DEVICE << 20); + /* Адресованный запрос приходит от ПМ, поэтому Route (бит 27) равен нулю. */ + uint32_t filter1_id = (CURRENT_TYPE_DEVICE << 24) | (CURRENT_ID_DEVICE << 20); uint32_t filter1_mask = BIT27 | BITS_24_26_MASK | BITS_20_23_MASK; // все проверяемые биты #define BITS_16_19_MASK (0xFUL << 16) @@ -1456,7 +1602,7 @@ void PROTOCAN_FILTERS() uint32_t filter3_id = PROTOCAN_MSGTYPE_PULSE << 16; uint32_t filter3_mask = BITS_16_19_MASK; - // Первый фильтр: проверяем 20-27 биты, где 27-й всегда 1 + // Первый фильтр: Route=0 (от ПМ), DeviceType и DeviceID текущего устройства. PROTOCAN_CONFIG_FILTER(0, filter1_id, filter1_mask); // Второй фильтр: проверяем 16-19 биты, равны PROTOCAN_MSGTYPE_BROADCASTE @@ -1510,8 +1656,12 @@ PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data) return PROTOCAN_SEND_ERROR(id, data.ErrorData); break; } + case PROTOCAN_MSGTYPE_SETTINGS: + { + return PROTOCAN_SEND_SETTINGS(id, data.SettingsData); + } default: return PROTOCAN_ERROR; } return PROTOCAN_ERROR; -} \ No newline at end of file +} From aea2a79d2ce155661c9ecbcc413a91e39a986fad Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 26 Aug 2026 20:55:54 +0300 Subject: [PATCH 04/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=82=D0=BE=D0=BA=D0=BE=D0=BB=D0=B0=20CAN=20?= =?UTF-8?q?=D0=B8=20=D0=9E=D0=90=D0=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Протокол CAN и ОАП.xlsx | Bin 0 -> 83058 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Протокол CAN и ОАП.xlsx diff --git a/Протокол CAN и ОАП.xlsx b/Протокол CAN и ОАП.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..68a666daf6e1b3d0478766d09964564853fa625d GIT binary patch literal 83058 zcmeFZ1yo(#k}gVccXtvXKyV1|5Zv80xCM6$8r)riySuvtcbDJ}!5!`<{~wZb`gFe@ z{lH2_nQ1O=t|43+I`S`)Uk7IV+R9{70Z_L{ldK8FE_U4T{P-g6Kir8;zL-{LA57y4U7O=OcZ4=_ z@RgvwO@C`80iRMg1?~Fy`ZDaia5z(RGa>3n=-YIvd0r)D{aOjcY@E(c59@*meomGO?knMUoXhY!%lG&Kp3(S@JgDiAlZt$h!jW(RkG5hRI%9sTG zrN$*o;zP{-wA$b#bF#L8JV`4?mkLK*F808-yh$XC z;44;s1a&`9rnN!0t5~|wT4ZfHKS>t8nOBuFCC{tvh-=U$4o!=Jk07vzRB~5OIh$y` z_MiH+k%nmzP;pK49)wrx%PniU#45zp>H$SS3m`WTkjVWdEEcbTfb0SJ`uB5%^H+EH zXszR5Y+-0aV{dLI@Yg*ZHQ@d*)?8|V7O|JRy~SI98QAH2zJSDNS68F?xc0o*2HQ-} z_v_aSaJyU&!y>9=0bgR8vm$X89ImdG9@Yvbf=Z@~!1hrSli&K&8EO;9_ETCvo^9=E zcO;y3MDt~OC6~6H1g%Xl`i#+1n_6o+t$dW(_y|`0$$!?9XaU!pii7I#wFxB)t)?Se z&a@16Z>|hg^lGMX(pmQVxx7!(?~KP*7YT%mDr=@qx$lz*hPOpKu4e@Tn0+936&Bvs z!tXC5f~ELK7{KY@_{D=0v@zucZ+D|ID18C1QeGXej0JTYPM7zVh^aPGCg)HH|3PIV zFP>TaU3VT{tkuLbpMJYmLp)6_t%uwYc`R1)fz;F38oT%If!Q!?ES&TP^hd}Kh2ecS z&iKRc1^z-1P262-O%V1%Xe_Pc#LDjwm_AM#@OmTRhRQOX;xzW8 z?=W6}YZ*D}yUB5Q^y6Zz9%#{pX^k$W<~0>EcPgLIp8>U8*qoD$b7QLDQzP!Zqhw9D z5_pqChc&|(%Kv=_<8>^4X&zN~%qYC`g0p`S_m6bp@iH8PblAy(dDL$*vp5(JwsOmF z#+9s6-M`;6C!YjZ(y!s3hY7Wq8@aLh5)V(LjBkHO8?B)5V>}X1zOmL&kx>TH7Dkw=FQ&g zV(|Mf*1S^l$AkG`pj#bjBpkedurD+xId3s54N^fCdAu7@rNrD^nc zS`@MpbK1Lfd+&`J5nUSd0U?`%Cz^SxQQ`B+X}OWu9Afo{*bhsdawouQKX4axKLuW6 z+N_kD9WOo2qQ$&{A>n8jU$dPC*CF=Ajp{eNPqW^^q6N8^UC$mMhLf zvjT&;p-5IJJV2{cwOfyXr-GD=J8c=csn7i|tQ>;5XXJhYgmI>yI^tK0IygrEb~~%R zHZW1PApx&bN4$D{+8dWT-7}03zwWaz#DLE*qEA-dJLFe3Cg=E!B;?t!W+LS<1x)v^ zV6jiiqxIlu1kxxR^SP)`2lmfj!86;DCWe&z!GF-(!**0w(<>GXN{=>FbJwQsc08UN z04F|;rifl4$>FH>kqI(XW`fE)5fKl@DLj9}Y>aZj#gifsbRIX_T6l3E6)dx6Y+h#A zNMm7M@PHyE>$=48>2xXl9*q2bH4T>@1UKCKT5a=R#SKk1*_VGVl$1wk?H~!ruf9{}CMl~!tXkj6Kpd7#}EE}t0 zqVS_?j!M$PeO|uW z{IO+a3>nMk8Ex-gLG|!%i@PeU_r)VkxvvjhG;=GE+=4q*MHM;OzSG0*OjN;b5avX( z zqC|#M`uV1K4qin@LBIbpsB4k(sK?2Dy7*_Qq(t-dAH-dA{1os{+b&VByn zq?#>J`hpHeUbRLbcwPg2bu8EGOXU>bn5xO%nU!lU7Y|mxuGM;8W*~Hpy}3AI~&TPqdFaw;uO9YZvYa(yq|sIz8r^5u`?#uU0JFxfU(CjvpM(s;-V{p3Zhl z{d-r^+!xGJxufA0x!soU4sUK|Rv#ZHW>%OSn575^+|7>$B99Tm9GFKoxd}WDxF4Js z7hPRgcaFAO*jW0mjx8*XuQb(ITtCh`UOzru?r-g^?h`m9-EGeZ;xltwrVgxfKiJ>x z=Nlg$SsEQ3UGA@UPIO*vhiMTU?Zx&Zxh}2TKiHko6XL+_9KB=6XiVx|dAhzRt@x(3 zN%m-ScXoNxO0#Z~baQsLOb~YEZ-?__;xB_|qkQRcy}dM&bGjnZAA&G^bHaT< z>rv0C@n)a=`WRt~{$ZrE^LUCo&@$}`{&L>CqoFg-6Y$jaZSTZc=aP}l-FoddJ>Dgk z>w;_R&HA>@)9Uu#<-(aIi5!8=(&xih(>dhInag`Wz0NTAL%sSMrV zJR`0uaHTyuT4zy;P&chW>h5+DQoDQA%{A)^IRyDtDTK&Q@RD%NwN?#~7 z|7=>V869%*xUe&jz|4Ek-BUaFEShdwjh5lCnMDsGJJIO4GJ26TP4+`v`CQ)xd|TKo zm3s&^c^<6`Y^i9D%@)lK5elgW?vQ?+`3GVO|1Vb)dAPZcloY-7++qDzr-m|4EO&RC zXcf)k6npgfnhVe%dTeq14gE~8ZiGTS;5>djpv9p`6tMf+c`zQY zfn6!4XTRztL1E5`4Der=kvSJ_=7Ij{2FE`_)#$}Tl`pKZYg zcT&JI&Q&7AXMjCycyt(2_!U){DRQ>)HmPGIA2LuvRtlulzTa7y&VtjP@2gahgjWe5 z^+488A76ch`UtiG-G|-x9`P9I0`Yy}8|B&y-GK3o60|J2X58_w({veZ_r~E;U`$#x zo{X3?P&IaeMxTuWcVNd@GgMe6$uuh2G~P*_8q^q+3i&%IO*P|9*>%9mE-lDtyd4Ca zswcvova6|$;FYKm^H7f3@oKfXVDYmD0F($C=21!vQ_5OkGsOCh&Eal>I)1X)45LRL z+iIK54t$**f*yn(!ur()avyLXavyXbTDYBC4sXTuM;EYjeE2g?0XN9X(iy(!BD*t7 zHx^vo&N}3K$UBO%QmciTg@M5|?fu*U(twYC(!}<$f@8gHAb^M*MKwPv6Qj^wv5ZRBU>G(8~RL*X-NiQq4{+bOB?vcDnxurzE>5^7qZ z@g*uTYoVz~gaxO;W{Sc$;oK= zG0`4Bq8r{WncO~nido4$B2Ev>9nz(Ow$^%0>Gusnx$+A+0Tcl_fjUwSYG`g42m<|r zbo|Jn{WmN2B3C9A8sl!>#(C`d&L0Wk;Ih(*#u4YSUXjCQrF$_lhWmj}&>mu|@9g9D z!S>RKHrwjE}1KyNmAg=z7L_H z#*I0JmtE%VXBWR|I@@vFAl$^ux_?*htklmB$dj*kbg9}h>GijFP=jsc;UaF6_C%7V z$SKB#zA007pBov%vBFuyVF=@R(0O8c6nRQKi@el9PVi+AWSTL}9BJ$wRUAK97#6^n zU+4+EIVfv`?-lodJ9|r>0hK}iS{)pJ#w*R&JFKE|zOlosmBsVkOgjAQ`#^@Ocm7GD zyn#$)ePh^%Ei`&^Zv;L}$cN`j6w``3ZHqd}DnVDFgo{i_6Q(ALuJ%b>p;%~;%S#0q zNbGx&Ta4OI)BI=?6MzvA6L=?}6fhl7g5*R~mfDu6kMboi@x!;p!Gp`wJ%2uzUSJ$3 zH&i|Xz4S1Y^kz9P2~Z}qctlqkft8UAx?UAAi$qacQhS#3{3JO_3SHBXC%gKow7wKoy^@uTjVj zcElC%K2%Xy#JNP*R_d086%m`Y?zNEbb3_z%c16ncAJ<~pT zhsuR7gh!Ey^ZJs{9%w?k1=}s*$}i#EedX1GXEIMn5rH%hK}0iGQ)4PoiS~uAl-5CS zIC^8ILEg{DQ<-x?3zKB!s{$#c`C64w^|dNd17DS(ZAhPs*9GV_2fM_1o#93NOuY<-&?)>D3tW}U+MOsp#|5y z?Aes`tB=w-0%GH1I=g))1lpDz{J? z$?P5YiI*Fhi|ycHU`)ttF!v7Om9 z06ic!Krx^Mu^36?&8em~r&skDEV?YpFiXmwv!#1CHKRLaS;VLgkuA%zecir`eY*c& z@y;f+4TCWS4Zj|KZ?Pcu`A!oXbqo9J8vzi3PHYm9GNdYfos#B?AN!TqzAI@&iHs27 zD_^S*g<5@gjvTp7Lt*8RM~lqO2DYeztXmp=AAr>w{{_XrIG=w|dwt-XKgX_B4aJEI zAlJDnWOHb~rj!r9~4qfCcjpogY?$VD#9AU+^M55>S5&BAJ(Bp z(~JaM#nT{iH%HOlJ=924h*U_$h#EwyZyE$Qn%kU#O*61Ou2C+(R-NfAi?AN7D{H?= zU*X%S)qu5d=+Qy=n;JTEjyg-%Dz@k+G)oBa!E$wPvUz!Xi2f#Hv=tQ$eTjii&wH}I zI_z$&nFq-u@%H5y8-dE48^ZNOujVML*;$edundw6w2XHGrUEkoO&H2j+7gVJ!Ezmf z5%yfm-&oSa^t?iR++osJ?CB1MS$?r1zRawt%;KJsEr?|unPUADvxs*`Fo>;>k*ASz zCd)cDx&iJHu(5Q!RR?uAsJl_tCmhHO0PgWtLt-L;Sr@TB|BGTDVp;b|Av$zzinHo4 zKzcFT6lK+Mg!EUh{lhFO2`}0aKEQ^xXDA{ZBAh8|u6k!jbSD)79JHL|>}iCphlx$j zrxA#shOGm|SQo+nwbjim=32%xofVOKwxe_ywAnlzz|UK}+J}}Xo7wKa8tj3%_BL=5 zAkEvjwMqi3ni1f>to|+^o((Hh(h!HIQ^D9A#rV=!38uq-U^Iq@{b;n{Zfke+XmV1- zN-r+KQ(05a<5y!=3)?;YFB6XcO`7C@0Z;(+@;j@~`JUn1u@k>=etrJwZ>A}RV8n)` zeK16NOInNaVO263-1o~Dc9~}vV#-jm^>uWoDc!*&=bfrJj0=1%={g+-8P_4LtBo~3 z3^}ycN&o1Nun}Mouo1ur_*Wk2;;Wy!qMWl(CDn&~{51anwTK9!KuTJHBrt-(SF2aQ zaCFS!*7(u($GW%uSl2N_e?zNwsxXAq3QL`f1WOb=m&f||qhl1qRmv`>p~Fa-I$h;iY_;^p!A(qcw zW{Dne>C*qT7g(eQoy%h4M#ER2)BgDvLwo@!mAg!$;%0x^7Z*R^Rc3I1U6$YG^M1|u z!EnM0w-&6ZA-vCv64=<&!=iHrZlLYHZ%H7b5| znl%F}gEa$2Ante5UWkH4snn6tO*~q7!|?|UU*>FaNJwiOD9ey8WdN(aHXh{E=<0%Fe_oMAXUirkXz7aM<4cm_(NR!Fv#^B1 z<0a0HiAk&MLXG^4LU(}2es_ocOXAKhvso91{~89(nu4p3$Vnk;bC?h|kkgeAa@>mAmEK@=(oLHv0Z%rnK;_Un% zjoO~b=L`A4fw9!;1%fFgjSw0(H~K6jJEaeNFRwp)C8`Sx+N^-KoEH>K56rusk&eoM zmG+TleZlqARB$jA)l6c?_OpmKa9|uJ%KOV~ecp_kUcvrhI}%Gdsygr2iHzH25|cGI zpD;+9R-uyEgkF65H!B90c!uR?{8p>hgt?SEaeqDp!0th()OU10eqTYET2q_BlXDjb3~ZaJ|{d(H!mqzpfpPNG$~J9tqU} zZe2vBt*$cQDULKfc)OQY;VCL2MCSUk%s$F8(UapO1c!+C2$Jf(i7JoyHrw~n>?1uB zJ=U*b!#7ct5#Q$eHq1U+Gtsl+BqWE34-1n19Huk-2#bT&DcDmM@o#Pi1bZqX%FRAf z;$Z#rt(DnFTpX-k!JhJnf4)uF@Pw1NxW%g>#Yx`q43V^M^V{B(i2o?T#6x4*MQmC@ zBnrQS*?g9BSVoGM>7dDnJ)Na@KJ2pEk!Tx?%qDo;R8CwZ(o2@Em$idQ&L$WbI>yc| z4QV<~=WK{zpd1Bw+bI96yL^LBlXo-h0Hq@Vc#k_o`-aeP$P*m{9^SH!SY{Etk;iIR7 z>4$(P00IaoDn#UYLgFeuVI%+WQDmZYDn33_AD>G|C@N&+d1B%!QDLLF@KJiAbaOtw zeSiQ8iV78Zo{YFkR@f*vd{mYwy%_L>ug@hk6csx1JSB0Js<2UQ_^35e`XS&6fB*)H z3KMyrmbgk+*r+#rG!kHgpU>3K=MpyXf3E*D0*RNf{~ujXOCV335RY*P_fiB#BVUdG z&%46MQ;D)U`9)p)qAy{|53ywD8M3Mjg^fr4_X}AAeDEbK)*%-CJj2H-!#<;t@Uc{)Oiq457r*~@!IPrUV|D1g z3*HR|`>CbZ%i@k_phWj(~Qo@e;~ zyI}h%6!giT__~$2{fQjv(Ng4xhxi)7{d*`j!TXh{?@wPr|2KyL&hPSn)z$g5Df%d- zbn4L<`LrH$uT{G7&s+fg%$D^48`-VnUsb7^!1db{nqt^ z^7?|*l?n+l1L_J}UGxgW7sAbSGb(oOYb?D}EQY85&QHr=IR#U`FQ&Rh1y&SJ$pzTC zk-hnU+!k7yI3+jWZr8i(B~RVTpUx{xVauOl%Wtx=%dD}n7x$A|&s9;dM-2=YRwSr1 zDNZFypUxL=nGui7eNC*4;4t(y85TTEhAUvj`DVkEx5gE@&Xu=iLp-wmHE|?@Bh7nn zQRuWDp}>Zq+3rYTxqshGy0|i;X&8KpJfJyd{kXLpw;xj2|NLBsC}pyaW2r@cR0;t? zmcR47EId;SOpEQw-JS)}$(<#9E6WldV%+uoaFs`u+s%O`d|I-#NddNty_=C;UF=Qb zmcJ>hsKTesS;h32Qo^b34-{C5oqTMq`K;;#`(IUGpT^`h2#b((-j^ZX)%g1|`gdBF zKs%Kjtg5oDH4JXIBo8a(43H?K4#f5B6_9HI72rGyx2z&Ozcj5%4cz&$HI@2qNC>91WdcB+lBteH5~ ze79nfyP2ZcG6p}uO4h}S8EYdQU?aU`xS=LuClnum(Y?3KjzsfiD#hWoCSu{;kwBBL zyu;ELN09uZdX$q(nI)^YYeSjNJ;?!QOqA<#0Vi0oC*)n%umjhqx~_iuu7S+AA zw#q$KhhgBR4)s8hYQ+TaUf-;(DUszQ* zN6x!xB?@~JS}=2Cru|K+;2u<47uz-~DJ%_73Hv`4b$?P<3VY*LZlo$`LM6D@;9RpG z^kITN0ERALU@yIt1|4poElBBT50dWNKw+>WPeR|RVYl&3gw$gfb14_>K0}B(4qrj?4>eF@~%iLCnxk7`|7=JR2l|#^_i(a z448ro>f)+>6IPKzV@)^vqafyX9jATjF14$&COeF^Vi!%ftfL^MEvE~SY8uVN?J0<< z7Dw|`r8K#_wQeU(H}S(DrERAR@@kq;H%&L;!&Z3rRw|d<)7_c%!-uoE((MKRyWEO{ znW3RFS;$WJJOM@5a6dWhfTFoR94jAOh2w~Z{3}V6*nVOJe4s7-_C2XU7<9ttc$II5Z#O}{vX&TDqe(^pYdFCSIa!qnmoS; zFRx*87_%UC<~XUgP6X5se&QBD2U}C&PqT4V2$Yb5SMd{WAvPC=w;`9yeVvGKAWT(g zl0B{k&d886s{&_iXo`3zm-SS}zX0!7(~gUG&hRT3j4YA5K;?shW~Qy7ql+ z*klp+IIa8p0SAw}2?vjdUCU#StIa3Jr?a@H&8w#Y z%cu2Rgr|q?)+Udq0Sp3!AGK)!xt9CQ=CPK?#ni~k)8<1M;K)@{+T-J+B|+=yb{g0H z^%4!i(+a}V<6y_uB+59%=5k zj|AK;PYX0@2&bzLTCI1R>!nX;TJG0(Bi2;}Pxj*0z*Sp(*2L>!#o_2eCBe)*H zS3E8r(^gua&SA`#XwKKKVpn#0kGbxzJnkQ~xbRPp2|R+HE<3e6t~WhgZ=2_J9v>XE z9@jfpTHJBhwdPAt_ODzYPPRQBj=3Kd0-tsb7LJP(>piL+S|7MIuAdx;uP$S3I@7m~ zZD|f#ryW*m-#i$xi{D{5xeB;HElBy_&mgou9j>(A)m}Yq0}$U|dAjIS0t_jIc-#^^ zT_GGlt#5ZeJ+94!?Rwnp<~}{{Kb;*(wcec`4qQs~&Y$iQoNIBro;+~7KW^p{v^qU? zwmxjeg?Yehxu4`-c|0Bwcs!6ip3gjO`*S~>#)S<&86;poal7A!DdM`H?e45RozJ9k zKWwjSpSl4aSqG%`er4t1Y{KKIce}Kx75_(JkmX63<;kI1&1L2_drq%|_#yk^d6IeK zed^5#XZyWeY_9|5NVZukRNP7hSBt*+N=4Ik=-~;T+FfW_>vinI3Dup=#hvA%UD#66 zePa_|>;5eS>rL-@(Cy6q-r4r|iQac^R|5`!p#9Sx*Mkt!T5e9PRJd!L@7vt&ja$(l zR`sSv(jFhU#?!dRJ)RyGEL(4{v=Hv{uGhB%H>Fo^1F!3KAF6z`c*j@hFIFOZEy>f` zOJU4c7_L_22uONY-k+1KaENxKf7}&Y<`j*+%xrZFmuekUB1oEH+mXOKPh+pcci&>F zLKI!(Vmz@KI0wm<#bZX|C$Gw}!%Er@`$Izq4lkVe+``r`(;>xG9!}TY)C-F3o z@3)sX-X}?`1KDmjKM)@7mG+%k6P#JyxW1Y`v3ST6Q$*%qnBOdZDV?YAAF)ggEwnX> zK`EmDL18#SVOTBtA>*}iOT8#}ku_Jzc%i~@S--CmmUtnoNlc)?2idy%{*x}`(8AjKZH1B?g_6HS&H&LIM`^DDcy+%*skMDm z|4>!GM6ql{p76XyiFF;}=3!m`hhl4Q1!v7o3)RgM#e89T;zMSodicV{utN1I3J2xQ zuEKk}PZh9CmL@6KA40}K=HePcDu))Vij!3L&-VShQ`MPLtO9ME%b|ZtF&e{y?0UP8 zoXg?SU92x`YrF=Wnw5Ps1iv*WruB3`>ZqGBBd~HJvc?B&MHS{%h6qTG2mmIIY-C4& zuu?bY#@KD|YyZfYrY@0U&S>q-G)`s`y|{Ej7Fu|?^(GgB7y@P7)mp)>2I<=_mPlrv zjI~2=7Gp_GQdBa2G_JVl>c-xlS!U!!Wu%}?=EhN|n3K9WGYu;zEo*#y$2W!PIYH7~ zL(&j{KTCK?{dMye7S_(6tZ7+&D+`OwZLOW{f7%;5`4)maWp@@e0Wz7X%|4GbFxOga z?qluj_m`NiKSXxQ&L(=odouH@*5S8LtL9PBGf~mcHZ3J(EuxEBlCqNVvpIrg2fkfQ zF9?#C3Xwk>UBS&>B-3zX7G>oWbBfQ7z4%xycqTd``;0&xWp%Q; zWwUwgsdMbJ$@?J{fXQix%IKNOXnz$GH+Gfce-uVeUuj0AW^)Y6?tf#QTQDFmHGHt%1LaY$yq2{f@iwWqSD@=5vd$Bb4sS=r2Oi0gx+u9iP{frG5AZQ{&o<#jQtd2dGL zM1XnKnRC?yz%FAyHd@FY2zw)YqC~^OY-aoQ zl|9FRx%jctJRqUtWTx_r1qkOmapOuWeKU>j5_+xna;^3*t)vT{?7Od& z{y|69=%-G|+dHALAop+S;tv%eeNp%ke>&z)9p+PtrXd3RAac4yxNZ#ghaQ^aN( zZ{DAJ9$hRmNoE}Vo&tLc!kJP0TbCuimV@P)Rm}Q@OsKU}N8IZPh(Sjj%p;J_5bZjY zBI)ToBYA?IF&YxaRwviy;~6eZLba(Ao4Uqworw^?Il%{!u-iXF?u=G^*gCmL*Ks$S zH8YuY&D3G4rZukq`eHUe>G-1A+Y%p)zjsnZtDr>cmRa!r8`GMUbJxsE4kp8{oqN)p zwXSVCCsjP?-XHXYbI+ldffj|#ZkDE#vm(AW;$de8H?+w)or+jW`U zdMtu(E6pduU5s~v++txF4Y zq+;vTVzUNNca%Drn|g~)j6Pulc+8T0ukiiKT12iWS*RWA5NGOf$}if;w2o^G!Wtu% zMW(X-Tu@mZk~ve@>z`;B3=ULAW`84jho$BaENHeZS@V9drrmMcyBtv3Su)S5-?pHg z)>~fRFIj*%?rAJMHkkOxu@WC_xbTr<|C{m)Ic=D+_UVpKF3R;XuM;IQPh9mFQ_V9^ ziiGq4VTfcF$&BR&no%D=5?%D}{OFw12xp1eCy z8Fo)A*K1~DJ!^R;q++(vH^owV2c+Rj{IdCJ!)9598lP<_pe2rzyUp7~w>G#*bhO#LkA;8>D^a z-PTCWTaO8f^A7X{>8hP{VF2jPUo~&FRMiF+jLbt2(EI2JEIgOHZYf#RA0B9lXR?`* zE}ZO*@z+jhGaG3X;y`Y!_4ZWFJZ=p>WXBVAw{I^a*L+Gy9NT&AAEXy2CjvL58 zh#N?dxu*JgQ{GErv(qpx^o!AUf-ZD%Ffcf&U(mJN?fu{;VhUD9wr;ca<0~tNF??9! zzOf9Te`?$s%fLKrx+<%ib*^RjfB5bCLs?$+wKdl}>KYZRvC51W2E@55PMXxCwPl!P zu4M@Q`9N~sl=ZvOAXRg{wSr!OmzlUmeN`>c$|x4Hs`o_1Uf7Ian;xt7oFlkmXYA(% z>92)h-bMOr?2HYHNwoxJVX879M}Msb4VR>-d7BrDzN+SO-37VOFVmNJ!({gcUbq%1 zo9lHK^gauAz1XT@i+~DExm7$>HAjSkrkGTVoU29wM(}t1R5jydsKO9(2IvS(RJcKJ zC|SfOC$1S|hi2;FjY_U|uMz+trbI!AH#@Q$cH-scDQYWb1RZMiR^d+<;{zTt*VUz)Qh4 z*fFbKR9i}nK#Ks!zT(ij60SK3 z-}#SOq^^v{p001}2CcBeJJmg?E$VEO%u|=oIesr>#S6}PaK61Wy?!ARp14~LI?Sm@ zb7q;hIYM?XsjyfY<~LX5XyIZqO9uZL`N^jdgD9Y+SfH1xUApymIrn)a!(?Y#PMxDf zxwY5hTQNhq&3SA4d!7fM5}|XU_F2032+D%zhdlu;SSuw^r87QPrX4U$7Xc-JR%fvk z01rM4s0hGcYHzGiG5{tLTrp#~%`yCAqNQN?ttqQ%NIt!BWlJeZl`ue z4c_N)s-CpK32@*^2wVD% zKx4U@R+&9+W86tIVWa-RvSsj6qxr$|#q6KHHC|kp^p?9|^&TzJ+aELc94#@~A3GmR zzZA-H$kMHK_4;gcu-=sgR^t^8;034Afz$r?x_sPYQFpXD*&Hl)Ws%Tug#&m=YH;AR z`$HqgqRx43v^ltB(*g^i!4H@Npke!mhM$Ew`5}u9O{Qo>h3SlSE1m6e&&+z~-N`E0 z%@03UfG(g%yD;0DI+*k(xZo)SMr&9$E?Baxr@`wR&E+OZ%8`y&&P?%8Im08_it1_yrfI_4z#Yx&%U+-~4szS{VUQS=;zplB4jOf}q&ml#{nWtjXr2@3%4M74q zoQoXOUL!BAvIeBNu4Dy~wv|g?_io$E5&93LTBV?SmUjml^uweI=`V&8u?5R@qHzS< zbrS!I(d0p--BD8-!;W>-?syT8L=T=Q6O}%YC=-`nnm!RtTVXaIh73&ac#>pEh3T=1 zLhU%1&yR12Y${lHh;aZ=0Tc(5h|!ak-&*wMTOpdQb-5A@dsdLx&7$vH_Oz zD@ETF95;9pf9EJ`Knj}JBRdmmgkIT1(+VNk{EdOmIV&pYUUmPWFwL->1E|;glF-vV zva(R*{lBeu?AYW%PTqZ9h|pv_4t-6Vv%(tC3WDxMqW#l=#vK_q)5cc@-Bh;35wiCvv2+mmMk6iYK1E~+b9k{_?7U ziv_WyoJ;$7(o+{2!Pa3MB!!M^l-HfG43hHIb8`1?QF$A>sAt(X8xkTxmr}@h4F{2J z5lR1;K{mXkm0?=Ox&`9HjOjQ$u2dKafC_1?9yEND&wPOnG5Pm@fVED6|?cDH*FdZ?4cY1@* z9Yz{3h8o{!2j~01>q5QQnej*Y?B&1fquGtYqQ;fph$6ic4CM>|8v3^e1X`q*zl^Wu z2dt_$%`DqXW9U6qd=OT?FX7ipVB%D}N+&;6i2 ziD^B&bcvC5G-!D#;Uom>3p^k43q(5G7W2UjE%p-z6L5hy!vU7C>bBu^FVQz}ks*~N zF-Ts|OEBn@)I7Hn6fPf+B#C-;63`jpGF(rZD-wbj z!2Ko8x~Q(5V3}a}3d|P=X5P{R9Wb!%kp=Z;h$n;hg{1w5}#cJ^P938ed zb;iXzxoNi;*dUF5(}`dL(gJ&n@pIDjUdd9`%`hCO-d?8ntk54bgl*)2wRnH6 z`ao+O#C{Vtj0v<$_zL+q+2D!mjlC?1$gGgW*VZIavlt9`*&w}NOe`TniCD}Np^mSi zVtT*EBmVFLKnL|=Ra;BzIB0toR0p1fHf)w{xG>a9!P3Pc%k#ebivn2+e^EdJKmkSO z9>orp713dIDuM)|rQWB?n&1&!R!9^R~w)>SOjRaIEcc7CgDOlYm(8n2G zxWN3;=<|~eQpRpDc_O?n5yG{KAcj5}0g=IYD|+;OJux5GRHxYB72 zc(h(tu3&8U!%Nz>ITdJU&QHj&--B7d!hhy@F`%(9^2mB{$P_@TJgEP4cS$kx@SL5)AJsI>!m#Q_|mwd>*xlq9d8$ z75}GEy(qfzao!w~f7F$WqVpK%1^S0k3k?1!x_9He%EW)_T3~=g(anzWR=oK=Dr#wvvPorF6bnaukkFWnxcRi4fa*S8?pGMCD>E=gyYl!|)7bJ+zf0P%IsEq6& z4+EuL9Iy|A)9f2M)HR_4hhP(i2SxXFYoK#ReAj6oKx{YQ9Q`%zaa*h9?#H7P;8z=~ z4{6*pZYlS`!Y}81IgBh^h{Kp z?dIFXq|*5UZ`F(CVpR#DO=&CT3)@R)3cb9q-txQv-Xj}mUC@`PhTbYyCnf?KcAbes zjmbJL7}oQGNj%uHr%*g^SEx8452#%wH)OKIU}JCiHE=-wMdID2l2og?OPr@~KKlo* z7mO_T7{i|1gzr4>K{^f!m!}GHEvA0-Ul?{NuMJ}O-?N6AOo`Q+%wk>^v6S2n z;=T71ikXx3T01u*xaG=$ACfWkH6ZrXh6*P)iDFg9gj-#al#baL?=IoD%0Uyt$BD zk?M%SGkj7843>ieXW?JK|AG(y!j64UZ_1e|Do|>{17Uy*Yq*JSaF9P93&1O=N*Wi` zSwKYk`>WynBq4F%-RlpxFe3mJ<=I@&P6kj)ak+<1CC(jwv zvEaC~>>RFD@e|{>6z8x2W_=xzsa(gD?Xkt(x1%f!eAv%c|JoMbF;cp*%Rt}0rA}dg zIKayNAYAtB@6YY9Tbg$EF^y<@_(=M4$LL-Ofyapha#0gqdq4kYwBIv;0)9~^`}`?x z1irdq9|P)|9Z7K+Q)iQ?1NwKXza7RW$4oVcU*|VH~qsSPWvG&8sv2A7>8>VW-PFK@XzL@f!TK0itg`JWV{6dz4F?e(mu|C5~yH=mg0 zlr4aVzm?AZSqaU)G=BieV!-$JHwDfY*!QP zKqJM_dIw?tvjo55ow_RLwxw$$lQCDQa{Ouv_3701_* zdm9r4Ou&DK=yUOVa)kX?g}SfB(24@T8RRcR?Vt3N;Unm90z&@l3xwlN=eC0QK3T9r z-3pZghYsf^x}siwWrSa$Q57@-l81sk*BkK4X@#GSS4sbB>;F;>VRxe%WG;t6yk zAPT4eD7~5xe>0pH6vF11XiI94Ra32)dp4U{|NWnW`99EjTxWb zMv#9W#;-{fW@8lSv}S#J@$4zyBJ4+x7`N~ zS!*eR6DaWM6<*?9F)V27=Al>6R6(P1*;EBygi<)^kw!yEr}&K|zrv1erS@60!dQn= z2}xUuJesAr!bx}m@b5G!_)>q2FUTkkocowRd_}3CR}|>4jP@%+09hz(Bf6AhaVF4W_=aLD0rkXGetQBVqWOs9zgM`a4lRuL&-3?hA0;FmpwFleT6DyM3kQIhzRXO zFCh|m^J}Y{lT>l6n?aNRG5m&4n~hVzXJ->DS4j8<=og&68Y*b39i)soA036i{hLv6 z6-UU5=TV(zg;zf}6v_Z?a>gDB$AF}t;|@iEWnqfl*Fetfdz}TI{upU!y-vE~9+z$z zU@0j?V}Ngr$QxsUB3*Q%fqH~t5F*fDJT0>+FY5Hz>@%Z6x{hQ9#cuG-M>l2EJ0xL| z0kK@6>XUz~>yma5LDP zdAjyo{;op&mu?=GIt46uT*guCK} z&yhjk=MMmjI_};Mjcs`WP1{tM4@fjRQf$ zI?1y$a4-{BKoWXlwWb)eFNk8P1BVKw@gkdK8Nh^#_q!0^H_+66ts!raJ5k2`Pw?|K zO2BPN5zTpnqd>Z8%yUASF9uVR{r;fX`v?=fPvmt!MK9uhKqjJk_K;p_yP zp1z>Tx>tu|vcH<1(GcT_UWm%~51OBUg3jnDjzS0-B)bKgr~(i$%;kUGIQoaAs=uxW z2u~pTy26n^&SetcW#5tVv3)I}9tYDAjo*e@(r7X6;+z|5MQ7=cap%kyQ1%!yuK%|S zw>_@bc502Ty5}|hVj%u3{cp~8?YQ<~mYdqU;>mfuJ}t6GXB#}Q3+CHgHMpzNl$eI+ z6m%A7W^=}0!812?C2I@Wg{s5-YBy;i3yb;V9?XkGAnzyjW!g(Sv&fh+FH|`nURmRL zi`e%~VcwNG=jasJjZE&mSZLrn0mc}_{DvxA3O3ns!A-F8up{5*x>n4k5(4hnC#%CrqV}}>oNvk*NDsV zeHhx!XP0e+!g(o~LRel1oC{Swv;2k7_Uah@NM$nDpwMqsq}6%#710ebdb}pRIgs1^ zdO_OxM(N>gYOQb<#oOoiEA9UBWVtH4E6<-hVDy{d20x-(Bwwb6^epOCYH(uiV3s-dD)QPnwkPoMmrQ(=WB>`da}up{z}H)l$zR)B zk63$Da{HR9+qG~ObLL*maK$sd@+>6p$gyqC!xLF{ z{TkL(u5xExmP!Uf;CF5t8|_61#6)%3t0Qe!(hyNf*>D!zb2+mmuDrZYp?2F~fa1}e z+wm(I*HoLdGw?LSPn~8USN-<2i09_v6~Y6zBD}>%U*3)nE>d{ir|~&QbpFD>%5jP*FedwWLT|tkky>L4^v;|T*$popJ=%5sx+n~ z#5ZQHd~H>Jn!3>4NwF;;-A{&!dV5|V>aVg9K2!SOZ8-kP5#p2YP^oI@JLHe6`*65?e#3f^skq0Uwwa_7-NvQPj{0U{YK?E zfK!C;yOcj_0rpQ2YaSU;>qc>5yx<{YG7GPB9Zfrga5aU!!g>@=8Bxrl*mS`S7Uz|# zjS9L%JY>b^7jQh3~yb#UIm-_gVlQH%mPLEs@$6X?fgWB$dEHoHCZ82N^Qf_{bGF*c8{(2d41%nYvR}>6YWW;2)7m%br$*3rl7xZ;RY|^s3^sJt?pMDy zDL?8k_nFQKJIYZ?r(q90yt`9?Deii>FwsLlMSyLq4(6ARv6R&PshXo4{mfv=sc-b< z*)ng^_K&JwA5mnBym$?2(QN04Gf(npFh$22b|(+E{6sJ28JtW8`8R!gH_eZDvP z{NsSw_WE5OH}fZv;{(a)qCMsB*%kQr^O|__@EUSXU27nhINiUvK2T+QRD81{c<(OR zw8EJyXr<6&IZMnc>={u8+>~4#)~$=67o^-wXK4vLbAfCLNqlX&J5Lr9vJqFx5_2Ek z(|MX)=+VSWH<^A;BrFU)#DD#6UqZan40sa1#uPkvBVERqhyAo7bX{!Bkvb|v=GJ?$ zzAsJq51a^b%_^um*rD6+-Tg6_E53I(f>+Yc|1aAq2A#o$^cYPZA$8Sk&D}}Z)fG4k zPm`7^iTc@jUQHHuwW`M(7FG5Nd+#xC3w1yN3vS7|D2y%me;0MXZTrn`KjwW;P4=Ee z@x%F5-gSJIC5d%qDqbz7+1K(E3YIPBF_z6s4GEgj?G?PH!PIb@DVSd%!{$tneX(z` zv|Li&UJudBx!ew1-Q=0Jzi_n@i_DQ@fvQ-O={tbe+E8)!0@Y|p)`&#(9jfBHOclV@ zW^LRxbn@(Ib=R#$G%J6wQklflxuKu+=tyHW?1n|YPFxeQ`IqmQmkmF?EjrTuv?cWS zjnbm=7{1CvUwzm`%&PV=N z|6LmPA;9rkCbk<$@~c~fCZKvqhy4`Kbz6o(27xBsKX(gjDl;c2XTi3hb(lMaYzYf) z>&Zoh^2M=-K{xZj4&E-%!NbwStvtB|H1~jp;m=7gT^e0)J6{T>cPuZePOgRVB2nGF zkXjT{p%=UfcK&eCQNaFYEZaArzbW`L6u9-C_m03bUTr&n4ODuzGIpgfQ5y=~@0oZU zu?)5wU4Zr{37(l2DjMtUw(0OifiB$Rxh3%85ZTuzk~};aFc!du*CKB~=15V|=j9?S zAx;&p#Dd{iRY7SXu<3+X`rg34Pp@_e9xw#Y9O?jij`@y4hGs&2U`ANV*G=I5{zz!V zRLIa)$l1CyjcIl9EX`FaMXE545GR*s6;PM>g4amPNPv{hi z?bMC${5b@->Zprn*abUSKu56?57%N#1*E(Fb?qlLfi*Ru zb>Glqs}7TR2A^Y2V+t{MDz@8$7U1a%a5112TCGAh&3CNOlBkBUou@-Q$@T)ts@79+ zyzg!OKb$D0;?3ZJ;YWCEHzK|}t8}k}Vp2f*#j#?z4Q-c30hDO=*=Y7+)IGu96v^b6 zPEoduc>}lgFkj2{O16mak{2+S>&3jRbZm-8*GqSEO@upaNc{u~4&aLXS=6e?M<~55 z{nnN7N;zfMue~chy@&S?qW&cLW>(3M_RoLQ zvBu8!wdXqqJxgRf&)s`d4y63kp(Es2h%hXbDcR8RigX8~q1H@Wp)B%Fq`_HnfG_Ut zqJ|$7He6LaVIo5cHn)P(61W)T0J&@(& zsf$)}gSwFLVAUeBa$a9Zl}Jl#`jKo2HK0Tz5w~{{19-L<(cvSuLJqxYD~2@wgB( z#yTO;y2b2VA|u%N4yWG?WxyLNT;+=&mw#8DH|dVG5RiRy`Rs79G^t-^jd!zKwF77b!=^rASIYpJ5D>qmX^Glq{$6$HCN)TNZ1Z0N+qtBOsjI(%4zat; zLt5Rak-J|BzPUXny579^uxec2a43$l7eAEgxfk{La&H?KeQkoFZukNrbt$j0O_2MU z-Cb9v0)I_&`$;(*da5V>7^1)xkYzYy2Y7JYg@mQ9T)*6vn`^T8ZoKH*)8v^OokJ8{ z0hNrYtRS7pn`h3|N92;UL#s3WL3`2w3I3_bz(NqT8R6dVGw1s52OlQGpP z%Srt$%uxXx7_tqd!k1x|9arKRwZLff1&6DW4nEKq$uOri?^t~uitXW-mATM^hB;`k z2YoDeES;?d=9c7KnSMG8H63=4?4Gp-y1ai9dvGW2rjHd4E*dB0e$u_Qn(P?;{KHu* z9(X`L_Uot9lNx)>sm8d~;c(-`JUJ=~b)6<#I`s2iyIHRU#oYBZYn$;_y0)QMGyz%c zGeOvwV2=PsgfScLOC2!&y6?&~>MUeM(23+l08^MR+Xa96`=Ay735?wenH#ieq*DcfMYyyQ38 z+b>*{>Mxp@vnb!hUWgInSWI3*F)&yoPcUOY7HX#Y;S;+{D;59Jo=B2=z zviHWyG3rFrM>m&3s&)9MbN=aZM#f^t1!bQ?&s7c5s7z6_W;dt%LEv%! zRKGwdScgNuUwgmr97UC9(DVJZ^8oGmSZoS#H^?F0?>Zjf(4F)g_hxLvNaZ%6c7RU% zu%}~9jrk}wMzt00G^hhJw+}@glyybxNwmv3lYtA?b;Q@3>xt;hlMZ^gYp5jgjh7$^ zs=_$4UcxxRX(s&7o}L-TnSTE^)VxOcaXoiOY@eX4+8NJcyP`%edl`lpMcnX;QL5P0 zpHw_eE}bNOXNK?cR)HG97Ah_Q*zGH^X2mP9g5ym1EiPbB*~5ZPM$c?NFwx`j*qKPS zb|5&6XWTl|9mrr6KF-Ec_iiAibB$HY!oO_l2lE<)lEag|s{p5Hth2)1{hu$BeYR4> z1fN5n`OKS*Z99`#n)$CDivVF@vV>6{d|Zr59l#J)pprnWqe(39O?Xfl&$*ujLdgfq z?qTQ@#qCT0&JawI!1&<8Z4-f5F3a2XMW)WnjkG_;V($paa)D2%PeQ5z0V0DK$I5(qoX88@`?n6{>G72b04g`X|}eOlXBm3EI0R&9w(6 zgAZy%i+PXG!RZq#`2F>?{?X z$U*Qi{prYU19{EOO9u_WU~lePmpz*K+6cjChf|-<19ArZGvT2pKzd^-1`I{1M?sfF z|3v_4?E`om1+B2G3(dLqenJdeN}q#5mYS@%?=)f7P?FAH%w&Ty$+wmuhVbM=r{+>& z?4eE)i}MLkAP?zoESZ@M+HEZT@Jc?k(!wDi&C#u2;GxD?>Y&)* z)H3&nqNoBO04jzH4z@#G9aLx%86A&j57!&M+ix{AJxM`muQ#}`eMy@h{PDRl4;VCq zMEFAw8g%4hbge^xZ&vmhPvub3nM#S>t-0 zkBR8;oQg*mDQ2=G41kAnuGgohtT9hXBWe8BDBP?4@Ok;oW$VYqH0a2XZpm3un}V5*-Hm5oNtqaCMuFw&P% zkzU(bGrkH$x<(JBj5HuFD$?(*cG1hG0Hq|PPde@Sn>*a_RSS&!A(_9v*7Mx(a+LYt z=KLwvSWMRQ;&31&qF-|ga6r2Sg51o1IYYA{1`wu?Y6XkNs|8JiC6XBTuUyO!%PxkO zb^@0xM$iwEM$nu7_ET z3!nmeh2kQgY=E#&f&xPk0~2|U9f*n^bjA0(fmj{Pf&2r6KO`u~lrWgzT!i4sbuZ^G zpk4TyyBKXx9~_>Ic1``Fiej}Xfcwqy?R>9jpQoH^D9hFNJAvgj_vZ4b>%Dn`3b1kY zLE+7kpz^3!7V3(CA9P!V0Ix=<-4iZ2Fb#GjB$)z*YIx*s1{^B38iF28gW=!bqXV2N z>WLa^DoXgd3$D5t55~gx-bERukc<{4U;ty<)C@1k&#k%`sO0Ae?8hv9*os+a`VLI; zG}BzOGtmQj`eH7^kARWf6?@;GhUYBjLdj`H$$LPXz1B*rbu?t4U~U1Aq~4t_uBZttI>~C~O=n4&o?Tq$>_#neUP0-4Z|B z{|A^Rze;QBMt|NlA*o+CPt!P+f!gxZ#URJ&LPR4xymCTq+MY*#4Ex20GY!e!$s1K) z<{_%nF>Lg|xh3=yua2;(XXH}axfnKa6$iQWLB*AQe|nSMK40;oUimtPZN6mhJ9wr@ z!7}ZU!+w&+Un6~;W}hjZP&52FGY;X+cL+(>FFbp?t3;5B>5<2*dqNZu4j9bifCe>f zhRPHa2!P`PbtF*(Pv}CWrCGAf9KV#a}*n1|Ic<{0wD}j-{e| z6jQuDV2>w{cL-pQW8>DJ ztDXJ{B#Q!Pe9`?!G&NE~>qun##3zQEqf@W0*KODk8Hz^UL>z>;O zr=Vd#-bpKFD%*6pAHio>Z&wxZo+@}R4{bx|9O`*~L%9l{*7MoiTU-_Jfyb|;FubSt92%Q?3N!_4#&1xrbGeMn@6pl#Qr=_ zM@aaN@;dZC57{p=+WIVVO;-6lQ>*M>>iYUYiypDq_;d`%{FjaIr@LoJ2Lo}wv4?t- zR4qN1*aAt;2hE>NW&>kPhTqtM7jYH?YJp3LAjJzeM!o;0{I~dWGSvh(m099lM!E~T z-;8hBn|GJV1RvDcJaa?@=BS_3i@HZ@wci(;dwCOhQsK;&fjHN|yZccW9&ud%;&I{9 z-U$tx7fa|baw^7+3Ku(_*KD9hX z84qm6TuMyM-&p%HpRq5vrIh@5=#6ieS)E<&o0~2CKk+sQni#q-NhhEBwB5WGY(kTD zB2jj;-^kJMg>@C#BxNvTGMWtR+#PV>4KsK7c%RSS*c^*28p?y$@pp|P-(O_F4rE}# zKV(x76Mm+LG~z)_St~OKy-~#?EO?MO8t^7j5ha7^S&amw8hMkU;`B zbfExVQ+}yWXCv`c`@X70Pnk(e9md|RD954;8AcVlHGQL>Jb$IY4Ei)&o1jzNt7$a$ zJtc$51@!eSdoqx&vD)}Ld$fcJwNF+&*l=vz!L!m(mcB^Is@K19_gyku$#sB5yoArO z0E=c9a5S)pYG@YIFjw4AE7cjIvP>Ml7dtF?n$8;Dapskm7C#4OOYK^^&JZ^ulkftz z8O1l(q>Jo3>c}D~gQerp{Q3O8_B`M?EWWqaWDoQa31#(If_tAAb;#Dj4INjR&9Tk- ztb8q0Oz*}*Mvsu*$d%lILI;IAzx)0HzQ>7v?4N~pZs5V~=3K*j$)o1?WNqLx+r5q9 zErS6=;42W~jW_PRwtd&7KT{oa6fBvTw&+aQjr~M+%_zX3yYE*ex?7c~Ex}I$k}A-2 z4O~Z95^jIb>lqYu5vywH(|P#5jQ-8u+0;Z^cB5qw1HAdC(h z<|7-;+r}>yc~&}8?Z>K8{hBwEa+m#XM@IaccHK01h=8Q@%&&qZtRk$$JSj-VkmbW= zjh+hP6#U{C7UwaT*1hyByx7ulXVqP^;URzP%jipX;_8&L;uy~^01+=g!z&4N93Dej zb_@|9FXFc*>lo~8OriR~_^{MAbUAdErwNYzV(83_vh<~RR!c%=oBj4-omo;9;`m=; zhbS3J&)nlGqWJQA9bYHmAUkZ_fwTJpjRrFdfzhADLdNa0SDCIN%5C38eZo*`(rdd^ z9C;doc}4k!j|-ngTPLbA23`dITo?roC*P7$x$t^N8yRY+2{renxp1-?uqx9`E<-~V>xNAD~ z$Et?e)#>AO|IoH6te4m?zC8ZZc-`Z~1Ep-%)q>1si(x)JUVlZ<7i2!)6SMu6m=hxJt%U4<8 zamW#Ts7Z;?i2&T>Vm*eYoP(-qb)pHmdwrsT8!PmCD6AyEqN!jU3Zs#-&8g>Ak%aqH2q3yWL=fo zsK@OR-tRn81sC2}dEm2hlqeI{DQ;Bc$P>scbDHacWciH8b=Bfw*FKTV9nKFs20PRh zvk!s=?=yS{Y5IbFXrp~S*;{?w6c0r{hER_ijF$f>`T0`tesFORm*D%?l>bi-XQBze!lr{b~i~idePdWx33SlskJnkIS1h zZRc60=^rhv-FGKvr;(I+`&Y*Qg`H(Q?pQmK+V!0~sGe$Ztp{%w6&KR(3=?oJerEXf zZBoM5Sg|Up#j}?rfvzywqpMY7BNla1Y!^OlAbSK1tc;Y^NMZi>PvJFE@)sK-0Bjk| z+0G|d5~%2xeZ8BopFi$U;r66m>0qJP*gO3(AmUEwu14}l=O1H9!}$}H7)v7$ zI}QyQc8}j&G8B~%?+axw>=&kQrr)rc`BU{ga=Y+~yZd%mEi0^|@Dkz(p{LB;!uzB;eM@~`e1plQCV+JB?Iws90Q2O0L1Z{&{eu1cAeh*vbZ;twbdgfY%sm;*NLIXl(;v!jq>g0JDNAvoE!V&;z-&i1bR=>3 zZe~=fFYHFD(hUZ6{G8A4qB4B{2BPz^kZ~bZ!02pPD%9@ES{>*ju$u$9(-cqcR|_!W zP+I;2DL3!9ai1akM1i@9ow@hK`E!!2TZ^NVmw}-}Dp-ZnwQ_!=99nam3G_7Zt!ZGy zO4$;wRyQ0cy$rh(TBvPjeXYC?;7(J#FL0Q5mXQnj{FE%qY=3^zrBkwGxk=cyx^IT# zxcWnRX&wDs^F*_gfA zX>nWaQXPNzSX|UtoZ<;&U*H(;tRWZD0afMzS`MA*|DANn)B0K+KL-jJ1(^k@Gw^R(7Q0Rw0ONT_FX>`1lLBUJAW5LYzX`Mn$Zd{W$2SHV`7 zil;S89e>1F9QRfzFO!R3u!gClUt~9P&)6MH{jR!Scnt1Vq_9#_7(ZTe9A>wQzjZwc ztf{I8Yf{GVwprt?(e+UH8!>0Ee^TKc)lg~3i_|!|o&vcZm1{OEmjxnlIgsVqFJ; zk0GBh`Uj`Ig* zN%Xo}=8GSH7Yi%X-%3-OKQ}c_yXQ%of3S2W1TzZ#b;ExCHvtLCq>QdHlbJ_db$kX= zl${yDP4|Wd=2m}}$3%WpX|t)7WwT&ivS(f?o#Vb)_Wd>Vm%Jbhy zkBj{FBrQ1javnr3=akP{(cLy1G)sX9J}Q&Adzo;X>t}E`3LqIpXK<9BAUb@2E_7b! z#&1JPMM^A9`3V_H%7FV&TqjiPZAX{gjeo1b2F>h>A_dm1li?I)*E1?XB}2&>oPRM#T}b+`u7;8p3DAS@CW zpV_}55SMTE8y8Xm>}`R;K4vw4y9XbA zuQ%(m6JAlo!0MIq6VRyYk!n);iN)u5fhMMbH2N(t)bZJn==d4F=r>Xyr}+lw)<81A zW*xY@M3qx|mY4bu<7FVoGZE;yNm6#K$YDGngelr;rP#PZIr%F$!rGb$>W1~DmoYWP zUu%l{^{X+IlPNAg17bM1+lWB|>=1!54Daa4Pr3?TEoB1%0B``dN<+NKbPUViszW(u~Y9g}Ep6#loo#sGS!Ey729+89{8N$YBsZ0}%}=FQpjh zLbp>WJCI0fL=n?L(L3f3Onx*U zq?~w8JY+BGj5(eE!W?o9UAp1FGpGAsn7jNHB6sC~XKwZ?H}c+pVD5>Bc2r3kkZ@0g z2!e8x7@xxpql8elvj&8?US9fUSYK(m0BUC~m-+m&<)r~A6w1p586Z3WybahjJsSGL0Q-3JWB=&1JkUji zqQ`zpG6V4)bS5)nh9FANnc@s7qfA6CSXWV0&4X_n9U}uMd!`|D(?Msn`EU66<;}Hk zP#Y+ra2o>-;Ie`Kt@TXD?*Ipo1{rIDKDqZVxRrJE>gN9dCk)s97hJ{$dU)Ia0or*<{gH{3=SxfhrDtL+6!aE#an2V zl<7Qkx4Ps#t(odd!^eiWfX&0(!*9zHmE>15oj5CvSC>-Vm;*f)#-73I)k`aC>SLJQ zg-Br|fxmcJ#JQ16$2P9hj-L6BNB0l5zrve@=f><`OT#CJ6xZPy?iG-)<^-O`4D+YN zfp6+u^ul|k;GYPzux#tgfZdRM+n!iq-+U~T0;XY1oqJ*HWA zJ84YnbqtNhRY-49zf4}1*`hGdg1(5u2KEJF_2AVOB~9zq_a%IlJ-g6n$iIAtShi1? z?s*^e8u=*U*=IbffLymAr~#Ou(z_z`L~m7@(bDSCopBYU%tpj>EB2dZ;pD@L5c`b4 z3dl{1-~nR>U2456JM6K#i%W+(L~|88hgjZa;SyBieL5*0okb9DGI|h^ zNKraG7QdbP8mPxgP(rf zA`$p{vRQM7DCr@b2(Kg&U2*~z`uC>WdmL_c*RPhEvMQJazMHvUszt5=fZ52%`3;O64S33g$ zIz7g&X-ugRcgahM%IaeePt&CxEc8L3%-{~NR7qQE-eC_YA-3EVD=*}{(ndGd-(MH; z?DAk`40Fd*Mzdh)RS0Gspwr$5_@0s#ntKu6J+(jZ94*sQch|C5mXa`oKh;Muo9;l+ z%n8Cw7+`dOMgIi}bs;qZPXAuHvnxjVQ4T=+NQuOe&LIIGB3%pNYlCg9ureoKSq}R= zn?M@RJ=BsW8PNX$(b`8E*VudW(JVE-620yE6+RF_8Ptwj2Yf z)7|U^ct-AKJ~UXOQ4Tet{u&xdNH0Yqj*@<hO;D#o@qHo9BIL&e! zc&x((QE;4)1Ym3bD|7KD%tdY;_%^t^Wq|2615R^;+AR&9cy~xdLkM^!7SK#gx-j5w zb(oe@HUS1}%EKaWghDeym~5xGGD7&3sd0McQANwHW?aO(7$Gu6YK7h=4qM647LykY4p*e<M(# za2^9OyW*)F2l+o$$2rm|Bg0uO1#VbQD^YrA$|pyLf7Fm4%L#_DF`dwzd9?qJ($L5< z>}WrtX-1e`HMllHdFg?F(#6tI37Q_1E+vC zUHeuoB3f6Y%^EmJS(QalVwuZ}$9+=+|G7-YKb&M$7C@=5>pRf&_ip_1tVH}>O#b24 zV1M59qz)Ta@Si&`DVNpwhd&2%a(uEgKVs`dIMa8s`BN@i$bXJKL1ZC+@Fm#4FBm;G z+!9OAzJoq<=uyz!;A=1LGVtQd2cy3P|1!&)U6cQOLmur*O9^^`&}>*Qr*I>i^krr? zBqkP)p4n^d0g)L)UQmq;!2(R8Ud6>Jd+W|65F|HnYL|5r@&w>Bs<9aE)h<_VYV*vm9!C6({tRnWTzRP+i`V{?rT1a#5001zE^4 zW(oMW1<~*Y;opZq9}GQFsJ?m7Hw4jt2YTCwxOM@k2?eAGVv;LK0{*rlCchy54fNpu z0BGnQ07N>d#ys+}32|)*{A(fZ_(1%dt@vel^NIbIIHqjG@!+g)mTCTf1oXTQumf#7 ze$jBOq;lzdnEZ&6sW{G1ml=GHVMMeAK~$1t{y_ZyDU|4E5JBT$mvn_Qa+$_Ly!i`) zD0`X4R6P2sX*sV?q?L(BaD}r!c&YV&f^v)8-y=NnssK1E@VVH*u8FcFj0+|V z`-V^}O8S2vD&_L_;edt99K)!nq8m|flKETl=UQ$=JtvyIQ(6R*9~G5$BU+pieY2hv z@MMl*T(re4^yMmZ_A2w*8CbDO`fB1Y@!U8?ni7GA2t{{NJoRf6N@NpCY7EZ<%%X8KzuLUEDf-MqjMPH8N!jnU^YTsw!-vs%(CE`nptFKKl1` zS~&Upa%9li``;Bb2yjKV1d>*3T!Si;L6y~@%D-fyqnhenTgpUz>a7~%x&(f*~LCnwD#H!8(mjtq(O(ngt`{LDX z!uz5sVNY{Y2Kib#m6}CsnvaIYe^F4|c8Gq9?aSq5wFyRP85huU#*jvG`j7<=wQG0^ zb0^Mf#Fts-Vo@b{*UP~~wPI0e`03^qv_W&7CE!cW>%Vfg5{Q&(9#+u~B_d}vnpqdI z4m=|BlTC*_axRC5@`}9CG;5pb(XMKV)0=`sGJVmc5-0zHQ|0JPi@s9A=DiEuQ|f#Y zFVQNk=7e;fWXSH5R(nixYzM(o7nlN0>n{dY(HAROJ{7!CRH7}Sj>x_R23C<5sMMYk zug{&F9$@hp89^gg*&{g;s~kczohZ_>;DRKh`GQKd>YYoMyT3{EiL@vYy*-#su~*5I zCvsAwkxL}H_KV@z#qF%b+0y+ict{vAzIASN3khYhSTOMMk~mVm@bx=oSui!&E?oNN zvwj)Lyk(SEkn`PzIOYZV8k~a6BokO&e(I->8yCp+8pUy3ph|~Kq7|bl`6;C^Rx=es z&dFOFal=-cOlBmc*m1Z4B7xFU6vuk*@1RqkjHSYD^qS@`AI*?|#4wG`=ZN80Prmb z%M1aur&1Fd(k+`}h_{&HC`sl`gBGyB@pynUWQ#+&bSe^jaKi?NdQci$TyZ~_86~!O z3z>L}8hG2O2^ymn#0NhS@eNA%5;J&!jx{8mJSdGA25u`V5D=mxoV|Ukr+dt6>rVNg z6fxgC00)eq3X3$!dm>pqkx8CNX<|-}5O44Lr^Y(irHJ-)K6oktWhCQ*bqMUhi!OrM zvW3jDMa{A$mEe@;?tK+){{jT$YMV%DoCswJZevG+00XlwZBiN`T!%M<#8Kw zi(fAJ@K%`88^viKDBj)-8Qz}dZFJzfovAmovnm}AbqwuvnI+^UwEF12H3jvLtuYB= z>DWnxAx*wB`J#44J5TB#Cgqt{wVL@21lV}k|6O+C2M< z9s<(r!z~Wk@j*Yq$EWr*r0r7YEDTr}a6j$G4m<>G`66;;>ai*{jv}SwEWw z1V#*^zAo;oO5WUIGHHQ4^)-H3~K#K;SU=7q*6 zxqcAIpTf$ULdlUoRcW*H(A@Qj@1lF!;-3s3o6ReBFQIlX0eL@&7*1jtOdiWSiGsWH z#5dYKEgFE++PuR449fm2Mv3u*2xI~ae*y&unGimt*?t}zxQ2#55r{t#airR*m2+SO zESAyL$)%^z`KKr`mY$ApG4;{&AwJ^FKZPzn1%9?iP(3Z)4OnsgA6}Qv8l}$CqKr4= z-KVbL(=xb0mpWsVGjnTUydM^bKME{M&3Uda88<%}Ha`+X!&sifC?>szg%3M6p9kMsM)MpF^c;>jl33Hqd1C}DmZ+u40t;x4 z#j&m}#G^a^aB?i5c^2yX2cOi_c3goKSN8sOskc$8_c4>+0F!(Gll63|-iOCl z=`ZC1Rz$L^<4yr&s{mz{?*$I~X*0x>55Hsd7l5v9_0t!BAP|4RQZok-#nn&7^;ncG zRmqgUfGD268!l-ZTNxjT{$5#Bf-WinqST0Z^%e6Z8r_~zbU!h020d`*)2l6+ zwLMuS%i=Fj#5)%4IeCdS9*m85{8@c=G~26{Q*<9#EP*qVoSaZLP8_i6#Dad6{^1F; zfO8V}=#9MxlJ%_A^0dtIG@mUi)LOh+N?f$)THT@7QO;d`IOn)aVY6&g)5fKc8JUn7 zC7+aq8`^4Iz>08ka*U3EL`I;j7#-nI^LdKVT-3wY$tlfgBjaQD)|Ev@=pti`5^=SN zR|}SB%dvG@gpIzhBa5HIq=>6Eh&_78tv&H|LLoY#?HNw@6Qickqo%+gAIOiIs)+#* z&ba%wIi|I(qY&Cbp?1(1rP?Zyk*`?8U#Y2+*_Dgh>^@el{Bmy@=u&e@>3VY*MeM&A3N|dV@P$qYXITR2OYfy4&Qzmc4O>5=Q0?!%m zvn>CbgyTSMa8Pb+kE3ptAY2iEV}k>=!%^Q?*|?#N$px&4YmXht{UBHTKob>^`>~dG zP{00!am5dE)sNMiW$()3U-HGj(MofbBH|yh#6E%s(iQ(0F*FmBG>#_rF;MJdgha#> z`~fe>fLD9Qm|^1f82a`Y$~@a+t?-Q|&(%xYV=~)gN-0Vbf$<-JW!XD@vx~*SkHrCu z+5whTi)e&-gqtsmLmJB}N+Fq}GMS@%Hnt|Y|$I0O)WFbDHBI2 zM6yytvQlNg`s+~l&7N*TFm{H!3-hz+_;#Fe=I6*4=hQqc_pjtllIKlED_yM=$*;o7 zt3t_;U*($JFWbbva!Kc>jLuIb2Za=w!VzHc*^ZK1|E`ewErcTbyW-s|&z8X&+EiD= z99Qv$<$0|fQ$t{}V2w<24wADCf!jn#5ssd&EsI^=b;$Lm;mUWMW% zfbxuS=Ih9p>eM_N_pansk>^!KD}5~&;dqC|{tl%)j(6&%X4D+-FtqQZ((#gSTR~u3 zfu*JuK=h#>-@{{~zx#ls$oKn_<#&1}`dnLaFZ=;r$bfEpMuowfJ|faVzms#$P*LVL zqST6ga0f8QdAY<8PMh(PRs@oVg`bC_caRIxJIKY@(mJ6RpA#6LW7#VQIFg+oiye>- z*FQOwBlZP2DvA+eQp;OF;RTl`&M`Fr77JG2Bxfu+TP(J2#t-4{l&kFdNqyP+wINA; zXkyut@)8jOZBoms9Lq)^APpT9%{k@fgRxc zgG+|57v{47ySEa~{2TJcH)>g<_j2wS0E@+_cXH_s`TQHenShRKZk+wk!RxfCcTg&s zy4-*LFi6&pEKDSc&e31t^vGcUQ`8evKnbN0*d%k9NGns~8@XHTjL2!Q&yFqZ+J1|ME?Z%f}`sDKxxJ&nF~@WAlRC?uFVueL}W|Y#FdrsNQ}Z zBDvW^atw!!f~%0mu?aY$*i-3r$Gj>DxhmP7@kc-LYd8AWZj^t2?XJ<;U^HKM_MMyy z15a@B8qKA^QV~o3I<(H&vkv}3PspAYe|uH&l&DnmCRiZLQ|3(V5kBu{Y5TS0PCoCB zil}9G^3vDT;>j2;FqDMBeqzaiV#$`h>zrMo)_$SZC?5;8=B+)(1WJ<1(E|%p}`W;-4 zmfVSY);asv6IBe0{{!nK!|R+@SA`KUoOyThMR&EVLcJUisXhyB_vF8sM;tQ`afPw= z=>izR6%lIfh=4&{V5sOtzi-+o^#2Fdp0kEB`A=W=}>^`W(Qi{3g-+T`9z&A7(dzs4C6WbG&fg9se!R_Iu_L36l--7g3X)_aTJcm#LBisgl+EbU;l10hx8F2~bKf3BVwNu#~KP zy_^YsV6hN(Pr}{FZH_(G-o4A}qmU3x!3HEGp{i4?(O3#B6)M2@*EoCDK;JJhSWE1D zYR~B&s>&O;n~Dae|xxdXwNL?;Ovul-3Mtx*1(D@6MbFUsh`?;f^Cl&NTBVB zOp&5@-W!L?f~m1XA6P7wU6Y*76us)rf#r@jZ>lKZvPn}COoJ&>W6G}^~ zMP;4Ac$yuUot4}Qy&2Zoc{x78ncINQyw4w*TO+FF>YS`CY;Eo89JFY4T%mfD*X|M5 zS+<+IIX_#OeLBM{tRn1G{|Y2Mp;TNlaJ7c7^$m z#La46@(YSt+qrZ_$j>doUAlVa2?_+Vj_|o&HPU$Y;YM{Gwy_J_6UB)o@wv<0_iT_8sIWA8xf7r~J6BYML=HG$|3&A)dO*`{d zyM5-9?$adz{&lM|oF?dJnTiFQD++W$R6HS>U*MK7d6Q4aR;kR0-u_>&qJ>U)XTEoj z&wQs5-9akTmULzKvSfYy_PSNSkR)blb*OO?fB zqrjbQc7T0Ba;uj+OsDs9UdBYjJ@XNtCw;$}1UDCoyIXlG|1aL&JRZvR{~tfClI^5$ z5XzDYb;?pksAR2BVQg8l#n{*EMUhH&CB`mY+`>YLk4#S z@_qH#mE?%Jy6Q2?kY(Z;$sTKYu!c?c$R9AP<;gq@f41@?p3jZ+`kSI;G z_)<6Sou{8uRb`3EU^?d_xVS#W*k8<>?;J>Z`$bw-RtG}jqaeJm2NU888yEb_+m5_Q zBWd|y;>wwvy1EAwl;v%o<@5$dnp+Jg#A`RKOmkj0nBGPf9TFoix)`D{BAaJtAF5$= z8V7u*>-9=p*_=uLLX_bdVR|j;)1Rg+441XXFgFPpp{0dTCxk`vATkIuIXPKf*AN2L zNJlKsnnG6o@q$baTZ6J^=@mu2cMoiQi`6)*))9YCL_`G3Z)*bYhtRUo%zL>~o^S|_ zx9q3rINHH;FVQ~I*2Kst(cVkm4CV-pcYk+(xFeY*=3asCD+i^=3LfdVuz1J2DQGkn z&uD@L2~04(&1BQKEle-X{;4`aD0VthwpY}BxTssS>ziwV^IZ;yNC9gjBMt{IDRWq; z?|1iiw?{j^vcv>1Lqsl2b&eE$7fsF+QFvDXLR>_`25PrKh);>vR@j9qU#ZdHE z^hx1GL5C4p8wYzK2cw5mL>K?Qp4j>3b#3>NcLiO~^PSa~IhU)IdeGcM-JNPZ=$KDX zFFR-AxD;i`hzNC%K0R&Du{!1Wu3)6Uz?l_%q@Uazza%2!T+Bc3M&xB3@FG#!GkvJA z*Rnt5-TDqG{xl54mJ!Y<)IaFWgF++KvA9h)a(oKPH z4IfWjxqj^tbEAX81qX%RJ55tpJQ0?dIy#=}I+ zq8~#R1L$PAm0|os@WcNAR3;7#8JOQRQkV1sCYIQzex7l!Kr(tAF?Qz%` zHjWpZ>p$jQxo#t@xx9CA|6+BEW+Zp*P-mxRWK7dsh zv!lt4^-;$rKVa2S#??l63psJn7P=Zavg1g^5dh|OB$_bFh$mv&BH?Y;bF@U_0%oVk zXJltWl2@)MysOX3TDc-ICk&hZ$J~R(NWEFdr$6SPpa?H=mg-HuV;jkI$H*zt_Pvpj zk&{=QEgTW+qveyLm2UHg)<-S-d89{(Fh8fr`6MGFKPN9%=xnJrMRXj3u`V1E9VbQX zzhTU7bc>F)90Iv7#3@oK*~low$?Ggpk}@pm?7|`CakCq}qP57;xapRp!td<`+-gnn z&qPHuI{33Q;CL|8O*fnt&dHE|sOwFk?dw|Xj8O1RN)uJU1d9r$DON4|vNERXE(0m6ahXp-Yrh3QN*;ep(7pz`bFUHUeASpLT3o zh(zC?X3Xz_ZDn7G1hy*Z;jk@)-K|HIW+eHDUFnD{w~M`fsnO_Dq6?F2*Y?;ymYl-LNk;`-EM4KnI5PO8emBsd~b%7^#N zZQe7&d}p3;!Jn^ueZZ!AQJi6IRhd_p}Io-5l<>I=VC~zlnP$_Z$IPr5I zGV{Nk_;xlC1u*kGdx`-DDp*YSl5caK5#~Dc zgp>GnPI8#RLnbcStAVsETzg=x4qlp#8k~>Xzd^j;B{PB~uRh_ zIk|Xw<5>B`duVw@ZsPT=WfrBVv>mM?w=<|x=??YHj={Ep+UTRj2(+7>hc^u~Rt3C;*8WSE@I*2AQ6?q;#s5$Z_Pd?EG-KR;svCB7UMR-eCUYupKTJ?LpNjwoL2{TA~wGmX}{?skx znC+#SR;UjucP!$Jm%n(2+v-EmV+4sJgCxpf+h2QaV2+%Yj*YAY`fF9)NdJ{ zjAuvQo=XZYgqxk#w{m7bB!0}F+`~rvI_(~RfnvY~!I_gWahy<}NL|@?>H~*->k-AR z&tWcSEd^gWNcMpPGM01yma*h$GdaUl@7k;1J$RESXx}C0`d=u@V2xyz)8hukj577Ip;1($e}&YgPr{lv1L&=^3y1LW2aH=W4{ zMkV4WVl;J=qH{?I<|O&ydmM9xtCJ#v)phscZiNPOhX$iVgG&NoK|P-xy7xhM{d;%V ziDWXkn|$R?@}yESZNm$i5`2ufL?M}LvH7=#e1)jSrF-4ujbz2& z6?@Mw54~PxRqEU<5LsVmTOAyWx)xs8%I$%ba9?!dT6OD=nsh)Z+7eRAESB2*N>*wY zM3X!=9NJgc#OJHp#65)`rf5JqL@(IS105csG;Imcq?RJV(pOy2+`Ad05V^say+_@Z zT~%bBEQujuy4`G#y5~6msyqevZ5eHg4;OzqNI>GwGy!oEJhG5D%7r>eoWz8zt5mPC z-98z%Uv7yDXhb2I^5W){n){}=SmUZugQ11;OC3T(RH0T>kv7i2!t5o+)owJmd6hc4 z$Mfu{`%-4{rbN`+b^eE*IVMsW_MEXBtDbEd?Mo9m(X!tsvFAOY0JM9|zlQ&`hz)R61HV0odVSCMfyp&H z_q~+*+RVpwPD18RuC_d-5{^t2qUE6gzhnh6_Djgv{$EVWvUpwfKCSk(ix7rIYMp34 zOd84OIHFBCxQXj!wWB)0dXrUElh|}>7NC7eo3r8p(WAIp9&=`&a9De`?4AZd@PXSu z4AWiVDx9=0qO*M%o9;XLt@JuXY{Qf>uCZuuXZu0#`!Z3mT_b#2hv`y$zf{ABdI)hR zb+1pW7x+8m?j1;?NnIe5@^g26lFtbUB5ts=OOzmlP&>h$)n0_K{ch~)tuuX%ZvNJH zq4ZocPIG$juewOMH`pr_`2L`m`JJZ1MQjj>CcG#?439jqhM&DbIeK(#;&vtFQkW`1 z>myz^l@|^iN9mRF?n2T())ZIK4mn%to$$2{lYKrXBT?zWyM5P}CrTrG^s*3Ed9ND*e zW7X+iNdK)=`*c+TrwS3_1tA{L$)*BC*Ft*6YTuGb+R_bEY3?pyH)pgdH_>kSS?%um zm1}kyi-Y=$c%=7hBFd`E=tquoxfwUfn{u4-uE%gPzuRpJn~vUPx247+_RjX#+z+m9 z+ii+21-;8|OLtP)eOdvcV53|Gwp-+L!l?dQO_fJ`)!r=^k1FhL_G+wR7Y-|2Z0%nX zF`J2ee&87H@1wXrI^5MChPo%A3}CjDt^1z}A!i^vWy1cyFWVXaH@^MaBHhfE*_6Hb zKOWZlcz72@%u*i_GO2r`o{woez((s6Jwh?6uRE+?GNJz@qK4>jJyXVIqxxj9J~0FG z699ACT=$fD36J@cFSSIs#RJS~b26Xs!bM3i0Jg?ZTN-MYptPUt;-~DPHd!a~^U({@ z3i0Welo{*3oP7j&4bfW}@uFsbm5-nJc-V#gy*qguS#hs1@Qyub-kJ#BM`&LE9TzhD z3q85*)exqfujUKiqjEm~T%xRNU63ro2`k|F&>#=8Q{5zw6M-ji$EnSZ6DCfqy?Dfa zaNY-`B|R^zQ!0%-DgnF9HE>#m%tv|f=!G@rkE2(PyzDvp@wq&`kvx5&JbhIa?E6!b zp54tAja9VU)|!ueE_n=h`6zCb4)T|6Ygrw`-T2LYkn?yX=Pqkq#v|Ex^f_A=rYf1P zD!HAB3KD(eRJmwVzH&cUy!4>ak-bf8W(`e`=B7nl~V*6Q#|9n97E9 z{y}f_gTC+wz3g{lyhalugPsi(BL?k)4f6LgeCKByHS^ zn^}Q6`^pJ#eY*PTaGtxI$M4Q}+TWeWyS<1y^E@#PUoA)!m0Cko6;bbwcj|OimR-*5 z{OW;SpehSUL3YdIp4!vd-b*(ouX2kR%G*DJ{RNJTESxi5&o(nCqDE_Nyum7QA@VuP zY4gfk->K7cS#~8w=T|@M19Jh1`=j=2vyA^?v}pGTa+say(#uW{nw;3}&f_yLTCeS5 zsPeQ5w@>R6?gvh6_6tx&oA&8=B5z+4F*$?iye1F(hOH4B%+Vw|W0B|~WWYm=v(KMg1FI1u4Dx8Mbl}3I+FFo! zJ5H6{N4fOq1=mj`f>f__-{j}Msl|PBP@kB}7wr|orMQp6^3HgDaw%th2j zq)^^|S9}qK5n=vtd;yP+1PmT6Cq(#kjnUzPc6oID|6r#XrOn;>hDcv@cXMQ%t3hV^ z(cKZ&%mW-I1V%)~KnPU>+LR!LFOwEuZG*;Dx1))KRZ6_ca5FFCn-*(ln z$s1N8MnCMG$_bpi>X*$i+^yddQ2Q7bc<@f&QQuf}v9sN0cl{cpO9|SQ5bN)xUi4|L zf-_L!+>O*iP*wR5ox(Pm%@g|EyXseDT#&&ogW1RCqWP^v3ZanN&d>zm7aFI2%g{GJ zEpqKjK|Bya=S#Ng1q*+0n5qvl_318s434GTdcftvZs^W&s_y88*~sVQh_IT7Tc05B z-S!?H&!7bDZEyY|dgSP_OJP3YkIHY$>?A~$(!T_LPe4DgzS&`5emtS{zC4ps*mH_Nu45$|;v`XV6Z9zHrSd zC@j|p2}RR(H61$c`S0XhJSelswL7-{gBvbC#z58eno*Iob>Fv_6~26NWux` z1D`B@tstp3&dn@d+j5p-3~CaUpYvx`Yh_jItI&s1;|Au0=ri#ftzx6~t>-M}9%?Xm zsyK@e5H5A;Wlml>^{q!Q^Hpr9QEX^oY^ZDtu}V!6ehT@;<^&|cmCU>t!U(-F5_(f8 z^rmWJB^2Yu<6>6Qf99w;_BmsvRO~_xQ+d_i#gh9T!-YP7>fO&@@jkN&K;K6 zdpI|mjrFtr$2ZvQg#&6_`qH={NsT!YtFmZLVqH)WhRr#DiTdpG}eLVOoWd7zImXv$NZZvq+YsG(nG3;Y0TIhpnN%3lV zrE0CQQ}`O?%*uNWrUzV|ca4ddq7?`Focjw#>K}A zRPK&?f<`(7uAYw`p<@%jj;6R;-VJa582J|u`I}gTN}}aDYxYME%RQ+Uqpw>dUSZ!n zsytkgkUn=b#ZgWU01sElIVC_#BjKfye@rmv>j`=rz!J5A#4jeSJ`G@PMm?^vyGrHx zjtMA^F({!}jQR?O+hi=#POHl1x7fKo5G-~#w>jG;RjGQZCBy8!ZaA_`=<>o|XiVK4 zm@H#R5neDk|55f~UTGe(Sn)4w!D9Q#bo;?x4k^CK={HO**Eb_Z7TnIzt=;-5ls;(2 z=?HRPNS|k)_WpEg4H>Cpk*+tM1)Iu@Ds|N)3#H#P8&vuYFs!$k<(K3y&rHkIB*Y(I zi;`hx3*E15H0!3|P5 zVZNqX%$;AQKuGhH09QYx#gbEeb9moemftG}uJwpd?Q022GW@uXPv##3G*nd&sd&(M zxF7k1Fg+ROS6nX^dmV2o^YCz2%`u_$Gp727f8Sf#n^Wt3 z#m!{yptY2nxi)j&1L@7jHP<-bDcz!-pmQBRtM^N6?XO~I@rvpB3q2qq)4Kfm>t$bS zf9Qtr>rCwery`@pdcFLm&H4*Loko-0YmCl`^&Ptwbv`wJvY?>V)t;2A>?izJw{Q{4%6JDXt8S=JNudpYmgolin~}sQ?oX?Z*FS+^QUGq z!(IA{9$o$N-B9V&^6aB1*DF1RY<>=_k3MxxpQeka8{0RgEt7u9?1wyC;F8<^nU(s0 zg)|m%j_IuWuLVo|KjotW-1{E=NN2NGTm5eD=2q<&-ZYLUD`tBzJ>ss7TVA7HEnfE) za}g=;QLuY~u0{H;vCWPkbBad`DppxGe#uVmQQ736sZ1*nJ^jeFVYV38S-IG~_R%%b zj{r!(maXh*>z&;kiA-7fVCCK)$-|vCUs+U9D-2{QQ*4rhMA@Kuhr7&B1-G!B^is&>d6kX7(5{;+M!6)~H;! z7F9*`y3x2EMEU99fhy`LjwcHRTT7hobNf%Isv?fN%VkZRf7c?G>yKSu)o>;gMIq)@ z7*?zBZtH10DS!~z6tb=%~-QPaxQPBE62 zT-Q3G`{W8dbLaY}tnbxyhRAb<$t(V2i9gW>+qQV!3H8BdAz$;v8~E7i+@MMEo_4L= z5xL5q@$2Gw>Q4@l+hAWT5n(U1Pt0z^_A&&&C2$%}$JA@4UEO~yONVaq*?gPQ$T(fr z)d%n>qWQJejqKd%3th4`JrZnrr4D_2U#Mjq-dgj8+KCI>!uB%+zab17K*9)b`t~}h zWgLWI*1lTjUk)0;e(+3_fa{A5%s_MU20ksp^|8yTX6G*uHIq~2BqyGm*{qkjQJp(W z-X&YgF8h}Y)w$TGk|`SJ<8kj1$n>X@fq!pVZ_(NEj&O%OHGNe{AIkCw3vaCF9$<_- zCl=m7Pq_FpSYuz}lUz{Ty-qZ)!zQjgu@;i^e9^EV3(22+TY~KGFo#$W1~p(J03z*q z(E*r;g*2HWcy<9iOc}@hOhda&h|Y(lEC2*uBkpm}yK&9JBDyLZ+qrgC>_Uyf0#|R@nJljalrw?8?*7bLox7K@{aQr=vsJoSqK)LhUf7eFz#{_?cP#E~->MCe8Qym>SF7#( zt;gPdpI8@C&PamQ%Fr4@$mH?zvV0h@SbrXXCu7LWL3K(PtDc||ktws~n_6%iIg4uf z8!|R3-HRn&7xF*}cZ@q8I~gOu8wfqhKd>|o3_wI7w^3!lPt_L{ndoK9sGI)2?+6>f z)23I%U(SC_Fn zs$QpQ?sjN*w!9@2;|LP@<9AuzTxX*YqKL-57_J%~RvNbaT)!pJUpo z*d|0UpAlLc+g?kX2cLOEUX*sbx|Tgpjr~&dx&v&8aH1i)c>}^p&fkTP|IQm2&SlMi z-vQnPQBcZ%5ybcCUj()A2EOCE%isM97W4tuCTS6)c4Jj`s^&DH(LEY| zxg=ep2T|Q5(hm`f5jq1|h}QV+xx9kah&nn!%26oOrRe$ykTP9&>!}1?GFX(a5Ui6I zadU#a0bZod72x9qCQnc~Ly^tL+n@D=Rvj`?$ix^nBZzlLRHR%fbzsI)gAt~!MBYX9 zyASn2IJoUHf{v3=_gf>YanwK4f?RI4<250V-Od0(E+mh=|7{zDZ2L#hXg#(AJDKb< zaiSMdg|n5Yg~Di5gGd7Oh!jS$#=3Bk!C@@8X8TKbMx!={?}7Z_sR`wTraXy@1>pRyVgq# z{nb!^3zB))kar+;p1MqA7jcbhc#sSN_NtPH4`K<;+d)|OmR zVeh4dHU%^x-%g`Xx6RsJ`~un&*g)a}&;+QnRUpWBQnowYkcN*7*ns>5&;+QnWm4Lm z8nSt|8gTc&?ix73Q&biO$cIcfm9AICo~VW znd@X-#00(KxkSShdF`A^-o>*>sUgVho(pG@r-n$S3YnpHrd_r=ZnkUZ2!1f$u z4b^lT1MBTdMHU`nLoSRIyP(Q*pD}?a&K7di5~l>7AX_MxiicFCv?&wlg?J`tGcoon z7u4?m>EufJx+>Nl0#-R;d4lW#@R#fH@0$;Y`)9E<=boA&v(%E``oF+B2yDE3kCI4V ziayMIAEc(SzZN&XjXfwPv+MZdruTsMfD}WZ;I~ePq=+B#I(jt9Cn*X#R$ zc0eC3wCLP$ibANZZ^qPp?)m6yT_G@N^bbHU7w^v^xGu>L^#2dg2r>wLTC0iR}uRYpPe#@_db zLyx}(iG{jt%o0q}8GV*iZag{THXBK`Ik@5{tb(V%S2h^6^fBsNS|FruA52Vo;WWqe zUFx6_>}-HZXNXDJz8;CFJoV&`hF+ohOT?%yHXF16$4{+=x*Axlx7y+&m@lf@gfg%L zZ?G?@%*-Ufzi0*dBpxr711k6o>Z3BV=2!fr`3Z zv>3l$D`<)twP0RlhTD(!UZJ0tNbSeBf-@JsaT+o|@9d2eLLSSaDkqjw9z$lI?W)|^ zEp?&GE#NKaNv*q6-+qt5D(O(ZGnXkhv3Cb0;!^(F`4Ar24td%fHS(@IrS`#a z4+c7S0_S!Q*6BJ`l&o1*VsD*Mi|BYwofAiD-A%d4NJKGU*D%&xz4-nwlO3rRgi#HV z?d)y8lXveFkcIH9v{7>#RvNmZqpg4NL6Z;9Eb=zxF z@dB@rx{2=MscM|i&$OtRSq&X;v2*!Q|9EUG+gTEJqi2;0?)d2y_Q)N=+G?)jc@g6a_3wnX+`UZ5 ztE7$_yhW<1moly~wo6seea*E;Y3}jmi6-^;;4KoH%pK9MP#n;(P#_2vqHD+{PD0RI za7R9!k*aBbfH~OOEMD_TFbY>qrn5bTb{tMYJLkkiP62n5V;Y(Kf1%`uc z)87{KtIGB|sb;X!H-P`b&86wQlPV`oR)*~|w&Md8C>uEJoxDzYbNZ@U54)`A=JbuV zkY=fc&=XR(XJ)2ko)Z)~=0dLWQWhW(oS+R)jD>Oembe)Ly z7?xKCO}})+(C>Ox@6v0%W=s>xQ*6g<7FL0(JMHSO9lm~=2le3Mr-y$N)Lje&u|pfQ zQ|(<110(qVDthz>^mTm>yNDIqMS%R*-rpj-D|NQ)8|!YhIvN4f0rdpMRMV}|@!NC2;YB6rs0K|2y7!42BZ$U4$j3bw5bd&c zq(NXxM`1{lOt@XvS64c-$u8CwefmC8t%M0qa2aBoGxZFVvKM!sHEG zkZ77cI_W;Q2}8r0=Yvcw0z$R`lo~g_91~9p-LBTjWF_7JV)JgV&LGlQE^m7Q+C@g; zIs3qupxJM6_kCkfbIwSCOV39?^}ZGt%53rm_?00QK*8WZx^!Ri&bOc{eO&f@m!{v@ zFj=7z9K&@{;G~2|S`0bUyXY7w5Df`};0Y=HUCN227yQ`vB#wuWD62&Z<;}-ASvfGhlix0^-*D_w^Q%wXJcRG5D$p3*jr!(fTq{4t>^5r ztg%6wd_gHbqH|TFCXDx~;8Uv!lQ2z^A@7eFa_Mr*s-7Zmt~dJx9c^)K_2ar>oZCgb z$8bo8TUhlJ*|)ZmiwIRIGGY-&fG4DV;c#jz;3R~2iX762ySUx=f_a|AVqtAHbT~ph zj($}HU|Yx0;9P)I=?P{k(76WjT-#ti?G@CA+SUmEvR-YQzJ})c48AXg=CtlbhN(Oc z3vin|Y~qqq>zikf7?gttwRz~W6*&W6wqjNTB>k4aTvdXDXUd{hX!O(|j-I{X=Go>z z?_QX#NquPi`rl#NL>S(GRqnb_X)Bp>2B#(@El9Vj)v`c0`ZaKrt=Gm(Jb=c6d*JQn%8(DJI3mZi$S>fwDz~Z& z{@HSH1HcNoFWJOGhA+4}YKqAhG5yAFNS_5RuheKi+B=4%3Vx)zZ7OjTa=f60cO6ov z;6WE9$*g&(%M=9$UELtGnI%)`JO`fGkw-vNteW$XDTgr0M{}^yfXZpa9O1>a{(Lc| z9yByty{382_6f9L7k&d=ZCPhgedisM&en!bR?UggWtZi}rC;!5mi$UR{@I`!AYdyYPG| znzFS*cS#_)RsNvqkp7MkZ%CTqdy=a%4;vR(Uv*@$!eG6$FEK zxFJzPObw(3L8DDdZ|f+iS+_#^>2{Q z<)O>U?JIygkW10cqP$iaPw!kgl1blj>nz1qGVmPuC~Z9DyH#iYB)!nt z34B#PeyCD^;d~T0<&~qyLW;?^rQ8q5hI4S@2VBXs41$T!SvrdN2Lu-1&DgOh32in| zAK??>Wa_So2LYN;ZrwnA;?=VkW)69EAP`Qi*pJVJ=%J<(90eB&(N|SKO{(h$C+2zY zw1T6o(+&+~rzBqLKU}@k)LtpVmL(+t<%vwOPhR%^F{E_D+$F)NenLXzYr{PFEFL5s z(S`b8QO2 z=`Ot>HS7y1R%FHz&{>dzvV|vwT9@l|OwBp}P8Qq9_wF?SnODtJ4k7FCJoaQhXj1Dl zEgJkqGB6ju(i5Pz&D{sOO!#97OR`;Erf6`fHD?qb7FI6 z8Us{-DdB`hv-ofx#Eu!%*HsHTn(+l}_mJOu;!XJi)3`DP*YzS(>XS8(;+cr2v2C=S z+pYe@?dmr6PIdO*Mb)*UP(G%l7O{K&6to_YJ;pW%Um_}4mMdr)Of-fd+a_X*DUV#hYQ{quG7jM8**pb%r#xH $@JB9KYr62;X(v zZk@(@a#?R5(Kv^1&D;sapPYXy0kk_6r|>pBPu>7uB>X=F75t+laBsT+?q5mAqxY-9 z{Q7#cIB%{i;Cn^=XbR;pyTcO=_cL~r2Xf9N3+(s!qmz5I!_3HEZOOF2w|4k!m6_J5 zOW`NTe^M_pKT~q}nCvHQKu@cq_nB(#*J=8N5V?f1542S{N^q9rxOA*b7IV;*BI(|T zywKIqlfBh3T$d#uNn%zaQjheGf89nILnj&NyS3OB@JNN4ujEWAk9F;cw(qivbdkZ# z#LHDece92BIsG$8R!QjLHz)hIWM!=EPd(Bxbm>N3;S^V*5~EauFBLNmL|g z7YUc!zvE$IP)t;^;S&UpLL_clzL!FTnanJ!==Uws3gXS}hH|A-z2pJ%k3Y1O>x3my$MNS$VL4^IipgaIf*p5^Xg~(RCb0pUu49+Xs)rBuz55I7Hi%E~*TxDL`f6rM3GV~+wIx^!`9};j&_=L-VsCfJvHw$eLbmSUs=%#c6Pp(V z0VFtul}{d4A2-~Wr$*Az2t{U<75Uxt#HHqRe8dBhTDopZ*hlg^ubPLFSnkAM`<}{u ziTP{od>r0xf!_W!mZzl6DvfB2X*3by?vNO?>G z^k}#8g8cD@`;tkbl!&^20FSnH=SGn={w={I1kA7{iVBF5!{{Y@`Nr!CXYWrul>SvP zDuqR|jMBJ6BTk_Gd#O}*#t}Z^4%Itk=(l&6hrh#F2L^dTXe)k zdX`V3NH7pId_?7YiH-|B+EyN8f2{Z7pautsyG)n|aMlVF4<2ntRN{^(mtoj(aYV

GeJPyRI;G9f9ps{4 zEm%)2IAtx_%XEIFO?7;?Y9rdxvuRIUP@KI@RUaX1Q@`a|ZF^LOtGL_CRE68N_a@?n z1r@wc;<|QUz!7f+MNw|Fb$cf)5v zG|#7{=|=J_(|?BZ%&@jza zz)23GMr;JJ!%Z`E9XBf0PGa%zdO8=1zGMA#d4_Z89|zv@EUPq~t`&rr4iW2RheGFn zTRNd0_Z(y=l=8R+-Hrniss5SvqR8;!JhNUR&TCC4MKew81f22uKgeul;v=R)dzeLD zmjqfW&+|#x1TiC@RVX)dYu+HH^|PcjyFa}4bH!`D41LX?SJU%`E0klbl;_DA?!YM< z^WqhccWB=+T}O;VC#5OiMy`U3X8s+@T$7FoDH&yX1WqRdA9nJ;&_1v#IMJxuS2+A` z*P@^@;R9udkt2lO+7I8$&dz7N5L<$1>_}i$3GfEhAW3=_%WnThp+?2|2+CaM zOC8Pms^L>AF+R$9Hm+9zGBe?nN`MbQF28h862J6`ebOZ-hl$fPGwa1=xJym19_^{sG_{W&N^f`A+U}bY9TU_``DKN5V}T9p zT5%37qb#7hbx*KQ=QA)YLvN+%8{KMfqm2NuK6t-mR z#es51UxpF*&DfW7K(UPWeNzjMozcx)F>8et-v*h^2R%U~NlVf9 z(pbWuis232%7zjQ?)l?iBXUGGScL2kI=K2t1T4?U(E{*nh?cC7V8xqz;SH`XwoejK zFKdho2BI|dj4W-IE+6xuNv8)YF=>zKyEW^$2xG~+E6KD?FXn5)(v$`54=!24(lVi? zXG7{bFY#?jn_1_IOYwlju_*v?DT}Z;ZKAjqmu6j}IBD&BP37Xl+1;}i@gMnfIh>Eb z_~Ok_3TX08x7}MbcA+Q&|8!~~&VpmC(@nmMW%C%5h$nM;WsHo=BS|XI-z>`|wlI6n z4z--JWn*(4lc`^{!A~tS)ORp`*A}Ig{84t(1~^~^5@FFp`Iol5+4ZH_#z|}>VFWBm z6AqU2b%K^`UnVYj_7fv%Nm&!ou6m$J|%Laaus5HQX zeNCUXFX{HEm{=w?aXmH`u-?l#Xg%-~h*ov!mu-9C4XSw)HMe*PG!JrwGzUL{SV)VL zocP1!Xuh9cssxb(?k{BMk~|vt2Oywb651ML?f!slDBTv5m?CWE@aty3XI)?UOZW#M zHx=ETc-V+|3=z&T(a_!nxy-e{?GIjJgN)pO0O8K0ootu=kmV}GV}RZ0>K_o>4#j|N zy(@riiHSe{$5JVO056~rpH8UjQ~B{K=(er z1%GPM{Yk#In^Xy}1#b97L-KIB-x=e*nVMp}{s1Ht-lZB-lz5E4l)p)TSDGnyNdQ=v z!Oi*`dI*BpCY^*mMM(nD@@KTrT}Q$2U#+*!1*GRjW*5w8XpB=%wX%5gK8bw`32V4} zVNCJXW4z2z>#ef^=_wHAr8>ZTWvS#Ii+Mv_@cdZAO@QGNZ3=Y3w#0Wo>#e=JDZ;s5h){%Q0jhFV*6AS^(CBu0iyR`G7HA~v z7tg7^B4F&$e<=eHB_Z-!p-JKl$Y&-_33r=fg8#q<$TJ#kgsz)IuehKX=0JcvQUi2IQ3Ua_e!@o4_m~^D>M->12ZdjbU==lESosWlqs~ z8W1Dzk>hNlt7MAI$??(^{^=s`06%m006#h~KW;>R)<^G%!~9tLx>z*=eb|D5K2hTk zKlh;!84Jmm^26+b`9TfxJcsys7!3Hi1MxG;MC3=%$(9P{N0USQ4_?3zG8*t>gMj#H zhy2zl0n-?VBJ#tu@%L*lmvXNXyp@dl3(}~` z)yWH}JCHS>=$4F{s$-fjPTM_!Xk)0Cj7H5DLf`8aSQ<+rT) zUU`E|?^^^Zfr=25n1J-ekZkAMewv<$xHSZ`tuKEF(5;56{qF>fE>IHkHNa(SYJ4}! zX^^RfvAeJ{8WoWo?~Tztm*;iHj>>bJO_UxNL93agJ-Tj`wf5lsfm>Xnwp2Dd+5>+B z%J1PZUJBHb#9Tu+qTf>GSA@v{+JD!5v?Ln$6Wwf|J{EvdG_ox=@WfcX2ekgKJekwq zqg2iyJ8vnb3>5pKJiRm)gL-=tqbqm6EShMcXfn^9PzU+0!uQh9s)a#R`BIvAx2S&- zSnIGO@FXKcj-L{+cy4xvt44l?s|YM`s+svJ&B4O*sfZjBaVG}G7x*w*3a~5R*Sp#d zyE26G+d&nu3>*e1#eYDlkx(Mv(w8i2SLoX#xQSkNVb>n=?TC9QK@TB$b2D9D@_aiA zr=j-0wk*})d2N~lkw~(_)R$a0mzNWj{}W|F389)&sswYheu*+5eJrd(9>u~@#39-Jqakp|EONF{c~#X>X-RWSnrc3U$)uedJfW{=aoAe5z1UUI+F1Rn-R zQs@TJcrrBO-)#((7v7(0@2mS+FKDT}K#x==StXVf`*s`2{;BAm7AQ3M9zRAU;&SZ~ zpvi}#pQMv0tkcOt+OM{Mrfb@w@fC?iseRLVKbWZU4myO^^9>+I`7oZl73v+` zz@f6QuQUwao6G#}*z9j=X|ytb`kX^gY3VSOWkIzyeRZ1oDuH>u+<@(&+0U4&h1>K9 z3ntn>$6tloe|}b{q1yCo-`zx|qkMG!M-G6>rleIjNJ;hS$jiq9oF{>QsbtJ_OBTn4NZOX`rLYY(Jw+-vjfdy ze{&*RkL&vKz>=H5hSIuN|8yj4(Sjap*Ld5evBY`DGz#n!R9w29U|asF7AFj&_Jl=7 zoA<|g0eX?e?lcxEaV@rr&biBLf7f{uq{KtVhYyksIAWC@FTc;jw$^@Kf0wc8wbc7` zo$b-4cgE&EaR!Nw$|p-!ht?kb9eUxF!IzKA=!u;BU$jKoB(SA!DdBD}$)eIe<04mt zlg;0qQVRFHBiPm4#CnB~u$b%e#i>a299veTh4UBbw2`i)<=h1qW;)h9`-kAm(3t>{ zryLHWRP6`dm3oyPJ@0ObX|qhD62yNiXcRYdP<|$jrIHj;$$rVotUbUjV2XR?a{86> z9((AZGXK^nH|meki#9dR60kf8d;xl z5#e-HxYA24+rv@MQ9m0Z&>n|?_bnLU-mu{hQD9DR1Po?xqp#*Mou-p?7gRxIq&qHrLq9JH5y z-}Q#M-x6Es8fNl&{IA!(mL-yYUCUt&^k#O&!usUA2 zAgH0b+!XeULw@;rR(g$U*so>o6tq4n+bsRod)k-r}rBFL_RXe2*MBZo=QL;%;8J;Qr8`?Ru>h-=|Z*R5KLB zDL1dE{CZ8$URyTp6gp0LBvTtx9JZ!$-K-z4wDQu^hXyO$Vu<03$vJ*Jw*M#U110OB z7$F-oa_lqIy+^{grPs_$`yXSIsVxcwizmGBHCV0|dd$kytLdx+hG}TgP(_X0;R2LP z6bo8oL@_)s=PABau(x}3O~6(tO2TXyPisQa?&7eadDqWn?*cXqbu)=ibFO=3Bq^_d z-*M|K3D-Cr-C)iL{(5V$Fk{t;U^JK{&5&LoPFpsE*1L*Cyc(+=0= z<@Ymy6+PM`zHDMZy(K)nv`E41*+}cQGH5oVmu{E5x0Jt~=H8AjC1fWnXp^)>i?=`P z`q{^vDc)`cZ@oyw9fN9YAKn&m|IuqHm)F;~x6`k_pUQlDLBx5td&mKsW7~Ah)!%9V z@gM)+|J(l`=_=h}k7BKk!GJ_NSliq{Buv6g?C&=ax8*6bi{(PcOg3m%wb*Ra(;I45 ztHag&>Z2-4G9Dd_p*aeEE&h*r-Meuk!oFg+jAz7_@6XvAQ);y>gcE#!J<@x0WpPey zG_NE~*e^w~tmc(CCT*-y?sl&ilSR8X!IJG4Mj7X@PrKgh-KJ-zUTGq^;b0|m*}&`- zGYJMi?&z3irxDfJ{+dWM>KJ?@y47R1^vnrLTtmp7)v6!_k}~b95J{6=Y_8pES7yl z)0c%zO4FPRf9g8Izx5~0M#kimHSV8y_K(h`CT^Z z%@si&&1q_FUa#H#U6T!6ORGNj-Y$Q6|CYF8E*a!Lt@cklBz`wLbFpjwR~HXkTX%Qa zDg8xjt3pElz?WtZA)w>ZxtQD2Wi7+n=~Da4#dLS`o{+EK{o(VR-x8`&i~rr|n*Y;A zM&;@nDE)A-wKd(pClm~*ZuJ2I&s|@E_t!H|VQbHxuY-W+Z)cDFN_Xv#HEYlJ_rN#Y zXD`4NrPqfmp_l7Qq1S08(7q<^z-tm_;4t&pNgHr;=c3Dh0_+vgXHc+JG2C||1?yhlj&!tZQ=5nG@_EDW69Ym|O{n1BeIZsx7GX6~ysyk+9O15Np`ru_$$WfinQh6G z5ex@=;k+)gjolm4+al>#ldw7>B!|EU*X^rl>>((R@CFuEw}fKVKobKf&>KEe{mD$Uv6@> zws5du{{7DS%QvH1OODH=XwQK!kejWYbFH+^D%BYpB)S@hb%*R#7X_X35L`AdZMZ%T zzH+&i6c$DhTkK)%>>Y8#W$k#-sKJpOR(94#+GuDv+a^PsoWL8GS1<67acLoGyHVvE znCR!WR|goC=Avv6N&J}fEurB_y$EFJH0(HUyhPF-adzHyt15U!iN=s%J4nWx>98kl zBy}!kxAzIf=5mlWzvHnC9*hXaj3`K8O89|>#`1+WIxHBCc72!fG9_V3EGabLQtWFo z>i3OSgBSF7ZA+>s#4HA4a<8O|`nfQ|J81QD?f6=dT|Rqn1&cNbHoblE1A>GlSoN1& za9&o+s$h!oQ5pf20&_R~o#!7&nzbs1Oy(C_>LhNsro(u-~ z(n$wHhBWWe7QPiQM1SXq+LK0f^Qk7Ob()Tml?`&n#A>Cu{fMF@FGf`s^)fu6QdACu zSE0L=?J(TkHbI}#R-1XQvzPFQb-fXoIkX+OF3MLho}wieRZT2^5>+ z&TgC?-tjESRKdII_4$d9d z?$2=t4$Jtd=c3Bo!=3KOzjn~6yeuEg-2m+MjYowjPxVMo=)ndk)Bv2t0~0 zHQdG4k0s!hB-FJLqT@*EYWDPxsd%bZJDd7qO?ow`cl?~*k~2i4wG+GQHXL%}o9gK! z#*)w2SJ1dMRp{N1M*`L7Toc~Hn>gcZ#=U>0Yu-YCQ+}tkG+6xr`>UZ@x}n=vqQ!IDbwZ~yd!LgYQ)Q3V(6O$k1njU4@> zhwpo9v&Z+CW^Trjg$T&-86*@>v95qtQ)D=Dd23eD?{AKW`;bMeB}MT+gq&77WpA_9 zG+B8!RX3M4mAwXZlis*mSXx+sUeBew$CUtscFPab`nIFYOkW7_gj5Ks(h;?AD#w_8 z-5j?s3lQ^)B+E5@95)V^YkNa>8{?NoX9p_BUyl|v%N#_eLuMP}E0<0P+VKhO3?7=i zK2*4wUP!ut3qDl#796=a+`Ao=Rn0~h>@LsD&W&0=J=U@|Yi8g#3v#!!m>TG`G)@R| zn=U1G?Cy2}vjJRIJ$Y(3(-eE-b-Ux)4%r@l&U|C>KCmyV&VoGrV>#1q?qe~vvrSl>zHMMRKF34P{e%8H(cz?(PB457B!9^=1zq8WYlv+;Xx)AnJBkIV7drtKM? z;y$u?+%jWr#K=ZB)p5;QxBu{7mi{o)3==dA*SB3RO0`UAw?tGcTx18j3RsbZx@#d- zmVaFQwg^A0bC)y^y^_~-D}wC7sT`V=LUIf!)HT((&PomXq8pupm+-7m_%_>5zK)&yhhI679l zN9hA8+VNv;pw&tQ5`ePFkdzOEH+&~NTvhDB&w+Oq*O^Q84B8&w{Z8|gVquwWv3AF1 zkAEM{ws5!}4mV;4h+OzeptIt>kKPw(RO>im@DUAstZhdBv5?m}OVYggjB|2DXCj$6 z?U*bEV~i^DV(aWF=)B{O*Vjyv<$I7;{t&iFAHwWb3!JJONmp?j*pha<0rWJdmJ=POm_2A8aBGv&& zS$o6o!PxSJ-=?-eWf)4|_+BD#1~wv^wQjV`+FwDXwV5vYF4(`^9WOi3{ur&zP<^MT zZ|zUycTY0fSa4qB4=~ixkGl#U-+SX&moc@q#J!wk@a#+pbc^8 z5Bu2A7o|4(*v_vsY1K`_iry(>GDSY#ICs7vI5K+H&4+bG)`dp3u-~eHE}d_^B*qqr zgh=d}IGJ1QMY>6d+skT2v=m0nJ{|sLm*2#FU!obw%a=zy3{`EM1rXep*Kf38Mxs3r zc?U1Q0xOLDGtgy9DZpn_gfz|+?f_QxE{lnEgY?HZ94mOm25x^(z;2@_n zZ}etBiad`tjL*UuW)A}g%Uy%LaoBOc)_WryO=uxC+wWbs{YHu{MeRE|pFVZNlg)ck zFwYpLJFrYXHM}LhgQ-GTB$BR)_0Gk5d14NgmKA+L9rN}&R%9Ed7(d^Mr>MH6ooBw{ zlKhw}mirZ#gh4ejP0A-X{B8LP@21-40JasWQ`Bunj|u7KI5T2$1;<{5Ec|X$SflGi z3G{Ksal&R?PO;67vNP5kbVtLwckS#%)kWWg@v*9J9jfLD8KeW5LZ=jEzi3JiP*jV? z16ED?=*VlLu&9;`1Q>Unx$t?{j61hmqH5mULdOpSSB&1WKtph?WhqPBeJ1l6y-BbP zdwO#R|M}DUC%b94!AQ{-=(h1r>Tts0>@jePLv2XRFwgWLb>9IJ-S1oPbi!c9lkKgn zX&EFaXE|6xa4=X+g7v)Ey!YYv#09nP)qdnqRHvXYp7%WI(O@v{1;!^a%w-Ixaq_fc z7H1MiE1<%d8K-g_cs#oyU@Q`Sl2R1OrwuzDqS1c$3ljufk|330 z&EbWaZ?Hi3lX^VPzJ}<5xn@#~gu?_)bY@L1;=y&>>XdhF&5oQaxAedSH{il;>Lmah z1iK)>fJ-8+%JOaFJA%=XKY7@eT{NN-{bIhvkv^qIhYNEEuvz=lm?+^$nHE$O`?(-% z+${B23yTl-lVh2JZB5T{_m~XRhqyk*+W@Q`gO~jH_>YPBW~-?48b}G)E8Yr5 zP3hkqY@&v#S7Ns=^P9{le&Kl^F;1`sMWNwq5_;#ECJYd{ZIJULef*YIJd1t0%8ci7 zV?zf|;&q_mK{K7VtNs%w)Ob>~;HaQRHC{PPmFI`v^(NB;Gw6|3CMk|m_QCT$qkP>HRGe-cG&@OMOG4v*V0OOA z%rzwIoluV3jj?a@@|4jepbbZ4BzLu|!{pcxsnrwdTNeLoMpBi7u(+_@aldo|+SV2d z|M{}B)Q>f&LV3Ed-P@@p#Rd2tR=~&yt8J~^yrClzqJg8e&bpW%TF{GY*EQ1Uij&B< zy#W$<2#~AGhi9L4+V4w0^i>Oizj_c#eueR8;ZRbXrH=KPAzq-H6F+%=>-3SNTu475 z1gV|8z3Sr_N+cY>*qF-`!ZgbaAIw0%wg*Y{ZMUps>BC&#aaDL#3F{#E6;062Y24Z8WG1o+!ME7YS&G4L(+C+qULPI{ zJCHHC4H|y1cYVD`eh_N;crQ}x)wRZAlwr&$@{>Vacmj{z)lbfSQkAOFoWcwncjN(ro;kA1?hLZKdwJVssa6h_d zmMbJWFCht3F;DK&RCiR5HE3|2(=zpM1#BFpTByC?v~g~vHm5@fxR)Y=&9gc4{p(_D z^@_@cMU2L3vP~2ZKXv(iO@KBhnM{DyR5#5hN5fnV+lG@LZ6>0}62hT+hdX+og`0OlL-u6WhI#KvL3Hdc0XfeA6>L3Bzfc`t zii3vQ;VX0G6q>F1=tEIWXQ6?N!!~W;+PPLp-pZeOBf8*ixdv zG3~8urZa1!i1L@XLT>DzEpFfz+m)SguYKFZA4eH2@kYU>DWQaaa9h!RR!ONP){p-B z>UU~S3b+1AeG0a4C7BD!y+=3NVD$V!B`un<>LR5(uKkmLuVbiBY>7{4Rq?RE1AXtP z!DXiUXMxqbeA8Do?>5aQ>Xi+uhvZrPjHxitC*UT;pD;1qNIrUOX z{d{MSPL`3K7#L~k-B!wa)~oOowV?02)AHyV>m1kX*}hDL#B1WEv2+Jj!KH<$uWumc z9iRu=_f9V2VcBxSU?KZ$4PM4C;ApaRnB1{aL9@#YjViKSU%N2;_dR{CVy&}IRro?% zP49B9EU1-&zRWN5-j0o}@-vUQ2}CxrvrxF6F8x>p)QJ&*ci}+6v!@~X`ae$ zh@?_UaWj39v0JL0J@PSR;Yp{yX5GBu*83ch9~#)D2=O&3*Pt-iQWj|^T(u1jdm^x9 zGF1`Eb>5Jd%^iNKL0ieBM-6W;^QR$TRiOZz*Krj&q;~Q}uojk7O1--I&^azj9df&Q zbMk&8=gM`NurT4u7{%i;o-JR89m-6_-UiMV*$^M53Qfo@ker*Pcp6+pjE@LyM5YK5 z<~`pBYJI*XGd>Qkd~0vD%D?}18UQVa~IjMZ%Bz;)EVqcB~~DNKIUk)tqQ&8axC zowx_2>Ss4@QVV?#$f*l-fPn3jLjy!Tz2eVlk=C3;Yuvj5t%IHt6(YKJU@(6r62=#Q0d4-Lp4?A->$FAv9Pu)XjwEt6V&iAQO?b{@_7E{A$sUAL3Ve44fuer{q8 z?pfZsx48rM?EdjV$-B+nXngMU2^hYGS+bf)f@)zm zfIQKjT_isI(HGb7NPv4n*WW|Q&GVX;+G=vBJ4bX{j?9+I#`{!FGJyGT-IDalCBUFr{Zl8fVLfws z9moEISY2jhXL*D8oDIouxDgvHUd8)lLw*`osShq2~L%8fjqYs~l=ssEaRas`%&B7Z? z{^!6>M9CsjbP57{ttmL9Gs!9nUUEzH()dGyd*=_h-jk0u=u;O8y1`q7^J|GU3zQDD z37@7D$>E8RX%pm22!!azzh;nzCpEz*u;gcu4kk5SXuZL6#iWc^gKBqy z6g%E;bS-t6pH6n%9Nc4vZ)BZ*UIGqI;wsuv5EY+_HGWK%-K3lHXJ`iv~qz ztmJf;h-$RAb0}�i0mf^R&xt*{kwC5A|chJUHZ^za)~0~ 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 literal 0 HcmV?d00001 From 23e37d1c4d0908ad14aafb8ed953b38773b7954f Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 27 Aug 2026 08:17:01 +0300 Subject: [PATCH 05/11] test --- Inc/protocan.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Inc/protocan.h b/Inc/protocan.h index 99fa270..43ac9bf 100644 --- a/Inc/protocan.h +++ b/Inc/protocan.h @@ -1,3 +1,5 @@ +//тест + #ifndef _protocan #define _protocan #include "main.h" From 01de7651e84e590e7cddc172ee5c391a1168a3aa Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 28 Aug 2026 13:45:39 +0300 Subject: [PATCH 06/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D1=83=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=20=D1=8F=D0=BD?= =?UTF-8?q?=D0=B4=D0=B5=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Протокол CAN и ОАП.md | 13026 ++++++++++++++++++++++++++ Протокол CAN и ОАП.xlsx | Bin 83058 -> 103216 bytes ссылки на док.md | 1 + 3 files changed, 13027 insertions(+) create mode 100644 Протокол CAN и ОАП.md create mode 100644 ссылки на док.md diff --git a/Протокол CAN и ОАП.md b/Протокол CAN и ОАП.md new file mode 100644 index 0000000..0f2867a --- /dev/null +++ b/Протокол CAN и ОАП.md @@ -0,0 +1,13026 @@ +# Протокол CAN и ОАП + +Таблицы перенесены из `Протокол CAN и ОАП.xlsx`. Цвета, объединённые ячейки и структура листов сохранены средствами HTML внутри Markdown. + +- [Интерфейс протокола](#sheet-protocol) +- [Общее адресное пространство](#sheet-oap) + + + + + +## Лист «Интерфейс протокола» + +

Таблица прокручивается по горизонтали; длинный лист ограничен по высоте окна.

+ +
+++++++++++++++++++++++++++++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
282726252423222120191817161514131211109876543210 DLC COUNT 76543210
Fields  DLC
ПриоритетАдресацияСообщение  
Priority (1 bit)ПМ (1 bit)Device Type (3 bits)Device (4 bits)Msg Type (4 bits)Body (16 bits)  
0x0. Критический0x0. ПМ0x0 Верхний уровеньNULL0x0. Широковещательные0x0. Статус  0 NULL
0x1. Стандартный0х1. Устройство0x10x0 - 0xF устройств0x1. Запрос на вкл/выклВыбор "страницы" из 64 устройств (Битовые флаги в Data) 8 64 битовых адресса
  0x20x0 - 0xF устройств0x2. Рестарт устройствВыбор "страницы" из 64 устройств (Битовые флаги в Data) 8 64 битовых адресса
  0x30x0 - 0xF устройств0x3. Установка времени  7 NULLWeekDayDateMonthYearSecondsMinutesHours
  0x40x0 - 0xF устройств0x0 – 0xFFFF. Резерв NULL NULL
  0x50x0 - 0xF устройств0x1. Дискретные0x0. Аварии     
  0x60x0 - 0xF устройств0x1. Предупреждения     
  0x70x0 - 0xF устройств0x2. Управляющие сигналы     
      0x3. Флаги     
      0x4. Рестарт устройства     
      0x5. Изменение режима работы устройства     
      0x6. Запрос на устройство - перечень параметров для отправки обратно. Возможность создания запроса с конт-м колличеством параметровТип Датчика. В Data - 64 "битовых адрессов" 8 64 битовых адресса
      0x7 – 0xF. Резерв0x0 – 0xFFF. Резерв NULL NULL
      0x2. Аналог0x0. Универсальный запросID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x1. УставкиID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x2. НапряжениеID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x3. ТокID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x4. ТемператураID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x5 – 0xF. Резерв0x0 – 0xFFF. Резерв NULL NULL
      0x3. Общее адресное пространствоАдрес регистра (Стартовый адрес, если DLC COUNT > 2) (0, 0x0000 - 65535, 0xFFFF) 0/2/4/6/8 Четвёртый регистрТретий регистрВторой регистрПервый регистр
      0x4. Modbus CoilСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15)   NULL
      0x5. Modbus DiscreteСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15)   NULL
      0x6. Modbus HoldingСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15(   NULL
      0x7. Modbus InputСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15)   NULL
      0x8 ОшибкиДополнительная информацияКод Ошибки 0 NULL
      0x9 – 0xE. Резерв0x0 – 0xFFFF. Резерв NULL NULL
         0xE Settings2BYTE1BYTE              
      0xF. ПульсNULL 1 NULLСчётчик
                                           
                                      
                                           
                                           
                                           
         0xE Settings2BYTE1BYTE              
0x1. Стандартный0х1. Устройство0x7 0xF sensor programmer   сборка(инв1, инв2,выпрям итд) позиция в сборке(VD1 VD2 итд)      ID temp sens
+ + +## Лист «Общее адресное пространство» + +

Таблица прокручивается по горизонтали; длинный лист ограничен по высоте окна.

+ +
++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
НаправлениеОбластьРегистрыСодержание регистраБитыБитовые поля  
ПередачаПоказанияОсновные данные0x00000Номер преобразователя ПЧ    
0x00011Версия прошивки ПЧ    
0x00022Статус ЛСУ    
0x00033Задание по мощности     
0x00044Ограничение по мощности    
0x00055Мощность (МВт)    
0x00066Задание по скорости вращения    
0x00077Обороты ГЭД (Об/мин)    
0x00088Обороты ДЧ1 (Об/мин)    
0x00099Обороты ДЧ2 (Об/мин)    
0x000A10Частота на выходе ПЧ (Гц)    
0x000B11Ток фазы U (А)    
0x000C12Ток фазы V (А)    
0x000D13Ток фазы W (А)    
0x000E14Средний ток в ЗПТ (А)    
0x000F15Средний ток в БТР (А)    
0x001016Напряжение выходное (В)    
0x001117Текущий ток в ГЭД (А)    
0x001218Подтверждение выполнения команды (Код команды)    
0x001319Ошибка при выполнении команды    
0x001420Счётчик отправок основных данных    
0x001521Счётчик отправок уставок    
0x001622Счётчик отправок данных датчиков    
0x001723Состояние0Готовность 11 - зеленый0 - серый
1Готовность 21 - зеленый0 - серый
2Ёмкость заряжена1 - зеленый0 - серый
3Неисправность1 - желтый0 - серый
4Перегрев1 - желтый0 - серый
5Ограничение мощности1 - желтый0 - серый
6Управление (По мощности, По оборотам)1 - по мощности0 - по оборотам
7Ход1 - зеленый0 - серый
8Авария1 - красный0 - серый
9Сработал аварийный стоп1 - красный0 - серый
10Схема собрана в режиме аварийного хода1 - желтый0 - серый
11Срабатывание предупредительные уставки по температурам1 - желтый0 - серый
12Срабатывание аварийной уставки по температурам 1 - красный0 - серый
13Неисправность СО1 - желтый0 - серый
14Авария СО1 - красный0 - серый
15   
БСУ0x001824Температура объёма БСУ ВК1    
0x001925Температура объёма БСУ ВК5    
0x001A26Показания УКСИ    
0x001B27 Статус датчиков температуры БСУ 0ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК5 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК5 - Статус инициализации  
6ВК5 - Предупреждение1 - желтый0 - серый
7ВК5 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x001C28Статус УКСИ0Связь с УКСИ1 - зеленый0 - серый
1Неисправность измерителя1 - желтый0 - серый
2Сопротивление изоляции снижено1 - желтый0 - серый
3Сопротивление изоляции аварийно низкое1 - красный0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
0x001D29Сигналы - Устройство коммутационное
проводное цифровое (OUT)
0Разреш. Вкл. Автомата главного тока1 - зеленый0 - серый
1Разреш. Вкл. Зарядного автомата1 - зеленый0 - серый
2Квитирование (Блокировка аварии)1 - зеленый0 - серый
3Тест лампы АВАРИЯ1 - зеленый0 - серый
4Авария СПК от контроллера1 - красный0 - серый
5Управление от СВУ1 - зеленый0 - серый
6Резерв 1  
7Вкл/Откл QT11 - зеленый0 - серый
8Вкл/Откл Q11 - зеленый0 - серый
9Пуск УПП1 - зеленый0 - серый
10Вкл. Насосы вод. Охл1 - зеленый0 - серый
11Блокировка дверей1 - зеленый0 - серый
12Включение обогревателей1 - зеленый0 - серый
13Резерв 4  
14Резерв 3  
15Резерв 2  
0x001E30Сигналы - Устройство коммутационное проводное цифровое (IN2)0Состояние QT11 - зеленый0 - серый
1Местное управление (ГРУ)1 - зеленый0 - серый
2Состояние Q11 - зеленый0 - серый
3Местное управление (УМП)1 - зеленый0 - серый
4Работа от УМП1 - зеленый0 - серый
5Готов от УМП1 - зеленый0 - серый
6Авария от УМП1 - красный0 - серый
7Блокировка от СВУ1 - желтый0 - серый
8Авария откл. От СВУ1 - красный0 - серый
9Мех. Тормоз вала1 - желтый0 - серый
10Готовность БТР1 - зеленый0 - серый
11Ограничение 11 - желтый0 - серый
12Ограничение 21 - желтый0 - серый
13Ограничение 31 - желтый0 - серый
14Ограничение 41 - желтый0 - серый
15Авария БТР1 - красный0 - серый
0x001F31Сигналы - Устройство коммутационное проводное цифровое (IN2)0"Тест ламп"1 - зеленый0 - серый
1"Квитирование"1 - зеленый0 - серый
2"Обороты больше"1 - зеленый0 - серый
3"Обороты меньше"1 - зеленый0 - серый
4"Приворот"1 - зеленый0 - серый
5Авария от УКСИ1 - красный0 - серый
6Обогреватели включены1 - зеленый0 - серый
7Резерв  
8Авария системы ВЭП 11 - красный0 - серый
9Авария системы ВЭП 21 - красный0 - серый
10Силовая схема - "Собрать"1 - зеленый0 - серый
11Силовая схема - "Разобрать"1 - зеленый0 - серый
12Управление - "Задатчик"; "Монитор"; "СВУ"00 - монитор; 01 - Задатчик; 10 - СВУ
13
14От кнопки АВАР. ОТКЛ1 - красный0 - серый
15Направление вращения вала1 - зеленый0 - серый
0x002032Показания ВЭП 10Контроль ИП1 (питание управляющего контроллера)1 - зеленый0 - серый
1Контроль ИП2 (питание периферийных устройств)1 - зеленый0 - серый
2Контроль ИП3 (питание эл. замков, ламп освещения, ДЧВ)1 - зеленый0 - серый
3Контроль ИП4 (питание датчиков тока и напряжения +)1 - зеленый0 - серый
4Контроль ИП5 (питание датчиков тока и напряжения –)1 - зеленый0 - серый
5Контроль ИП6 (питание драйверов)1 - зеленый0 - серый
6Контроль 3х фазного 380 В1 - зеленый0 - серый
7Заряд накопителя1 - желтый0 - серый
8Работа от батареи1 - желтый0 - серый
9Авария в сети 24 В1 - красный0 - серый
10Контроль питания ЛСУ1 - зеленый0 - серый
11Контроль питания 380 В1 - зеленый0 - серый
12резерв  
13Контроль питания СН1 - зеленый0 - серый
14резерв  
15резерв  
0x002133Показания ВЭП 20Контроль ИП1 (питание управляющего контроллера)1 - зеленый0 - серый
1Контроль ИП2 (питание периферийных устройств)1 - зеленый0 - серый
2Контроль ИП3 (питание эл. замков, ламп освещения, ДЧВ)1 - зеленый0 - серый
3Контроль ИП4 (питание датчиков тока и напряжения +)1 - зеленый0 - серый
4Контроль ИП5 (питание датчиков тока и напряжения –)1 - зеленый0 - серый
5Контроль ИП6 (питание драйверов)1 - зеленый0 - серый
6Контроль 3х фазного 380 В1 - зеленый0 - серый
7Заряд накопителя1 - желтый0 - серый
8Работа от батареи1 - желтый0 - серый
9Авария в сети 24 В1 - красный0 - серый
10Контроль питания ЛСУ1 - зеленый0 - серый
11Контроль питания 380 В1 - зеленый0 - серый
12резерв  
13Контроль питания СН1 - зеленый0 - серый
14резерв  
15резерв  
0x002234Ограничения мощности0Ограничение мощности по току1 - желтый0 - серый
1Ограничение мощности по моменту1 - желтый0 - серый
2Ограничение мощности по температурам1 - желтый0 - серый
3Ограничение мощности по напряжению1 - желтый0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
0x002335Состояния входов датчиков оборотов0Состояние входа датчика оборотов 1  
1Состояние входа датчика оборотов 2  
2   
3   
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
Блок БВ0x002436Входное линейное напряжение А1В1 (В)    
0x002537Входное линейное напряжение В1С1 (В)    
0x002638Входное линейное напряжение А2В2 (В)    
0x002739Входное линейное напряжение В2С2 (В)    
0x002840Частота входного напряжения выпрямителя UZ1 (Гц)    
0x002941Частота входного напряжения выпрямителя UZ2 (Гц)    
0x002A42Температура охладителя выпрямительной ячейки UZ1 ВК1    
0x002B43Температура охладителя выпрямительной ячейки UZ1 ВК2    
0x002C44Температура охладителя выпрямительной ячейки UZ2 ВК1    
0x002D45Температура охладителя выпрямительной ячейки UZ2 ВК2    
0x002E46Температура охладителя резисторного модуля UR1 ВК1    
0x002F47Температура охладителя резисторного модуля UR1 ВК2    
0x003048Температура охладителя резисторного модуля UR2 ВК1    
0x003149Температура охладителя резисторного модуля UR2 ВК2    
0x003250Температура охладителя резисторного модуля UR3 ВК1    
0x003351Температура охладителя резисторного модуля UR3 ВК2    
0x003452Температура объёма Блок БВ ВК2    
0x003553Температура объёма Блок БВ ВК6    
0x003654Температура воды выпрямительной ячейки UZ1 BK11    
0x003755Температура воды выпрямительной ячейки UZ2 BK12    
0x003856Температура воды резисторного модуля UR1 BK17    
0x003957Температура воды резисторного модуля UR2 BK18    
0x003A58Температура воды резисторного модуля UR3 BK19    
0x003B59Статус датчиков температуры охладителя выпрямительной ячейки UZ10ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003C60Статус датчиков температуры охладителя выпрямительной ячейки UZ20ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003D61Статус датчиков температуры охладителя резисторного модуля UR10ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003E62Статус датчиков температуры охладителя резисторного модуля UR20ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003F63Статус датчиков температуры охладителя резисторного модуля UR30ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x004064Статус датчиков температуры объема Блок БВ0ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК2 - Статус инициализации  
2BK3 - Предупреждение1 - желтый0 - серый
3ВК2 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15Блок БВ - дверь закрыта1 - зеленый0 - серый
0x004165Статус датчиков температуры воды - Блок БВ0Выпрямительная ячейка UZ1 BK11 - Статус1 - зеленый0 - желтый
1Выпрямительная ячейка UZ1 BK11 - Резерв  
2Выпрямительная ячейка UZ1 BK11 - Предупреждение1 - желтый0 - серый
3Выпрямительная ячейка UZ1 BK11 - Авария1 - красный0 - серый
4Выпрямительная ячейка UZ2 BK12 - Статус1 - зеленый0 - желтый
5Выпрямительная ячейка UZ2 BK12 - Резерв  
6Выпрямительная ячейка UZ2 BK12 - Предупреждение1 - желтый0 - серый
7Выпрямительная ячейка UZ2 BK12 - Авария1 - красный0 - серый
8Резисторный модуль UR1 BK17 - Статус1 - зеленый0 - желтый
9Резисторный модуль UR1 BK17 - Резерв  
10Резисторный модуль UR1 BK17 - Предупреждение1 - желтый0 - серый
11Резисторный модуль UR1 BK17 - Авария1 - красный0 - серый
12Резисторный модуль UR2 BK18 - Статус1 - зеленый0 - желтый
13Резисторный модуль UR2 BK18 - Резерв  
14Резисторный модуль UR2 BK18 - Предупреждение1 - желтый0 - серый
15Резисторный модуль UR2 BK18 - Авария1 - красный0 - серый
0x004266Статус датчиков температуры воды - Блок БВ0Резисторный модуль UR3 BK19 - Статус1 - зеленый0 - желтый
1Резисторный модуль UR3 BK19 - Резерв  
2Резисторный модуль UR3 BK19 - Предупреждение1 - желтый0 - серый
3Резисторный модуль UR3 BK19 - Авария1 - красный0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
БК0x004367Напряжение звена постоянного тока (В)    
0x004468Ток звена постоянного тока (+) (А)    
0x004569Ток звена постоянного тока (-) (А)     
0x004670Температура объёма БК ВК3    
0x004771Температура объёма БК ВК7    
0x004872Статус датчиков температуры объема БК0ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК3 - Статус инициализации  
2ВК3 - Предупреждение1 - желтый0 - серый
3ВК3 - Авария1 - красный0 - серый
4ВК7 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК7 - Статус инициализации  
6ВК7 - Предупреждение1 - желтый0 - серый
7ВК7 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15БК - дверь закрыта1 - зеленый0 - серый
БИ0x004973Ток ячейки чопперной UF1 (А)    
0x004A74Ток ячейки фазной AF1 (А)    
0x004B75Ток ячейки фазной AF2 (А)    
0x004C76Ток ячейки фазной AF3 (А)    
0x004D77Температура охладителя фазной ячейки AF1 ВК1    
0x004E78Температура охладителя фазной ячейки AF1 ВК2    
0x004F79Температура охладителя фазной ячейки AF1 ВК3    
0x005080Температура охладителя фазной ячейки AF1 ВК4    
0x005181Температура охладителя фазной ячейки AF1 ВК5    
0x005282Температура охладителя фазной ячейки AF1 ВК6    
0x005383Температура охладителя фазной ячейки AF1 ВК7    
0x005484Температура охладителя фазной ячейки AF1 ВК8    
0x005585Температура охладителя фазной ячейки AF2 ВК1    
0x005686Температура охладителя фазной ячейки AF2 ВК2    
0x005787Температура охладителя фазной ячейки AF2 ВК3    
0x005888Температура охладителя фазной ячейки AF2 ВК4    
0x005989Температура охладителя фазной ячейки AF2 ВК5    
0x005A90Температура охладителя фазной ячейки AF2 ВК6    
0x005B91Температура охладителя фазной ячейки AF2 ВК7    
0x005C92Температура охладителя фазной ячейки AF2 ВК8    
0x005D93Температура охладителя фазной ячейки AF3 ВК1    
0x005E94Температура охладителя фазной ячейки AF3 ВК2    
0x005F95Температура охладителя фазной ячейки AF3 ВК3    
0x006096Температура охладителя фазной ячейки AF3 ВК4    
0x006197Температура охладителя фазной ячейки AF3 ВК5    
0x006298Температура охладителя фазной ячейки AF3 ВК6    
0x006399Температура охладителя фазной ячейки AF3 ВК7    
0x0064100Температура охладителя фазной ячейки AF3 ВК8    
0x0065101Температура охладителя чопперной ячейки UF1 ВК1    
0x0066102Температура охладителя чопперной ячейки UF1 ВК2    
0x0067103Температура охладителя чопперной ячейки UF1 ВК3    
0x0068104Температура охладителя чопперной ячейки UF1 ВК4    
0x0069105Температура объёма БИ ВК4    
0x006A106Температура объёма БИ ВК8    
0x006B107Температура воды чопперной ячейки UF1 ВК28    
0x006C108Температура воды фазной ячейки AF1 ВК13    
0x006D109Температура воды фазной ячейки AF2 ВК20    
0x006E110Температура воды фазной ячейки AF3 ВК24    
0x006F111Статусы фазных и чопперной ячеек0Состояние фазного модуля AF10 норма1 предупреждение
12 авария4 резерв
2Состояние фазного модуля AF20 норма1 предупреждение
32 авария4 резерв
4Состояние фазного модуля AF30 норма1 предупреждение
52 авария4 резерв
6Состояние чопперного модуля UF10 норма1 предупреждение
72 авария4 резерв
8   
9   
10   
11   
12   
13   
14   
15   
0x0070112Статус датчиков температуры охладителя фазной ячейки AF10ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0071113Статус датчиков температуры охладителя фазной ячейки AF10ВК5 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК5 - Статус инициализации  
2BK5 - Предупреждение1 - желтый0 - серый
3ВК5 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8ВК7 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК7 - Статус инициализации  
10BK7 - Предупреждение1 - желтый0 - серый
11ВК7 - Авария1 - красный0 - серый
12ВК8 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК8 - Статус инициализации  
14ВК8 - Предупреждение1 - желтый0 - серый
15ВК8 - Авария1 - красный0 - серый
0x0072114Статус датчиков температуры охладителя фазной ячейки AF20ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0073115Статус датчиков температуры охладителя фазной ячейки AF20ВК5 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК5 - Статус инициализации  
2BK5 - Предупреждение1 - желтый0 - серый
3ВК5 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8ВК7 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК7 - Статус инициализации  
10BK7 - Предупреждение1 - желтый0 - серый
11ВК7 - Авария1 - красный0 - серый
12ВК8 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК8 - Статус инициализации  
14ВК8 - Предупреждение1 - желтый0 - серый
15ВК8 - Авария1 - красный0 - серый
0x0074116Статус датчиков температуры охладителя фазной ячейки AF30ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0075117Статус датчиков температуры охладителя фазной ячейки AF30ВК5 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК5 - Статус инициализации  
2BK5 - Предупреждение1 - желтый0 - серый
3ВК5 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8ВК7 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК7 - Статус инициализации  
10BK7 - Предупреждение1 - желтый0 - серый
11ВК7 - Авария1 - красный0 - серый
12ВК8 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК8 - Статус инициализации  
14ВК8 - Предупреждение1 - желтый0 - серый
15ВК8 - Авария1 - красный0 - серый
0x0076118Статус датчиков температуры охладителя чопперной ячейки UF10ВК1 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0077119Статус датчиков температуры объема БИ0ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК4 - Статус инициализации  
2ВК4 - Предупреждение1 - желтый0 - серый
3ВК4 - Авария1 - красный0 - серый
4ВК8 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК8 - Статус инициализации  
6ВК8 - Предупреждение1 - желтый0 - серый
7ВК8 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15БИ - дверь закрыта1 - зеленый0 - серый
0x0078120Статус датчиков температуры воды - БИ0Чопперная ячейка UF1 ВК28 - Статус1 - зеленый0 - серый
1Чопперная ячейка UF1 ВК28 - Резерв  
2Чопперная ячейка UF1 ВК28 - Предупреждение1 - желтый0 - серый
3Чопперная ячейка UF1 ВК28 - Авария1 - красный0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
0x0079121Статус датчиков температуры воды - БИ0Фазной ячейки AF1 ВК13 - Статус1 - зеленый0 - серый
1Фазной ячейки AF1 ВК13 - Резерв  
2Фазной ячейки AF1 ВК13 - Предупреждение1 - желтый0 - серый
3Фазной ячейки AF1 ВК13 - Авария1 - красный0 - серый
4Фазной ячейки AF2 ВК20 - Статус1 - зеленый0 - серый
5Фазной ячейки AF2 ВК20 - Резерв  
6Фазной ячейки AF2 ВК20 - Предупреждение1 - желтый0 - серый
7Фазной ячейки AF2 ВК20 - Авария1 - красный0 - серый
8Фазной ячейки AF3 ВК24 - Статус1 - зеленый0 - серый
9Фазной ячейки AF3 ВК24 - Резерв  
10Фазной ячейки AF3 ВК24 - Предупреждение1 - желтый0 - серый
11Фазной ячейки AF3 ВК24 - Авария1 - красный0 - серый
12 1 - зеленый0 - серый
13   
14 1 - желтый0 - серый
15 1 - красный0 - серый
БВШ0x007A122Температура объёма БВШ ВК4    
0x007B123Температура объёма БВШ ВК8    
0x007C124Статус датчиков температуры воды - БВШ0ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15БВШ - дверь закрыта1 - зеленый0 - серый
Система охлаждения0x007D125Давление на входе внутреннего контура PT1 (МПа)    
0x007E126Давление на выходе внутреннего контура PT2 (МПа)    
0x007F127Показания расходомера (м3/ч)    
0x0080128Температуры воды "Вход" BK9    
0x0081129Температуры воды "Выход" BK10    
0x0082130Статус датчиков температуры воды - Система охлаждения0Вход воды BK9 - Статус1 - зеленый0 - серый
1Вход воды BK9 - Резерв  
2Вход воды BK9 - Предупреждение1 - желтый0 - серый
3Вход воды BK9 - Авария1 - красный0 - серый
4Выход воды BK10 - Статус1 - зеленый0 - желтый
5Выход воды BK10 - Резерв  
6Выход воды BK10 - Предупреждение1 - желтый0 - серый
7Выход воды BK10 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15Датчик протечки1 - зеленый0 - красный
Передача значений уставок (Верхний порог предупреждения)Осн. данные0x0083131Порог предупреждения о высоком токе на выходе фазы U    
0x0084132Порог предупреждения о высоком токе на выходе фазы V    
0x0085133Порог предупреждения о высоком токе на выходе фазы W    
Блок БСУ0x0086134УКСИ - Предупредительная уставка    
0x0087135Температура объёма БСУ ВК1 - Верхний порог предупреждения    
0x0088136Температура объёма БСУ ВК5 - Верхний порог предупреждения    
Блок БВ0x0089137Порог предупреждения о высоком напряжении на входе А1В1    
0x008A138Порог предупреждения о высоком напряжении на входе В1С1    
0x008B139Порог предупреждения о высоком напряжении на входе А2В2    
0x008C140Порог предупреждения о высоком напряжении на входе В2С2    
0x008D141Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог предупреждения    
0x008E142Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог предупреждения    
0x008F143Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог предупреждения    
0x0090144Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог предупреждения    
0x0091145Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог предупреждения    
0x0092146Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог предупреждения    
0x0093147Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог предупреждения    
0x0094148Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог предупреждения    
0x0095149Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог предупреждения    
0x0096150Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог предупреждения    
0x0097151Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог предупреждения    
0x0098152Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог предупреждения    
0x0099153Температура объёма Блок БВ ВК2 - Верхний порог предупреждения    
0x009A154Температура объёма Блок БВ ВК6 - Верхний порог предупреждения    
0x009B155Температура воды выпрямительной ячейки UZ1 ВК11 - Верхний порог предупреждения    
0x009C156Температура воды выпрямительной ячейки UZ2 ВК12 - Верхний порог предупреждения    
0x009D157Температура воды резисторного модуля UR1 ВК17 - Верхний порог предупреждения    
0x009E158Температура воды резисторного модуля UR2 ВК18 - Верхний порог предупреждения    
0x009F159Температура воды резисторного модуля UR3 ВК19 - Верхний порог предупреждения    
БК0x00A0160Напряжение звена постоянного тока (В) - Верхний порог предупреждения    
0x00A1161Ток звена постоянного тока (+) (А) - Верхний порог предупреждения    
0x00A2162Ток звена постоянного тока (-) (А) - Верхний порог предупреждения    
0x00A3163Температура объёма БК ВК3 - Верхний порог предупреждения    
0x00A4164Температура объёма БК ВК7 - Верхний порог предупреждения    
БИ0x00A5165Ток ячейки чопперной UF1 (А) - Верхний порог предупреждения    
0x00A6166Ток ячейки фазной AF1 (А) - Верхний порог предупреждения    
0x00A7167Ток ячейки фазной AF2 (А) - Верхний порог предупреждения    
0x00A8168Ток ячейки фазной AF3 (А) - Верхний порог предупреждения    
0x00A9169Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог предупреждения    
0x00AA170Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог предупреждения    
0x00AB171Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог предупреждения    
0x00AC172Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог предупреждения    
0x00AD173Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог предупреждения    
0x00AE174Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог предупреждения    
0x00AF175Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог предупреждения    
0x00B0176Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог предупреждения    
0x00B1177Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог предупреждения    
0x00B2178Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог предупреждения    
0x00B3179Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог предупреждения    
0x00B4180Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог предупреждения    
0x00B5181Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог предупреждения    
0x00B6182Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог предупреждения    
0x00B7183Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог предупреждения    
0x00B8184Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог предупреждения    
0x00B9185Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог предупреждения    
0x00BA186Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог предупреждения    
0x00BB187Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог предупреждения    
0x00BC188Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог предупреждения    
0x00BD189Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог предупреждения    
0x00BE190Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог предупреждения    
0x00BF191Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог предупреждения    
0x00C0192Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог предупреждения    
0x00C1193Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог предупреждения    
0x00C2194Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог предупреждения    
0x00C3195Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог предупреждения    
0x00C4196Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог предупреждения    
0x00C5197Температура объёма БИ ВК4 - Верхний порог предупреждения    
0x00C6198Температура объёма БИ ВК8 - Верхний порог предупреждения    
0x00C7199Температура воды чопперной ячейки UF1 ВК28 - Верхний порог предупреждения    
0x00C8200Температура воды фазной ячейки AF1 ВК13 - Верхний порог предупреждения    
0x00C9201Температура воды фазной ячейки AF2 ВК20 - Верхний порог предупреждения    
0x00CA202Температура воды фазной ячейки AF3 ВК24 - Верхний порог предупреждения    
БВШ0x00CB203Температура объёма БВШ ВК4 - Верхний порог предупреждения    
0x00CC204Температура объёма БВШ ВК8 - Верхний порог предупреждения    
Система охлаждения0x00CD205Давление на входе внутреннего контура PT1 (МПа) - Верхний порог предупреждения    
0x00CE206Давление на выходе внутреннего контура PT2 (МПа)-Верхний порог предупреждения    
0x00CF207Показания расходомера (м3/ч) - Верхний порог предупреждения    
0x00D0208Температуры воды "Вход" BK9 - Верхний порог предупреждения    
0x00D1209Температуры воды "Выход" BK10 - Верхний порог предупреждения    
Передача значений уставок (Верхний порог аварии)Основные данные0x00D2210Порог аварийно высокого тока на выходе фазы U    
0x00D3211Порог аварийно высокого тока на выходе фазы V    
0x00D4212Порог аварийно высокого тока на выходе фазы W    
Блок БСУ0x00D5213УКСИ - Аварийная уставка    
0x00D6214Температура объёма БСУ ВК1 - Верхний порог аварии    
0x00D7215Температура объёма БСУ ВК5 - Верхний порог аварии    
Блок БВ0x00D8216Порог аварийно высокого напряжения на входе А1В1    
0x00D9217Порог аварийно высокого напряжения на входе В1С1    
0x00DA218Порог аварийно высокого напряжения на входе А2В2    
0x00DB219Порог аварийно высокого напряжения на входе В2С2    
0x00DC220Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог аварии    
0x00DD221Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог аварии    
0x00DE222Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог аварии    
0x00DF223Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог аварии    
0x00E0224Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог аварии    
0x00E1225Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог аварии    
0x00E2226Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог аварии    
0x00E3227Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог аварии    
0x00E4228Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог аварии    
0x00E5229Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог аварии    
0x00E6230Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог аварии    
0x00E7231Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог аварии    
0x00E8232Температура объёма Блок БВ ВК2 - Верхний порог аварии    
0x00E9233Температура объёма Блок БВ ВК6 - Верхний порог аварии    
0x00EA234Температура воды выпрямительной ячейки UZ1 BK11 - Верхний порог аварии    
0x00EB235Температура воды выпрямительной ячейки UZ2 BK12 - Верхний порог аварии    
0x00EC236Температура воды резисторного модуля UR1 BK17 - Верхний порог аварии    
0x00ED237Температура воды резисторного модуля UR2 BK18 - Верхний порог аварии    
0x00EE238Температура воды резисторного модуля UR3 BK19 - Верхний порог аварии    
БК0x00EF239Напряжение звена постоянного тока (В) - Верхний порог аварии    
0x00F0240Ток звена постоянного тока (+) (А) - Верхний порог аварии    
0x00F1241Ток звена постоянного тока (-) (А) - Верхний порог аварии    
0x00F2242Температура объёма БК ВК3 - Верхний порог аварии    
0x00F3243Температура объёма БК ВК7 - Верхний порог аварии    
БИ0x00F4244Ток ячейки чопперной UF1 (А) - Верхний порог аварии    
0x00F5245Ток ячейки фазной AF1 (А) - Верхний порог аварии    
0x00F6246Ток ячейки фазной AF2 (А) - Верхний порог аварии    
0x00F7247Ток ячейки фазной AF3 (А) - Верхний порог аварии    
0x00F8248Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог аварии    
0x00F9249Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог аварии    
0x00FA250Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог аварии    
0x00FB251Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог аварии    
0x00FC252Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог аварии    
0x00FD253Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог аварии    
0x00FE254Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог аварии    
0x00FF255Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог аварии    
0x0100256Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог аварии    
0x0101257Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог аварии    
0x0102258Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог аварии    
0x0103259Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог аварии    
0x0104260Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог аварии    
0x0105261Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог аварии    
0x0106262Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог аварии    
0x0107263Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог аварии    
0x0108264Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог аварии    
0x0109265Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог аварии    
0x010A266Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог аварии    
0x010B267Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог аварии    
0x010C268Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог аварии    
0x010D269Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог аварии    
0x010E270Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог аварии    
0x010F271Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог аварии    
0x0110272Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог аварии    
0x0111273Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог аварии    
0x0112274Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог аварии    
0x0113275Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог аварии    
0x0114276Температура объёма БИ ВК4 - Верхний порог аварии    
0x0115277Температура объёма БИ ВК8 - Верхний порог аварии    
0x0116278Температура воды чопперной ячейки UF1 ВК28 - Верхний порог аварии    
0x0117279Температура воды фазной ячейки AF1 ВК13 - Верхний порог аварии    
0x0118280Температура воды фазной ячейки AF2 ВК20 - Верхний порог аварии    
0x0119281Температура воды фазной ячейки AF3 ВК24 - Верхний порог аварии    
БВШ0x011A282Температура объёма БВШ ВК4 - Верхний порог аварии    
0x011B283Температура объёма БВШ ВК8 - Верхний порог аварии    
Система охлаждения0x011C284Давление на входе внутреннего контура PT1 (МПа) - Верхний порог аварии    
0x011D285Давление на выходе внутреннего контура PT2 (МПа) - Верхний порог аварии    
0x011E286Показания расходомера (м3/ч) - Верхний порог аварии    
0x011F287Температуры воды "Вход" BK9 - Верхний порог аварии    
0x0120288Температуры воды "Выход" BK10 - Верхний порог аварии    
Передача значений уставок (Нижний порог предупреждения)Блок БСУ0x0121289Температура объёма БСУ ВК1 - Нижний порог предупреждения    
0x0122290Температура объёма БСУ ВК5 - Нижний порог предупреждения    
Блок БВ0x0123291Порог предупреждения о низком напряжении на входе А1В1    
0x0124292Порог предупреждения о низком напряжении на входе В1С1    
0x0125293Порог предупреждения о низком напряжении на входе А2В2    
0x0126294Порог предупреждения о низком напряжении на входе В2С2    
0x0127295Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог предупреждения    
0x0128296Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог предупреждения    
0x0129297Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог предупреждения    
0x012A298Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог предупреждения    
0x012B299Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог предупреждения    
0x012C300Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог предупреждения    
0x012D301Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог предупреждения    
0x012E302Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог предупреждения    
0x012F303Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог предупреждения    
0x0130304Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог предупреждения    
0x0131305Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог предупреждения    
0x0132306Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог предупреждения    
0x0133307Температура объёма Блок БВ ВК2 - Нижний порог предупреждения    
0x0134308Температура объёма Блок БВ ВК6 - Нижний порог предупреждения    
0x0135309Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог предупреждения    
0x0136310Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог предупреждения    
0x0137311Температура воды резисторного модуля UR1 ВК17 - Нижний порог предупреждения    
0x0138312Температура воды резисторного модуля UR2 ВК18 - Нижний порог предупреждения    
0x0139313Температура воды резисторного модуля UR3 ВК19 - Нижний порог предупреждения    
БК0x013A314Напряжение звена постоянного тока (В) - Нижний порог предупреждения    
0x013B315Температура объёма БК ВК3 - Нижний порог предупреждения    
0x013C316Температура объёма БК ВК7 - Нижний порог предупреждения    
БИ0x013D317Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог предупреждения    
0x013E318Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог предупреждения    
0x013F319Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог предупреждения    
0x0140320Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог предупреждения    
0x0141321Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог предупреждения    
0x0142322Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог предупреждения    
0x0143323Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог предупреждения    
0x0144324Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог предупреждения    
0x0145325Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог предупреждения    
0x0146326Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог предупреждения    
0x0147327Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог предупреждения    
0x0148328Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог предупреждения    
0x0149329Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог предупреждения    
0x014A330Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог предупреждения    
0x014B331Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог предупреждения    
0x014C332Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог предупреждения    
0x014D333Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог предупреждения    
0x014E334Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог предупреждения    
0x014F335Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог предупреждения    
0x0150336Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог предупреждения    
0x0151337Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог предупреждения    
0x0152338Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог предупреждения    
0x0153339Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог предупреждения    
0x0154340Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог предупреждения    
0x0155341Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог предупреждения    
0x0156342Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог предупреждения    
0x0157343Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог предупреждения    
0x0158344Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог предупреждения    
0x0159345Температура объёма БИ ВК4 - Нижний порог предупреждения    
0x015A346Температура объёма БИ ВК8 - Нижний порог предупреждения    
0x015B347Температура воды чопперной ячейки UF1 ВК28 - Нижний порог предупреждения    
0x015C348Температура воды фазной ячейки AF1 ВК13 - Нижний порог предупреждения    
0x015D349Температура воды фазной ячейки AF2 ВК20 - Нижний порог предупреждения    
0x015E350Температура воды фазной ячейки AF3 ВК24 - Нижний порог предупреждения    
БВШ0x015F351Температура объёма БВШ ВК4 - Нижний порог предупреждения    
0x0160352Температура объёма БВШ ВК8 - Нижний порог предупреждения    
Система охлаждения0x0161353Давление на входе внутреннего контура PT1 (МПа) - Нижний порог предупреждения    
0x0162354Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог предупреждения    
0x0163355Показания расходомера (м3/ч) - Нижний порог предупреждения    
0x0164356Температуры воды "Вход" BK9 - Нижний порог предупреждения    
0x0165357Температуры воды "Выход" BK10 - Нижний порог предупреждения    
Передача значений уставок (Нижний порог аварии)Блок БСУ0x0166358Температура объёма БСУ ВК1 - Нижний порог аварии    
0x0167359Температура объёма БСУ ВК5 - Нижний порог аварии    
Блок БВ0x0168360Порог аварийно низкого напряжения на входе А1В1    
0x0169361Порог аварийно низкого напряжения на входе В1С1    
0x016A362Порог аварийно низкого напряжения на входе А2В2    
0x016B363Порог аварийно низкого напряжения на входе В2С2    
0x016C364Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог аварии    
0x016D365Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог аварии    
0x016E366Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог аварии    
0x016F367Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог аварии    
0x0170368Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог аварии    
0x0171369Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог аварии    
0x0172370Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог аварии    
0x0173371Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог аварии    
0x0174372Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог аварии    
0x0175373Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог аварии    
0x0176374Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог аварии    
0x0177375Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог аварии    
0x0178376Температура объёма Блок БВ ВК2 - Нижний порог аварии    
0x0179377Температура объёма Блок БВ ВК6 - Нижний порог аварии    
0x017A378Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог аварии    
0x017B379Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог аварии    
0x017C380Температура воды резисторного модуля UR1 ВК17 - Нижний порог аварии    
0x017D381Температура воды резисторного модуля UR2 ВК18 - Нижний порог аварии    
0x017E382Температура воды резисторного модуля UR3 ВК19 - Нижний порог аварии    
БК0x017F383Напряжение звена постоянного тока (В) - Нижний порог аварии    
0x0180384Температура объёма БК ВК3 - Нижний порог аварии    
0x0181385Температура объёма БК ВК7 - Нижний порог аварии    
БИ0x0182386Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог аварии    
0x0183387Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог аварии    
0x0184388Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог аварии    
0x0185389Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог аварии    
0x0186390Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог аварии    
0x0187391Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог аварии    
0x0188392Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог аварии    
0x0189393Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог аварии    
0x018A394Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог аварии    
0x018B395Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог аварии    
0x018C396Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог аварии    
0x018D397Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог аварии    
0x018E398Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог аварии    
0x018F399Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог аварии    
0x0190400Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог аварии    
0x0191401Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог аварии    
0x0192402Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог аварии    
0x0193403Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог аварии    
0x0194404Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог аварии    
0x0195405Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог аварии    
0x0196406Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог аварии    
0x0197407Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог аварии    
0x0198408Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог аварии    
0x0199409Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог аварии    
0x019A410Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог аварии    
0x019B411Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог аварии    
0x019C412Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог аварии    
0x019D413Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог аварии    
0x019E414Температура объёма БИ ВК4 - Нижний порог аварии    
0x019F415Температура объёма БИ ВК8 - Нижний порог аварии    
0x01A0416Температура воды чопперной ячейки UF1 ВК28 - Нижний порог аварии    
0x01A1417Температура воды фазной ячейки AF1 ВК13 - Нижний порог аварии    
0x01A2418Температура воды фазной ячейки AF2 ВК20 - Нижний порог аварии    
0x01A3419Температура воды фазной ячейки AF3 ВК24 - Нижний порог аварии    
БВШ0x01A4420Температура объёма БВШ ВК4 - Нижний порог аварии    
0x01A5421Температура объёма БВШ ВК8 - Нижний порог аварии    
Система охлаждения0x01A6422Давление на входе внутреннего контура PT1 (МПа) - Нижний порог аварии    
0x01A7423Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог аварии    
0x01A8424Показания расходомера (м3/ч) - Нижний порог аварии    
0x01A9425Температуры воды "Вход" BK9 - Нижний порог аварии    
0x01AA426Температуры воды "Выход" BK10 - Нижний порог аварии    
Данные датчиковБСУ0x01AB427Температура объёма БСУ ВК10 - 15User Bytes  
0x01AC42816 - 64ID  
0x01AD429  
0x01AE430  
0x01AF431Температура объёма БСУ ВК50 - 15User Bytes  
0x01B043216 - 64ID  
0x01B1433  
0x01B2434  
Блок БВ0x01B3435Температура охладителя выпрямительной ячейки UZ1 ВК10 - 15User Bytes  
0x01B443616 - 64ID  
0x01B5437  
0x01B6438  
0x01B7439Температура охладителя выпрямительной ячейки UZ1 ВК20 - 15User Bytes  
0x01B844016 - 64ID  
0x01B9441  
0x01BA442  
0x01BB443Температура охладителя выпрямительной ячейки UZ2 ВК10 - 15User Bytes  
0x01BC44416 - 64ID  
0x01BD445  
0x01BE446  
0x01BF447Температура охладителя выпрямительной ячейки UZ2 ВК20 - 15User Bytes  
0x01C044816 - 64ID  
0x01C1449  
0x01C2450  
0x01C3451Температура охладителя резисторного модуля UR1 ВК10 - 15User Bytes  
0x01C445216 - 64ID  
0x01C5453  
0x01C6454  
0x01C7455Температура охладителя резисторного модуля UR1 ВК20 - 15User Bytes  
0x01C845616 - 64ID  
0x01C9457  
0x01CA458  
0x01CB459Температура охладителя резисторного модуля UR2 ВК10 - 15User Bytes  
0x01CC46016 - 64ID  
0x01CD461  
0x01CE462  
0x01CF463Температура охладителя резисторного модуля UR2 ВК20 - 15User Bytes  
0x01D046416 - 64ID  
0x01D1465  
0x01D2466  
0x01D3467Температура охладителя резисторного модуля UR3 ВК10 - 15User Bytes  
0x01D446816 - 64ID  
0x01D5469  
0x01D6470  
0x01D7471Температура охладителя резисторного модуля UR3 ВК20 - 15User Bytes  
0x01D847216 - 64ID  
0x01D9473  
0x01DA474  
0x01DB475Температура объёма Блок БВ ВК20 - 15User Bytes  
0x01DC47616 - 64ID  
0x01DD477  
0x01DE478  
0x01DF479Температура объёма Блок БВ ВК60 - 15User Bytes  
0x01E048016 - 64ID  
0x01E1481  
0x01E2482  
БК0x01E3483Температура объёма БК ВК30 - 15User Bytes  
0x01E448416 - 64ID  
0x01E5485  
0x01E6486  
0x01E7487Температура объёма БК ВК70 - 15User Bytes  
0x01E848816 - 64ID  
0x01E9489  
0x01EA490  
БИ0x01EB491Температура охладителя фазной ячейки AF1 ВК10 - 15User Bytes  
0x01EC49216 - 64ID  
0x01ED493  
0x01EE494  
0x01EF495Температура охладителя фазной ячейки AF1 ВК20 - 15User Bytes  
0x01F049616 - 64ID  
0x01F1497  
0x01F2498  
0x01F3499Температура охладителя фазной ячейки AF1 ВК30 - 15User Bytes  
0x01F450016 - 64ID  
0x01F5501  
0x01F6502  
0x01F7503Температура охладителя фазной ячейки AF1 ВК40 - 15User Bytes  
0x01F850416 - 64ID  
0x01F9505  
0x01FA506  
0x01FB507Температура охладителя фазной ячейки AF1 ВК50 - 15User Bytes  
0x01FC50816 - 64ID  
0x01FD509  
0x01FE510  
0x01FF511Температура охладителя фазной ячейки AF1 ВК60 - 15User Bytes  
0x020051216 - 64ID  
0x0201513  
0x0202514  
0x0203515Температура охладителя фазной ячейки AF1 ВК70 - 15User Bytes  
0x020451616 - 64ID  
0x0205517  
0x0206518  
0x0207519Температура охладителя фазной ячейки AF1 ВК80 - 15User Bytes  
0x020852016 - 64ID  
0x0209521  
0x020A522  
0x020B523Температура охладителя фазной ячейки AF2 ВК10 - 15User Bytes  
0x020C52416 - 64ID  
0x020D525  
0x020E526  
0x020F527Температура охладителя фазной ячейки AF2 ВК20 - 15User Bytes  
0x021052816 - 64ID  
0x0211529  
0x0212530  
0x0213531Температура охладителя фазной ячейки AF2 ВК30 - 15User Bytes  
0x021453216 - 64ID  
0x0215533  
0x0216534  
0x0217535Температура охладителя фазной ячейки AF2 ВК40 - 15User Bytes  
0x021853616 - 64ID  
0x0219537  
0x021A538  
0x021B539Температура охладителя фазной ячейки AF2 ВК50 - 15User Bytes  
0x021C54016 - 64ID  
0x021D541  
0x021E542  
0x021F543Температура охладителя фазной ячейки AF2 ВК60 - 15User Bytes  
0x022054416 - 64ID  
0x0221545  
0x0222546  
0x0223547Температура охладителя фазной ячейки AF2 ВК70 - 15User Bytes  
0x022454816 - 64ID  
0x0225549  
0x0226550  
0x0227551Температура охладителя фазной ячейки AF2 ВК80 - 15User Bytes  
0x022855216 - 64ID  
0x0229553  
0x022A554  
0x022B555Температура охладителя фазной ячейки AF3 ВК10 - 15User Bytes  
0x022C55616 - 64ID  
0x022D557  
0x022E558  
0x022F559Температура охладителя фазной ячейки AF3 ВК20 - 15User Bytes  
0x023056016 - 64ID  
0x0231561  
0x0232562  
0x0233563Температура охладителя фазной ячейки AF3 ВК30 - 15User Bytes  
0x023456416 - 64ID  
0x0235565  
0x0236566  
0x0237567Температура охладителя фазной ячейки AF3 ВК40 - 15User Bytes  
0x023856816 - 64ID  
0x0239569  
0x023A570  
0x023B571Температура охладителя фазной ячейки AF3 ВК50 - 15User Bytes  
0x023C57216 - 64ID  
0x023D573  
0x023E574  
0x023F575Температура охладителя фазной ячейки AF3 ВК60 - 15User Bytes  
0x024057616 - 64ID  
0x0241577  
0x0242578  
0x0243579Температура охладителя фазной ячейки AF3 ВК70 - 15User Bytes  
0x024458016 - 64ID  
0x0245581  
0x0246582  
0x0247583Температура охладителя фазной ячейки AF3 ВК80 - 15User Bytes  
0x024858416 - 64ID  
0x0249585  
0x024A586  
0x024B587Температура охладителя чопперной ячейки UF1 ВК10 - 15User Bytes  
0x024C58816 - 64ID  
0x024D589  
0x024E590  
0x024F591Температура охладителя чопперной ячейки UF1 ВК20 - 15User Bytes  
0x025059216 - 64ID  
0x0251593  
0x0252594  
0x0253595Температура охладителя чопперной ячейки UF1 ВК30 - 15User Bytes  
0x025459616 - 64ID  
0x0255597  
0x0256598  
0x0257599Температура охладителя чопперной ячейки UF1 ВК40 - 15User Bytes  
0x025860016 - 64ID  
0x0259601  
0x025A602  
0x025B603Температура объёма БИ ВК40 - 15User Bytes  
0x025C60416 - 64ID  
0x025D605  
0x025E606  
0x025F607Температура объёма БИ ВК80 - 15User Bytes  
0x026060816 - 64ID  
0x0261609  
0x0262610  
БВШ0x0263611Температура объёма БВШ ВК40 - 15User Bytes  
0x026461216 - 64ID  
0x0265613  
0x0266614  
0x0267615Температура объёма БВШ ВК80 - 15User Bytes  
0x026861616 - 64ID  
0x0269617  
0x026A618  
Приём     
ПриёмКоманды0x13885000Код протокола CAN (Обычный, расширенный, суперрасширенный)    
0x13895001Сохранить уставки    
0x138A5002Сброс ошибок (квитирование)    
0x138B5003Команда запроса ID    
0x138C5004Команда запроса User Bytes    
0x138D5005Команда запроса уставок    
0x138E5006Счётчик запросов основных данных    
0x138F5007Счётчик запросов уставок    
0x13905008Счётчик запросов данных датчиков    
0x13915009Команда для устройства0Блокировка  
1Собрать силовую схему  
2Разобрать силовую схему  
3Схема собрана в режиме аварийного хода  
4Установить управление по мощности  
5Установить управление по оборотам  
6Установить режим устройства "конфигурация" (меню настроек)  
7Установить режим устройства "эксплуатация"  
8Запросить все предупредительные уставки  
9Запросить все аварийные уставки  
10   
11   
12   
13   
14   
15Сохранить настройки  
Приём значений уставок (Верхний порог предупреждения)Осн. данные0x13925010Порог предупреждения о высоком токе на выходе фазы U    
0x13935011Порог предупреждения о высоком токе на выходе фазы V    
0x13945012Порог предупреждения о высоком токе на выходе фазы W    
Блок БСУ0x13955013УКСИ - Предупредительная уставка    
0x13965014Температура объёма БСУ ВК1 - Верхний порог предупреждения    
0x13975015Температура объёма БСУ ВК5 - Верхний порог предупреждения    
Блок БВ0x13985016Порог предупреждения о высоком напряжении на входе А1В1    
0x13995017Порог предупреждения о высоком напряжении на входе В1С1    
0x139A5018Порог предупреждения о высоком напряжении на входе А2В2    
0x139B5019Порог предупреждения о высоком напряжении на входе В2С2    
0x139C5020Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог предупреждения    
0x139D5021Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог предупреждения    
0x139E5022Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог предупреждения    
0x139F5023Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог предупреждения    
0x13A05024Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог предупреждения    
0x13A15025Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог предупреждения    
0x13A25026Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог предупреждения    
0x13A35027Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог предупреждения    
0x13A45028Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог предупреждения    
0x13A55029Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог предупреждения    
0x13A65030Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог предупреждения    
0x13A75031Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог предупреждения    
0x13A85032Температура объёма Блок БВ ВК2 - Верхний порог предупреждения    
0x13A95033Температура объёма Блок БВ ВК6 - Верхний порог предупреждения    
0x13AA5034Температура воды выпрямительной ячейки UZ1 ВК11 - Верхний порог предупреждения    
0x13AB5035Температура воды выпрямительной ячейки UZ2 ВК12 - Верхний порог предупреждения    
0x13AC5036Температура воды резисторного модуля UR1 ВК17 - Верхний порог предупреждения    
0x13AD5037Температура воды резисторного модуля UR2 ВК18 - Верхний порог предупреждения    
0x13AE5038Температура воды резисторного модуля UR3 ВК19 - Верхний порог предупреждения    
БК0x13AF5039Напряжение звена постоянного тока (В) - Верхний порог предупреждения    
0x13B05040Ток звена постоянного тока (+) (А) - Верхний порог предупреждения    
0x13B15041Ток звена постоянного тока (-) (А) - Верхний порог предупреждения    
0x13B25042Температура объёма БК ВК3 - Верхний порог предупреждения    
0x13B35043Температура объёма БК ВК7 - Верхний порог предупреждения    
БИ0x13B45044Ток ячейки чопперной UF1 (А) - Верхний порог предупреждения    
0x13B55045Ток ячейки фазной AF1 (А) - Верхний порог предупреждения    
0x13B65046Ток ячейки фазной AF2 (А) - Верхний порог предупреждения    
0x13B75047Ток ячейки фазной AF3 (А) - Верхний порог предупреждения    
0x13B85048Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог предупреждения    
0x13B95049Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог предупреждения    
0x13BA5050Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог предупреждения    
0x13BB5051Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог предупреждения    
0x13BC5052Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог предупреждения    
0x13BD5053Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог предупреждения    
0x13BE5054Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог предупреждения    
0x13BF5055Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог предупреждения    
0x13C05056Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог предупреждения    
0x13C15057Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог предупреждения    
0x13C25058Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог предупреждения    
0x13C35059Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог предупреждения    
0x13C45060Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог предупреждения    
0x13C55061Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог предупреждения    
0x13C65062Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог предупреждения    
0x13C75063Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог предупреждения    
0x13C85064Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог предупреждения    
0x13C95065Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог предупреждения    
0x13CA5066Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог предупреждения    
0x13CB5067Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог предупреждения    
0x13CC5068Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог предупреждения    
0x13CD5069Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог предупреждения    
0x13CE5070Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог предупреждения    
0x13CF5071Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог предупреждения    
0x13D05072Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог предупреждения    
0x13D15073Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог предупреждения    
0x13D25074Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог предупреждения    
0x13D35075Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог предупреждения    
0x13D45076Температура объёма БИ ВК4 - Верхний порог предупреждения    
0x13D55077Температура объёма БИ ВК8 - Верхний порог предупреждения    
0x13D65078Температура воды чопперной ячейки UF1 ВК28 - Верхний порог предупреждения    
0x13D75079Температура воды фазной ячейки AF1 ВК13 - Верхний порог предупреждения    
0x13D85080Температура воды фазной ячейки AF2 ВК20 - Верхний порог предупреждения    
0x13D95081Температура воды фазной ячейки AF3 ВК24 - Верхний порог предупреждения    
БВШ0x13DA5082Температура объёма БВШ ВК4 - Верхний порог предупреждения    
0x13DB5083Температура объёма БВШ ВК8 - Верхний порог предупреждения    
Система охлаждения0x13DC5084Давление на входе внутреннего контура PT1 (МПа) - Верхний порог предупреждения    
0x13DD5085Давление на выходе внутреннего контура PT2 (МПа)-Верхний порог предупреждения    
0x13DE5086Показания расходомера (м3/ч) - Верхний порог предупреждения    
0x13DF5087Температуры воды "Вход" BK9 - Верхний порог предупреждения    
0x13E05088Температуры воды "Выход" BK10 - Верхний порог предупреждения    
Приём значений уставок (Верхний порог аварии)Осн. данные0x13E15089Порог аварийно высокого тока на выходе фазы U    
0x13E25090Порог аварийно высокого тока на выходе фазы V    
0x13E35091Порог аварийно высокого тока на выходе фазы W    
Блок БСУ0x13E45092УКСИ - Аварийная уставка    
0x13E55093Температура объёма БСУ ВК1 - Верхний порог аварии    
0x13E65094Температура объёма БСУ ВК5 - Верхний порог аварии    
Блок БВ0x13E75095Порог аварийно высокого напряжения на входе А1В1    
0x13E85096Порог аварийно высокого напряжения на входе В1С1    
0x13E95097Порог аварийно высокого напряжения на входе А2В2    
0x13EA5098Порог аварийно высокого напряжения на входе В2С2    
0x13EB5099Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог аварии    
0x13EC5100Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог аварии    
0x13ED5101Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог аварии    
0x13EE5102Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог аварии    
0x13EF5103Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог аварии    
0x13F05104Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог аварии    
0x13F15105Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог аварии    
0x13F25106Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог аварии    
0x13F35107Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог аварии    
0x13F45108Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог аварии    
0x13F55109Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог аварии    
0x13F65110Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог аварии    
0x13F75111Температура объёма Блок БВ ВК2 - Верхний порог аварии    
0x13F85112Температура объёма Блок БВ ВК6 - Верхний порог аварии    
0x13F95113Температура воды выпрямительной ячейки UZ1 BK11 - Верхний порог аварии    
0x13FA5114Температура воды выпрямительной ячейки UZ2 BK12 - Верхний порог аварии    
0x13FB5115Температура воды резисторного модуля UR1 BK17 - Верхний порог аварии    
0x13FC5116Температура воды резисторного модуля UR2 BK18 - Верхний порог аварии    
0x13FD5117Температура воды резисторного модуля UR3 BK19 - Верхний порог аварии    
БК0x13FE5118Напряжение звена постоянного тока (В) - Верхний порог аварии    
0x13FF5119Ток звена постоянного тока (+) (А) - Верхний порог аварии    
0x14005120Ток звена постоянного тока (-) (А) - Верхний порог аварии    
0x14015121Температура объёма БК ВК3 - Верхний порог аварии    
0x14025122Температура объёма БК ВК7 - Верхний порог аварии    
БИ0x14035123Ток ячейки чопперной UF1 (А) - Верхний порог аварии    
0x14045124Ток ячейки фазной AF1 (А) - Верхний порог аварии    
0x14055125Ток ячейки фазной AF2 (А) - Верхний порог аварии    
0x14065126Ток ячейки фазной AF3 (А) - Верхний порог аварии    
0x14075127Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог аварии    
0x14085128Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог аварии    
0x14095129Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог аварии    
0x140A5130Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог аварии    
0x140B5131Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог аварии    
0x140C5132Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог аварии    
0x140D5133Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог аварии    
0x140E5134Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог аварии    
0x140F5135Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог аварии    
0x14105136Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог аварии    
0x14115137Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог аварии    
0x14125138Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог аварии    
0x14135139Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог аварии    
0x14145140Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог аварии    
0x14155141Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог аварии    
0x14165142Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог аварии    
0x14175143Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог аварии    
0x14185144Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог аварии    
0x14195145Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог аварии    
0x141A5146Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог аварии    
0x141B5147Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог аварии    
0x141C5148Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог аварии    
0x141D5149Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог аварии    
0x141E5150Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог аварии    
0x141F5151Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог аварии    
0x14205152Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог аварии    
0x14215153Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог аварии    
0x14225154Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог аварии    
0x14235155Температура объёма БИ ВК4 - Верхний порог аварии    
0x14245156Температура объёма БИ ВК8 - Верхний порог аварии    
0x14255157Температура воды чопперной ячейки UF1 ВК28 - Верхний порог аварии    
0x14265158Температура воды фазной ячейки AF1 ВК13 - Верхний порог аварии    
0x14275159Температура воды фазной ячейки AF2 ВК20 - Верхний порог аварии    
0x14285160Температура воды фазной ячейки AF3 ВК24 - Верхний порог аварии    
БВШ0x14295161Температура объёма БВШ ВК4 - Верхний порог аварии    
0x142A5162Температура объёма БВШ ВК8 - Верхний порог аварии    
Система охлаждения0x142B5163Давление на входе внутреннего контура PT1 (МПа) - Верхний порог аварии    
0x142C5164Давление на выходе внутреннего контура PT2 (МПа) - Верхний порог аварии    
0x142D5165Показания расходомера (м3/ч) - Верхний порог аварии    
0x142E5166Температуры воды "Вход" BK9 - Верхний порог аварии    
0x142F5167Температуры воды "Выход" BK10 - Верхний порог аварии    
Приём значений уставок (Нижний порог предупреждения)Блок БСУ0x14305168Температура объёма БСУ ВК1 - Нижний порог предупреждения    
0x14315169Температура объёма БСУ ВК5 - Нижний порог предупреждения    
Блок БВ0x14325170Порог предупреждения о низком напряжении на входе А1В1    
0x14335171Порог предупреждения о низком напряжении на входе В1С1    
0x14345172Порог предупреждения о низком напряжении на входе А2В2    
0x14355173Порог предупреждения о низком напряжении на входе В2С2    
0x14365174Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог предупреждения    
0x14375175Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог предупреждения    
0x14385176Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог предупреждения    
0x14395177Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог предупреждения    
0x143A5178Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог предупреждения    
0x143B5179Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог предупреждения    
0x143C5180Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог предупреждения    
0x143D5181Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог предупреждения    
0x143E5182Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог предупреждения    
0x143F5183Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог предупреждения    
0x14405184Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог предупреждения    
0x14415185Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог предупреждения    
0x14425186Температура объёма Блок БВ ВК2 - Нижний порог предупреждения    
0x14435187Температура объёма Блок БВ ВК6 - Нижний порог предупреждения    
0x14445188Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог предупреждения    
0x14455189Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог предупреждения    
0x14465190Температура воды резисторного модуля UR1 ВК17 - Нижний порог предупреждения    
0x14475191Температура воды резисторного модуля UR2 ВК18 - Нижний порог предупреждения    
0x14485192Температура воды резисторного модуля UR3 ВК19 - Нижний порог предупреждения    
БК0x14495193Напряжение звена постоянного тока (В) - Нижний порог предупреждения    
0x144A5194Температура объёма БК ВК3 - Нижний порог предупреждения    
0x144B5195Температура объёма БК ВК7 - Нижний порог предупреждения    
БИ0x144C5196Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог предупреждения    
0x144D5197Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог предупреждения    
0x144E5198Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог предупреждения    
0x144F5199Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог предупреждения    
0x14505200Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог предупреждения    
0x14515201Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог предупреждения    
0x14525202Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог предупреждения    
0x14535203Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог предупреждения    
0x14545204Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог предупреждения    
0x14555205Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог предупреждения    
0x14565206Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог предупреждения    
0x14575207Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог предупреждения    
0x14585208Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог предупреждения    
0x14595209Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог предупреждения    
0x145A5210Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог предупреждения    
0x145B5211Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог предупреждения    
0x145C5212Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог предупреждения    
0x145D5213Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог предупреждения    
0x145E5214Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог предупреждения    
0x145F5215Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог предупреждения    
0x14605216Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог предупреждения    
0x14615217Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог предупреждения    
0x14625218Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог предупреждения    
0x14635219Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог предупреждения    
0x14645220Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог предупреждения    
0x14655221Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог предупреждения    
0x14665222Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог предупреждения    
0x14675223Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог предупреждения    
0x14685224Температура объёма БИ ВК4 - Нижний порог предупреждения    
0x14695225Температура объёма БИ ВК8 - Нижний порог предупреждения    
0x146A5226Температура воды чопперной ячейки UF1 ВК28 - Нижний порог предупреждения    
0x146B5227Температура воды фазной ячейки AF1 ВК13 - Нижний порог предупреждения    
0x146C5228Температура воды фазной ячейки AF2 ВК20 - Нижний порог предупреждения    
0x146D5229Температура воды фазной ячейки AF3 ВК24 - Нижний порог предупреждения    
БВШ0x146E5230Температура объёма БВШ ВК4 - Нижний порог предупреждения    
0x146F5231Температура объёма БВШ ВК8 - Нижний порог предупреждения    
Система охлаждения0x14705232Давление на входе внутреннего контура PT1 (МПа) - Нижний порог предупреждения    
0x14715233Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог предупреждения    
0x14725234Показания расходомера (м3/ч) - Нижний порог предупреждения    
0x14735235Температуры воды "Вход" BK9 - Нижний порог предупреждения    
0x14745236Температуры воды "Выход" BK10 - Нижний порог предупреждения    
Приём значений уставок (Нижний порог аварии)Блок БСУ0x14755237Температура объёма БСУ ВК1 - Нижний порог аварии    
0x14765238Температура объёма БСУ ВК5 - Нижний порог аварии    
Блок БВ0x14775239Порог аварийно низкого напряжения на входе А1В1    
0x14785240Порог аварийно низкого напряжения на входе В1С1    
0x14795241Порог аварийно низкого напряжения на входе А2В2    
0x147A5242Порог аварийно низкого напряжения на входе В2С2    
0x147B5243Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог аварии    
0x147C5244Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог аварии    
0x147D5245Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог аварии    
0x147E5246Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог аварии    
0x147F5247Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог аварии    
0x14805248Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог аварии    
0x14815249Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог аварии    
0x14825250Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог аварии    
0x14835251Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог аварии    
0x14845252Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог аварии    
0x14855253Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог аварии    
0x14865254Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог аварии    
0x14875255Температура объёма Блок БВ ВК2 - Нижний порог аварии    
0x14885256Температура объёма Блок БВ ВК6 - Нижний порог аварии    
0x14895257Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог аварии    
0x148A5258Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог аварии    
0x148B5259Температура воды резисторного модуля UR1 ВК17 - Нижний порог аварии    
0x148C5260Температура воды резисторного модуля UR2 ВК18 - Нижний порог аварии    
0x148D5261Температура воды резисторного модуля UR3 ВК19 - Нижний порог аварии    
БК0x148E5262Напряжение звена постоянного тока (В) - Нижний порог аварии    
0x148F5263Температура объёма БК ВК3 - Нижний порог аварии    
0x14905264Температура объёма БК ВК7 - Нижний порог аварии    
БИ0x14915265Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог аварии    
0x14925266Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог аварии    
0x14935267Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог аварии    
0x14945268Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог аварии    
0x14955269Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог аварии    
0x14965270Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог аварии    
0x14975271Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог аварии    
0x14985272Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог аварии    
0x14995273Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог аварии    
0x149A5274Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог аварии    
0x149B5275Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог аварии    
0x149C5276Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог аварии    
0x149D5277Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог аварии    
0x149E5278Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог аварии    
0x149F5279Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог аварии    
0x14A05280Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог аварии    
0x14A15281Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог аварии    
0x14A25282Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог аварии    
0x14A35283Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог аварии    
0x14A45284Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог аварии    
0x14A55285Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог аварии    
0x14A65286Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог аварии    
0x14A75287Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог аварии    
0x14A85288Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог аварии    
0x14A95289Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог аварии    
0x14AA5290Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог аварии    
0x14AB5291Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог аварии    
0x14AC5292Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог аварии    
0x14AD5293Температура объёма БИ ВК4 - Нижний порог аварии    
0x14AE5294Температура объёма БИ ВК8 - Нижний порог аварии    
0x14AF5295Температура воды чопперной ячейки UF1 ВК28 - Нижний порог аварии    
0x14B05296Температура воды фазной ячейки AF1 ВК13 - Нижний порог аварии    
0x14B15297Температура воды фазной ячейки AF2 ВК20 - Нижний порог аварии    
0x14B25298Температура воды фазной ячейки AF3 ВК24 - Нижний порог аварии    
БВШ0x14B35299Температура объёма БВШ ВК4 - Нижний порог аварии    
0x14B45300Температура объёма БВШ ВК8 - Нижний порог аварии    
Система охлаждения0x14B55301Давление на входе внутреннего контура PT1 (МПа) - Нижний порог аварии    
0x14B65302Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог аварии    
0x14B75303Показания расходомера (м3/ч) - Нижний порог аварии    
0x14B85304Температуры воды "Вход" BK9 - Нижний порог аварии    
0x14B95305Температуры воды "Выход" BK10 - Нижний порог аварии    
          
          
          
          
          
          
          
          
   0x14925266Порог аварийно низкого напряжения на входе В2С2    
   0x14935267Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог аварии    
   0x14945268Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог аварии    
   0x14955269Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог аварии    
   0x14965270Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог аварии    
   0x14975271Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог аварии    
   0x14985272Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог аварии    
   0x14995273Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог аварии    
   0x149A5274Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог аварии    
   0x149B5275Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог аварии    
   0x149C5276Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог аварии    
   0x149D5277Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог аварии    
   0x149E5278Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог аварии    
   0x149F5279Температура объёма Блок вводной ВК2 - Нижний порог аварии    
   0x14A05280Температура объёма Блок вводной ВК6 - Нижний порог аварии    
   0x14A15281Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог аварии    
   0x14A25282Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог аварии    
   0x14A35283Температура воды резисторного модуля UR1 ВК17 - Нижний порог аварии    
   0x14A45284Температура воды резисторного модуля UR2 ВК18 - Нижний порог аварии    
   0x14A55285Температура воды резисторного модуля UR3 ВК19 - Нижний порог аварии    
  БС10x14A65286Напряжение звена постоянного тока (В) - Нижний порог аварии    
  0x14A75287Температура объёма БС1 ВК3 - Нижний порог аварии    
  0x14A85288Температура объёма БС1 ВК7 - Нижний порог аварии    
  БС20x14A95289Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог аварии    
  0x14AA5290Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог аварии    
  0x14AB5291Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог аварии    
  0x14AC5292Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог аварии    
  0x14AD5293Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог аварии    
  0x14AE5294Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог аварии    
  0x14AF5295Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог аварии    
  0x14B05296Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог аварии    
  0x14B15297Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог аварии    
  0x14B25298Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог аварии    
  0x14B35299Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог аварии    
  0x14B45300Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог аварии    
  0x14B55301Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог аварии    
  0x14B65302Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог аварии    
  0x14B75303Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог аварии    
  0x14B85304Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог аварии    
  0x14B95305Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог аварии    
  0x14BA5306Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог аварии    
  0x14BB5307Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог аварии    
  0x14BC5308Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог аварии    
  0x14BD5309Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог аварии    
  0x14BE5310Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог аварии    
  0x14BF5311Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог аварии    
  0x14C05312Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог аварии    
  0x14C15313Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог аварии    
  0x14C25314Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог аварии    
  0x14C35315Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог аварии    
  0x14C45316Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог аварии    
  0x14C55317Температура объёма БС2 ВК4 - Нижний порог аварии    
  0x14C65318Температура объёма БС2 ВК8 - Нижний порог аварии    
  0x14C75319Температура воды чопперной ячейки UF1 ВК28 - Нижний порог аварии    
  0x14C85320Температура воды чопперной ячейки UF1 ВК29 - Нижний порог аварии    
  0x14C95321Температура воды фазной ячейки AF1 ВК13 - Нижний порог аварии    
  0x14CA5322Температура воды фазной ячейки AF1 ВК14 - Нижний порог аварии    
  0x14CB5323Температура воды фазной ячейки AF1 ВК15 - Нижний порог аварии    
  0x14CC5324Температура воды фазной ячейки AF1 ВК16 - Нижний порог аварии    
  0x14CD5325Температура воды фазной ячейки AF2 ВК20 - Нижний порог аварии    
  0x14CE5326Температура воды фазной ячейки AF2 ВК21 - Нижний порог аварии    
  0x14CF5327Температура воды фазной ячейки AF2 ВК22 - Нижний порог аварии    
  0x14D05328Температура воды фазной ячейки AF2 ВК23 - Нижний порог аварии    
  0x14D15329Температура воды фазной ячейки AF3 ВК24 - Нижний порог аварии    
  0x14D25330Температура воды фазной ячейки AF3 ВК25 - Нижний порог аварии    
  0x14D35331Температура воды фазной ячейки AF3 ВК26 - Нижний порог аварии    
  0x14D45332Температура воды фазной ячейки AF3 ВК27 - Нижний порог аварии    
  Система охлаждения0x14D55333Давление на входе внутреннего контура PT1 (МПа) - Нижний порог аварии    
  0x14D65334Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог аварии    
  0x14D75335Показания расходомера (м3/ч) - Нижний порог аварии    
  0x14D85336Температуры воды "Вход" BK9 - Нижний порог аварии    
  0x14D95337Температуры воды "Выход" BK10 - Нижний порог аварии    
diff --git a/Протокол CAN и ОАП.xlsx b/Протокол CAN и ОАП.xlsx index 68a666daf6e1b3d0478766d09964564853fa625d..7ddba5f08aabed041d3dd2b145e341a7c40310b6 100644 GIT binary patch literal 103216 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 literal 83058 zcmeFZ1yo(#k}gVccXtvXKyV1|5Zv80xCM6$8r)riySuvtcbDJ}!5!`<{~wZb`gFe@ z{lH2_nQ1O=t|43+I`S`)Uk7IV+R9{70Z_L{ldK8FE_U4T{P-g6Kir8;zL-{LA57y4U7O=OcZ4=_ z@RgvwO@C`80iRMg1?~Fy`ZDaia5z(RGa>3n=-YIvd0r)D{aOjcY@E(c59@*meomGO?knMUoXhY!%lG&Kp3(S@JgDiAlZt$h!jW(RkG5hRI%9sTG zrN$*o;zP{-wA$b#bF#L8JV`4?mkLK*F808-yh$XC z;44;s1a&`9rnN!0t5~|wT4ZfHKS>t8nOBuFCC{tvh-=U$4o!=Jk07vzRB~5OIh$y` z_MiH+k%nmzP;pK49)wrx%PniU#45zp>H$SS3m`WTkjVWdEEcbTfb0SJ`uB5%^H+EH zXszR5Y+-0aV{dLI@Yg*ZHQ@d*)?8|V7O|JRy~SI98QAH2zJSDNS68F?xc0o*2HQ-} z_v_aSaJyU&!y>9=0bgR8vm$X89ImdG9@Yvbf=Z@~!1hrSli&K&8EO;9_ETCvo^9=E zcO;y3MDt~OC6~6H1g%Xl`i#+1n_6o+t$dW(_y|`0$$!?9XaU!pii7I#wFxB)t)?Se z&a@16Z>|hg^lGMX(pmQVxx7!(?~KP*7YT%mDr=@qx$lz*hPOpKu4e@Tn0+936&Bvs z!tXC5f~ELK7{KY@_{D=0v@zucZ+D|ID18C1QeGXej0JTYPM7zVh^aPGCg)HH|3PIV zFP>TaU3VT{tkuLbpMJYmLp)6_t%uwYc`R1)fz;F38oT%If!Q!?ES&TP^hd}Kh2ecS z&iKRc1^z-1P262-O%V1%Xe_Pc#LDjwm_AM#@OmTRhRQOX;xzW8 z?=W6}YZ*D}yUB5Q^y6Zz9%#{pX^k$W<~0>EcPgLIp8>U8*qoD$b7QLDQzP!Zqhw9D z5_pqChc&|(%Kv=_<8>^4X&zN~%qYC`g0p`S_m6bp@iH8PblAy(dDL$*vp5(JwsOmF z#+9s6-M`;6C!YjZ(y!s3hY7Wq8@aLh5)V(LjBkHO8?B)5V>}X1zOmL&kx>TH7Dkw=FQ&g zV(|Mf*1S^l$AkG`pj#bjBpkedurD+xId3s54N^fCdAu7@rNrD^nc zS`@MpbK1Lfd+&`J5nUSd0U?`%Cz^SxQQ`B+X}OWu9Afo{*bhsdawouQKX4axKLuW6 z+N_kD9WOo2qQ$&{A>n8jU$dPC*CF=Ajp{eNPqW^^q6N8^UC$mMhLf zvjT&;p-5IJJV2{cwOfyXr-GD=J8c=csn7i|tQ>;5XXJhYgmI>yI^tK0IygrEb~~%R zHZW1PApx&bN4$D{+8dWT-7}03zwWaz#DLE*qEA-dJLFe3Cg=E!B;?t!W+LS<1x)v^ zV6jiiqxIlu1kxxR^SP)`2lmfj!86;DCWe&z!GF-(!**0w(<>GXN{=>FbJwQsc08UN z04F|;rifl4$>FH>kqI(XW`fE)5fKl@DLj9}Y>aZj#gifsbRIX_T6l3E6)dx6Y+h#A zNMm7M@PHyE>$=48>2xXl9*q2bH4T>@1UKCKT5a=R#SKk1*_VGVl$1wk?H~!ruf9{}CMl~!tXkj6Kpd7#}EE}t0 zqVS_?j!M$PeO|uW z{IO+a3>nMk8Ex-gLG|!%i@PeU_r)VkxvvjhG;=GE+=4q*MHM;OzSG0*OjN;b5avX( z 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 $@JB9KYr62;X(v zZk@(@a#?R5(Kv^1&D;sapPYXy0kk_6r|>pBPu>7uB>X=F75t+laBsT+?q5mAqxY-9 z{Q7#cIB%{i;Cn^=XbR;pyTcO=_cL~r2Xf9N3+(s!qmz5I!_3HEZOOF2w|4k!m6_J5 zOW`NTe^M_pKT~q}nCvHQKu@cq_nB(#*J=8N5V?f1542S{N^q9rxOA*b7IV;*BI(|T zywKIqlfBh3T$d#uNn%zaQjheGf89nILnj&NyS3OB@JNN4ujEWAk9F;cw(qivbdkZ# z#LHDece92BIsG$8R!QjLHz)hIWM!=EPd(Bxbm>N3;S^V*5~EauFBLNmL|g z7YUc!zvE$IP)t;^;S&UpLL_clzL!FTnanJ!==Uws3gXS}hH|A-z2pJ%k3Y1O>x3my$MNS$VL4^IipgaIf*p5^Xg~(RCb0pUu49+Xs)rBuz55I7Hi%E~*TxDL`f6rM3GV~+wIx^!`9};j&_=L-VsCfJvHw$eLbmSUs=%#c6Pp(V z0VFtul}{d4A2-~Wr$*Az2t{U<75Uxt#HHqRe8dBhTDopZ*hlg^ubPLFSnkAM`<}{u ziTP{od>r0xf!_W!mZzl6DvfB2X*3by?vNO?>G z^k}#8g8cD@`;tkbl!&^20FSnH=SGn={w={I1kA7{iVBF5!{{Y@`Nr!CXYWrul>SvP zDuqR|jMBJ6BTk_Gd#O}*#t}Z^4%Itk=(l&6hrh#F2L^dTXe)k zdX`V3NH7pId_?7YiH-|B+EyN8f2{Z7pautsyG)n|aMlVF4<2ntRN{^(mtoj(aYV

GeJPyRI;G9f9ps{4 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�i0mf^R&xt*{kwC5A|chJUHZ^za)~0~ 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 diff --git a/ссылки на док.md b/ссылки на док.md new file mode 100644 index 0000000..15d18ea --- /dev/null +++ b/ссылки на док.md @@ -0,0 +1 @@ +https://disk.yandex.ru/i/TMyHlpYxIP75YQ \ No newline at end of file From bd8d22312e72af4c88815d78d89dc0fe11f2b6ee Mon Sep 17 00:00:00 2001 From: Andrey Kruchinkin Date: Sat, 29 Aug 2026 21:45:30 +0300 Subject: [PATCH 07/11] docs: document CAN bootloader protocol --- README.md | 198 + docs/protocan/BOOTLOADER.md | 183 + docs/protocan/CHANGELOG.md | 21 + docs/protocan/OAP.md | 56 + docs/protocan/PROTOCOL.md | 114 + docs/protocan/README.md | 42 + docs/protocan/build-html.bat | 19 + docs/protocan/build-html.ps1 | 57 + docs/protocan/build/protocol.html | 833 ++ docs/protocan/examples/test-vectors.json | 45 + docs/protocan/protocol.html | 833 ++ Протокол CAN и ОАП.html | 13405 +++++++++++++++++++++ Протокол CAN и ОАП.md | 258 +- 13 files changed, 16060 insertions(+), 4 deletions(-) create mode 100644 docs/protocan/BOOTLOADER.md create mode 100644 docs/protocan/CHANGELOG.md create mode 100644 docs/protocan/OAP.md create mode 100644 docs/protocan/PROTOCOL.md create mode 100644 docs/protocan/README.md create mode 100644 docs/protocan/build-html.bat create mode 100644 docs/protocan/build-html.ps1 create mode 100644 docs/protocan/build/protocol.html create mode 100644 docs/protocan/examples/test-vectors.json create mode 100644 docs/protocan/protocol.html create mode 100644 Протокол CAN и ОАП.html diff --git a/README.md b/README.md index 96b179e..c8039ab 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,20 @@ SETCAN/ Модуль зависит от файлов `main.h` и `can.h`, сгенерированных STM32CubeMX, а также от HAL-драйверов CAN, RTC и TIM. +## Документация протокола + +Нормативное описание разделено по назначению: + +- [`docs/protocan/PROTOCOL.md`](docs/protocan/PROTOCOL.md) — структура ProtoCAN; +- [`docs/protocan/BOOTLOADER.md`](docs/protocan/BOOTLOADER.md) — прошивка по CAN; +- [`docs/protocan/OAP.md`](docs/protocan/OAP.md) — правила ведения ОАП; +- [`docs/protocan/examples/test-vectors.json`](docs/protocan/examples/test-vectors.json) — машинные эталоны; +- [`docs/protocan/build/protocol.html`](docs/protocan/build/protocol.html) — собранная HTML-версия. + +Большой файл `Протокол CAN и ОАП.md` и исходный XLSX сохранены как табличное +представление реестра. Правила приоритета источников описаны в +[`docs/protocan/README.md`](docs/protocan/README.md). + ## Формат расширенного CAN ID Протокол размещает служебные поля в 29-битном Extended ID: @@ -42,6 +56,11 @@ SETCAN/ | `0x6` | Modbus Holding | | `0x7` | Modbus Input | | `0x8` | ошибка | +| `0x9` | управление загрузчиком (`BOOT_CONTROL`, зарезервировано) | +| `0xA` | данные прошивки, слот A (`BOOT_DATA_A`, зарезервировано) | +| `0xB` | данные прошивки, слот B (`BOOT_DATA_B`, зарезервировано) | +| `0xC` | состояние загрузчика (`BOOT_STATUS`, зарезервировано) | +| `0xD` | обнаружение загрузчиков (`BOOT_DISCOVERY`, зарезервировано) | | `0xE` | настройка привязки датчика (`SETTINGS`) | | `0xF` | пульс присутствия устройства | @@ -56,6 +75,11 @@ SETCAN/ Для регистров `uint16_t` в CAN payload используется порядок байтов little-endian: сначала младший байт, затем старший. +Пара `DeviceType/DeviceID` образует уникальный адрес прибора. Три бита +`DeviceType` задают 8 типов, четыре бита `DeviceID` — 16 экземпляров каждого +типа; всего на одной шине можно адресовать до 128 приборов. Загрузочные кадры +так же адресуются этой парой и не требуют изменения 29-битного CAN ID. + > Разметка ID реализована C-битовыми полями. Она соответствует используемому STM32 GCC ABI, но не является переносимой между произвольными компиляторами без проверки фактического расположения битов. ## Подключение к STM32-проекту @@ -348,6 +372,180 @@ Broadcast-команда `PROTOCAN_BROADCAST_RTCSETUP` ожидает ровно Перед записью проверяются диапазоны и количество дней с учётом високосного года. +## Прошивка приборов по CAN + +Ниже зафиксирован формат планируемого загрузочного сервиса. Значения +`MsgType=0x9..0xD` зарезервированы в протоколе, но обработчики загрузчика в +текущих `protocan.c/.h` ещё не реализованы. + +Загрузчик работает поверх classic CAN 2.0B с Extended ID. Управляющий модуль +использует `Route=0`, прибор отвечает с `Route=1`. Команды стирания и записи +всегда должны быть адресованы конкретной паре `DeviceType/DeviceID`; +широковещательный режим допустим только для обнаружения. + +### Карта загрузочных сообщений + +| `MsgType` | Имя | Назначение `MsgBody` | CAN payload | +|---:|---|---|---| +| `0x9` | `BOOT_CONTROL` | `SessionID:8 \| Command:8` | параметры команды | +| `0xA` | `BOOT_DATA_A` | номер 8-байтового блока слота A | 8 байт образа | +| `0xB` | `BOOT_DATA_B` | номер 8-байтового блока слота B | 8 байт образа | +| `0xC` | `BOOT_STATUS` | `SessionID:8 \| Command:8` | статус и прогресс | +| `0xD` | `BOOT_DISCOVERY` | подтип запроса/ответа | идентификация прибора | + +`MsgBody` в кадрах данных является не байтовым адресом, а номером блока: + +```c +block_offset = (uint32_t)MsgBody * 8U; + +if (MsgType == PROTOCAN_MSGTYPE_BOOT_DATA_A) { + address = SLOT_A_BASE + block_offset; +} else if (MsgType == PROTOCAN_MSGTYPE_BOOT_DATA_B) { + address = SLOT_B_BASE + block_offset; +} +``` + +Диапазон `MsgBody=0x0000..0xFFFF` адресует 65536 блоков: + +```text +65536 блоков * 8 байт = 524288 байт = 512 КиБ на слот +``` + +Таким образом, `BOOT_DATA_A` и `BOOT_DATA_B` адресуют два логических слота +по 512 КиБ, всего 1 МиБ пространства образов. Физические `SLOT_A_BASE` и +`SLOT_B_BASE` задаёт конкретный загрузчик. Если внутренняя Flash имеет ровно +1 МиБ, два полных слота в ней не поместятся вместе с загрузчиком и метаданными: +нужно уменьшить слоты, выбрать MCU с большей Flash или хранить staging-образ +во внешней памяти. + +### Кадр данных + +```text +Extended CAN ID + Priority = STANDARD + Route = FROM_PM + DeviceType = тип целевого прибора + DeviceID = экземпляр целевого прибора + MsgType = 0xA (слот A) или 0xB (слот B) + MsgBody = BlockIndex, 0x0000..0xFFFF + +DATA[0..7] = очередные 8 байт образа +``` + +Например, `MsgBody=0x0123` задаёт смещение `0x0123 * 8 = 0x0918` от +начала выбранного слота. Последний неполный блок дополняется значениями +`0xFF`; фактический размер передаётся командой `BEGIN_UPDATE`, поэтому CRC32 +считается только по байтам образа. + +### Управляющие команды + +В `BOOT_CONTROL` поле `MsgBody` имеет формат: + +```text +15........8 7.........0 + SessionID Command +``` + +Рекомендуемые команды: + +| Код | Команда | Назначение | +|---:|---|---| +| `0x01` | `IDENTIFY` | прочитать тип, аппаратную и программную версии | +| `0x02` | `ENTER_BOOT` | перейти из приложения в загрузчик | +| `0x03` | `BEGIN_IMAGE` | передать размер и CRC32 образа | +| `0x04` | `BEGIN_COMPAT` | передать тип, аппаратную и программную версии | +| `0x05` | `ERASE` | подготовить неактивный слот | +| `0x06` | `VERIFY` | проверить размер, CRC32 и подпись | +| `0x07` | `COMMIT` | назначить проверенный слот кандидатом на запуск | +| `0x08` | `CONFIRM` | подтвердить успешный запуск новой программы | +| `0x09` | `REBOOT` | перезагрузить прибор | +| `0x0A` | `ABORT` | отменить текущую сессию | +| `0x0B` | `QUERY_PROGRESS` | запросить слот и следующий ожидаемый блок | + +`BEGIN_IMAGE` содержит размер и CRC образа: + +```text +DATA[0..3] ImageSize, uint32 little-endian +DATA[4..7] ImageCRC32, uint32 little-endian +``` + +`BEGIN_COMPAT` содержит совместимость и версию: + +```text +DATA[0..1] ProductType, uint16 little-endian +DATA[2] минимальная HardwareRevision +DATA[3] максимальная HardwareRevision +DATA[4..7] FirmwareVersion, uint32 little-endian +``` + +Обе команды передаются с одним `SessionID`. До стирания Flash загрузчик обязан +получить обе части метаданных и проверить `ProductType`, аппаратную ревизию, +размер образа, границы выбранного слота и допустимость версии. + +### Ответ состояния + +`BOOT_STATUS` возвращает результат команды и точку продолжения: + +```text +MsgBody[15..8] = SessionID +MsgBody[7..0] = команда, на которую дан ответ + +DATA[0] Status +DATA[1] TargetSlot: 0 = A, 1 = B +DATA[2..3] NextBlock, uint16 little-endian +DATA[4..7] RunningCRC32, uint32 little-endian +``` + +Минимальный набор статусов: + +| Код | Статус | +|---:|---| +| `0x00` | `OK` | +| `0x01` | `BUSY` | +| `0x02` | `INVALID_COMMAND` | +| `0x03` | `WRONG_DEVICE` | +| `0x04` | `WRONG_HARDWARE` | +| `0x05` | `INVALID_SIZE` | +| `0x06` | `CRC_ERROR` | +| `0x07` | `FLASH_ERROR` | +| `0x08` | `SEQUENCE_ERROR` | +| `0x09` | `SIGNATURE_ERROR` | +| `0x0A` | `SESSION_ERROR` | +| `0x0B` | `VOLTAGE_ERROR` | + +`NextBlock` позволяет возобновить загрузку после разрыва связи. Для первой +реализации допустимо подтверждать каждый блок. Для рабочей скорости лучше +передавать окна по 16 кадров и подтверждать окно одним `BOOT_STATUS`; при +необходимости протокол статуса можно расширить битовой картой потерянных +блоков. + +### Выбор слота и безопасное обновление + +GUI не должен самостоятельно перезаписывать активный слот. После получения +`BEGIN_IMAGE` и `BEGIN_COMPAT` загрузчик выбирает неактивный слот и сообщает его в +`BOOT_STATUS`: + +```text +активен A -> принимать BOOT_DATA_B +активен B -> принимать BOOT_DATA_A +``` + +Рекомендуемый цикл обновления: + +1. Обнаружить прибор и сверить `DeviceType/DeviceID`, `ProductType`, UID и версии. +2. Выполнить адресную команду `ENTER_BOOT` и получить новый `SessionID`. +3. Передать `BEGIN_IMAGE` и `BEGIN_COMPAT`; загрузчик выберет неактивный слот. +4. Стереть выбранный слот и передать блоки `BOOT_DATA_A` или `BOOT_DATA_B`. +5. Выполнить `VERIFY`: проверить размер, CRC32 и цифровую подпись образа. +6. Выполнить `COMMIT` и перезагрузить устройство. +7. Новое приложение вызывает `CONFIRM` после успешной самопроверки. +8. При отсутствии подтверждения загрузчик возвращается к предыдущему слоту. + +CRC32 обнаруживает случайное повреждение, но не защищает от подмены. Для +серийных изделий образ следует подписывать, а открытый ключ проверки хранить +в неизменяемой части загрузчика. Сам загрузчик не должен обновляться обычными +командами `BOOT_DATA_A/B`. + ## Важные ограничения текущей реализации - Модуль рассчитан на classic CAN с payload до 8 байт, не на CAN FD. diff --git a/docs/protocan/BOOTLOADER.md b/docs/protocan/BOOTLOADER.md new file mode 100644 index 0000000..f4ccf78 --- /dev/null +++ b/docs/protocan/BOOTLOADER.md @@ -0,0 +1,183 @@ +# ProtoCAN Boot Protocol + +Статус: **Draft** +Версия протокола: **1.0** +Совместимость: **classic CAN 2.0B, Extended ID, DLC 0…8** +Реализация: [`templates/c/protocan-boot`](../../../templates/c/protocan-boot) + +## Назначение + +Сервис обновляет адресованный прибор по CAN и поддерживает два логических +слота A/B. Активный слот не стирается: новый образ записывается в неактивный, +проверяется и атомарно назначается кандидатом на запуск. + +## Карта сообщений + +| `MsgType` | Имя | `MsgBody` | Payload | +|---:|---|---|---| +| `0x9` | `BOOT_CONTROL` | `SessionID[15:8] \| Command[7:0]` | параметры команды | +| `0xA` | `BOOT_DATA_A` | `BlockIndex[15:0]` | 8 байт слота A | +| `0xB` | `BOOT_DATA_B` | `BlockIndex[15:0]` | 8 байт слота B | +| `0xC` | `BOOT_STATUS` | `SessionID[15:8] \| Command[7:0]` | статус и прогресс | +| `0xD` | `BOOT_DISCOVERY` | подтип ответа | идентификация | + +Все команды записи адресуются конкретному `DeviceType/DeviceID` и имеют +`Route=0`. Ответы сохраняют адрес прибора и имеют `Route=1`. + +## Адресация образа + +`MsgBody` кадра данных — номер 8-байтового блока: + +```c +offset = (uint32_t)BlockIndex * 8U; +address = SLOT_X_BASE + offset; +``` + +```text +512 КиБ = 524 288 байт +524 288 / 8 = 65 536 блоков +BlockIndex = 0x0000…0xFFFF +``` + +| `BlockIndex` | Смещение | Диапазон байтов | +|---:|---:|---:| +| `0x0000` | `0x00000` | `0x00000…0x00007` | +| `0x0001` | `0x00008` | `0x00008…0x0000F` | +| `0xFFFF` | `0x7FFF8` | `0x7FFF8…0x7FFFF` | + +`0x80000` является первой позицией за границей слота. Последний кадр +дополняется `0xFF`, но CRC32 вычисляется только по `ImageSize` байтам. + +## Команды `BOOT_CONTROL` + +| Код | Команда | DLC | Payload | Допустимое состояние | +|---:|---|---:|---|---| +| `0x01` | `IDENTIFY` | 0 | отсутствует | любое | +| `0x02` | `ENTER_BOOT` | 0 | отсутствует | любое; `SessionID != 0` | +| `0x03` | `BEGIN_IMAGE` | 8 | размер и CRC32 | metadata | +| `0x04` | `BEGIN_COMPAT` | 8 | совместимость и версия | metadata | +| `0x05` | `ERASE` | 0 | отсутствует | ready-to-erase | +| `0x06` | `VERIFY` | 0 | отсутствует | образ получен | +| `0x07` | `COMMIT` | 0 | отсутствует | verified | +| `0x08` | `CONFIRM` | 0 | отсутствует | запущенное приложение | +| `0x09` | `REBOOT` | 0 | отсутствует | активная сессия | +| `0x0A` | `ABORT` | 0 | отсутствует | активная сессия | +| `0x0B` | `QUERY_PROGRESS` | 0 | отсутствует | активная сессия | + +### `BEGIN_IMAGE` + +```text +DATA[0..3] ImageSize, uint32 little-endian +DATA[4..7] ImageCRC32, uint32 little-endian +``` + +### `BEGIN_COMPAT` + +```text +DATA[0..1] ProductType, uint16 little-endian +DATA[2] HardwareRevisionMin +DATA[3] HardwareRevisionMax +DATA[4..7] FirmwareVersion, uint32 little-endian +``` + +До `ERASE` прибор обязан получить обе части метаданных и проверить размер, +тип изделия, аппаратную ревизию, версию и политику anti-rollback. + +## `BOOT_STATUS` + +```text +MsgBody[15..8] SessionID +MsgBody[7..0] команда, на которую дан ответ + +DATA[0] Status +DATA[1] TargetSlot: 0=A, 1=B, 0xFF=не выбран +DATA[2..3] NextBlock, uint16 little-endian +DATA[4..7] RunningCRC32, uint32 little-endian +``` + +| Код | Статус | Повтор допустим | +|---:|---|---| +| `0x00` | `OK` | — | +| `0x01` | `BUSY` | да, после задержки | +| `0x02` | `INVALID_COMMAND` | после исправления | +| `0x03` | `WRONG_DEVICE` | нет для этого образа | +| `0x04` | `WRONG_HARDWARE` | нет для этого образа | +| `0x05` | `INVALID_SIZE` | нет для этого образа | +| `0x06` | `CRC_ERROR` | новая передача | +| `0x07` | `FLASH_ERROR` | зависит от платформы | +| `0x08` | `SEQUENCE_ERROR` | да, с `NextBlock` | +| `0x09` | `SIGNATURE_ERROR` | нет | +| `0x0A` | `SESSION_ERROR` | открыть новую сессию | +| `0x0B` | `VOLTAGE_ERROR` | да после нормализации питания | +| `0x0C` | `INVALID_STATE` | выполнить правильный переход | + +## State machine + +```text +IDLE + └─ ENTER_BOOT ─> METADATA + ├─ BEGIN_IMAGE + └─ BEGIN_COMPAT + │ + v + READY_TO_ERASE + │ ERASE + v + RECEIVING + │ VERIFY + v + VERIFIED + │ COMMIT + v + PENDING + REBOOT + │ CONFIRM + v + CONFIRMED +``` + +Ошибка Flash, CRC, совместимости или подписи переводит сессию в `FAILED`. +Новая `ENTER_BOOT` создаёт чистую сессию. `ABORT` прекращает текущую передачу, +не активируя частично записанный слот. + +## Надёжность и повторы + +- Блоки передаются строго по возрастанию `BlockIndex`. +- Дубликат или пропуск возвращает `SEQUENCE_ERROR` и ожидаемый `NextBlock`. +- Базовый режим подтверждает каждый блок. +- Рабочий режим может подтверждать окно из 16 блоков. +- После потери связи `QUERY_PROGRESS` возвращает следующий ожидаемый блок, + пока состояние загрузчика сохранено. +- Для продолжения после перезагрузки порт должен сохранять session metadata + и восстановить её при инициализации; ядро версии 1.0 само это не делает. + +## Безопасность и A/B-обновление + +```text +active=A -> target=B -> verify -> pending=B +active=B -> target=A -> verify -> pending=A +``` + +CRC32 защищает только от случайного повреждения. Серийный загрузчик должен +дополнительно проверить подпись контейнера, границы вектора, совместимость и +anti-rollback. Bootloader не обновляется командами `BOOT_DATA_A/B`. + +Boot metadata должна атомарно хранить: + +- активный слот; +- pending-слот; +- подтверждение запуска; +- число неудачных попыток; +- версию и CRC32 образа. + +Если приложение не выполняет `CONFIRM` за установленное число запусков, +загрузчик возвращается к предыдущему подтверждённому слоту. + +## Эталонный сценарий + +1. ПМ адресно отправляет `IDENTIFY`. +2. ПМ открывает ненулевой `SessionID` командой `ENTER_BOOT`. +3. ПМ отправляет `BEGIN_IMAGE` и `BEGIN_COMPAT`. +4. Прибор сообщает выбранный неактивный слот. +5. ПМ выполняет `ERASE` и передаёт `BOOT_DATA_A` либо `BOOT_DATA_B`. +6. ПМ выполняет `VERIFY`, затем `COMMIT` и `REBOOT`. +7. Новое приложение после самопроверки выполняет `CONFIRM`. diff --git a/docs/protocan/CHANGELOG.md b/docs/protocan/CHANGELOG.md new file mode 100644 index 0000000..1fa80bf --- /dev/null +++ b/docs/protocan/CHANGELOG.md @@ -0,0 +1,21 @@ +# История изменений ProtoCAN + +Формат основан на Keep a Changelog. Версия относится к спецификации, а не к +версии прошивки отдельного прибора. + +## [Unreleased] + +### Added + +- Структурированный комплект документации `docs/protocan`. +- Загрузочный сервис `MsgType=0x9…0xD`. +- Два логических слота по 512 КиБ, 65 536 блоков по 8 байт каждый. +- Машинные эталоны CAN ID в `examples/test-vectors.json`. + +## [1.0] — 2026-08-29 + +### Added + +- Зафиксирована 29-битная структура ProtoCAN ID. +- Зафиксирована адресация 8 типов по 16 экземпляров. +- Существующие сообщения `0x0…0x8`, `0xE`, `0xF` сохранены. diff --git a/docs/protocan/OAP.md b/docs/protocan/OAP.md new file mode 100644 index 0000000..b33a350 --- /dev/null +++ b/docs/protocan/OAP.md @@ -0,0 +1,56 @@ +# Общее адресное пространство + +Статус: **Stable, данные ведутся в XLSX** +Порядок значений: **16-битные регистры, little-endian в CAN payload** + +Редактируемый источник реестра: +[`Протокол CAN и ОАП.xlsx`](../../Протокол%20CAN%20и%20ОАП.xlsx). + +Просматриваемая большая таблица находится в +[`Протокол CAN и ОАП.html`](../../Протокол%20CAN%20и%20ОАП.html) и +[`Протокол CAN и ОАП.md`](../../Протокол%20CAN%20и%20ОАП.md). + +## Назначение + +ОАП связывает 16-битный адрес регистра с его типом, назначением, доступом и +масштабом. В ProtoCAN используется `MsgType=0x3`, а `MsgBody` содержит адрес +первого регистра. + +## Обязательные поля реестра + +| Поле | Требование | +|---|---| +| AddressHex | `0x0000…0xFFFF`, уникальное значение | +| AddressDec | десятичный эквивалент AddressHex | +| Group | функциональная группа | +| Name | однозначное имя параметра | +| Type | `u16`, `i16`, `u32`, `i32`, `float32`, bitmap или массив | +| Registers | число занятых 16-битных регистров | +| Access | `R`, `W` или `RW` | +| Unit | физическая единица либо `—` | +| Scale | множитель/делитель представления | +| Default | значение после сброса, если применимо | +| Description | семантика, диапазон и особые значения | + +## Правила ведения + +- Адрес не переиспользуется с другим смыслом после выпуска стабильной версии. +- Многорегистровое значение занимает непрерывный диапазон. +- Порядок 16-битных слов для 32-битного значения фиксируется в строке типа. +- Резервные диапазоны явно отмечаются и не используются без изменения версии. +- Удалённый параметр помечается deprecated, а не исчезает молча. +- Изменение адреса, типа или масштаба отражается в `CHANGELOG.md`. + +## Экспорт + +Для программной генерации каталог следует экспортировать из XLSX в CSV с +UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на: + +- уникальность адресов; +- пересечение многорегистровых значений; +- допустимые типы и права доступа; +- равенство шестнадцатеричного и десятичного адреса; +- попадание адреса в диапазон `0x0000…0xFFFF`. + +До появления автоматического экспортёра нормативным источником адресов +остаётся XLSX, а HTML/Markdown считаются представлением. diff --git a/docs/protocan/PROTOCOL.md b/docs/protocan/PROTOCOL.md new file mode 100644 index 0000000..5f76f3c --- /dev/null +++ b/docs/protocan/PROTOCOL.md @@ -0,0 +1,114 @@ +# ProtoCAN — базовый протокол + +Статус: **Stable с зарезервированным загрузочным расширением** +Версия: **1.0** +Порядок байтов payload: **little-endian**, если явно не указано иное + +## Назначение + +ProtoCAN — прикладной протокол поверх classic CAN 2.0B. Используются только +расширенные 29-битные идентификаторы (`IDE=1`) и payload длиной 0…8 байт. + +## Термины + +| Термин | Значение | +|---|---| +| ПМ | управляющий модуль | +| прибор | адресуемый узел на шине | +| `DeviceType` | тип прибора, 0…7 | +| `DeviceID` | экземпляр прибора данного типа, 0…15 | +| `MsgType` | класс сообщения или сервис | +| `MsgBody` | 16-битное поле, формат которого зависит от `MsgType` | + +Пара `DeviceType/DeviceID` задаёт до `8 × 16 = 128` уникальных адресов. + +## Расширенный CAN ID + +```text +28 27 26...24 23...20 19...16 15........0 +Priority Route DeviceType DeviceID MsgType MsgBody + 1 бит 1 бит 3 бита 4 бита 4 бита 16 бит +``` + +```c +can_id = + ((uint32_t)priority << 28) | + ((uint32_t)route << 27) | + ((uint32_t)device_type << 24) | + ((uint32_t)device_id << 20) | + ((uint32_t)msg_type << 16) | + msg_body; +``` + +| Поле | Значения | Назначение | +|---|---|---| +| `Priority` | `0` critical, `1` standard | CAN-арбитраж | +| `Route` | `0` от ПМ, `1` от прибора | логическое направление | +| `DeviceType` | `0…7` | тип прибора | +| `DeviceID` | `0…15` | номер экземпляра | +| `MsgType` | `0…15` | тип сообщения | +| `MsgBody` | `0…65535` | команда, адрес или номер блока | + +`Route` не является направлением физического трансивера. Ответ прибора +сохраняет адрес `DeviceType/DeviceID` и устанавливает `Route=1`. + +## Реестр `MsgType` + +| Код | Имя | Основное направление | DLC | Статус | +|---:|---|---|---:|---| +| `0x0` | `BROADCAST` | ПМ → все | зависит от команды | stable | +| `0x1` | `DISCRETE` | оба | 0…8 | stable | +| `0x2` | `ANALOG` | оба | 0…8 | stable | +| `0x3` | `GAS` | оба | 0/2/4/6/8 | stable | +| `0x4` | `MODBUS_COIL` | оба | 0…8 | stable | +| `0x5` | `MODBUS_DISCRETE` | оба | 0…8 | stable | +| `0x6` | `MODBUS_HOLDING` | оба | 0…8 | stable | +| `0x7` | `MODBUS_INPUT` | оба | 0…8 | stable | +| `0x8` | `ERROR` | прибор → ПМ | 0 | stable | +| `0x9` | `BOOT_CONTROL` | ПМ → прибор | 0/8 | draft | +| `0xA` | `BOOT_DATA_A` | ПМ → прибор | 8 | draft | +| `0xB` | `BOOT_DATA_B` | ПМ → прибор | 8 | draft | +| `0xC` | `BOOT_STATUS` | прибор → ПМ | 8 | draft | +| `0xD` | `BOOT_DISCOVERY` | прибор → ПМ | 8 | draft | +| `0xE` | `SETTINGS` | оба | 0/1/8 | stable | +| `0xF` | `PULSE` | прибор → сеть | 1 | stable | + +Подробный формат `0x9…0xD` находится в [BOOTLOADER.md](BOOTLOADER.md). + +## Разметки `MsgBody` + +| `MsgType` | Биты `MsgBody` | +|---|---| +| broadcast | команда `[15:4]`, параметр `[3:0]` | +| discrete/analog | подтип `[15:12]`, значение/адрес `[11:0]` | +| Modbus | начальный адрес `[15:4]`, количество `[3:0]` | +| GAS | адрес первого 16-битного регистра `[15:0]` | +| error | дополнительная информация `[15:8]`, код `[7:0]` | +| settings | номер сборки `[15:8]`, позиция `[7:0]` | +| boot control/status | `SessionID[15:8]`, команда `[7:0]` | +| boot data | `BlockIndex[15:0]` | + +## Общие правила обмена + +- Многобайтовые значения в `DATA` передаются little-endian. +- Узел игнорирует адресованные кадры с чужим `DeviceType/DeviceID`. +- Прибор принимает команды ПМ с `Route=0`; ПМ принимает ответы с `Route=1`. +- Стандартные 11-битные CAN ID не являются кадрами ProtoCAN. +- RTR для загрузочного сервиса запрещён. +- Неописанные комбинации `MsgType/MsgBody/DLC` должны отвергаться. + +## Эталон упаковки ID + +```text +Priority = 1 +Route = 0 +DeviceType = 3 +DeviceID = 5 +MsgType = 0x9 +MsgBody = 0x0702 + +CAN ID = 0x13590702 +``` + +Этот пример соответствует `ENTER_BOOT`, `SessionID=7`. Машинные варианты +находятся в [examples/test-vectors.json](examples/test-vectors.json). diff --git a/docs/protocan/README.md b/docs/protocan/README.md new file mode 100644 index 0000000..36019ea --- /dev/null +++ b/docs/protocan/README.md @@ -0,0 +1,42 @@ +# Документация ProtoCAN + +Статус комплекта: **Draft** +Версия комплекта: **1.0** +Дата редакции: **2026-08-29** +Транспорт: **Classic CAN 2.0B, Extended ID, DLC 0…8** + +Этот каталог разделяет нормативное описание протокола, загрузчик и реестр +общего адресного пространства. Большой исходный документ +[`Протокол CAN и ОАП.md`](../../Протокол%20CAN%20и%20ОАП.md) сохранён как +совместимое представление таблиц из Excel. + +## Документы + +| Документ | Назначение | Статус источника | +|---|---|---| +| [PROTOCOL.md](PROTOCOL.md) | 29-битный CAN ID, адресация, реестр `MsgType`, порядок байтов | нормативный | +| [BOOTLOADER.md](BOOTLOADER.md) | обновление прошивки, кадры, состояния, ошибки и A/B-слоты | нормативный draft | +| [OAP.md](OAP.md) | правила ведения общего адресного пространства | нормативный индекс | +| [../../Протокол CAN и ОАП.xlsx](../../Протокол%20CAN%20и%20ОАП.xlsx) | редактируемый реестр ОАП | источник таблиц | +| [examples/test-vectors.json](examples/test-vectors.json) | машинные эталоны CAN ID и payload | нормативные примеры | +| [CHANGELOG.md](CHANGELOG.md) | история версий документа | нормативный | + +## Приоритет источников + +При расхождении данных действует следующий порядок: + +1. `PROTOCOL.md` — структура ProtoCAN и реестр типов сообщений. +2. `BOOTLOADER.md` — загрузочный сервис `0x9…0xD`. +3. XLSX — адреса и свойства регистров ОАП. +4. Сгенерированный HTML — только представление, не самостоятельный источник. + +## Сборка HTML + +В PowerShell 7: + +```powershell +./build-html.ps1 +``` + +Результат создаётся в `build/protocol.html`. Скрипт не изменяет исходные +Markdown/XLSX и пригоден для запуска в CI. diff --git a/docs/protocan/build-html.bat b/docs/protocan/build-html.bat new file mode 100644 index 0000000..52096a9 --- /dev/null +++ b/docs/protocan/build-html.bat @@ -0,0 +1,19 @@ +@echo off +setlocal + +set "SCRIPT_DIR=%~dp0" + +where pwsh.exe >nul 2>nul +if %ERRORLEVEL% EQU 0 ( + pwsh.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build-html.ps1" %* +) else ( + powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build-html.ps1" %* +) + +set "EXIT_CODE=%ERRORLEVEL%" +if not "%EXIT_CODE%"=="0" ( + echo. + echo Ошибка сборки HTML. Код: %EXIT_CODE% +) + +exit /b %EXIT_CODE% diff --git a/docs/protocan/build-html.ps1 b/docs/protocan/build-html.ps1 new file mode 100644 index 0000000..2310dd8 --- /dev/null +++ b/docs/protocan/build-html.ps1 @@ -0,0 +1,57 @@ +[CmdletBinding()] +param( + [string]$OutputPath = (Join-Path $PSScriptRoot 'build\protocol.html') +) + +$ErrorActionPreference = 'Stop' +$documents = @( + 'README.md', + 'PROTOCOL.md', + 'BOOTLOADER.md', + 'OAP.md', + 'CHANGELOG.md' +) + +$sections = foreach ($document in $documents) { + $path = Join-Path $PSScriptRoot $document + $markdown = Get-Content -Raw -LiteralPath $path + (ConvertFrom-Markdown -InputObject $markdown).Html +} + +$style = @' +body { max-width: 1180px; margin: 32px auto; padding: 0 24px; + color: #111827; background: #fff; font: 15px/1.55 Arial, sans-serif; } +h1, h2, h3 { line-height: 1.25; } +h1 { margin-top: 48px; border-bottom: 2px solid #334155; padding-bottom: 8px; } +h2 { margin-top: 32px; } +a { color: #1155cc; } +code { font-family: Consolas, "Courier New", monospace; } +pre { overflow: auto; padding: 12px; border: 1px solid #cbd5e1; background: #f8fafc; } +table { width: 100%; border-collapse: collapse; margin: 12px 0 24px; } +th, td { border: 1px solid #94a3b8; padding: 6px 9px; vertical-align: top; } +th { background: #e2e8f0; } +tr:nth-child(even) td { background: #f8fafc; } +'@ + +$outputDirectory = Split-Path -Parent $OutputPath +if (-not (Test-Path -LiteralPath $outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory | Out-Null +} + +$html = @" + + + + + +ProtoCAN — спецификация + + + +$($sections -join "`n


`n") + + +"@ + +Set-Content -LiteralPath $OutputPath -Value $html -Encoding utf8 +Write-Host "Создан $OutputPath" diff --git a/docs/protocan/build/protocol.html b/docs/protocan/build/protocol.html new file mode 100644 index 0000000..fa8a3c6 --- /dev/null +++ b/docs/protocan/build/protocol.html @@ -0,0 +1,833 @@ + + + + + +ProtoCAN — спецификация + + + +

Документация ProtoCAN

+

Статус комплекта: Draft
+Версия комплекта: 1.0
+Дата редакции: 2026-08-29
+Транспорт: Classic CAN 2.0B, Extended ID, DLC 0…8

+

Этот каталог разделяет нормативное описание протокола, загрузчик и реестр +общего адресного пространства. Большой исходный документ +Протокол CAN и ОАП.md сохранён как +совместимое представление таблиц из Excel.

+

Документы

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ДокументНазначениеСтатус источника
PROTOCOL.md29-битный CAN ID, адресация, реестр MsgType, порядок байтовнормативный
BOOTLOADER.mdобновление прошивки, кадры, состояния, ошибки и A/B-слотынормативный draft
OAP.mdправила ведения общего адресного пространстванормативный индекс
../../Протокол CAN и ОАП.xlsxредактируемый реестр ОАПисточник таблиц
examples/test-vectors.jsonмашинные эталоны CAN ID и payloadнормативные примеры
CHANGELOG.mdистория версий документанормативный
+

Приоритет источников

+

При расхождении данных действует следующий порядок:

+
    +
  1. PROTOCOL.md — структура ProtoCAN и реестр типов сообщений.
  2. +
  3. BOOTLOADER.md — загрузочный сервис 0x9…0xD.
  4. +
  5. XLSX — адреса и свойства регистров ОАП.
  6. +
  7. Сгенерированный HTML — только представление, не самостоятельный источник.
  8. +
+

Сборка HTML

+

В PowerShell 7:

+
./build-html.ps1
+
+

Результат создаётся в build/protocol.html. Скрипт не изменяет исходные +Markdown/XLSX и пригоден для запуска в CI.

+ +
+

ProtoCAN — базовый протокол

+

Статус: Stable с зарезервированным загрузочным расширением
+Версия: 1.0
+Порядок байтов payload: little-endian, если явно не указано иное

+

Назначение

+

ProtoCAN — прикладной протокол поверх classic CAN 2.0B. Используются только +расширенные 29-битные идентификаторы (IDE=1) и payload длиной 0…8 байт.

+

Термины

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ТерминЗначение
ПМуправляющий модуль
приборадресуемый узел на шине
DeviceTypeтип прибора, 0…7
DeviceIDэкземпляр прибора данного типа, 0…15
MsgTypeкласс сообщения или сервис
MsgBody16-битное поле, формат которого зависит от MsgType
+

Пара DeviceType/DeviceID задаёт до 8 × 16 = 128 уникальных адресов.

+

Расширенный CAN ID

+
28       27       26...24      23...20     19...16     15........0
+Priority Route    DeviceType   DeviceID    MsgType     MsgBody
+ 1 бит    1 бит      3 бита      4 бита      4 бита      16 бит
+
+
can_id =
+    ((uint32_t)priority    << 28) |
+    ((uint32_t)route       << 27) |
+    ((uint32_t)device_type << 24) |
+    ((uint32_t)device_id   << 20) |
+    ((uint32_t)msg_type    << 16) |
+    msg_body;
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ПолеЗначенияНазначение
Priority0 critical, 1 standardCAN-арбитраж
Route0 от ПМ, 1 от приборалогическое направление
DeviceType0…7тип прибора
DeviceID0…15номер экземпляра
MsgType0…15тип сообщения
MsgBody0…65535команда, адрес или номер блока
+

Route не является направлением физического трансивера. Ответ прибора +сохраняет адрес DeviceType/DeviceID и устанавливает Route=1.

+

Реестр MsgType

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодИмяОсновное направлениеDLCСтатус
0x0BROADCASTПМ → всезависит от командыstable
0x1DISCRETEоба0…8stable
0x2ANALOGоба0…8stable
0x3GASоба0/2/4/6/8stable
0x4MODBUS_COILоба0…8stable
0x5MODBUS_DISCRETEоба0…8stable
0x6MODBUS_HOLDINGоба0…8stable
0x7MODBUS_INPUTоба0…8stable
0x8ERRORприбор → ПМ0stable
0x9BOOT_CONTROLПМ → прибор0/8draft
0xABOOT_DATA_AПМ → прибор8draft
0xBBOOT_DATA_BПМ → прибор8draft
0xCBOOT_STATUSприбор → ПМ8draft
0xDBOOT_DISCOVERYприбор → ПМ8draft
0xESETTINGSоба0/1/8stable
0xFPULSEприбор → сеть1stable
+

Подробный формат 0x9…0xD находится в BOOTLOADER.md.

+

Разметки MsgBody

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgTypeБиты MsgBody
broadcastкоманда [15:4], параметр [3:0]
discrete/analogподтип [15:12], значение/адрес [11:0]
Modbusначальный адрес [15:4], количество [3:0]
GASадрес первого 16-битного регистра [15:0]
errorдополнительная информация [15:8], код [7:0]
settingsномер сборки [15:8], позиция [7:0]
boot control/statusSessionID[15:8], команда [7:0]
boot dataBlockIndex[15:0]
+

Общие правила обмена

+
    +
  • Многобайтовые значения в DATA передаются little-endian.
  • +
  • Узел игнорирует адресованные кадры с чужим DeviceType/DeviceID.
  • +
  • Прибор принимает команды ПМ с Route=0; ПМ принимает ответы с Route=1.
  • +
  • Стандартные 11-битные CAN ID не являются кадрами ProtoCAN.
  • +
  • RTR для загрузочного сервиса запрещён.
  • +
  • Неописанные комбинации MsgType/MsgBody/DLC должны отвергаться.
  • +
+

Эталон упаковки ID

+
Priority   = 1
+Route      = 0
+DeviceType = 3
+DeviceID   = 5
+MsgType    = 0x9
+MsgBody    = 0x0702
+
+CAN ID = 0x13590702
+
+

Этот пример соответствует ENTER_BOOT, SessionID=7. Машинные варианты +находятся в examples/test-vectors.json.

+ +
+

ProtoCAN Boot Protocol

+

Статус: Draft
+Версия протокола: 1.0
+Совместимость: classic CAN 2.0B, Extended ID, DLC 0…8
+Реализация: templates/c/protocan-boot

+

Назначение

+

Сервис обновляет адресованный прибор по CAN и поддерживает два логических +слота A/B. Активный слот не стирается: новый образ записывается в неактивный, +проверяется и атомарно назначается кандидатом на запуск.

+

Карта сообщений

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgTypeИмяMsgBodyPayload
0x9BOOT_CONTROLSessionID[15:8] \| Command[7:0]параметры команды
0xABOOT_DATA_ABlockIndex[15:0]8 байт слота A
0xBBOOT_DATA_BBlockIndex[15:0]8 байт слота B
0xCBOOT_STATUSSessionID[15:8] \| Command[7:0]статус и прогресс
0xDBOOT_DISCOVERYподтип ответаидентификация
+

Все команды записи адресуются конкретному DeviceType/DeviceID и имеют +Route=0. Ответы сохраняют адрес прибора и имеют Route=1.

+

Адресация образа

+

MsgBody кадра данных — номер 8-байтового блока:

+
offset = (uint32_t)BlockIndex * 8U;
+address = SLOT_X_BASE + offset;
+
+
512 КиБ = 524 288 байт
+524 288 / 8 = 65 536 блоков
+BlockIndex = 0x0000…0xFFFF
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
BlockIndexСмещениеДиапазон байтов
0x00000x000000x00000…0x00007
0x00010x000080x00008…0x0000F
0xFFFF0x7FFF80x7FFF8…0x7FFFF
+

0x80000 является первой позицией за границей слота. Последний кадр +дополняется 0xFF, но CRC32 вычисляется только по ImageSize байтам.

+

Команды BOOT_CONTROL

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодКомандаDLCPayloadДопустимое состояние
0x01IDENTIFY0отсутствуетлюбое
0x02ENTER_BOOT0отсутствуетлюбое; SessionID != 0
0x03BEGIN_IMAGE8размер и CRC32metadata
0x04BEGIN_COMPAT8совместимость и версияmetadata
0x05ERASE0отсутствуетready-to-erase
0x06VERIFY0отсутствуетобраз получен
0x07COMMIT0отсутствуетverified
0x08CONFIRM0отсутствуетзапущенное приложение
0x09REBOOT0отсутствуетактивная сессия
0x0AABORT0отсутствуетактивная сессия
0x0BQUERY_PROGRESS0отсутствуетактивная сессия
+

BEGIN_IMAGE

+
DATA[0..3] ImageSize, uint32 little-endian
+DATA[4..7] ImageCRC32, uint32 little-endian
+
+

BEGIN_COMPAT

+
DATA[0..1] ProductType, uint16 little-endian
+DATA[2]    HardwareRevisionMin
+DATA[3]    HardwareRevisionMax
+DATA[4..7] FirmwareVersion, uint32 little-endian
+
+

До ERASE прибор обязан получить обе части метаданных и проверить размер, +тип изделия, аппаратную ревизию, версию и политику anti-rollback.

+

BOOT_STATUS

+
MsgBody[15..8] SessionID
+MsgBody[7..0]  команда, на которую дан ответ
+
+DATA[0]        Status
+DATA[1]        TargetSlot: 0=A, 1=B, 0xFF=не выбран
+DATA[2..3]     NextBlock, uint16 little-endian
+DATA[4..7]     RunningCRC32, uint32 little-endian
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодСтатусПовтор допустим
0x00OK—
0x01BUSYда, после задержки
0x02INVALID_COMMANDпосле исправления
0x03WRONG_DEVICEнет для этого образа
0x04WRONG_HARDWAREнет для этого образа
0x05INVALID_SIZEнет для этого образа
0x06CRC_ERRORновая передача
0x07FLASH_ERRORзависит от платформы
0x08SEQUENCE_ERRORда, с NextBlock
0x09SIGNATURE_ERRORнет
0x0ASESSION_ERRORоткрыть новую сессию
0x0BVOLTAGE_ERRORда после нормализации питания
0x0CINVALID_STATEвыполнить правильный переход
+

State machine

+
IDLE
+  └─ ENTER_BOOT ─> METADATA
+                     ├─ BEGIN_IMAGE
+                     └─ BEGIN_COMPAT
+                            │
+                            v
+                    READY_TO_ERASE
+                            │ ERASE
+                            v
+                      RECEIVING
+                            │ VERIFY
+                            v
+                       VERIFIED
+                            │ COMMIT
+                            v
+                    PENDING + REBOOT
+                            │ CONFIRM
+                            v
+                       CONFIRMED
+
+

Ошибка Flash, CRC, совместимости или подписи переводит сессию в FAILED. +Новая ENTER_BOOT создаёт чистую сессию. ABORT прекращает текущую передачу, +не активируя частично записанный слот.

+

Надёжность и повторы

+
    +
  • Блоки передаются строго по возрастанию BlockIndex.
  • +
  • Дубликат или пропуск возвращает SEQUENCE_ERROR и ожидаемый NextBlock.
  • +
  • Базовый режим подтверждает каждый блок.
  • +
  • Рабочий режим может подтверждать окно из 16 блоков.
  • +
  • После потери связи QUERY_PROGRESS возвращает следующий ожидаемый блок, +пока состояние загрузчика сохранено.
  • +
  • Для продолжения после перезагрузки порт должен сохранять session metadata +и восстановить её при инициализации; ядро версии 1.0 само это не делает.
  • +
+

Безопасность и A/B-обновление

+
active=A -> target=B -> verify -> pending=B
+active=B -> target=A -> verify -> pending=A
+
+

CRC32 защищает только от случайного повреждения. Серийный загрузчик должен +дополнительно проверить подпись контейнера, границы вектора, совместимость и +anti-rollback. Bootloader не обновляется командами BOOT_DATA_A/B.

+

Boot metadata должна атомарно хранить:

+
    +
  • активный слот;
  • +
  • pending-слот;
  • +
  • подтверждение запуска;
  • +
  • число неудачных попыток;
  • +
  • версию и CRC32 образа.
  • +
+

Если приложение не выполняет CONFIRM за установленное число запусков, +загрузчик возвращается к предыдущему подтверждённому слоту.

+

Эталонный сценарий

+
    +
  1. ПМ адресно отправляет IDENTIFY.
  2. +
  3. ПМ открывает ненулевой SessionID командой ENTER_BOOT.
  4. +
  5. ПМ отправляет BEGIN_IMAGE и BEGIN_COMPAT.
  6. +
  7. Прибор сообщает выбранный неактивный слот.
  8. +
  9. ПМ выполняет ERASE и передаёт BOOT_DATA_A либо BOOT_DATA_B.
  10. +
  11. ПМ выполняет VERIFY, затем COMMIT и REBOOT.
  12. +
  13. Новое приложение после самопроверки выполняет CONFIRM.
  14. +
+ +
+

Общее адресное пространство

+

Статус: Stable, данные ведутся в XLSX
+Порядок значений: 16-битные регистры, little-endian в CAN payload

+

Редактируемый источник реестра: +Протокол CAN и ОАП.xlsx.

+

Просматриваемая большая таблица находится в +Протокол CAN и ОАП.html и +Протокол CAN и ОАП.md.

+

Назначение

+

ОАП связывает 16-битный адрес регистра с его типом, назначением, доступом и +масштабом. В ProtoCAN используется MsgType=0x3, а MsgBody содержит адрес +первого регистра.

+

Обязательные поля реестра

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ПолеТребование
AddressHex0x0000…0xFFFF, уникальное значение
AddressDecдесятичный эквивалент AddressHex
Groupфункциональная группа
Nameоднозначное имя параметра
Typeu16, i16, u32, i32, float32, bitmap или массив
Registersчисло занятых 16-битных регистров
AccessR, W или RW
Unitфизическая единица либо —
Scaleмножитель/делитель представления
Defaultзначение после сброса, если применимо
Descriptionсемантика, диапазон и особые значения
+

Правила ведения

+
    +
  • Адрес не переиспользуется с другим смыслом после выпуска стабильной версии.
  • +
  • Многорегистровое значение занимает непрерывный диапазон.
  • +
  • Порядок 16-битных слов для 32-битного значения фиксируется в строке типа.
  • +
  • Резервные диапазоны явно отмечаются и не используются без изменения версии.
  • +
  • Удалённый параметр помечается deprecated, а не исчезает молча.
  • +
  • Изменение адреса, типа или масштаба отражается в CHANGELOG.md.
  • +
+

Экспорт

+

Для программной генерации каталог следует экспортировать из XLSX в CSV с +UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на:

+
    +
  • уникальность адресов;
  • +
  • пересечение многорегистровых значений;
  • +
  • допустимые типы и права доступа;
  • +
  • равенство шестнадцатеричного и десятичного адреса;
  • +
  • попадание адреса в диапазон 0x0000…0xFFFF.
  • +
+

До появления автоматического экспортёра нормативным источником адресов +остаётся XLSX, а HTML/Markdown считаются представлением.

+ +
+

История изменений ProtoCAN

+

Формат основан на Keep a Changelog. Версия относится к спецификации, а не к +версии прошивки отдельного прибора.

+

[Unreleased]

+

Added

+
    +
  • Структурированный комплект документации docs/protocan.
  • +
  • Загрузочный сервис MsgType=0x9…0xD.
  • +
  • Два логических слота по 512 КиБ, 65 536 блоков по 8 байт каждый.
  • +
  • Машинные эталоны CAN ID в examples/test-vectors.json.
  • +
+

[1.0] — 2026-08-29

+

Added

+
    +
  • Зафиксирована 29-битная структура ProtoCAN ID.
  • +
  • Зафиксирована адресация 8 типов по 16 экземпляров.
  • +
  • Существующие сообщения 0x0…0x8, 0xE, 0xF сохранены.
  • +
+ + + diff --git a/docs/protocan/examples/test-vectors.json b/docs/protocan/examples/test-vectors.json new file mode 100644 index 0000000..72d6eb7 --- /dev/null +++ b/docs/protocan/examples/test-vectors.json @@ -0,0 +1,45 @@ +{ + "schema_version": 1, + "byte_order": "little-endian", + "frames": [ + { + "name": "enter_boot_session_7", + "direction": "pm_to_device", + "priority": 1, + "route": 0, + "device_type": 3, + "device_id": 5, + "msg_type": 9, + "msg_body": 1794, + "can_id_hex": "0x13590702", + "dlc": 0, + "data_hex": "" + }, + { + "name": "slot_b_block_1", + "direction": "pm_to_device", + "priority": 1, + "route": 0, + "device_type": 3, + "device_id": 5, + "msg_type": 11, + "msg_body": 1, + "can_id_hex": "0x135B0001", + "dlc": 8, + "data_hex": "1011121314151617" + }, + { + "name": "enter_boot_ok", + "direction": "device_to_pm", + "priority": 1, + "route": 1, + "device_type": 3, + "device_id": 5, + "msg_type": 12, + "msg_body": 1794, + "can_id_hex": "0x1B5C0702", + "dlc": 8, + "data_hex": "00FF000000000000" + } + ] +} diff --git a/docs/protocan/protocol.html b/docs/protocan/protocol.html new file mode 100644 index 0000000..fa8a3c6 --- /dev/null +++ b/docs/protocan/protocol.html @@ -0,0 +1,833 @@ + + + + + +ProtoCAN — спецификация + + + +

Документация ProtoCAN

+

Статус комплекта: Draft
+Версия комплекта: 1.0
+Дата редакции: 2026-08-29
+Транспорт: Classic CAN 2.0B, Extended ID, DLC 0…8

+

Этот каталог разделяет нормативное описание протокола, загрузчик и реестр +общего адресного пространства. Большой исходный документ +Протокол CAN и ОАП.md сохранён как +совместимое представление таблиц из Excel.

+

Документы

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ДокументНазначениеСтатус источника
PROTOCOL.md29-битный CAN ID, адресация, реестр MsgType, порядок байтовнормативный
BOOTLOADER.mdобновление прошивки, кадры, состояния, ошибки и A/B-слотынормативный draft
OAP.mdправила ведения общего адресного пространстванормативный индекс
../../Протокол CAN и ОАП.xlsxредактируемый реестр ОАПисточник таблиц
examples/test-vectors.jsonмашинные эталоны CAN ID и payloadнормативные примеры
CHANGELOG.mdистория версий документанормативный
+

Приоритет источников

+

При расхождении данных действует следующий порядок:

+
    +
  1. PROTOCOL.md — структура ProtoCAN и реестр типов сообщений.
  2. +
  3. BOOTLOADER.md — загрузочный сервис 0x9…0xD.
  4. +
  5. XLSX — адреса и свойства регистров ОАП.
  6. +
  7. Сгенерированный HTML — только представление, не самостоятельный источник.
  8. +
+

Сборка HTML

+

В PowerShell 7:

+
./build-html.ps1
+
+

Результат создаётся в build/protocol.html. Скрипт не изменяет исходные +Markdown/XLSX и пригоден для запуска в CI.

+ +
+

ProtoCAN — базовый протокол

+

Статус: Stable с зарезервированным загрузочным расширением
+Версия: 1.0
+Порядок байтов payload: little-endian, если явно не указано иное

+

Назначение

+

ProtoCAN — прикладной протокол поверх classic CAN 2.0B. Используются только +расширенные 29-битные идентификаторы (IDE=1) и payload длиной 0…8 байт.

+

Термины

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ТерминЗначение
ПМуправляющий модуль
приборадресуемый узел на шине
DeviceTypeтип прибора, 0…7
DeviceIDэкземпляр прибора данного типа, 0…15
MsgTypeкласс сообщения или сервис
MsgBody16-битное поле, формат которого зависит от MsgType
+

Пара DeviceType/DeviceID задаёт до 8 × 16 = 128 уникальных адресов.

+

Расширенный CAN ID

+
28       27       26...24      23...20     19...16     15........0
+Priority Route    DeviceType   DeviceID    MsgType     MsgBody
+ 1 бит    1 бит      3 бита      4 бита      4 бита      16 бит
+
+
can_id =
+    ((uint32_t)priority    << 28) |
+    ((uint32_t)route       << 27) |
+    ((uint32_t)device_type << 24) |
+    ((uint32_t)device_id   << 20) |
+    ((uint32_t)msg_type    << 16) |
+    msg_body;
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ПолеЗначенияНазначение
Priority0 critical, 1 standardCAN-арбитраж
Route0 от ПМ, 1 от приборалогическое направление
DeviceType0…7тип прибора
DeviceID0…15номер экземпляра
MsgType0…15тип сообщения
MsgBody0…65535команда, адрес или номер блока
+

Route не является направлением физического трансивера. Ответ прибора +сохраняет адрес DeviceType/DeviceID и устанавливает Route=1.

+

Реестр MsgType

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодИмяОсновное направлениеDLCСтатус
0x0BROADCASTПМ → всезависит от командыstable
0x1DISCRETEоба0…8stable
0x2ANALOGоба0…8stable
0x3GASоба0/2/4/6/8stable
0x4MODBUS_COILоба0…8stable
0x5MODBUS_DISCRETEоба0…8stable
0x6MODBUS_HOLDINGоба0…8stable
0x7MODBUS_INPUTоба0…8stable
0x8ERRORприбор → ПМ0stable
0x9BOOT_CONTROLПМ → прибор0/8draft
0xABOOT_DATA_AПМ → прибор8draft
0xBBOOT_DATA_BПМ → прибор8draft
0xCBOOT_STATUSприбор → ПМ8draft
0xDBOOT_DISCOVERYприбор → ПМ8draft
0xESETTINGSоба0/1/8stable
0xFPULSEприбор → сеть1stable
+

Подробный формат 0x9…0xD находится в BOOTLOADER.md.

+

Разметки MsgBody

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgTypeБиты MsgBody
broadcastкоманда [15:4], параметр [3:0]
discrete/analogподтип [15:12], значение/адрес [11:0]
Modbusначальный адрес [15:4], количество [3:0]
GASадрес первого 16-битного регистра [15:0]
errorдополнительная информация [15:8], код [7:0]
settingsномер сборки [15:8], позиция [7:0]
boot control/statusSessionID[15:8], команда [7:0]
boot dataBlockIndex[15:0]
+

Общие правила обмена

+
    +
  • Многобайтовые значения в DATA передаются little-endian.
  • +
  • Узел игнорирует адресованные кадры с чужим DeviceType/DeviceID.
  • +
  • Прибор принимает команды ПМ с Route=0; ПМ принимает ответы с Route=1.
  • +
  • Стандартные 11-битные CAN ID не являются кадрами ProtoCAN.
  • +
  • RTR для загрузочного сервиса запрещён.
  • +
  • Неописанные комбинации MsgType/MsgBody/DLC должны отвергаться.
  • +
+

Эталон упаковки ID

+
Priority   = 1
+Route      = 0
+DeviceType = 3
+DeviceID   = 5
+MsgType    = 0x9
+MsgBody    = 0x0702
+
+CAN ID = 0x13590702
+
+

Этот пример соответствует ENTER_BOOT, SessionID=7. Машинные варианты +находятся в examples/test-vectors.json.

+ +
+

ProtoCAN Boot Protocol

+

Статус: Draft
+Версия протокола: 1.0
+Совместимость: classic CAN 2.0B, Extended ID, DLC 0…8
+Реализация: templates/c/protocan-boot

+

Назначение

+

Сервис обновляет адресованный прибор по CAN и поддерживает два логических +слота A/B. Активный слот не стирается: новый образ записывается в неактивный, +проверяется и атомарно назначается кандидатом на запуск.

+

Карта сообщений

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgTypeИмяMsgBodyPayload
0x9BOOT_CONTROLSessionID[15:8] \| Command[7:0]параметры команды
0xABOOT_DATA_ABlockIndex[15:0]8 байт слота A
0xBBOOT_DATA_BBlockIndex[15:0]8 байт слота B
0xCBOOT_STATUSSessionID[15:8] \| Command[7:0]статус и прогресс
0xDBOOT_DISCOVERYподтип ответаидентификация
+

Все команды записи адресуются конкретному DeviceType/DeviceID и имеют +Route=0. Ответы сохраняют адрес прибора и имеют Route=1.

+

Адресация образа

+

MsgBody кадра данных — номер 8-байтового блока:

+
offset = (uint32_t)BlockIndex * 8U;
+address = SLOT_X_BASE + offset;
+
+
512 КиБ = 524 288 байт
+524 288 / 8 = 65 536 блоков
+BlockIndex = 0x0000…0xFFFF
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
BlockIndexСмещениеДиапазон байтов
0x00000x000000x00000…0x00007
0x00010x000080x00008…0x0000F
0xFFFF0x7FFF80x7FFF8…0x7FFFF
+

0x80000 является первой позицией за границей слота. Последний кадр +дополняется 0xFF, но CRC32 вычисляется только по ImageSize байтам.

+

Команды BOOT_CONTROL

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодКомандаDLCPayloadДопустимое состояние
0x01IDENTIFY0отсутствуетлюбое
0x02ENTER_BOOT0отсутствуетлюбое; SessionID != 0
0x03BEGIN_IMAGE8размер и CRC32metadata
0x04BEGIN_COMPAT8совместимость и версияmetadata
0x05ERASE0отсутствуетready-to-erase
0x06VERIFY0отсутствуетобраз получен
0x07COMMIT0отсутствуетverified
0x08CONFIRM0отсутствуетзапущенное приложение
0x09REBOOT0отсутствуетактивная сессия
0x0AABORT0отсутствуетактивная сессия
0x0BQUERY_PROGRESS0отсутствуетактивная сессия
+

BEGIN_IMAGE

+
DATA[0..3] ImageSize, uint32 little-endian
+DATA[4..7] ImageCRC32, uint32 little-endian
+
+

BEGIN_COMPAT

+
DATA[0..1] ProductType, uint16 little-endian
+DATA[2]    HardwareRevisionMin
+DATA[3]    HardwareRevisionMax
+DATA[4..7] FirmwareVersion, uint32 little-endian
+
+

До ERASE прибор обязан получить обе части метаданных и проверить размер, +тип изделия, аппаратную ревизию, версию и политику anti-rollback.

+

BOOT_STATUS

+
MsgBody[15..8] SessionID
+MsgBody[7..0]  команда, на которую дан ответ
+
+DATA[0]        Status
+DATA[1]        TargetSlot: 0=A, 1=B, 0xFF=не выбран
+DATA[2..3]     NextBlock, uint16 little-endian
+DATA[4..7]     RunningCRC32, uint32 little-endian
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодСтатусПовтор допустим
0x00OK—
0x01BUSYда, после задержки
0x02INVALID_COMMANDпосле исправления
0x03WRONG_DEVICEнет для этого образа
0x04WRONG_HARDWAREнет для этого образа
0x05INVALID_SIZEнет для этого образа
0x06CRC_ERRORновая передача
0x07FLASH_ERRORзависит от платформы
0x08SEQUENCE_ERRORда, с NextBlock
0x09SIGNATURE_ERRORнет
0x0ASESSION_ERRORоткрыть новую сессию
0x0BVOLTAGE_ERRORда после нормализации питания
0x0CINVALID_STATEвыполнить правильный переход
+

State machine

+
IDLE
+  └─ ENTER_BOOT ─> METADATA
+                     ├─ BEGIN_IMAGE
+                     └─ BEGIN_COMPAT
+                            │
+                            v
+                    READY_TO_ERASE
+                            │ ERASE
+                            v
+                      RECEIVING
+                            │ VERIFY
+                            v
+                       VERIFIED
+                            │ COMMIT
+                            v
+                    PENDING + REBOOT
+                            │ CONFIRM
+                            v
+                       CONFIRMED
+
+

Ошибка Flash, CRC, совместимости или подписи переводит сессию в FAILED. +Новая ENTER_BOOT создаёт чистую сессию. ABORT прекращает текущую передачу, +не активируя частично записанный слот.

+

Надёжность и повторы

+
    +
  • Блоки передаются строго по возрастанию BlockIndex.
  • +
  • Дубликат или пропуск возвращает SEQUENCE_ERROR и ожидаемый NextBlock.
  • +
  • Базовый режим подтверждает каждый блок.
  • +
  • Рабочий режим может подтверждать окно из 16 блоков.
  • +
  • После потери связи QUERY_PROGRESS возвращает следующий ожидаемый блок, +пока состояние загрузчика сохранено.
  • +
  • Для продолжения после перезагрузки порт должен сохранять session metadata +и восстановить её при инициализации; ядро версии 1.0 само это не делает.
  • +
+

Безопасность и A/B-обновление

+
active=A -> target=B -> verify -> pending=B
+active=B -> target=A -> verify -> pending=A
+
+

CRC32 защищает только от случайного повреждения. Серийный загрузчик должен +дополнительно проверить подпись контейнера, границы вектора, совместимость и +anti-rollback. Bootloader не обновляется командами BOOT_DATA_A/B.

+

Boot metadata должна атомарно хранить:

+
    +
  • активный слот;
  • +
  • pending-слот;
  • +
  • подтверждение запуска;
  • +
  • число неудачных попыток;
  • +
  • версию и CRC32 образа.
  • +
+

Если приложение не выполняет CONFIRM за установленное число запусков, +загрузчик возвращается к предыдущему подтверждённому слоту.

+

Эталонный сценарий

+
    +
  1. ПМ адресно отправляет IDENTIFY.
  2. +
  3. ПМ открывает ненулевой SessionID командой ENTER_BOOT.
  4. +
  5. ПМ отправляет BEGIN_IMAGE и BEGIN_COMPAT.
  6. +
  7. Прибор сообщает выбранный неактивный слот.
  8. +
  9. ПМ выполняет ERASE и передаёт BOOT_DATA_A либо BOOT_DATA_B.
  10. +
  11. ПМ выполняет VERIFY, затем COMMIT и REBOOT.
  12. +
  13. Новое приложение после самопроверки выполняет CONFIRM.
  14. +
+ +
+

Общее адресное пространство

+

Статус: Stable, данные ведутся в XLSX
+Порядок значений: 16-битные регистры, little-endian в CAN payload

+

Редактируемый источник реестра: +Протокол CAN и ОАП.xlsx.

+

Просматриваемая большая таблица находится в +Протокол CAN и ОАП.html и +Протокол CAN и ОАП.md.

+

Назначение

+

ОАП связывает 16-битный адрес регистра с его типом, назначением, доступом и +масштабом. В ProtoCAN используется MsgType=0x3, а MsgBody содержит адрес +первого регистра.

+

Обязательные поля реестра

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ПолеТребование
AddressHex0x0000…0xFFFF, уникальное значение
AddressDecдесятичный эквивалент AddressHex
Groupфункциональная группа
Nameоднозначное имя параметра
Typeu16, i16, u32, i32, float32, bitmap или массив
Registersчисло занятых 16-битных регистров
AccessR, W или RW
Unitфизическая единица либо —
Scaleмножитель/делитель представления
Defaultзначение после сброса, если применимо
Descriptionсемантика, диапазон и особые значения
+

Правила ведения

+
    +
  • Адрес не переиспользуется с другим смыслом после выпуска стабильной версии.
  • +
  • Многорегистровое значение занимает непрерывный диапазон.
  • +
  • Порядок 16-битных слов для 32-битного значения фиксируется в строке типа.
  • +
  • Резервные диапазоны явно отмечаются и не используются без изменения версии.
  • +
  • Удалённый параметр помечается deprecated, а не исчезает молча.
  • +
  • Изменение адреса, типа или масштаба отражается в CHANGELOG.md.
  • +
+

Экспорт

+

Для программной генерации каталог следует экспортировать из XLSX в CSV с +UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на:

+
    +
  • уникальность адресов;
  • +
  • пересечение многорегистровых значений;
  • +
  • допустимые типы и права доступа;
  • +
  • равенство шестнадцатеричного и десятичного адреса;
  • +
  • попадание адреса в диапазон 0x0000…0xFFFF.
  • +
+

До появления автоматического экспортёра нормативным источником адресов +остаётся XLSX, а HTML/Markdown считаются представлением.

+ +
+

История изменений ProtoCAN

+

Формат основан на Keep a Changelog. Версия относится к спецификации, а не к +версии прошивки отдельного прибора.

+

[Unreleased]

+

Added

+
    +
  • Структурированный комплект документации docs/protocan.
  • +
  • Загрузочный сервис MsgType=0x9…0xD.
  • +
  • Два логических слота по 512 КиБ, 65 536 блоков по 8 байт каждый.
  • +
  • Машинные эталоны CAN ID в examples/test-vectors.json.
  • +
+

[1.0] — 2026-08-29

+

Added

+
    +
  • Зафиксирована 29-битная структура ProtoCAN ID.
  • +
  • Зафиксирована адресация 8 типов по 16 экземпляров.
  • +
  • Существующие сообщения 0x0…0x8, 0xE, 0xF сохранены.
  • +
+ + + diff --git a/Протокол CAN и ОАП.html b/Протокол CAN и ОАП.html new file mode 100644 index 0000000..1040288 --- /dev/null +++ b/Протокол CAN и ОАП.html @@ -0,0 +1,13405 @@ + + + + + +Протокол CAN и ОАП + + +

Протокол CAN и ОАП

+

Таблицы перенесены из Протокол CAN и ОАП.xlsx. Цвета, объединённые ячейки и структура листов сохранены средствами HTML внутри Markdown.

+ +

+

Прошивка приборов по CAN

+

Ниже зафиксирован формат планируемого загрузочного сервиса. Значения +MsgType=0x9..0xD зарезервированы в протоколе, но обработчики загрузчика в +текущих protocan.c/.h ещё не реализованы.

+

Загрузчик работает поверх classic CAN 2.0B с Extended ID. Управляющий модуль +использует Route=0, прибор отвечает с Route=1. Команды стирания и записи +всегда должны быть адресованы конкретной паре DeviceType/DeviceID; +широковещательный режим допустим только для обнаружения.

+

Карта загрузочных сообщений

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgTypeИмяНазначение MsgBodyCAN payload
0x9BOOT_CONTROLSessionID:8 \| Command:8параметры команды
0xABOOT_DATA_Aномер 8-байтового блока слота A8 байт образа
0xBBOOT_DATA_Bномер 8-байтового блока слота B8 байт образа
0xCBOOT_STATUSSessionID:8 \| Command:8статус и прогресс
0xDBOOT_DISCOVERYподтип запроса/ответаидентификация прибора
+

MsgBody в кадрах данных является не байтовым адресом, а номером блока:

+
block_offset = (uint32_t)MsgBody * 8U;
+
+if (MsgType == PROTOCAN_MSGTYPE_BOOT_DATA_A) {
+    address = SLOT_A_BASE + block_offset;
+} else if (MsgType == PROTOCAN_MSGTYPE_BOOT_DATA_B) {
+    address = SLOT_B_BASE + block_offset;
+}
+
+

Диапазон MsgBody=0x0000..0xFFFF адресует ровно 65 536 блоков:

+
512 КиБ = 512 * 1024 = 524 288 байт
+524 288 / 8 = 65 536 блоков
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgBodyНомер блокаСмещение от начала слотаДиапазон байтов
0x000000x000000x00000..0x00007
0x000110x000080x00008..0x0000F
0x000220x000100x00010..0x00017
0xFFFF65 5350x7FFF80x7FFF8..0x7FFFF
+

Формула физического адреса блока:

+
address = SLOT_X_BASE + ((uint32_t)MsgBody * 8U);
+
+

Последний допустимый блок начинается со смещения 0x7FFF8 и заканчивается +на 0x7FFFF включительно. Следующее смещение 0x80000 уже находится за +границей 512-КиБ слота.

+

Таким образом, BOOT_DATA_A и BOOT_DATA_B адресуют два логических слота +по 512 КиБ, всего 1 МиБ пространства образов. Физические SLOT_A_BASE и +SLOT_B_BASE задаёт конкретный загрузчик. Если внутренняя Flash имеет ровно +1 МиБ, два полных слота в ней не поместятся вместе с загрузчиком и метаданными: +нужно уменьшить слоты, выбрать MCU с большей Flash или хранить staging-образ +во внешней памяти.

+

Кадр данных

+
Extended CAN ID
+  Priority   = STANDARD
+  Route      = FROM_PM
+  DeviceType = тип целевого прибора
+  DeviceID   = экземпляр целевого прибора
+  MsgType    = 0xA (слот A) или 0xB (слот B)
+  MsgBody    = BlockIndex, 0x0000..0xFFFF
+
+DATA[0..7]   = очередные 8 байт образа
+
+

Например, MsgBody=0x0123 задаёт смещение 0x0123 * 8 = 0x0918 от +начала выбранного слота. Последний неполный блок дополняется значениями +0xFF; фактический размер передаётся командой BEGIN_UPDATE, поэтому CRC32 +считается только по байтам образа.

+

Управляющие команды

+

В BOOT_CONTROL поле MsgBody имеет формат:

+
15........8 7.........0
+ SessionID     Command
+
+

Рекомендуемые команды:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодКомандаНазначение
0x01IDENTIFYпрочитать тип, аппаратную и программную версии
0x02ENTER_BOOTперейти из приложения в загрузчик
0x03BEGIN_IMAGEпередать размер и CRC32 образа
0x04BEGIN_COMPATпередать тип, аппаратную и программную версии
0x05ERASEподготовить неактивный слот
0x06VERIFYпроверить размер, CRC32 и подпись
0x07COMMITназначить проверенный слот кандидатом на запуск
0x08CONFIRMподтвердить успешный запуск новой программы
0x09REBOOTперезагрузить прибор
0x0AABORTотменить текущую сессию
0x0BQUERY_PROGRESSзапросить слот и следующий ожидаемый блок
+

BEGIN_IMAGE содержит размер и CRC образа:

+
DATA[0..3] ImageSize, uint32 little-endian
+DATA[4..7] ImageCRC32, uint32 little-endian
+
+

BEGIN_COMPAT содержит совместимость и версию:

+
DATA[0..1] ProductType, uint16 little-endian
+DATA[2]    минимальная HardwareRevision
+DATA[3]    максимальная HardwareRevision
+DATA[4..7] FirmwareVersion, uint32 little-endian
+
+

Обе команды передаются с одним SessionID. До стирания Flash загрузчик обязан +получить обе части метаданных и проверить ProductType, аппаратную ревизию, +размер образа, границы выбранного слота и допустимость версии.

+

Ответ состояния

+

BOOT_STATUS возвращает результат команды и точку продолжения:

+
MsgBody[15..8] = SessionID
+MsgBody[7..0]  = команда, на которую дан ответ
+
+DATA[0]        Status
+DATA[1]        TargetSlot: 0 = A, 1 = B
+DATA[2..3]     NextBlock, uint16 little-endian
+DATA[4..7]     RunningCRC32, uint32 little-endian
+
+

Минимальный набор статусов:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодСтатус
0x00OK
0x01BUSY
0x02INVALID_COMMAND
0x03WRONG_DEVICE
0x04WRONG_HARDWARE
0x05INVALID_SIZE
0x06CRC_ERROR
0x07FLASH_ERROR
0x08SEQUENCE_ERROR
0x09SIGNATURE_ERROR
0x0ASESSION_ERROR
0x0BVOLTAGE_ERROR
+

NextBlock позволяет возобновить загрузку после разрыва связи. Для первой +реализации допустимо подтверждать каждый блок. Для рабочей скорости лучше +передавать окна по 16 кадров и подтверждать окно одним BOOT_STATUS; при +необходимости протокол статуса можно расширить битовой картой потерянных +блоков.

+

Выбор слота и безопасное обновление

+

GUI не должен самостоятельно перезаписывать активный слот. После получения +BEGIN_IMAGE и BEGIN_COMPAT загрузчик выбирает неактивный слот и сообщает его в +BOOT_STATUS:

+
активен A -> принимать BOOT_DATA_B
+активен B -> принимать BOOT_DATA_A
+
+

Рекомендуемый цикл обновления:

+
    +
  1. Обнаружить прибор и сверить DeviceType/DeviceID, ProductType, UID и версии.
  2. +
  3. Выполнить адресную команду ENTER_BOOT и получить новый SessionID.
  4. +
  5. Передать BEGIN_IMAGE и BEGIN_COMPAT; загрузчик выберет неактивный слот.
  6. +
  7. Стереть выбранный слот и передать блоки BOOT_DATA_A или BOOT_DATA_B.
  8. +
  9. Выполнить VERIFY: проверить размер, CRC32 и цифровую подпись образа.
  10. +
  11. Выполнить COMMIT и перезагрузить устройство.
  12. +
  13. Новое приложение вызывает CONFIRM после успешной самопроверки.
  14. +
  15. При отсутствии подтверждения загрузчик возвращается к предыдущему слоту.
  16. +
+

CRC32 обнаруживает случайное повреждение, но не защищает от подмены. Для +серийных изделий образ следует подписывать, а открытый ключ проверки хранить +в неизменяемой части загрузчика. Сам загрузчик не должен обновляться обычными +командами BOOT_DATA_A/B.

+ +

+

Лист «Интерфейс протокола»

+

Таблица прокручивается по горизонтали; длинный лист ограничен по высоте окна.

+
+++++++++++++++++++++++++++++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
282726252423222120191817161514131211109876543210 DLC COUNT 76543210
Fields  DLC
ПриоритетАдресацияСообщение  
Priority (1 bit)ПМ (1 bit)Device Type (3 bits)Device (4 bits)Msg Type (4 bits)Body (16 bits)  
0x0. Критический0x0. ПМ0x0 Верхний уровеньNULL0x0. Широковещательные0x0. Статус  0 NULL
0x1. Стандартный0х1. Устройство0x10x0 - 0xF устройств0x1. Запрос на вкл/выклВыбор "страницы" из 64 устройств (Битовые флаги в Data) 8 64 битовых адресса
  0x20x0 - 0xF устройств0x2. Рестарт устройствВыбор "страницы" из 64 устройств (Битовые флаги в Data) 8 64 битовых адресса
  0x30x0 - 0xF устройств0x3. Установка времени  7 NULLWeekDayDateMonthYearSecondsMinutesHours
  0x40x0 - 0xF устройств0x0 – 0xFFFF. Резерв NULL NULL
  0x50x0 - 0xF устройств0x1. Дискретные0x0. Аварии     
  0x60x0 - 0xF устройств0x1. Предупреждения     
  0x70x0 - 0xF устройств0x2. Управляющие сигналы     
      0x3. Флаги     
      0x4. Рестарт устройства     
      0x5. Изменение режима работы устройства     
      0x6. Запрос на устройство - перечень параметров для отправки обратно. Возможность создания запроса с конт-м колличеством параметровТип Датчика. В Data - 64 "битовых адрессов" 8 64 битовых адресса
      0x7 – 0xF. Резерв0x0 – 0xFFF. Резерв NULL NULL
      0x2. Аналог0x0. Универсальный запросID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x1. УставкиID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x2. НапряжениеID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x3. ТокID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x4. ТемператураID датчика (0х0 - 0xFFF) Кол-во запр значений. 0...8 NULL
      0x5 – 0xF. Резерв0x0 – 0xFFF. Резерв NULL NULL
      0x3. Общее адресное пространствоАдрес регистра (Стартовый адрес, если DLC COUNT > 2) (0, 0x0000 - 65535, 0xFFFF) 0/2/4/6/8 Четвёртый регистрТретий регистрВторой регистрПервый регистр
      0x4. Modbus CoilСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15)   NULL
      0x5. Modbus DiscreteСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15)   NULL
      0x6. Modbus HoldingСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15(   NULL
      0x7. Modbus InputСтартовый адрес регистра (0x0 - 0xFFF)Кол-во регистров (0-15)   NULL
      0x8 ОшибкиДополнительная информацияКод Ошибки 0 NULL
      0x9. BOOT_CONTROLSessionID[15:8] | Command[7:0]. Управление загрузчиком 0/8 Параметры команды
      0xA. BOOT_DATA_AMsgBody = BlockIndex 0x0000–0xFFFF: 65 536 блоков по 8 байт, слот A 512 КиБ 8 8 байт прошивки слота A
      0xB. BOOT_DATA_BMsgBody = BlockIndex 0x0000–0xFFFF: 65 536 блоков по 8 байт, слот B 512 КиБ 8 8 байт прошивки слота B
      0xC. BOOT_STATUSSessionID[15:8] | Command[7:0]. Ответ и точка продолжения 8 Status, Slot, NextBlock, RunningCRC32
      0xD. BOOT_DISCOVERYПодтип запроса/ответа идентификации загрузчика 0/8 ProductType, HardwareRevision, BootVersion, FirmwareVersion
         0xE Settings2BYTE1BYTE              
      0xF. ПульсNULL 1 NULLСчётчик
                                           
                                      
                                           
                                           
                                           
         0xE Settings2BYTE1BYTE              
0x1. Стандартный0х1. Устройство0x7 0xF sensor programmer   сборка(инв1, инв2,выпрям итд) позиция в сборке(VD1 VD2 итд)      ID temp sens
+

+

Лист «Общее адресное пространство»

+

Таблица прокручивается по горизонтали; длинный лист ограничен по высоте окна.

+
++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
НаправлениеОбластьРегистрыСодержание регистраБитыБитовые поля  
ПередачаПоказанияОсновные данные0x00000Номер преобразователя ПЧ    
0x00011Версия прошивки ПЧ    
0x00022Статус ЛСУ    
0x00033Задание по мощности     
0x00044Ограничение по мощности    
0x00055Мощность (МВт)    
0x00066Задание по скорости вращения    
0x00077Обороты ГЭД (Об/мин)    
0x00088Обороты ДЧ1 (Об/мин)    
0x00099Обороты ДЧ2 (Об/мин)    
0x000A10Частота на выходе ПЧ (Гц)    
0x000B11Ток фазы U (А)    
0x000C12Ток фазы V (А)    
0x000D13Ток фазы W (А)    
0x000E14Средний ток в ЗПТ (А)    
0x000F15Средний ток в БТР (А)    
0x001016Напряжение выходное (В)    
0x001117Текущий ток в ГЭД (А)    
0x001218Подтверждение выполнения команды (Код команды)    
0x001319Ошибка при выполнении команды    
0x001420Счётчик отправок основных данных    
0x001521Счётчик отправок уставок    
0x001622Счётчик отправок данных датчиков    
0x001723Состояние0Готовность 11 - зеленый0 - серый
1Готовность 21 - зеленый0 - серый
2Ёмкость заряжена1 - зеленый0 - серый
3Неисправность1 - желтый0 - серый
4Перегрев1 - желтый0 - серый
5Ограничение мощности1 - желтый0 - серый
6Управление (По мощности, По оборотам)1 - по мощности0 - по оборотам
7Ход1 - зеленый0 - серый
8Авария1 - красный0 - серый
9Сработал аварийный стоп1 - красный0 - серый
10Схема собрана в режиме аварийного хода1 - желтый0 - серый
11Срабатывание предупредительные уставки по температурам1 - желтый0 - серый
12Срабатывание аварийной уставки по температурам 1 - красный0 - серый
13Неисправность СО1 - желтый0 - серый
14Авария СО1 - красный0 - серый
15   
БСУ0x001824Температура объёма БСУ ВК1    
0x001925Температура объёма БСУ ВК5    
0x001A26Показания УКСИ    
0x001B27 Статус датчиков температуры БСУ 0ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК5 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК5 - Статус инициализации  
6ВК5 - Предупреждение1 - желтый0 - серый
7ВК5 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x001C28Статус УКСИ0Связь с УКСИ1 - зеленый0 - серый
1Неисправность измерителя1 - желтый0 - серый
2Сопротивление изоляции снижено1 - желтый0 - серый
3Сопротивление изоляции аварийно низкое1 - красный0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
0x001D29Сигналы - Устройство коммутационное
проводное цифровое (OUT)
0Разреш. Вкл. Автомата главного тока1 - зеленый0 - серый
1Разреш. Вкл. Зарядного автомата1 - зеленый0 - серый
2Квитирование (Блокировка аварии)1 - зеленый0 - серый
3Тест лампы АВАРИЯ1 - зеленый0 - серый
4Авария СПК от контроллера1 - красный0 - серый
5Управление от СВУ1 - зеленый0 - серый
6Резерв 1  
7Вкл/Откл QT11 - зеленый0 - серый
8Вкл/Откл Q11 - зеленый0 - серый
9Пуск УПП1 - зеленый0 - серый
10Вкл. Насосы вод. Охл1 - зеленый0 - серый
11Блокировка дверей1 - зеленый0 - серый
12Включение обогревателей1 - зеленый0 - серый
13Резерв 4  
14Резерв 3  
15Резерв 2  
0x001E30Сигналы - Устройство коммутационное проводное цифровое (IN2)0Состояние QT11 - зеленый0 - серый
1Местное управление (ГРУ)1 - зеленый0 - серый
2Состояние Q11 - зеленый0 - серый
3Местное управление (УМП)1 - зеленый0 - серый
4Работа от УМП1 - зеленый0 - серый
5Готов от УМП1 - зеленый0 - серый
6Авария от УМП1 - красный0 - серый
7Блокировка от СВУ1 - желтый0 - серый
8Авария откл. От СВУ1 - красный0 - серый
9Мех. Тормоз вала1 - желтый0 - серый
10Готовность БТР1 - зеленый0 - серый
11Ограничение 11 - желтый0 - серый
12Ограничение 21 - желтый0 - серый
13Ограничение 31 - желтый0 - серый
14Ограничение 41 - желтый0 - серый
15Авария БТР1 - красный0 - серый
0x001F31Сигналы - Устройство коммутационное проводное цифровое (IN2)0"Тест ламп"1 - зеленый0 - серый
1"Квитирование"1 - зеленый0 - серый
2"Обороты больше"1 - зеленый0 - серый
3"Обороты меньше"1 - зеленый0 - серый
4"Приворот"1 - зеленый0 - серый
5Авария от УКСИ1 - красный0 - серый
6Обогреватели включены1 - зеленый0 - серый
7Резерв  
8Авария системы ВЭП 11 - красный0 - серый
9Авария системы ВЭП 21 - красный0 - серый
10Силовая схема - "Собрать"1 - зеленый0 - серый
11Силовая схема - "Разобрать"1 - зеленый0 - серый
12Управление - "Задатчик"; "Монитор"; "СВУ"00 - монитор; 01 - Задатчик; 10 - СВУ
13
14От кнопки АВАР. ОТКЛ1 - красный0 - серый
15Направление вращения вала1 - зеленый0 - серый
0x002032Показания ВЭП 10Контроль ИП1 (питание управляющего контроллера)1 - зеленый0 - серый
1Контроль ИП2 (питание периферийных устройств)1 - зеленый0 - серый
2Контроль ИП3 (питание эл. замков, ламп освещения, ДЧВ)1 - зеленый0 - серый
3Контроль ИП4 (питание датчиков тока и напряжения +)1 - зеленый0 - серый
4Контроль ИП5 (питание датчиков тока и напряжения –)1 - зеленый0 - серый
5Контроль ИП6 (питание драйверов)1 - зеленый0 - серый
6Контроль 3х фазного 380 В1 - зеленый0 - серый
7Заряд накопителя1 - желтый0 - серый
8Работа от батареи1 - желтый0 - серый
9Авария в сети 24 В1 - красный0 - серый
10Контроль питания ЛСУ1 - зеленый0 - серый
11Контроль питания 380 В1 - зеленый0 - серый
12резерв  
13Контроль питания СН1 - зеленый0 - серый
14резерв  
15резерв  
0x002133Показания ВЭП 20Контроль ИП1 (питание управляющего контроллера)1 - зеленый0 - серый
1Контроль ИП2 (питание периферийных устройств)1 - зеленый0 - серый
2Контроль ИП3 (питание эл. замков, ламп освещения, ДЧВ)1 - зеленый0 - серый
3Контроль ИП4 (питание датчиков тока и напряжения +)1 - зеленый0 - серый
4Контроль ИП5 (питание датчиков тока и напряжения –)1 - зеленый0 - серый
5Контроль ИП6 (питание драйверов)1 - зеленый0 - серый
6Контроль 3х фазного 380 В1 - зеленый0 - серый
7Заряд накопителя1 - желтый0 - серый
8Работа от батареи1 - желтый0 - серый
9Авария в сети 24 В1 - красный0 - серый
10Контроль питания ЛСУ1 - зеленый0 - серый
11Контроль питания 380 В1 - зеленый0 - серый
12резерв  
13Контроль питания СН1 - зеленый0 - серый
14резерв  
15резерв  
0x002234Ограничения мощности0Ограничение мощности по току1 - желтый0 - серый
1Ограничение мощности по моменту1 - желтый0 - серый
2Ограничение мощности по температурам1 - желтый0 - серый
3Ограничение мощности по напряжению1 - желтый0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
0x002335Состояния входов датчиков оборотов0Состояние входа датчика оборотов 1  
1Состояние входа датчика оборотов 2  
2   
3   
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
Блок БВ0x002436Входное линейное напряжение А1В1 (В)    
0x002537Входное линейное напряжение В1С1 (В)    
0x002638Входное линейное напряжение А2В2 (В)    
0x002739Входное линейное напряжение В2С2 (В)    
0x002840Частота входного напряжения выпрямителя UZ1 (Гц)    
0x002941Частота входного напряжения выпрямителя UZ2 (Гц)    
0x002A42Температура охладителя выпрямительной ячейки UZ1 ВК1    
0x002B43Температура охладителя выпрямительной ячейки UZ1 ВК2    
0x002C44Температура охладителя выпрямительной ячейки UZ2 ВК1    
0x002D45Температура охладителя выпрямительной ячейки UZ2 ВК2    
0x002E46Температура охладителя резисторного модуля UR1 ВК1    
0x002F47Температура охладителя резисторного модуля UR1 ВК2    
0x003048Температура охладителя резисторного модуля UR2 ВК1    
0x003149Температура охладителя резисторного модуля UR2 ВК2    
0x003250Температура охладителя резисторного модуля UR3 ВК1    
0x003351Температура охладителя резисторного модуля UR3 ВК2    
0x003452Температура объёма Блок БВ ВК2    
0x003553Температура объёма Блок БВ ВК6    
0x003654Температура воды выпрямительной ячейки UZ1 BK11    
0x003755Температура воды выпрямительной ячейки UZ2 BK12    
0x003856Температура воды резисторного модуля UR1 BK17    
0x003957Температура воды резисторного модуля UR2 BK18    
0x003A58Температура воды резисторного модуля UR3 BK19    
0x003B59Статус датчиков температуры охладителя выпрямительной ячейки UZ10ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003C60Статус датчиков температуры охладителя выпрямительной ячейки UZ20ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003D61Статус датчиков температуры охладителя резисторного модуля UR10ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003E62Статус датчиков температуры охладителя резисторного модуля UR20ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x003F63Статус датчиков температуры охладителя резисторного модуля UR30ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15   
0x004064Статус датчиков температуры объема Блок БВ0ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК2 - Статус инициализации  
2BK3 - Предупреждение1 - желтый0 - серый
3ВК2 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15Блок БВ - дверь закрыта1 - зеленый0 - серый
0x004165Статус датчиков температуры воды - Блок БВ0Выпрямительная ячейка UZ1 BK11 - Статус1 - зеленый0 - желтый
1Выпрямительная ячейка UZ1 BK11 - Резерв  
2Выпрямительная ячейка UZ1 BK11 - Предупреждение1 - желтый0 - серый
3Выпрямительная ячейка UZ1 BK11 - Авария1 - красный0 - серый
4Выпрямительная ячейка UZ2 BK12 - Статус1 - зеленый0 - желтый
5Выпрямительная ячейка UZ2 BK12 - Резерв  
6Выпрямительная ячейка UZ2 BK12 - Предупреждение1 - желтый0 - серый
7Выпрямительная ячейка UZ2 BK12 - Авария1 - красный0 - серый
8Резисторный модуль UR1 BK17 - Статус1 - зеленый0 - желтый
9Резисторный модуль UR1 BK17 - Резерв  
10Резисторный модуль UR1 BK17 - Предупреждение1 - желтый0 - серый
11Резисторный модуль UR1 BK17 - Авария1 - красный0 - серый
12Резисторный модуль UR2 BK18 - Статус1 - зеленый0 - желтый
13Резисторный модуль UR2 BK18 - Резерв  
14Резисторный модуль UR2 BK18 - Предупреждение1 - желтый0 - серый
15Резисторный модуль UR2 BK18 - Авария1 - красный0 - серый
0x004266Статус датчиков температуры воды - Блок БВ0Резисторный модуль UR3 BK19 - Статус1 - зеленый0 - желтый
1Резисторный модуль UR3 BK19 - Резерв  
2Резисторный модуль UR3 BK19 - Предупреждение1 - желтый0 - серый
3Резисторный модуль UR3 BK19 - Авария1 - красный0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
БК0x004367Напряжение звена постоянного тока (В)    
0x004468Ток звена постоянного тока (+) (А)    
0x004569Ток звена постоянного тока (-) (А)     
0x004670Температура объёма БК ВК3    
0x004771Температура объёма БК ВК7    
0x004872Статус датчиков температуры объема БК0ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК3 - Статус инициализации  
2ВК3 - Предупреждение1 - желтый0 - серый
3ВК3 - Авария1 - красный0 - серый
4ВК7 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК7 - Статус инициализации  
6ВК7 - Предупреждение1 - желтый0 - серый
7ВК7 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15БК - дверь закрыта1 - зеленый0 - серый
БИ0x004973Ток ячейки чопперной UF1 (А)    
0x004A74Ток ячейки фазной AF1 (А)    
0x004B75Ток ячейки фазной AF2 (А)    
0x004C76Ток ячейки фазной AF3 (А)    
0x004D77Температура охладителя фазной ячейки AF1 ВК1    
0x004E78Температура охладителя фазной ячейки AF1 ВК2    
0x004F79Температура охладителя фазной ячейки AF1 ВК3    
0x005080Температура охладителя фазной ячейки AF1 ВК4    
0x005181Температура охладителя фазной ячейки AF1 ВК5    
0x005282Температура охладителя фазной ячейки AF1 ВК6    
0x005383Температура охладителя фазной ячейки AF1 ВК7    
0x005484Температура охладителя фазной ячейки AF1 ВК8    
0x005585Температура охладителя фазной ячейки AF2 ВК1    
0x005686Температура охладителя фазной ячейки AF2 ВК2    
0x005787Температура охладителя фазной ячейки AF2 ВК3    
0x005888Температура охладителя фазной ячейки AF2 ВК4    
0x005989Температура охладителя фазной ячейки AF2 ВК5    
0x005A90Температура охладителя фазной ячейки AF2 ВК6    
0x005B91Температура охладителя фазной ячейки AF2 ВК7    
0x005C92Температура охладителя фазной ячейки AF2 ВК8    
0x005D93Температура охладителя фазной ячейки AF3 ВК1    
0x005E94Температура охладителя фазной ячейки AF3 ВК2    
0x005F95Температура охладителя фазной ячейки AF3 ВК3    
0x006096Температура охладителя фазной ячейки AF3 ВК4    
0x006197Температура охладителя фазной ячейки AF3 ВК5    
0x006298Температура охладителя фазной ячейки AF3 ВК6    
0x006399Температура охладителя фазной ячейки AF3 ВК7    
0x0064100Температура охладителя фазной ячейки AF3 ВК8    
0x0065101Температура охладителя чопперной ячейки UF1 ВК1    
0x0066102Температура охладителя чопперной ячейки UF1 ВК2    
0x0067103Температура охладителя чопперной ячейки UF1 ВК3    
0x0068104Температура охладителя чопперной ячейки UF1 ВК4    
0x0069105Температура объёма БИ ВК4    
0x006A106Температура объёма БИ ВК8    
0x006B107Температура воды чопперной ячейки UF1 ВК28    
0x006C108Температура воды фазной ячейки AF1 ВК13    
0x006D109Температура воды фазной ячейки AF2 ВК20    
0x006E110Температура воды фазной ячейки AF3 ВК24    
0x006F111Статусы фазных и чопперной ячеек0Состояние фазного модуля AF10 норма1 предупреждение
12 авария4 резерв
2Состояние фазного модуля AF20 норма1 предупреждение
32 авария4 резерв
4Состояние фазного модуля AF30 норма1 предупреждение
52 авария4 резерв
6Состояние чопперного модуля UF10 норма1 предупреждение
72 авария4 резерв
8   
9   
10   
11   
12   
13   
14   
15   
0x0070112Статус датчиков температуры охладителя фазной ячейки AF10ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0071113Статус датчиков температуры охладителя фазной ячейки AF10ВК5 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК5 - Статус инициализации  
2BK5 - Предупреждение1 - желтый0 - серый
3ВК5 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8ВК7 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК7 - Статус инициализации  
10BK7 - Предупреждение1 - желтый0 - серый
11ВК7 - Авария1 - красный0 - серый
12ВК8 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК8 - Статус инициализации  
14ВК8 - Предупреждение1 - желтый0 - серый
15ВК8 - Авария1 - красный0 - серый
0x0072114Статус датчиков температуры охладителя фазной ячейки AF20ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0073115Статус датчиков температуры охладителя фазной ячейки AF20ВК5 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК5 - Статус инициализации  
2BK5 - Предупреждение1 - желтый0 - серый
3ВК5 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8ВК7 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК7 - Статус инициализации  
10BK7 - Предупреждение1 - желтый0 - серый
11ВК7 - Авария1 - красный0 - серый
12ВК8 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК8 - Статус инициализации  
14ВК8 - Предупреждение1 - желтый0 - серый
15ВК8 - Авария1 - красный0 - серый
0x0074116Статус датчиков температуры охладителя фазной ячейки AF30ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0075117Статус датчиков температуры охладителя фазной ячейки AF30ВК5 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК5 - Статус инициализации  
2BK5 - Предупреждение1 - желтый0 - серый
3ВК5 - Авария1 - красный0 - серый
4ВК6 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК6 - Статус инициализации  
6ВК6 - Предупреждение1 - желтый0 - серый
7ВК6 - Авария1 - красный0 - серый
8ВК7 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК7 - Статус инициализации  
10BK7 - Предупреждение1 - желтый0 - серый
11ВК7 - Авария1 - красный0 - серый
12ВК8 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК8 - Статус инициализации  
14ВК8 - Предупреждение1 - желтый0 - серый
15ВК8 - Авария1 - красный0 - серый
0x0076118Статус датчиков температуры охладителя чопперной ячейки UF10ВК1 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8ВК3 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
9ВК3 - Статус инициализации  
10BK3 - Предупреждение1 - желтый0 - серый
11ВК3 - Авария1 - красный0 - серый
12ВК4 - Статус (Онлайн/Оффлайн)1 - зеленый0 - желтый
13ВК4 - Статус инициализации  
14ВК4 - Предупреждение1 - желтый0 - серый
15ВК4 - Авария1 - красный0 - серый
0x0077119Статус датчиков температуры объема БИ0ВК4 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК4 - Статус инициализации  
2ВК4 - Предупреждение1 - желтый0 - серый
3ВК4 - Авария1 - красный0 - серый
4ВК8 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК8 - Статус инициализации  
6ВК8 - Предупреждение1 - желтый0 - серый
7ВК8 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15БИ - дверь закрыта1 - зеленый0 - серый
0x0078120Статус датчиков температуры воды - БИ0Чопперная ячейка UF1 ВК28 - Статус1 - зеленый0 - серый
1Чопперная ячейка UF1 ВК28 - Резерв  
2Чопперная ячейка UF1 ВК28 - Предупреждение1 - желтый0 - серый
3Чопперная ячейка UF1 ВК28 - Авария1 - красный0 - серый
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
0x0079121Статус датчиков температуры воды - БИ0Фазной ячейки AF1 ВК13 - Статус1 - зеленый0 - серый
1Фазной ячейки AF1 ВК13 - Резерв  
2Фазной ячейки AF1 ВК13 - Предупреждение1 - желтый0 - серый
3Фазной ячейки AF1 ВК13 - Авария1 - красный0 - серый
4Фазной ячейки AF2 ВК20 - Статус1 - зеленый0 - серый
5Фазной ячейки AF2 ВК20 - Резерв  
6Фазной ячейки AF2 ВК20 - Предупреждение1 - желтый0 - серый
7Фазной ячейки AF2 ВК20 - Авария1 - красный0 - серый
8Фазной ячейки AF3 ВК24 - Статус1 - зеленый0 - серый
9Фазной ячейки AF3 ВК24 - Резерв  
10Фазной ячейки AF3 ВК24 - Предупреждение1 - желтый0 - серый
11Фазной ячейки AF3 ВК24 - Авария1 - красный0 - серый
12 1 - зеленый0 - серый
13   
14 1 - желтый0 - серый
15 1 - красный0 - серый
БВШ0x007A122Температура объёма БВШ ВК4    
0x007B123Температура объёма БВШ ВК8    
0x007C124Статус датчиков температуры воды - БВШ0ВК1 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
1ВК 1 - Статус инициализации  
2BK1 - Предупреждение1 - желтый0 - серый
3ВК1 - Авария1 - красный0 - серый
4ВК2 - Статус (Онлайн/Офлайн)1 - зеленый0 - желтый
5ВК2 - Статус инициализации  
6ВК2 - Предупреждение1 - желтый0 - серый
7ВК2 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15БВШ - дверь закрыта1 - зеленый0 - серый
Система охлаждения0x007D125Давление на входе внутреннего контура PT1 (МПа)    
0x007E126Давление на выходе внутреннего контура PT2 (МПа)    
0x007F127Показания расходомера (м3/ч)    
0x0080128Температуры воды "Вход" BK9    
0x0081129Температуры воды "Выход" BK10    
0x0082130Статус датчиков температуры воды - Система охлаждения0Вход воды BK9 - Статус1 - зеленый0 - серый
1Вход воды BK9 - Резерв  
2Вход воды BK9 - Предупреждение1 - желтый0 - серый
3Вход воды BK9 - Авария1 - красный0 - серый
4Выход воды BK10 - Статус1 - зеленый0 - желтый
5Выход воды BK10 - Резерв  
6Выход воды BK10 - Предупреждение1 - желтый0 - серый
7Выход воды BK10 - Авария1 - красный0 - серый
8   
9   
10   
11   
12   
13   
14   
15Датчик протечки1 - зеленый0 - красный
Передача значений уставок (Верхний порог предупреждения)Осн. данные0x0083131Порог предупреждения о высоком токе на выходе фазы U    
0x0084132Порог предупреждения о высоком токе на выходе фазы V    
0x0085133Порог предупреждения о высоком токе на выходе фазы W    
Блок БСУ0x0086134УКСИ - Предупредительная уставка    
0x0087135Температура объёма БСУ ВК1 - Верхний порог предупреждения    
0x0088136Температура объёма БСУ ВК5 - Верхний порог предупреждения    
Блок БВ0x0089137Порог предупреждения о высоком напряжении на входе А1В1    
0x008A138Порог предупреждения о высоком напряжении на входе В1С1    
0x008B139Порог предупреждения о высоком напряжении на входе А2В2    
0x008C140Порог предупреждения о высоком напряжении на входе В2С2    
0x008D141Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог предупреждения    
0x008E142Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог предупреждения    
0x008F143Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог предупреждения    
0x0090144Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог предупреждения    
0x0091145Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог предупреждения    
0x0092146Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог предупреждения    
0x0093147Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог предупреждения    
0x0094148Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог предупреждения    
0x0095149Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог предупреждения    
0x0096150Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог предупреждения    
0x0097151Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог предупреждения    
0x0098152Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог предупреждения    
0x0099153Температура объёма Блок БВ ВК2 - Верхний порог предупреждения    
0x009A154Температура объёма Блок БВ ВК6 - Верхний порог предупреждения    
0x009B155Температура воды выпрямительной ячейки UZ1 ВК11 - Верхний порог предупреждения    
0x009C156Температура воды выпрямительной ячейки UZ2 ВК12 - Верхний порог предупреждения    
0x009D157Температура воды резисторного модуля UR1 ВК17 - Верхний порог предупреждения    
0x009E158Температура воды резисторного модуля UR2 ВК18 - Верхний порог предупреждения    
0x009F159Температура воды резисторного модуля UR3 ВК19 - Верхний порог предупреждения    
БК0x00A0160Напряжение звена постоянного тока (В) - Верхний порог предупреждения    
0x00A1161Ток звена постоянного тока (+) (А) - Верхний порог предупреждения    
0x00A2162Ток звена постоянного тока (-) (А) - Верхний порог предупреждения    
0x00A3163Температура объёма БК ВК3 - Верхний порог предупреждения    
0x00A4164Температура объёма БК ВК7 - Верхний порог предупреждения    
БИ0x00A5165Ток ячейки чопперной UF1 (А) - Верхний порог предупреждения    
0x00A6166Ток ячейки фазной AF1 (А) - Верхний порог предупреждения    
0x00A7167Ток ячейки фазной AF2 (А) - Верхний порог предупреждения    
0x00A8168Ток ячейки фазной AF3 (А) - Верхний порог предупреждения    
0x00A9169Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог предупреждения    
0x00AA170Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог предупреждения    
0x00AB171Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог предупреждения    
0x00AC172Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог предупреждения    
0x00AD173Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог предупреждения    
0x00AE174Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог предупреждения    
0x00AF175Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог предупреждения    
0x00B0176Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог предупреждения    
0x00B1177Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог предупреждения    
0x00B2178Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог предупреждения    
0x00B3179Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог предупреждения    
0x00B4180Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог предупреждения    
0x00B5181Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог предупреждения    
0x00B6182Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог предупреждения    
0x00B7183Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог предупреждения    
0x00B8184Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог предупреждения    
0x00B9185Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог предупреждения    
0x00BA186Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог предупреждения    
0x00BB187Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог предупреждения    
0x00BC188Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог предупреждения    
0x00BD189Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог предупреждения    
0x00BE190Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог предупреждения    
0x00BF191Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог предупреждения    
0x00C0192Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог предупреждения    
0x00C1193Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог предупреждения    
0x00C2194Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог предупреждения    
0x00C3195Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог предупреждения    
0x00C4196Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог предупреждения    
0x00C5197Температура объёма БИ ВК4 - Верхний порог предупреждения    
0x00C6198Температура объёма БИ ВК8 - Верхний порог предупреждения    
0x00C7199Температура воды чопперной ячейки UF1 ВК28 - Верхний порог предупреждения    
0x00C8200Температура воды фазной ячейки AF1 ВК13 - Верхний порог предупреждения    
0x00C9201Температура воды фазной ячейки AF2 ВК20 - Верхний порог предупреждения    
0x00CA202Температура воды фазной ячейки AF3 ВК24 - Верхний порог предупреждения    
БВШ0x00CB203Температура объёма БВШ ВК4 - Верхний порог предупреждения    
0x00CC204Температура объёма БВШ ВК8 - Верхний порог предупреждения    
Система охлаждения0x00CD205Давление на входе внутреннего контура PT1 (МПа) - Верхний порог предупреждения    
0x00CE206Давление на выходе внутреннего контура PT2 (МПа)-Верхний порог предупреждения    
0x00CF207Показания расходомера (м3/ч) - Верхний порог предупреждения    
0x00D0208Температуры воды "Вход" BK9 - Верхний порог предупреждения    
0x00D1209Температуры воды "Выход" BK10 - Верхний порог предупреждения    
Передача значений уставок (Верхний порог аварии)Основные данные0x00D2210Порог аварийно высокого тока на выходе фазы U    
0x00D3211Порог аварийно высокого тока на выходе фазы V    
0x00D4212Порог аварийно высокого тока на выходе фазы W    
Блок БСУ0x00D5213УКСИ - Аварийная уставка    
0x00D6214Температура объёма БСУ ВК1 - Верхний порог аварии    
0x00D7215Температура объёма БСУ ВК5 - Верхний порог аварии    
Блок БВ0x00D8216Порог аварийно высокого напряжения на входе А1В1    
0x00D9217Порог аварийно высокого напряжения на входе В1С1    
0x00DA218Порог аварийно высокого напряжения на входе А2В2    
0x00DB219Порог аварийно высокого напряжения на входе В2С2    
0x00DC220Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог аварии    
0x00DD221Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог аварии    
0x00DE222Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог аварии    
0x00DF223Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог аварии    
0x00E0224Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог аварии    
0x00E1225Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог аварии    
0x00E2226Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог аварии    
0x00E3227Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог аварии    
0x00E4228Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог аварии    
0x00E5229Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог аварии    
0x00E6230Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог аварии    
0x00E7231Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог аварии    
0x00E8232Температура объёма Блок БВ ВК2 - Верхний порог аварии    
0x00E9233Температура объёма Блок БВ ВК6 - Верхний порог аварии    
0x00EA234Температура воды выпрямительной ячейки UZ1 BK11 - Верхний порог аварии    
0x00EB235Температура воды выпрямительной ячейки UZ2 BK12 - Верхний порог аварии    
0x00EC236Температура воды резисторного модуля UR1 BK17 - Верхний порог аварии    
0x00ED237Температура воды резисторного модуля UR2 BK18 - Верхний порог аварии    
0x00EE238Температура воды резисторного модуля UR3 BK19 - Верхний порог аварии    
БК0x00EF239Напряжение звена постоянного тока (В) - Верхний порог аварии    
0x00F0240Ток звена постоянного тока (+) (А) - Верхний порог аварии    
0x00F1241Ток звена постоянного тока (-) (А) - Верхний порог аварии    
0x00F2242Температура объёма БК ВК3 - Верхний порог аварии    
0x00F3243Температура объёма БК ВК7 - Верхний порог аварии    
БИ0x00F4244Ток ячейки чопперной UF1 (А) - Верхний порог аварии    
0x00F5245Ток ячейки фазной AF1 (А) - Верхний порог аварии    
0x00F6246Ток ячейки фазной AF2 (А) - Верхний порог аварии    
0x00F7247Ток ячейки фазной AF3 (А) - Верхний порог аварии    
0x00F8248Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог аварии    
0x00F9249Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог аварии    
0x00FA250Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог аварии    
0x00FB251Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог аварии    
0x00FC252Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог аварии    
0x00FD253Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог аварии    
0x00FE254Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог аварии    
0x00FF255Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог аварии    
0x0100256Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог аварии    
0x0101257Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог аварии    
0x0102258Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог аварии    
0x0103259Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог аварии    
0x0104260Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог аварии    
0x0105261Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог аварии    
0x0106262Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог аварии    
0x0107263Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог аварии    
0x0108264Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог аварии    
0x0109265Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог аварии    
0x010A266Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог аварии    
0x010B267Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог аварии    
0x010C268Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог аварии    
0x010D269Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог аварии    
0x010E270Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог аварии    
0x010F271Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог аварии    
0x0110272Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог аварии    
0x0111273Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог аварии    
0x0112274Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог аварии    
0x0113275Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог аварии    
0x0114276Температура объёма БИ ВК4 - Верхний порог аварии    
0x0115277Температура объёма БИ ВК8 - Верхний порог аварии    
0x0116278Температура воды чопперной ячейки UF1 ВК28 - Верхний порог аварии    
0x0117279Температура воды фазной ячейки AF1 ВК13 - Верхний порог аварии    
0x0118280Температура воды фазной ячейки AF2 ВК20 - Верхний порог аварии    
0x0119281Температура воды фазной ячейки AF3 ВК24 - Верхний порог аварии    
БВШ0x011A282Температура объёма БВШ ВК4 - Верхний порог аварии    
0x011B283Температура объёма БВШ ВК8 - Верхний порог аварии    
Система охлаждения0x011C284Давление на входе внутреннего контура PT1 (МПа) - Верхний порог аварии    
0x011D285Давление на выходе внутреннего контура PT2 (МПа) - Верхний порог аварии    
0x011E286Показания расходомера (м3/ч) - Верхний порог аварии    
0x011F287Температуры воды "Вход" BK9 - Верхний порог аварии    
0x0120288Температуры воды "Выход" BK10 - Верхний порог аварии    
Передача значений уставок (Нижний порог предупреждения)Блок БСУ0x0121289Температура объёма БСУ ВК1 - Нижний порог предупреждения    
0x0122290Температура объёма БСУ ВК5 - Нижний порог предупреждения    
Блок БВ0x0123291Порог предупреждения о низком напряжении на входе А1В1    
0x0124292Порог предупреждения о низком напряжении на входе В1С1    
0x0125293Порог предупреждения о низком напряжении на входе А2В2    
0x0126294Порог предупреждения о низком напряжении на входе В2С2    
0x0127295Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог предупреждения    
0x0128296Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог предупреждения    
0x0129297Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог предупреждения    
0x012A298Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог предупреждения    
0x012B299Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог предупреждения    
0x012C300Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог предупреждения    
0x012D301Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог предупреждения    
0x012E302Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог предупреждения    
0x012F303Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог предупреждения    
0x0130304Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог предупреждения    
0x0131305Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог предупреждения    
0x0132306Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог предупреждения    
0x0133307Температура объёма Блок БВ ВК2 - Нижний порог предупреждения    
0x0134308Температура объёма Блок БВ ВК6 - Нижний порог предупреждения    
0x0135309Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог предупреждения    
0x0136310Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог предупреждения    
0x0137311Температура воды резисторного модуля UR1 ВК17 - Нижний порог предупреждения    
0x0138312Температура воды резисторного модуля UR2 ВК18 - Нижний порог предупреждения    
0x0139313Температура воды резисторного модуля UR3 ВК19 - Нижний порог предупреждения    
БК0x013A314Напряжение звена постоянного тока (В) - Нижний порог предупреждения    
0x013B315Температура объёма БК ВК3 - Нижний порог предупреждения    
0x013C316Температура объёма БК ВК7 - Нижний порог предупреждения    
БИ0x013D317Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог предупреждения    
0x013E318Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог предупреждения    
0x013F319Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог предупреждения    
0x0140320Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог предупреждения    
0x0141321Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог предупреждения    
0x0142322Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог предупреждения    
0x0143323Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог предупреждения    
0x0144324Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог предупреждения    
0x0145325Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог предупреждения    
0x0146326Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог предупреждения    
0x0147327Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог предупреждения    
0x0148328Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог предупреждения    
0x0149329Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог предупреждения    
0x014A330Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог предупреждения    
0x014B331Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог предупреждения    
0x014C332Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог предупреждения    
0x014D333Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог предупреждения    
0x014E334Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог предупреждения    
0x014F335Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог предупреждения    
0x0150336Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог предупреждения    
0x0151337Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог предупреждения    
0x0152338Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог предупреждения    
0x0153339Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог предупреждения    
0x0154340Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог предупреждения    
0x0155341Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог предупреждения    
0x0156342Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог предупреждения    
0x0157343Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог предупреждения    
0x0158344Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог предупреждения    
0x0159345Температура объёма БИ ВК4 - Нижний порог предупреждения    
0x015A346Температура объёма БИ ВК8 - Нижний порог предупреждения    
0x015B347Температура воды чопперной ячейки UF1 ВК28 - Нижний порог предупреждения    
0x015C348Температура воды фазной ячейки AF1 ВК13 - Нижний порог предупреждения    
0x015D349Температура воды фазной ячейки AF2 ВК20 - Нижний порог предупреждения    
0x015E350Температура воды фазной ячейки AF3 ВК24 - Нижний порог предупреждения    
БВШ0x015F351Температура объёма БВШ ВК4 - Нижний порог предупреждения    
0x0160352Температура объёма БВШ ВК8 - Нижний порог предупреждения    
Система охлаждения0x0161353Давление на входе внутреннего контура PT1 (МПа) - Нижний порог предупреждения    
0x0162354Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог предупреждения    
0x0163355Показания расходомера (м3/ч) - Нижний порог предупреждения    
0x0164356Температуры воды "Вход" BK9 - Нижний порог предупреждения    
0x0165357Температуры воды "Выход" BK10 - Нижний порог предупреждения    
Передача значений уставок (Нижний порог аварии)Блок БСУ0x0166358Температура объёма БСУ ВК1 - Нижний порог аварии    
0x0167359Температура объёма БСУ ВК5 - Нижний порог аварии    
Блок БВ0x0168360Порог аварийно низкого напряжения на входе А1В1    
0x0169361Порог аварийно низкого напряжения на входе В1С1    
0x016A362Порог аварийно низкого напряжения на входе А2В2    
0x016B363Порог аварийно низкого напряжения на входе В2С2    
0x016C364Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог аварии    
0x016D365Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог аварии    
0x016E366Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог аварии    
0x016F367Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог аварии    
0x0170368Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог аварии    
0x0171369Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог аварии    
0x0172370Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог аварии    
0x0173371Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог аварии    
0x0174372Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог аварии    
0x0175373Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог аварии    
0x0176374Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог аварии    
0x0177375Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог аварии    
0x0178376Температура объёма Блок БВ ВК2 - Нижний порог аварии    
0x0179377Температура объёма Блок БВ ВК6 - Нижний порог аварии    
0x017A378Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог аварии    
0x017B379Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог аварии    
0x017C380Температура воды резисторного модуля UR1 ВК17 - Нижний порог аварии    
0x017D381Температура воды резисторного модуля UR2 ВК18 - Нижний порог аварии    
0x017E382Температура воды резисторного модуля UR3 ВК19 - Нижний порог аварии    
БК0x017F383Напряжение звена постоянного тока (В) - Нижний порог аварии    
0x0180384Температура объёма БК ВК3 - Нижний порог аварии    
0x0181385Температура объёма БК ВК7 - Нижний порог аварии    
БИ0x0182386Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог аварии    
0x0183387Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог аварии    
0x0184388Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог аварии    
0x0185389Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог аварии    
0x0186390Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог аварии    
0x0187391Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог аварии    
0x0188392Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог аварии    
0x0189393Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог аварии    
0x018A394Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог аварии    
0x018B395Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог аварии    
0x018C396Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог аварии    
0x018D397Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог аварии    
0x018E398Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог аварии    
0x018F399Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог аварии    
0x0190400Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог аварии    
0x0191401Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог аварии    
0x0192402Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог аварии    
0x0193403Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог аварии    
0x0194404Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог аварии    
0x0195405Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог аварии    
0x0196406Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог аварии    
0x0197407Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог аварии    
0x0198408Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог аварии    
0x0199409Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог аварии    
0x019A410Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог аварии    
0x019B411Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог аварии    
0x019C412Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог аварии    
0x019D413Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог аварии    
0x019E414Температура объёма БИ ВК4 - Нижний порог аварии    
0x019F415Температура объёма БИ ВК8 - Нижний порог аварии    
0x01A0416Температура воды чопперной ячейки UF1 ВК28 - Нижний порог аварии    
0x01A1417Температура воды фазной ячейки AF1 ВК13 - Нижний порог аварии    
0x01A2418Температура воды фазной ячейки AF2 ВК20 - Нижний порог аварии    
0x01A3419Температура воды фазной ячейки AF3 ВК24 - Нижний порог аварии    
БВШ0x01A4420Температура объёма БВШ ВК4 - Нижний порог аварии    
0x01A5421Температура объёма БВШ ВК8 - Нижний порог аварии    
Система охлаждения0x01A6422Давление на входе внутреннего контура PT1 (МПа) - Нижний порог аварии    
0x01A7423Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог аварии    
0x01A8424Показания расходомера (м3/ч) - Нижний порог аварии    
0x01A9425Температуры воды "Вход" BK9 - Нижний порог аварии    
0x01AA426Температуры воды "Выход" BK10 - Нижний порог аварии    
Данные датчиковБСУ0x01AB427Температура объёма БСУ ВК10 - 15User Bytes  
0x01AC42816 - 64ID  
0x01AD429  
0x01AE430  
0x01AF431Температура объёма БСУ ВК50 - 15User Bytes  
0x01B043216 - 64ID  
0x01B1433  
0x01B2434  
Блок БВ0x01B3435Температура охладителя выпрямительной ячейки UZ1 ВК10 - 15User Bytes  
0x01B443616 - 64ID  
0x01B5437  
0x01B6438  
0x01B7439Температура охладителя выпрямительной ячейки UZ1 ВК20 - 15User Bytes  
0x01B844016 - 64ID  
0x01B9441  
0x01BA442  
0x01BB443Температура охладителя выпрямительной ячейки UZ2 ВК10 - 15User Bytes  
0x01BC44416 - 64ID  
0x01BD445  
0x01BE446  
0x01BF447Температура охладителя выпрямительной ячейки UZ2 ВК20 - 15User Bytes  
0x01C044816 - 64ID  
0x01C1449  
0x01C2450  
0x01C3451Температура охладителя резисторного модуля UR1 ВК10 - 15User Bytes  
0x01C445216 - 64ID  
0x01C5453  
0x01C6454  
0x01C7455Температура охладителя резисторного модуля UR1 ВК20 - 15User Bytes  
0x01C845616 - 64ID  
0x01C9457  
0x01CA458  
0x01CB459Температура охладителя резисторного модуля UR2 ВК10 - 15User Bytes  
0x01CC46016 - 64ID  
0x01CD461  
0x01CE462  
0x01CF463Температура охладителя резисторного модуля UR2 ВК20 - 15User Bytes  
0x01D046416 - 64ID  
0x01D1465  
0x01D2466  
0x01D3467Температура охладителя резисторного модуля UR3 ВК10 - 15User Bytes  
0x01D446816 - 64ID  
0x01D5469  
0x01D6470  
0x01D7471Температура охладителя резисторного модуля UR3 ВК20 - 15User Bytes  
0x01D847216 - 64ID  
0x01D9473  
0x01DA474  
0x01DB475Температура объёма Блок БВ ВК20 - 15User Bytes  
0x01DC47616 - 64ID  
0x01DD477  
0x01DE478  
0x01DF479Температура объёма Блок БВ ВК60 - 15User Bytes  
0x01E048016 - 64ID  
0x01E1481  
0x01E2482  
БК0x01E3483Температура объёма БК ВК30 - 15User Bytes  
0x01E448416 - 64ID  
0x01E5485  
0x01E6486  
0x01E7487Температура объёма БК ВК70 - 15User Bytes  
0x01E848816 - 64ID  
0x01E9489  
0x01EA490  
БИ0x01EB491Температура охладителя фазной ячейки AF1 ВК10 - 15User Bytes  
0x01EC49216 - 64ID  
0x01ED493  
0x01EE494  
0x01EF495Температура охладителя фазной ячейки AF1 ВК20 - 15User Bytes  
0x01F049616 - 64ID  
0x01F1497  
0x01F2498  
0x01F3499Температура охладителя фазной ячейки AF1 ВК30 - 15User Bytes  
0x01F450016 - 64ID  
0x01F5501  
0x01F6502  
0x01F7503Температура охладителя фазной ячейки AF1 ВК40 - 15User Bytes  
0x01F850416 - 64ID  
0x01F9505  
0x01FA506  
0x01FB507Температура охладителя фазной ячейки AF1 ВК50 - 15User Bytes  
0x01FC50816 - 64ID  
0x01FD509  
0x01FE510  
0x01FF511Температура охладителя фазной ячейки AF1 ВК60 - 15User Bytes  
0x020051216 - 64ID  
0x0201513  
0x0202514  
0x0203515Температура охладителя фазной ячейки AF1 ВК70 - 15User Bytes  
0x020451616 - 64ID  
0x0205517  
0x0206518  
0x0207519Температура охладителя фазной ячейки AF1 ВК80 - 15User Bytes  
0x020852016 - 64ID  
0x0209521  
0x020A522  
0x020B523Температура охладителя фазной ячейки AF2 ВК10 - 15User Bytes  
0x020C52416 - 64ID  
0x020D525  
0x020E526  
0x020F527Температура охладителя фазной ячейки AF2 ВК20 - 15User Bytes  
0x021052816 - 64ID  
0x0211529  
0x0212530  
0x0213531Температура охладителя фазной ячейки AF2 ВК30 - 15User Bytes  
0x021453216 - 64ID  
0x0215533  
0x0216534  
0x0217535Температура охладителя фазной ячейки AF2 ВК40 - 15User Bytes  
0x021853616 - 64ID  
0x0219537  
0x021A538  
0x021B539Температура охладителя фазной ячейки AF2 ВК50 - 15User Bytes  
0x021C54016 - 64ID  
0x021D541  
0x021E542  
0x021F543Температура охладителя фазной ячейки AF2 ВК60 - 15User Bytes  
0x022054416 - 64ID  
0x0221545  
0x0222546  
0x0223547Температура охладителя фазной ячейки AF2 ВК70 - 15User Bytes  
0x022454816 - 64ID  
0x0225549  
0x0226550  
0x0227551Температура охладителя фазной ячейки AF2 ВК80 - 15User Bytes  
0x022855216 - 64ID  
0x0229553  
0x022A554  
0x022B555Температура охладителя фазной ячейки AF3 ВК10 - 15User Bytes  
0x022C55616 - 64ID  
0x022D557  
0x022E558  
0x022F559Температура охладителя фазной ячейки AF3 ВК20 - 15User Bytes  
0x023056016 - 64ID  
0x0231561  
0x0232562  
0x0233563Температура охладителя фазной ячейки AF3 ВК30 - 15User Bytes  
0x023456416 - 64ID  
0x0235565  
0x0236566  
0x0237567Температура охладителя фазной ячейки AF3 ВК40 - 15User Bytes  
0x023856816 - 64ID  
0x0239569  
0x023A570  
0x023B571Температура охладителя фазной ячейки AF3 ВК50 - 15User Bytes  
0x023C57216 - 64ID  
0x023D573  
0x023E574  
0x023F575Температура охладителя фазной ячейки AF3 ВК60 - 15User Bytes  
0x024057616 - 64ID  
0x0241577  
0x0242578  
0x0243579Температура охладителя фазной ячейки AF3 ВК70 - 15User Bytes  
0x024458016 - 64ID  
0x0245581  
0x0246582  
0x0247583Температура охладителя фазной ячейки AF3 ВК80 - 15User Bytes  
0x024858416 - 64ID  
0x0249585  
0x024A586  
0x024B587Температура охладителя чопперной ячейки UF1 ВК10 - 15User Bytes  
0x024C58816 - 64ID  
0x024D589  
0x024E590  
0x024F591Температура охладителя чопперной ячейки UF1 ВК20 - 15User Bytes  
0x025059216 - 64ID  
0x0251593  
0x0252594  
0x0253595Температура охладителя чопперной ячейки UF1 ВК30 - 15User Bytes  
0x025459616 - 64ID  
0x0255597  
0x0256598  
0x0257599Температура охладителя чопперной ячейки UF1 ВК40 - 15User Bytes  
0x025860016 - 64ID  
0x0259601  
0x025A602  
0x025B603Температура объёма БИ ВК40 - 15User Bytes  
0x025C60416 - 64ID  
0x025D605  
0x025E606  
0x025F607Температура объёма БИ ВК80 - 15User Bytes  
0x026060816 - 64ID  
0x0261609  
0x0262610  
БВШ0x0263611Температура объёма БВШ ВК40 - 15User Bytes  
0x026461216 - 64ID  
0x0265613  
0x0266614  
0x0267615Температура объёма БВШ ВК80 - 15User Bytes  
0x026861616 - 64ID  
0x0269617  
0x026A618  
Приём     
ПриёмКоманды0x13885000Код протокола CAN (Обычный, расширенный, суперрасширенный)    
0x13895001Сохранить уставки    
0x138A5002Сброс ошибок (квитирование)    
0x138B5003Команда запроса ID    
0x138C5004Команда запроса User Bytes    
0x138D5005Команда запроса уставок    
0x138E5006Счётчик запросов основных данных    
0x138F5007Счётчик запросов уставок    
0x13905008Счётчик запросов данных датчиков    
0x13915009Команда для устройства0Блокировка  
1Собрать силовую схему  
2Разобрать силовую схему  
3Схема собрана в режиме аварийного хода  
4Установить управление по мощности  
5Установить управление по оборотам  
6Установить режим устройства "конфигурация" (меню настроек)  
7Установить режим устройства "эксплуатация"  
8Запросить все предупредительные уставки  
9Запросить все аварийные уставки  
10   
11   
12   
13   
14   
15Сохранить настройки  
Приём значений уставок (Верхний порог предупреждения)Осн. данные0x13925010Порог предупреждения о высоком токе на выходе фазы U    
0x13935011Порог предупреждения о высоком токе на выходе фазы V    
0x13945012Порог предупреждения о высоком токе на выходе фазы W    
Блок БСУ0x13955013УКСИ - Предупредительная уставка    
0x13965014Температура объёма БСУ ВК1 - Верхний порог предупреждения    
0x13975015Температура объёма БСУ ВК5 - Верхний порог предупреждения    
Блок БВ0x13985016Порог предупреждения о высоком напряжении на входе А1В1    
0x13995017Порог предупреждения о высоком напряжении на входе В1С1    
0x139A5018Порог предупреждения о высоком напряжении на входе А2В2    
0x139B5019Порог предупреждения о высоком напряжении на входе В2С2    
0x139C5020Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог предупреждения    
0x139D5021Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог предупреждения    
0x139E5022Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог предупреждения    
0x139F5023Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог предупреждения    
0x13A05024Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог предупреждения    
0x13A15025Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог предупреждения    
0x13A25026Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог предупреждения    
0x13A35027Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог предупреждения    
0x13A45028Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог предупреждения    
0x13A55029Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог предупреждения    
0x13A65030Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог предупреждения    
0x13A75031Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог предупреждения    
0x13A85032Температура объёма Блок БВ ВК2 - Верхний порог предупреждения    
0x13A95033Температура объёма Блок БВ ВК6 - Верхний порог предупреждения    
0x13AA5034Температура воды выпрямительной ячейки UZ1 ВК11 - Верхний порог предупреждения    
0x13AB5035Температура воды выпрямительной ячейки UZ2 ВК12 - Верхний порог предупреждения    
0x13AC5036Температура воды резисторного модуля UR1 ВК17 - Верхний порог предупреждения    
0x13AD5037Температура воды резисторного модуля UR2 ВК18 - Верхний порог предупреждения    
0x13AE5038Температура воды резисторного модуля UR3 ВК19 - Верхний порог предупреждения    
БК0x13AF5039Напряжение звена постоянного тока (В) - Верхний порог предупреждения    
0x13B05040Ток звена постоянного тока (+) (А) - Верхний порог предупреждения    
0x13B15041Ток звена постоянного тока (-) (А) - Верхний порог предупреждения    
0x13B25042Температура объёма БК ВК3 - Верхний порог предупреждения    
0x13B35043Температура объёма БК ВК7 - Верхний порог предупреждения    
БИ0x13B45044Ток ячейки чопперной UF1 (А) - Верхний порог предупреждения    
0x13B55045Ток ячейки фазной AF1 (А) - Верхний порог предупреждения    
0x13B65046Ток ячейки фазной AF2 (А) - Верхний порог предупреждения    
0x13B75047Ток ячейки фазной AF3 (А) - Верхний порог предупреждения    
0x13B85048Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог предупреждения    
0x13B95049Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог предупреждения    
0x13BA5050Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог предупреждения    
0x13BB5051Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог предупреждения    
0x13BC5052Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог предупреждения    
0x13BD5053Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог предупреждения    
0x13BE5054Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог предупреждения    
0x13BF5055Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог предупреждения    
0x13C05056Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог предупреждения    
0x13C15057Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог предупреждения    
0x13C25058Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог предупреждения    
0x13C35059Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог предупреждения    
0x13C45060Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог предупреждения    
0x13C55061Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог предупреждения    
0x13C65062Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог предупреждения    
0x13C75063Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог предупреждения    
0x13C85064Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог предупреждения    
0x13C95065Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог предупреждения    
0x13CA5066Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог предупреждения    
0x13CB5067Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог предупреждения    
0x13CC5068Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог предупреждения    
0x13CD5069Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог предупреждения    
0x13CE5070Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог предупреждения    
0x13CF5071Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог предупреждения    
0x13D05072Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог предупреждения    
0x13D15073Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог предупреждения    
0x13D25074Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог предупреждения    
0x13D35075Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог предупреждения    
0x13D45076Температура объёма БИ ВК4 - Верхний порог предупреждения    
0x13D55077Температура объёма БИ ВК8 - Верхний порог предупреждения    
0x13D65078Температура воды чопперной ячейки UF1 ВК28 - Верхний порог предупреждения    
0x13D75079Температура воды фазной ячейки AF1 ВК13 - Верхний порог предупреждения    
0x13D85080Температура воды фазной ячейки AF2 ВК20 - Верхний порог предупреждения    
0x13D95081Температура воды фазной ячейки AF3 ВК24 - Верхний порог предупреждения    
БВШ0x13DA5082Температура объёма БВШ ВК4 - Верхний порог предупреждения    
0x13DB5083Температура объёма БВШ ВК8 - Верхний порог предупреждения    
Система охлаждения0x13DC5084Давление на входе внутреннего контура PT1 (МПа) - Верхний порог предупреждения    
0x13DD5085Давление на выходе внутреннего контура PT2 (МПа)-Верхний порог предупреждения    
0x13DE5086Показания расходомера (м3/ч) - Верхний порог предупреждения    
0x13DF5087Температуры воды "Вход" BK9 - Верхний порог предупреждения    
0x13E05088Температуры воды "Выход" BK10 - Верхний порог предупреждения    
Приём значений уставок (Верхний порог аварии)Осн. данные0x13E15089Порог аварийно высокого тока на выходе фазы U    
0x13E25090Порог аварийно высокого тока на выходе фазы V    
0x13E35091Порог аварийно высокого тока на выходе фазы W    
Блок БСУ0x13E45092УКСИ - Аварийная уставка    
0x13E55093Температура объёма БСУ ВК1 - Верхний порог аварии    
0x13E65094Температура объёма БСУ ВК5 - Верхний порог аварии    
Блок БВ0x13E75095Порог аварийно высокого напряжения на входе А1В1    
0x13E85096Порог аварийно высокого напряжения на входе В1С1    
0x13E95097Порог аварийно высокого напряжения на входе А2В2    
0x13EA5098Порог аварийно высокого напряжения на входе В2С2    
0x13EB5099Частота входного напряжения выпрямителя UZ1 (Гц) - Верхний порог аварии    
0x13EC5100Частота входного напряжения выпрямителя UZ2 (Гц) - Верхний порог аварии    
0x13ED5101Температура охладителя выпрямительной ячейки UZ1 ВК1 - Верхний порог аварии    
0x13EE5102Температура охладителя выпрямительной ячейки UZ1 ВК2 - Верхний порог аварии    
0x13EF5103Температура охладителя выпрямительной ячейки UZ2 ВК1 - Верхний порог аварии    
0x13F05104Температура охладителя выпрямительной ячейки UZ2 ВК2 - Верхний порог аварии    
0x13F15105Температура охладителя резисторного модуля UR1 ВК1 - Верхний порог аварии    
0x13F25106Температура охладителя резисторного модуля UR1 ВК2 - Верхний порог аварии    
0x13F35107Температура охладителя резисторного модуля UR2 ВК1 - Верхний порог аварии    
0x13F45108Температура охладителя резисторного модуля UR2 ВК2 - Верхний порог аварии    
0x13F55109Температура охладителя резисторного модуля UR3 ВК1 - Верхний порог аварии    
0x13F65110Температура охладителя резисторного модуля UR3 ВК2 - Верхний порог аварии    
0x13F75111Температура объёма Блок БВ ВК2 - Верхний порог аварии    
0x13F85112Температура объёма Блок БВ ВК6 - Верхний порог аварии    
0x13F95113Температура воды выпрямительной ячейки UZ1 BK11 - Верхний порог аварии    
0x13FA5114Температура воды выпрямительной ячейки UZ2 BK12 - Верхний порог аварии    
0x13FB5115Температура воды резисторного модуля UR1 BK17 - Верхний порог аварии    
0x13FC5116Температура воды резисторного модуля UR2 BK18 - Верхний порог аварии    
0x13FD5117Температура воды резисторного модуля UR3 BK19 - Верхний порог аварии    
БК0x13FE5118Напряжение звена постоянного тока (В) - Верхний порог аварии    
0x13FF5119Ток звена постоянного тока (+) (А) - Верхний порог аварии    
0x14005120Ток звена постоянного тока (-) (А) - Верхний порог аварии    
0x14015121Температура объёма БК ВК3 - Верхний порог аварии    
0x14025122Температура объёма БК ВК7 - Верхний порог аварии    
БИ0x14035123Ток ячейки чопперной UF1 (А) - Верхний порог аварии    
0x14045124Ток ячейки фазной AF1 (А) - Верхний порог аварии    
0x14055125Ток ячейки фазной AF2 (А) - Верхний порог аварии    
0x14065126Ток ячейки фазной AF3 (А) - Верхний порог аварии    
0x14075127Температура охладителя фазной ячейки AF1 ВК1 - Верхний порог аварии    
0x14085128Температура охладителя фазной ячейки AF1 ВК2 - Верхний порог аварии    
0x14095129Температура охладителя фазной ячейки AF1 ВК3 - Верхний порог аварии    
0x140A5130Температура охладителя фазной ячейки AF1 ВК4 - Верхний порог аварии    
0x140B5131Температура охладителя фазной ячейки AF1 ВК5 - Верхний порог аварии    
0x140C5132Температура охладителя фазной ячейки AF1 ВК6 - Верхний порог аварии    
0x140D5133Температура охладителя фазной ячейки AF1 ВК7 - Верхний порог аварии    
0x140E5134Температура охладителя фазной ячейки AF1 ВК8 - Верхний порог аварии    
0x140F5135Температура охладителя фазной ячейки AF2 ВК1 - Верхний порог аварии    
0x14105136Температура охладителя фазной ячейки AF2 ВК2 - Верхний порог аварии    
0x14115137Температура охладителя фазной ячейки AF2 ВК3 - Верхний порог аварии    
0x14125138Температура охладителя фазной ячейки AF2 ВК4 - Верхний порог аварии    
0x14135139Температура охладителя фазной ячейки AF2 ВК5 - Верхний порог аварии    
0x14145140Температура охладителя фазной ячейки AF2 ВК6 - Верхний порог аварии    
0x14155141Температура охладителя фазной ячейки AF2 ВК7 - Верхний порог аварии    
0x14165142Температура охладителя фазной ячейки AF2 ВК8 - Верхний порог аварии    
0x14175143Температура охладителя фазной ячейки AF3 ВК1 - Верхний порог аварии    
0x14185144Температура охладителя фазной ячейки AF3 ВК2 - Верхний порог аварии    
0x14195145Температура охладителя фазной ячейки AF3 ВК3 - Верхний порог аварии    
0x141A5146Температура охладителя фазной ячейки AF3 ВК4 - Верхний порог аварии    
0x141B5147Температура охладителя фазной ячейки AF3 ВК5 - Верхний порог аварии    
0x141C5148Температура охладителя фазной ячейки AF3 ВК6 - Верхний порог аварии    
0x141D5149Температура охладителя фазной ячейки AF3 ВК7 - Верхний порог аварии    
0x141E5150Температура охладителя фазной ячейки AF3 ВК8 - Верхний порог аварии    
0x141F5151Температура охладителя чопперной ячейки UF1 ВК1 - Верхний порог аварии    
0x14205152Температура охладителя чопперной ячейки UF1 ВК2 - Верхний порог аварии    
0x14215153Температура охладителя чопперной ячейки UF1 ВК3 - Верхний порог аварии    
0x14225154Температура охладителя чопперной ячейки UF1 ВК4 - Верхний порог аварии    
0x14235155Температура объёма БИ ВК4 - Верхний порог аварии    
0x14245156Температура объёма БИ ВК8 - Верхний порог аварии    
0x14255157Температура воды чопперной ячейки UF1 ВК28 - Верхний порог аварии    
0x14265158Температура воды фазной ячейки AF1 ВК13 - Верхний порог аварии    
0x14275159Температура воды фазной ячейки AF2 ВК20 - Верхний порог аварии    
0x14285160Температура воды фазной ячейки AF3 ВК24 - Верхний порог аварии    
БВШ0x14295161Температура объёма БВШ ВК4 - Верхний порог аварии    
0x142A5162Температура объёма БВШ ВК8 - Верхний порог аварии    
Система охлаждения0x142B5163Давление на входе внутреннего контура PT1 (МПа) - Верхний порог аварии    
0x142C5164Давление на выходе внутреннего контура PT2 (МПа) - Верхний порог аварии    
0x142D5165Показания расходомера (м3/ч) - Верхний порог аварии    
0x142E5166Температуры воды "Вход" BK9 - Верхний порог аварии    
0x142F5167Температуры воды "Выход" BK10 - Верхний порог аварии    
Приём значений уставок (Нижний порог предупреждения)Блок БСУ0x14305168Температура объёма БСУ ВК1 - Нижний порог предупреждения    
0x14315169Температура объёма БСУ ВК5 - Нижний порог предупреждения    
Блок БВ0x14325170Порог предупреждения о низком напряжении на входе А1В1    
0x14335171Порог предупреждения о низком напряжении на входе В1С1    
0x14345172Порог предупреждения о низком напряжении на входе А2В2    
0x14355173Порог предупреждения о низком напряжении на входе В2С2    
0x14365174Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог предупреждения    
0x14375175Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог предупреждения    
0x14385176Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог предупреждения    
0x14395177Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог предупреждения    
0x143A5178Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог предупреждения    
0x143B5179Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог предупреждения    
0x143C5180Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог предупреждения    
0x143D5181Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог предупреждения    
0x143E5182Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог предупреждения    
0x143F5183Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог предупреждения    
0x14405184Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог предупреждения    
0x14415185Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог предупреждения    
0x14425186Температура объёма Блок БВ ВК2 - Нижний порог предупреждения    
0x14435187Температура объёма Блок БВ ВК6 - Нижний порог предупреждения    
0x14445188Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог предупреждения    
0x14455189Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог предупреждения    
0x14465190Температура воды резисторного модуля UR1 ВК17 - Нижний порог предупреждения    
0x14475191Температура воды резисторного модуля UR2 ВК18 - Нижний порог предупреждения    
0x14485192Температура воды резисторного модуля UR3 ВК19 - Нижний порог предупреждения    
БК0x14495193Напряжение звена постоянного тока (В) - Нижний порог предупреждения    
0x144A5194Температура объёма БК ВК3 - Нижний порог предупреждения    
0x144B5195Температура объёма БК ВК7 - Нижний порог предупреждения    
БИ0x144C5196Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог предупреждения    
0x144D5197Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог предупреждения    
0x144E5198Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог предупреждения    
0x144F5199Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог предупреждения    
0x14505200Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог предупреждения    
0x14515201Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог предупреждения    
0x14525202Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог предупреждения    
0x14535203Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог предупреждения    
0x14545204Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог предупреждения    
0x14555205Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог предупреждения    
0x14565206Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог предупреждения    
0x14575207Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог предупреждения    
0x14585208Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог предупреждения    
0x14595209Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог предупреждения    
0x145A5210Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог предупреждения    
0x145B5211Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог предупреждения    
0x145C5212Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог предупреждения    
0x145D5213Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог предупреждения    
0x145E5214Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог предупреждения    
0x145F5215Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог предупреждения    
0x14605216Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог предупреждения    
0x14615217Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог предупреждения    
0x14625218Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог предупреждения    
0x14635219Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог предупреждения    
0x14645220Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог предупреждения    
0x14655221Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог предупреждения    
0x14665222Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог предупреждения    
0x14675223Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог предупреждения    
0x14685224Температура объёма БИ ВК4 - Нижний порог предупреждения    
0x14695225Температура объёма БИ ВК8 - Нижний порог предупреждения    
0x146A5226Температура воды чопперной ячейки UF1 ВК28 - Нижний порог предупреждения    
0x146B5227Температура воды фазной ячейки AF1 ВК13 - Нижний порог предупреждения    
0x146C5228Температура воды фазной ячейки AF2 ВК20 - Нижний порог предупреждения    
0x146D5229Температура воды фазной ячейки AF3 ВК24 - Нижний порог предупреждения    
БВШ0x146E5230Температура объёма БВШ ВК4 - Нижний порог предупреждения    
0x146F5231Температура объёма БВШ ВК8 - Нижний порог предупреждения    
Система охлаждения0x14705232Давление на входе внутреннего контура PT1 (МПа) - Нижний порог предупреждения    
0x14715233Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог предупреждения    
0x14725234Показания расходомера (м3/ч) - Нижний порог предупреждения    
0x14735235Температуры воды "Вход" BK9 - Нижний порог предупреждения    
0x14745236Температуры воды "Выход" BK10 - Нижний порог предупреждения    
Приём значений уставок (Нижний порог аварии)Блок БСУ0x14755237Температура объёма БСУ ВК1 - Нижний порог аварии    
0x14765238Температура объёма БСУ ВК5 - Нижний порог аварии    
Блок БВ0x14775239Порог аварийно низкого напряжения на входе А1В1    
0x14785240Порог аварийно низкого напряжения на входе В1С1    
0x14795241Порог аварийно низкого напряжения на входе А2В2    
0x147A5242Порог аварийно низкого напряжения на входе В2С2    
0x147B5243Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог аварии    
0x147C5244Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог аварии    
0x147D5245Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог аварии    
0x147E5246Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог аварии    
0x147F5247Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог аварии    
0x14805248Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог аварии    
0x14815249Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог аварии    
0x14825250Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог аварии    
0x14835251Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог аварии    
0x14845252Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог аварии    
0x14855253Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог аварии    
0x14865254Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог аварии    
0x14875255Температура объёма Блок БВ ВК2 - Нижний порог аварии    
0x14885256Температура объёма Блок БВ ВК6 - Нижний порог аварии    
0x14895257Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог аварии    
0x148A5258Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог аварии    
0x148B5259Температура воды резисторного модуля UR1 ВК17 - Нижний порог аварии    
0x148C5260Температура воды резисторного модуля UR2 ВК18 - Нижний порог аварии    
0x148D5261Температура воды резисторного модуля UR3 ВК19 - Нижний порог аварии    
БК0x148E5262Напряжение звена постоянного тока (В) - Нижний порог аварии    
0x148F5263Температура объёма БК ВК3 - Нижний порог аварии    
0x14905264Температура объёма БК ВК7 - Нижний порог аварии    
БИ0x14915265Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог аварии    
0x14925266Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог аварии    
0x14935267Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог аварии    
0x14945268Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог аварии    
0x14955269Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог аварии    
0x14965270Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог аварии    
0x14975271Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог аварии    
0x14985272Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог аварии    
0x14995273Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог аварии    
0x149A5274Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог аварии    
0x149B5275Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог аварии    
0x149C5276Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог аварии    
0x149D5277Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог аварии    
0x149E5278Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог аварии    
0x149F5279Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог аварии    
0x14A05280Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог аварии    
0x14A15281Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог аварии    
0x14A25282Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог аварии    
0x14A35283Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог аварии    
0x14A45284Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог аварии    
0x14A55285Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог аварии    
0x14A65286Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог аварии    
0x14A75287Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог аварии    
0x14A85288Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог аварии    
0x14A95289Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог аварии    
0x14AA5290Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог аварии    
0x14AB5291Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог аварии    
0x14AC5292Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог аварии    
0x14AD5293Температура объёма БИ ВК4 - Нижний порог аварии    
0x14AE5294Температура объёма БИ ВК8 - Нижний порог аварии    
0x14AF5295Температура воды чопперной ячейки UF1 ВК28 - Нижний порог аварии    
0x14B05296Температура воды фазной ячейки AF1 ВК13 - Нижний порог аварии    
0x14B15297Температура воды фазной ячейки AF2 ВК20 - Нижний порог аварии    
0x14B25298Температура воды фазной ячейки AF3 ВК24 - Нижний порог аварии    
БВШ0x14B35299Температура объёма БВШ ВК4 - Нижний порог аварии    
0x14B45300Температура объёма БВШ ВК8 - Нижний порог аварии    
Система охлаждения0x14B55301Давление на входе внутреннего контура PT1 (МПа) - Нижний порог аварии    
0x14B65302Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог аварии    
0x14B75303Показания расходомера (м3/ч) - Нижний порог аварии    
0x14B85304Температуры воды "Вход" BK9 - Нижний порог аварии    
0x14B95305Температуры воды "Выход" BK10 - Нижний порог аварии    
          
          
          
          
          
          
          
          
   0x14925266Порог аварийно низкого напряжения на входе В2С2    
   0x14935267Частота входного напряжения выпрямителя UZ1 (Гц) - Нижний порог аварии    
   0x14945268Частота входного напряжения выпрямителя UZ2 (Гц) - Нижний порог аварии    
   0x14955269Температура охладителя выпрямительной ячейки UZ1 ВК1 - Нижний порог аварии    
   0x14965270Температура охладителя выпрямительной ячейки UZ1 ВК2 - Нижний порог аварии    
   0x14975271Температура охладителя выпрямительной ячейки UZ2 ВК1 - Нижний порог аварии    
   0x14985272Температура охладителя выпрямительной ячейки UZ2 ВК2 - Нижний порог аварии    
   0x14995273Температура охладителя резисторного модуля UR1 ВК1 - Нижний порог аварии    
   0x149A5274Температура охладителя резисторного модуля UR1 ВК2 - Нижний порог аварии    
   0x149B5275Температура охладителя резисторного модуля UR2 ВК1 - Нижний порог аварии    
   0x149C5276Температура охладителя резисторного модуля UR2 ВК2 - Нижний порог аварии    
   0x149D5277Температура охладителя резисторного модуля UR3 ВК1 - Нижний порог аварии    
   0x149E5278Температура охладителя резисторного модуля UR3 ВК2 - Нижний порог аварии    
   0x149F5279Температура объёма Блок вводной ВК2 - Нижний порог аварии    
   0x14A05280Температура объёма Блок вводной ВК6 - Нижний порог аварии    
   0x14A15281Температура воды выпрямительной ячейки UZ1 ВК11 - Нижний порог аварии    
   0x14A25282Температура воды выпрямительной ячейки UZ2 ВК12 - Нижний порог аварии    
   0x14A35283Температура воды резисторного модуля UR1 ВК17 - Нижний порог аварии    
   0x14A45284Температура воды резисторного модуля UR2 ВК18 - Нижний порог аварии    
   0x14A55285Температура воды резисторного модуля UR3 ВК19 - Нижний порог аварии    
  БС10x14A65286Напряжение звена постоянного тока (В) - Нижний порог аварии    
  0x14A75287Температура объёма БС1 ВК3 - Нижний порог аварии    
  0x14A85288Температура объёма БС1 ВК7 - Нижний порог аварии    
  БС20x14A95289Температура охладителя фазной ячейки AF1 ВК1 - Нижний порог аварии    
  0x14AA5290Температура охладителя фазной ячейки AF1 ВК2 - Нижний порог аварии    
  0x14AB5291Температура охладителя фазной ячейки AF1 ВК3 - Нижний порог аварии    
  0x14AC5292Температура охладителя фазной ячейки AF1 ВК4 - Нижний порог аварии    
  0x14AD5293Температура охладителя фазной ячейки AF1 ВК5 - Нижний порог аварии    
  0x14AE5294Температура охладителя фазной ячейки AF1 ВК6 - Нижний порог аварии    
  0x14AF5295Температура охладителя фазной ячейки AF1 ВК7 - Нижний порог аварии    
  0x14B05296Температура охладителя фазной ячейки AF1 ВК8 - Нижний порог аварии    
  0x14B15297Температура охладителя фазной ячейки AF2 ВК1 - Нижний порог аварии    
  0x14B25298Температура охладителя фазной ячейки AF2 ВК2 - Нижний порог аварии    
  0x14B35299Температура охладителя фазной ячейки AF2 ВК3 - Нижний порог аварии    
  0x14B45300Температура охладителя фазной ячейки AF2 ВК4 - Нижний порог аварии    
  0x14B55301Температура охладителя фазной ячейки AF2 ВК5 - Нижний порог аварии    
  0x14B65302Температура охладителя фазной ячейки AF2 ВК6 - Нижний порог аварии    
  0x14B75303Температура охладителя фазной ячейки AF2 ВК7 - Нижний порог аварии    
  0x14B85304Температура охладителя фазной ячейки AF2 ВК8 - Нижний порог аварии    
  0x14B95305Температура охладителя фазной ячейки AF3 ВК1 - Нижний порог аварии    
  0x14BA5306Температура охладителя фазной ячейки AF3 ВК2 - Нижний порог аварии    
  0x14BB5307Температура охладителя фазной ячейки AF3 ВК3 - Нижний порог аварии    
  0x14BC5308Температура охладителя фазной ячейки AF3 ВК4 - Нижний порог аварии    
  0x14BD5309Температура охладителя фазной ячейки AF3 ВК5 - Нижний порог аварии    
  0x14BE5310Температура охладителя фазной ячейки AF3 ВК6 - Нижний порог аварии    
  0x14BF5311Температура охладителя фазной ячейки AF3 ВК7 - Нижний порог аварии    
  0x14C05312Температура охладителя фазной ячейки AF3 ВК8 - Нижний порог аварии    
  0x14C15313Температура охладителя чопперной ячейки UF1 ВК1 - Нижний порог аварии    
  0x14C25314Температура охладителя чопперной ячейки UF1 ВК2 - Нижний порог аварии    
  0x14C35315Температура охладителя чопперной ячейки UF1 ВК3 - Нижний порог аварии    
  0x14C45316Температура охладителя чопперной ячейки UF1 ВК4 - Нижний порог аварии    
  0x14C55317Температура объёма БС2 ВК4 - Нижний порог аварии    
  0x14C65318Температура объёма БС2 ВК8 - Нижний порог аварии    
  0x14C75319Температура воды чопперной ячейки UF1 ВК28 - Нижний порог аварии    
  0x14C85320Температура воды чопперной ячейки UF1 ВК29 - Нижний порог аварии    
  0x14C95321Температура воды фазной ячейки AF1 ВК13 - Нижний порог аварии    
  0x14CA5322Температура воды фазной ячейки AF1 ВК14 - Нижний порог аварии    
  0x14CB5323Температура воды фазной ячейки AF1 ВК15 - Нижний порог аварии    
  0x14CC5324Температура воды фазной ячейки AF1 ВК16 - Нижний порог аварии    
  0x14CD5325Температура воды фазной ячейки AF2 ВК20 - Нижний порог аварии    
  0x14CE5326Температура воды фазной ячейки AF2 ВК21 - Нижний порог аварии    
  0x14CF5327Температура воды фазной ячейки AF2 ВК22 - Нижний порог аварии    
  0x14D05328Температура воды фазной ячейки AF2 ВК23 - Нижний порог аварии    
  0x14D15329Температура воды фазной ячейки AF3 ВК24 - Нижний порог аварии    
  0x14D25330Температура воды фазной ячейки AF3 ВК25 - Нижний порог аварии    
  0x14D35331Температура воды фазной ячейки AF3 ВК26 - Нижний порог аварии    
  0x14D45332Температура воды фазной ячейки AF3 ВК27 - Нижний порог аварии    
  Система охлаждения0x14D55333Давление на входе внутреннего контура PT1 (МПа) - Нижний порог аварии    
  0x14D65334Давление на выходе внутреннего контура PT2 (МПа) - Нижний порог аварии    
  0x14D75335Показания расходомера (м3/ч) - Нижний порог аварии    
  0x14D85336Температуры воды "Вход" BK9 - Нижний порог аварии    
  0x14D95337Температуры воды "Выход" BK10 - Нижний порог аварии    
+ + + + diff --git a/Протокол CAN и ОАП.md b/Протокол CAN и ОАП.md index 0f2867a..da42337 100644 --- a/Протокол CAN и ОАП.md +++ b/Протокол CAN и ОАП.md @@ -4,6 +4,200 @@ - [Интерфейс протокола](#sheet-protocol) - [Общее адресное пространство](#sheet-oap) +- [Прошивка приборов по CAN](#can-firmware) + + +## Прошивка приборов по CAN + +Ниже зафиксирован формат планируемого загрузочного сервиса. Значения +`MsgType=0x9..0xD` зарезервированы в протоколе, но обработчики загрузчика в +текущих `protocan.c/.h` ещё не реализованы. + +Загрузчик работает поверх classic CAN 2.0B с Extended ID. Управляющий модуль +использует `Route=0`, прибор отвечает с `Route=1`. Команды стирания и записи +всегда должны быть адресованы конкретной паре `DeviceType/DeviceID`; +широковещательный режим допустим только для обнаружения. + +### Карта загрузочных сообщений + +| `MsgType` | Имя | Назначение `MsgBody` | CAN payload | +|---:|---|---|---| +| `0x9` | `BOOT_CONTROL` | `SessionID:8 \| Command:8` | параметры команды | +| `0xA` | `BOOT_DATA_A` | номер 8-байтового блока слота A | 8 байт образа | +| `0xB` | `BOOT_DATA_B` | номер 8-байтового блока слота B | 8 байт образа | +| `0xC` | `BOOT_STATUS` | `SessionID:8 \| Command:8` | статус и прогресс | +| `0xD` | `BOOT_DISCOVERY` | подтип запроса/ответа | идентификация прибора | + +`MsgBody` в кадрах данных является не байтовым адресом, а номером блока: + +```c +block_offset = (uint32_t)MsgBody * 8U; + +if (MsgType == PROTOCAN_MSGTYPE_BOOT_DATA_A) { + address = SLOT_A_BASE + block_offset; +} else if (MsgType == PROTOCAN_MSGTYPE_BOOT_DATA_B) { + address = SLOT_B_BASE + block_offset; +} +``` + +Диапазон `MsgBody=0x0000..0xFFFF` адресует ровно 65 536 блоков: + +```text +512 КиБ = 512 * 1024 = 524 288 байт +524 288 / 8 = 65 536 блоков +``` + +| `MsgBody` | Номер блока | Смещение от начала слота | Диапазон байтов | +|---:|---:|---:|---:| +| `0x0000` | 0 | `0x00000` | `0x00000..0x00007` | +| `0x0001` | 1 | `0x00008` | `0x00008..0x0000F` | +| `0x0002` | 2 | `0x00010` | `0x00010..0x00017` | +| `0xFFFF` | 65 535 | `0x7FFF8` | `0x7FFF8..0x7FFFF` | + +Формула физического адреса блока: + +```c +address = SLOT_X_BASE + ((uint32_t)MsgBody * 8U); +``` + +Последний допустимый блок начинается со смещения `0x7FFF8` и заканчивается +на `0x7FFFF` включительно. Следующее смещение `0x80000` уже находится за +границей 512-КиБ слота. + +Таким образом, `BOOT_DATA_A` и `BOOT_DATA_B` адресуют два логических слота +по 512 КиБ, всего 1 МиБ пространства образов. Физические `SLOT_A_BASE` и +`SLOT_B_BASE` задаёт конкретный загрузчик. Если внутренняя Flash имеет ровно +1 МиБ, два полных слота в ней не поместятся вместе с загрузчиком и метаданными: +нужно уменьшить слоты, выбрать MCU с большей Flash или хранить staging-образ +во внешней памяти. + +### Кадр данных + +```text +Extended CAN ID + Priority = STANDARD + Route = FROM_PM + DeviceType = тип целевого прибора + DeviceID = экземпляр целевого прибора + MsgType = 0xA (слот A) или 0xB (слот B) + MsgBody = BlockIndex, 0x0000..0xFFFF + +DATA[0..7] = очередные 8 байт образа +``` + +Например, `MsgBody=0x0123` задаёт смещение `0x0123 * 8 = 0x0918` от +начала выбранного слота. Последний неполный блок дополняется значениями +`0xFF`; фактический размер передаётся командой `BEGIN_UPDATE`, поэтому CRC32 +считается только по байтам образа. + +### Управляющие команды + +В `BOOT_CONTROL` поле `MsgBody` имеет формат: + +```text +15........8 7.........0 + SessionID Command +``` + +Рекомендуемые команды: + +| Код | Команда | Назначение | +|---:|---|---| +| `0x01` | `IDENTIFY` | прочитать тип, аппаратную и программную версии | +| `0x02` | `ENTER_BOOT` | перейти из приложения в загрузчик | +| `0x03` | `BEGIN_IMAGE` | передать размер и CRC32 образа | +| `0x04` | `BEGIN_COMPAT` | передать тип, аппаратную и программную версии | +| `0x05` | `ERASE` | подготовить неактивный слот | +| `0x06` | `VERIFY` | проверить размер, CRC32 и подпись | +| `0x07` | `COMMIT` | назначить проверенный слот кандидатом на запуск | +| `0x08` | `CONFIRM` | подтвердить успешный запуск новой программы | +| `0x09` | `REBOOT` | перезагрузить прибор | +| `0x0A` | `ABORT` | отменить текущую сессию | +| `0x0B` | `QUERY_PROGRESS` | запросить слот и следующий ожидаемый блок | + +`BEGIN_IMAGE` содержит размер и CRC образа: + +```text +DATA[0..3] ImageSize, uint32 little-endian +DATA[4..7] ImageCRC32, uint32 little-endian +``` + +`BEGIN_COMPAT` содержит совместимость и версию: + +```text +DATA[0..1] ProductType, uint16 little-endian +DATA[2] минимальная HardwareRevision +DATA[3] максимальная HardwareRevision +DATA[4..7] FirmwareVersion, uint32 little-endian +``` + +Обе команды передаются с одним `SessionID`. До стирания Flash загрузчик обязан +получить обе части метаданных и проверить `ProductType`, аппаратную ревизию, +размер образа, границы выбранного слота и допустимость версии. + +### Ответ состояния + +`BOOT_STATUS` возвращает результат команды и точку продолжения: + +```text +MsgBody[15..8] = SessionID +MsgBody[7..0] = команда, на которую дан ответ + +DATA[0] Status +DATA[1] TargetSlot: 0 = A, 1 = B +DATA[2..3] NextBlock, uint16 little-endian +DATA[4..7] RunningCRC32, uint32 little-endian +``` + +Минимальный набор статусов: + +| Код | Статус | +|---:|---| +| `0x00` | `OK` | +| `0x01` | `BUSY` | +| `0x02` | `INVALID_COMMAND` | +| `0x03` | `WRONG_DEVICE` | +| `0x04` | `WRONG_HARDWARE` | +| `0x05` | `INVALID_SIZE` | +| `0x06` | `CRC_ERROR` | +| `0x07` | `FLASH_ERROR` | +| `0x08` | `SEQUENCE_ERROR` | +| `0x09` | `SIGNATURE_ERROR` | +| `0x0A` | `SESSION_ERROR` | +| `0x0B` | `VOLTAGE_ERROR` | + +`NextBlock` позволяет возобновить загрузку после разрыва связи. Для первой +реализации допустимо подтверждать каждый блок. Для рабочей скорости лучше +передавать окна по 16 кадров и подтверждать окно одним `BOOT_STATUS`; при +необходимости протокол статуса можно расширить битовой картой потерянных +блоков. + +### Выбор слота и безопасное обновление + +GUI не должен самостоятельно перезаписывать активный слот. После получения +`BEGIN_IMAGE` и `BEGIN_COMPAT` загрузчик выбирает неактивный слот и сообщает его в +`BOOT_STATUS`: + +```text +активен A -> принимать BOOT_DATA_B +активен B -> принимать BOOT_DATA_A +``` + +Рекомендуемый цикл обновления: + +1. Обнаружить прибор и сверить `DeviceType/DeviceID`, `ProductType`, UID и версии. +2. Выполнить адресную команду `ENTER_BOOT` и получить новый `SessionID`. +3. Передать `BEGIN_IMAGE` и `BEGIN_COMPAT`; загрузчик выберет неактивный слот. +4. Стереть выбранный слот и передать блоки `BOOT_DATA_A` или `BOOT_DATA_B`. +5. Выполнить `VERIFY`: проверить размер, CRC32 и цифровую подпись образа. +6. Выполнить `COMMIT` и перезагрузить устройство. +7. Новое приложение вызывает `CONFIRM` после успешной самопроверки. +8. При отсутствии подтверждения загрузчик возвращается к предыдущему слоту. + +CRC32 обнаруживает случайное повреждение, но не защищает от подмены. Для +серийных изделий образ следует подписывать, а открытый ключ проверки хранить +в неизменяемой части загрузчика. Сам загрузчик не должен обновляться обычными +командами `BOOT_DATA_A/B`. + + +
+
+
STM32 · Classic CAN 2.0B · HAL
+

SETCAN
руководство разработчика

+

Карта библиотеки ProtoCAN, формат кадров и практический маршрут переноса в существующую прошивку STM32.

+
+ 29 бит Extended ID0…8 байт payload128 адресов устройств127 кадров в RX-очереди +
+
+ +
+ +
+ +
+

Что находится в проекте

+

SETCAN — не готовый CubeIDE-проект, а подключаемый C-модуль поверх STM32 HAL. Его задача — фильтровать, принимать, разбирать и отправлять прикладные сообщения ProtoCAN.

+
+
Структура

Минимальное ядро + нормативные документы

SETCAN/ +├── Inc/protocan.h публичные типы, настройки и API +├── Src/protocan.c фильтры, RX-очередь, разбор и отправка +├── docs/protocan/ спецификация протокола +│ ├── PROTOCOL.md 29-битный ID и типы сообщений +│ ├── OAP.md общее адресное пространство +│ ├── BOOTLOADER.md обновление прошивки по CAN (draft) +│ └── examples/ эталонные кадры JSON +├── Протокол CAN и ОАП.xlsx редактируемый реестр ОАП +└── doc/index.html эта страница
+
Зависимости

Что ожидает модуль

  • main.h и can.h из CubeMX
  • STM32 HAL CAN, RTC и TIM
  • CAN FIFO0 и Extended ID
  • STM32 GCC ABI для C bit-fields
+
Входящие

Путь кадра

IRQ вычитывает FIFO0. Pulse обрабатывается сразу, остальные Extended-кадры попадают в кольцевой буфер и разбираются в основном цикле.

+
Исходящие

Единая точка отправки

PROTOCAN_SEND() выбирает упаковщик по MsgType. GAS и Modbus автоматически разбиваются на кадры до 8 байт.

+
Граница

Что приложение реализует само

Прикладные действия, хранение SETTINGS, EEPROM, DS18B20, таймаут online/offline и полноценный bootloader не входят в ядро.

+
+
+
01 · FIFO0 IRQHAL сообщает о новом кадре
02 · RX bufferExtended ID помещается в очередь
03 · DispatcherРазбор по MsgType
04 · Weak handlerЛогика приложения
+
+
+ +
+

Состав библиотеки

Два файла образуют один модуль. Заголовок — контракт интеграции; C-файл — транспортная реализация и демонстрационные слабые обработчики.

+
+
Inc

protocan.h

Конфигурация текущего устройства, размеры буфера, enum типов сообщений, битовые представления ID/Body, структуры TX/RX и публичные функции.

Меняют при переносе: CURRENT_TYPE_DEVICE, CURRENT_ID_DEVICE, иногда PROTOCAN_RX_BUFFER_SIZE.

+
Src

protocan.c

Инициализация, фильтры, кольцевой буфер, диспетчеризация, RTC sync, pulse и упаковка кадров.

Обычно не правят: прикладную логику лучше добавлять переопределением __weak-функций.

+
HAL

Внешний слой

CAN_HandleTypeDef, RTC_HandleTypeDef и TIM_HandleTypeDef передаются в PROTOCAN_INIT(). Запуск периферии выполняет приложение.

+

Основной API

+ + + + + + + +
ФункцияНазначениеГде вызывать
PROTOCAN_INITСохраняет HAL handles, настраивает фильтры и callback’и при доступной регистрации.После MX_*_Init(), до HAL_CAN_Start().
PROTOCAN_ProcessAllRxMsgsОбрабатывает всю накопленную RX-очередь и возвращает первую ошибку.В основном цикле.
PROTOCAN_ProcessSingleRxMsgОбрабатывает максимум один кадр.В планировщике или ограниченном временном слоте.
PROTOCAN_SENDУпаковывает и отправляет сообщение выбранного типа.Из логики приложения, не удерживая изменяемые данные.
ProtoCanRxFifo0MsgPendingCallbackЗабирает кадры из CAN FIFO0.Из HAL callback, если авто-регистрация выключена.
ProtoCanPulseCallbackОтправляет периодический pulse со счётчиком.Из callback нужного базового таймера.
PROTOCAN_SEND_SETTINGS_RESPONSE / ERRORФормирует успешный либо ошибочный ответ привязки ROM.Из пользовательского обработчика SETTINGS.
+

Точки расширения

Переопределите нужную __weak-функцию в собственном C-файле: семейства ProtoCanMsgToBroadcast…, …Discrete…, …Analog…, ProtoCanMsgToSettings, ProtoCanMsgToGeneralAddressSpace и …Modbus…. Не редактируйте демонстрационную реализацию в ядре — так обновлять библиотеку проще.

+
+
+ +
+

Формат ProtoCAN

Протокол использует только CAN 2.0B Extended ID. Адрес устройства — пара DeviceType/DeviceID; назначение младших 16 бит зависит от типа сообщения.

+

29-битный идентификатор

28        27        26··24       23··20      19··16      15········0
+Priority  Route     DeviceType   DeviceID    MsgType     MsgBody
+1 бит     1 бит     3 бита       4 бита      4 бита      16 бит
Многобайтовые значения payload передаются little-endian. Разметка ID через C bit-fields требует проверки при смене компилятора или ABI.
+
+

Реестр MsgType

+ +
КодТипНазначениеСтатус
0x0BROADCASTОбщие команды всем устройствамstable
0x1DISCRETEСостояния, команды, флагиstable
0x2ANALOGДатчики U / I / T и универсальные данныеstable
0x3GASОбщее 16-битное адресное пространствоstable
0x4…0x7MODBUSCoil, Discrete, Holding, Inputstable
0x8ERRORКод ошибки и дополнительная информацияstable
0x9…0xDBOOTУправление, блоки A/B, статус, discoverydraft
0xESETTINGSПривязка 1-Wire ROM к локации Z/Ystable
0xFPULSEПрисутствие устройстваstable
+
+
+ +
+

Как портировать в свой STM32-проект

Рабочая последовательность для CubeMX/CubeIDE. Имена hcan, hrtc и htim2 замените на handles своего проекта.

+
+
Шаг 1

Добавьте исходники

  • Inc/protocan.h в include path
  • Src/protocan.c в сборку
  • Проверьте доступность main.h и can.h
+
Шаг 2

Настройте адрес

В protocan.h задайте тип 0…7 и ID 0…15. Пара должна быть уникальной на шине.

#define CURRENT_TYPE_DEVICE 0b011
+#define CURRENT_ID_DEVICE   0b0101
+
Шаг 3

Настройте CubeMX

  • CAN: Extended ID, FIFO0
  • RTC: если нужна синхронизация времени
  • TIM: период pulse
  • Проверьте filter banks 0, 1, 2 и границу 14
+
Шаг 4

Инициализация и основной цикл

#include "protocan.h"
+
+int main(void)
+{
+    HAL_Init();
+    SystemClock_Config();
+
+    MX_GPIO_Init();
+    MX_CAN_Init();
+    MX_RTC_Init();
+    MX_TIM2_Init();
+
+    if (PROTOCAN_INIT(&hcan, &hrtc, &htim2) != PROTOCAN_INIT_OK) {
+        Error_Handler();
+    }
+    if (HAL_CAN_Start(&hcan) != HAL_OK) {
+        Error_Handler();
+    }
+    if (HAL_CAN_ActivateNotification(
+            &hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
+        Error_Handler();
+    }
+    if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
+        Error_Handler();
+    }
+
+    while (1) {
+        (void)PROTOCAN_ProcessAllRxMsgs();
+    }
+}
+
Шаг 5

Свяжите callback’и при отключённой регистрации HAL

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan_ptr)
+{
+    if (hcan_ptr == &hcan) {
+        ProtoCanRxFifo0MsgPendingCallback(hcan_ptr);
+    }
+}
+
+void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim_ptr)
+{
+    if (htim_ptr == &htim2) {
+        ProtoCanPulseCallback(htim_ptr);
+    }
+}
+
Важно

Не дублируйте события

Если USE_HAL_*_REGISTER_CALLBACKS == 1, библиотека регистрирует callback’и сама. Не вызывайте те же функции ещё раз из стандартных callback’ов.

+
Шаг 6

Перенесите прикладную логику

Создайте, например, protocan_app.c и определите там только нужные weak handlers. Так ядро остаётся обновляемым.

#include "protocan.h"
+
+PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg msg)
+{
+    msgBodyAnalogType body = {0};
+    body.Body = msg.eID.Fields.MsgBody;
+
+    uint16_t sensor_id = body.Fields.SensorID;
+    /* Получить температуру sensor_id и сформировать ответ. */
+
+    return PROTOCAN_OK;
+}
+

Проверка после переноса

  • Проект собирается без повторных определений HAL callback’ов.
  • CAN стартует и принимает только Extended ID.
  • Pulse появляется с периодом выбранного таймера.
  • Эталонный ID 0x13590702 декодируется как DeviceType=3, DeviceID=5, MsgType=9, Body=0x0702.
  • При нагрузке учтено, что буфер размера 128 хранит максимум 127 кадров.
+
+
+ +
+

Готовые шаблоны

Минимальные примеры формирования исходящего кадра и обработчика SETTINGS. Их можно вынести в прикладной слой проекта.

+
+

Отправка трёх регистров GAS

uint16_t registers[] = { 0x1234, 0x5678, 0x9ABC };
+
+ProtoCanId_t id = {0};
+id.Fields.Priority   = PROTOCAN_PRIORITY_STANDARD;
+id.Fields.Route      = PROTOCAN_ROUTE_FROM_DEVICE;
+id.Fields.DeviceType = CURRENT_TYPE_DEVICE;
+id.Fields.DeviceID   = CURRENT_ID_DEVICE;
+id.Fields.MsgType    = PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE;
+
+ProtoCanData_t tx = {0};
+tx.GeneralAddressSpaceData.RegStartAdr = 100;
+tx.GeneralAddressSpaceData.Data        = registers;
+tx.GeneralAddressSpaceData.RegCount    = 3;
+
+if (PROTOCAN_SEND(id, tx) != PROTOCAN_OK) {
+    /* CAN занят или HAL вернул ошибку. */
+}
+

SETTINGS: прикладное хранение ROM

PROTOCAN_StatusTypeDef ProtoCanMsgToSettings(
+    const ProtoCanSettingsMsg_t *message)
+{
+    uint8_t current_rom[PROTOCAN_SETTINGS_ROM_SIZE] = {0};
+
+    switch (message->Operation) {
+    case PROTOCAN_SETTINGS_GET:
+        /* Загрузить ROM из EEPROM в current_rom. */
+        return PROTOCAN_SEND_SETTINGS_RESPONSE(
+            message->AssemblySerial, message->Position, current_rom);
+
+    case PROTOCAN_SETTINGS_WRITE:
+        /* Проверить CRC/наличие и атомарно записать message->Rom. */
+        return PROTOCAN_SEND_SETTINGS_RESPONSE(
+            message->AssemblySerial, message->Position, message->Rom);
+
+    case PROTOCAN_SETTINGS_CLEAR:
+        /* Очистить запись; current_rom должен содержать нули. */
+        return PROTOCAN_SEND_SETTINGS_RESPONSE(
+            message->AssemblySerial, message->Position, current_rom);
+
+    default:
+        return PROTOCAN_SEND_SETTINGS_ERROR(
+            message->AssemblySerial, message->Position,
+            PROTOCAN_SETTINGS_RESULT_INVALID_DLC);
+    }
+}
+
+ +
+ +
Сформировано по исходникам и документации SETCAN. Нормативный приоритет сохраняют PROTOCOL.md, BOOTLOADER.md и реестр ОАП.
+
+ + + From ab60e58318517c727186917b9f84a4940d6b2f58 Mon Sep 17 00:00:00 2001 From: Andrey Kruchinkin Date: Sun, 30 Aug 2026 06:12:49 +0300 Subject: [PATCH 10/11] docs: consolidate documentation under doc --- README.md | 12 +- {docs/protocan => doc}/build-html.bat | 12 +- doc/build-html.ps1 | 87 ++ doc/index.html | 893 +++++++++++++++++- {docs => doc}/protocan/BOOTLOADER.md | 0 {docs => doc}/protocan/CHANGELOG.md | 2 +- {docs => doc}/protocan/OAP.md | 0 {docs => doc}/protocan/PROTOCOL.md | 0 {docs => doc}/protocan/README.md | 10 +- .../protocan/examples/test-vectors.json | 0 .../Протокол CAN и ОАП.html | 0 .../Протокол CAN и ОАП.md | 0 .../Протокол CAN и ОАП.xlsx | Bin .../ссылки на док.md | 0 docs/protocan/build-html.ps1 | 57 -- docs/protocan/build/protocol.html | 833 ---------------- docs/protocan/protocol.html | 833 ---------------- 17 files changed, 991 insertions(+), 1748 deletions(-) rename {docs/protocan => doc}/build-html.bat (51%) create mode 100644 doc/build-html.ps1 rename {docs => doc}/protocan/BOOTLOADER.md (100%) rename {docs => doc}/protocan/CHANGELOG.md (96%) rename {docs => doc}/protocan/OAP.md (100%) rename {docs => doc}/protocan/PROTOCOL.md (100%) rename {docs => doc}/protocan/README.md (82%) rename {docs => doc}/protocan/examples/test-vectors.json (100%) rename Протокол CAN и ОАП.html => doc/Протокол CAN и ОАП.html (100%) rename Протокол CAN и ОАП.md => doc/Протокол CAN и ОАП.md (100%) rename Протокол CAN и ОАП.xlsx => doc/Протокол CAN и ОАП.xlsx (100%) rename ссылки на док.md => doc/ссылки на док.md (100%) delete mode 100644 docs/protocan/build-html.ps1 delete mode 100644 docs/protocan/build/protocol.html delete mode 100644 docs/protocan/protocol.html diff --git a/README.md b/README.md index c8039ab..cd18a82 100644 --- a/README.md +++ b/README.md @@ -20,15 +20,15 @@ SETCAN/ Нормативное описание разделено по назначению: -- [`docs/protocan/PROTOCOL.md`](docs/protocan/PROTOCOL.md) — структура ProtoCAN; -- [`docs/protocan/BOOTLOADER.md`](docs/protocan/BOOTLOADER.md) — прошивка по CAN; -- [`docs/protocan/OAP.md`](docs/protocan/OAP.md) — правила ведения ОАП; -- [`docs/protocan/examples/test-vectors.json`](docs/protocan/examples/test-vectors.json) — машинные эталоны; -- [`docs/protocan/build/protocol.html`](docs/protocan/build/protocol.html) — собранная HTML-версия. +- [`doc/protocan/PROTOCOL.md`](doc/protocan/PROTOCOL.md) — структура ProtoCAN; +- [`doc/protocan/BOOTLOADER.md`](doc/protocan/BOOTLOADER.md) — прошивка по CAN; +- [`doc/protocan/OAP.md`](doc/protocan/OAP.md) — правила ведения ОАП; +- [`doc/protocan/examples/test-vectors.json`](doc/protocan/examples/test-vectors.json) — машинные эталоны; +- [`doc/index.html`](doc/index.html) — единая собранная HTML-версия всей документации. Большой файл `Протокол CAN и ОАП.md` и исходный XLSX сохранены как табличное представление реестра. Правила приоритета источников описаны в -[`docs/protocan/README.md`](docs/protocan/README.md). +[`doc/protocan/README.md`](doc/protocan/README.md). ## Формат расширенного CAN ID diff --git a/docs/protocan/build-html.bat b/doc/build-html.bat similarity index 51% rename from docs/protocan/build-html.bat rename to doc/build-html.bat index 52096a9..4891a17 100644 --- a/docs/protocan/build-html.bat +++ b/doc/build-html.bat @@ -5,15 +5,9 @@ set "SCRIPT_DIR=%~dp0" where pwsh.exe >nul 2>nul if %ERRORLEVEL% EQU 0 ( - pwsh.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build-html.ps1" %* + pwsh.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build-html.ps1" ) else ( - powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build-html.ps1" %* + powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build-html.ps1" ) -set "EXIT_CODE=%ERRORLEVEL%" -if not "%EXIT_CODE%"=="0" ( - echo. - echo Ошибка сборки HTML. Код: %EXIT_CODE% -) - -exit /b %EXIT_CODE% +exit /b %ERRORLEVEL% diff --git a/doc/build-html.ps1 b/doc/build-html.ps1 new file mode 100644 index 0000000..09f898a --- /dev/null +++ b/doc/build-html.ps1 @@ -0,0 +1,87 @@ +[CmdletBinding()] +param() + +$ErrorActionPreference = 'Stop' +$outputPath = Join-Path $PSScriptRoot 'index.html' +$sourceDirectory = Join-Path $PSScriptRoot 'protocan' +$documents = @( + 'README.md', + 'PROTOCOL.md', + 'BOOTLOADER.md', + 'OAP.md', + 'CHANGELOG.md' +) + +function Convert-LocalLinks { + param( + [string]$Html, + [string]$SourcePath + ) + + $sourceParent = Split-Path -Parent $SourcePath + $outputParent = Split-Path -Parent $outputPath + $pattern = '(?href|src)="(?(?![a-z]+:|/|#)[^"]+)"' + + return [regex]::Replace($Html, $pattern, { + param($match) + + $target = $match.Groups['target'].Value + $parts = $target -split '#', 2 + $targetPath = [Uri]::UnescapeDataString($parts[0]) + $absoluteTarget = [System.IO.Path]::GetFullPath((Join-Path $sourceParent $targetPath)) + $relativeTarget = [System.IO.Path]::GetRelativePath($outputParent, $absoluteTarget).Replace('\', '/') + if ($parts.Count -eq 2) { + $relativeTarget += '#' + $parts[1] + } + + return $match.Groups['attribute'].Value + '="' + $relativeTarget + '"' + }) +} + +$sections = foreach ($document in $documents) { + $path = Join-Path $sourceDirectory $document + $markdown = Get-Content -Raw -LiteralPath $path -Encoding UTF8 + $html = (ConvertFrom-Markdown -InputObject $markdown).Html + $html = Convert-LocalLinks -Html $html -SourcePath $path + "
$html
" +} + +$vectorsPath = Join-Path $sourceDirectory 'examples\test-vectors.json' +$vectors = [System.Net.WebUtility]::HtmlEncode( + (Get-Content -Raw -LiteralPath $vectorsPath -Encoding UTF8) +) +$sections += @" +
+

Тестовые векторы

+

Машинные эталоны из examples/test-vectors.json.

+
$vectors
+
+"@ + +$generatedBlock = @" + +
+

Полная документация ProtoCAN

+

Нормативные документы и тестовые векторы собраны в эту страницу из исходников doc/protocan.

+
+$($sections -join "`n") +
+
+ +"@ + +$page = Get-Content -Raw -LiteralPath $outputPath -Encoding UTF8 +$pattern = '(?s).*?' +if ($page -notmatch $pattern) { + throw 'Не найдены маркеры PROTOCAN:START/END в doc/index.html.' +} + +$page = [regex]::Replace($page, $pattern, [System.Text.RegularExpressions.MatchEvaluator]{ + param($match) + $generatedBlock +}, 1) + +$page = $page.TrimEnd("`r", "`n") + [Environment]::NewLine +$utf8WithoutBom = [System.Text.UTF8Encoding]::new($false) +[System.IO.File]::WriteAllText($outputPath, $page, $utf8WithoutBom) +Write-Host "[DONE] Создан единый HTML: $outputPath" diff --git a/doc/index.html b/doc/index.html index e827ec3..319163a 100644 --- a/doc/index.html +++ b/doc/index.html @@ -72,9 +72,28 @@ .docs { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; } .doclink { display: inline-flex; align-items: center; gap: 8px; padding: 9px 12px; border: 1px solid var(--line); border-radius: 9px; background: var(--panel); } .doclink:hover { border-color: var(--cyan); text-decoration: none; } + #protocan-full { margin-top: 64px; scroll-margin-top: 82px; } + #protocan-full > .lead { margin-bottom: 24px; } + .protocan-grid { display: block; } + .protocan-document { width: 100%; margin-top: 16px; padding: clamp(20px, 4vw, 42px); overflow: hidden; } + .protocan-document:first-child { margin-top: 0; } + .protocan-document h1 { max-width: none; margin: 0 0 20px; font-size: clamp(30px, 4vw, 44px); line-height: 1.08; letter-spacing: -.035em; } + .protocan-document h2 { margin: 36px 0 12px; font-size: clamp(24px, 3vw, 32px); line-height: 1.15; } + .protocan-document h3 { margin: 26px 0 10px; font-size: 20px; } + .protocan-document h1 + p, + .protocan-document h2 + p, + .protocan-document h3 + p { margin-top: 0; } + .protocan-document p { max-width: 88ch; } + .protocan-document table { display: block; width: 100%; min-width: 0; margin: 16px 0 26px; overflow-x: auto; } + .protocan-document thead, + .protocan-document tbody { min-width: 720px; } + .protocan-document th, + .protocan-document td { min-width: 130px; } + .protocan-document pre { max-width: 100%; padding-top: 18px; } + .protocan-document hr { margin: 34px 0; border: 0; border-top: 1px solid var(--line); } footer { margin-top: 42px; padding-top: 20px; border-top: 1px solid var(--line); color: var(--muted); font-size: 13px; } @media (max-width: 850px) { .card, .card.wide { grid-column: 1 / -1; } .flow { grid-template-columns: 1fr 1fr; } } - @media (max-width: 520px) { .shell { width: min(100% - 20px, 1180px); padding-top: 20px; } .hero { padding-top: 22px; } .flow { grid-template-columns: 1fr; } .tabs-wrap { margin-bottom: 18px; } } + @media (max-width: 520px) { .shell { width: min(100% - 20px, 1180px); padding-top: 20px; } .hero { padding-top: 22px; } .flow { grid-template-columns: 1fr; } .tabs-wrap { margin-bottom: 18px; } .protocan-document { padding: 18px 14px; } } @media (prefers-reduced-motion: reduce) { * { scroll-behavior: auto !important; animation: none !important; } } @@ -106,7 +125,7 @@
Структура

Минимальное ядро + нормативные документы

SETCAN/ ├── Inc/protocan.h публичные типы, настройки и API ├── Src/protocan.c фильтры, RX-очередь, разбор и отправка -├── docs/protocan/ спецификация протокола +├── doc/protocan/ спецификация протокола │ ├── PROTOCOL.md 29-битный ID и типы сообщений │ ├── OAP.md общее адресное пространство │ ├── BOOTLOADER.md обновление прошивки по CAN (draft) @@ -270,11 +289,877 @@ if (PROTOCAN_SEND(id, tx) != PROTOCAN_OK) { }
-
Сформировано по исходникам и документации SETCAN. Нормативный приоритет сохраняют PROTOCOL.md, BOOTLOADER.md и реестр ОАП.
+ +
+

Полная документация ProtoCAN

+

Нормативные документы и тестовые векторы собраны в эту страницу из исходников doc/protocan.

+
+

Документация ProtoCAN

+

Статус комплекта: Draft
+Версия комплекта: 1.0
+Дата редакции: 2026-08-29
+Транспорт: Classic CAN 2.0B, Extended ID, DLC 0…8

+

Этот каталог разделяет нормативное описание протокола, загрузчик и реестр +общего адресного пространства. Большой исходный документ +Протокол CAN и ОАП.md сохранён как +совместимое представление таблиц из Excel.

+

Документы

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ДокументНазначениеСтатус источника
PROTOCOL.md29-битный CAN ID, адресация, реестр MsgType, порядок байтовнормативный
BOOTLOADER.mdобновление прошивки, кадры, состояния, ошибки и A/B-слотынормативный draft
OAP.mdправила ведения общего адресного пространстванормативный индекс
../../Протокол CAN и ОАП.xlsxредактируемый реестр ОАПисточник таблиц
examples/test-vectors.jsonмашинные эталоны CAN ID и payloadнормативные примеры
CHANGELOG.mdистория версий документанормативный
+

Приоритет источников

+

При расхождении данных действует следующий порядок:

+
    +
  1. PROTOCOL.md — структура ProtoCAN и реестр типов сообщений.
  2. +
  3. BOOTLOADER.md — загрузочный сервис 0x9…0xD.
  4. +
  5. XLSX — адреса и свойства регистров ОАП.
  6. +
  7. Сгенерированный ../index.html — только представление, не самостоятельный источник.
  8. +
+

Сборка HTML

+

Из корня проекта:

+
./doc/build-html.bat
+
+

Все документы и тестовые векторы включаются в единый файл doc/index.html. +Скрипт не изменяет исходные Markdown/XLSX и пригоден для запуска в CI.

+
+

ProtoCAN — базовый протокол

+

Статус: Stable с зарезервированным загрузочным расширением
+Версия: 1.0
+Порядок байтов payload: little-endian, если явно не указано иное

+

Назначение

+

ProtoCAN — прикладной протокол поверх classic CAN 2.0B. Используются только +расширенные 29-битные идентификаторы (IDE=1) и payload длиной 0…8 байт.

+

Термины

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ТерминЗначение
ПМуправляющий модуль
приборадресуемый узел на шине
DeviceTypeтип прибора, 0…7
DeviceIDэкземпляр прибора данного типа, 0…15
MsgTypeкласс сообщения или сервис
MsgBody16-битное поле, формат которого зависит от MsgType
+

Пара DeviceType/DeviceID задаёт до 8 × 16 = 128 уникальных адресов.

+

Расширенный CAN ID

+
28       27       26...24      23...20     19...16     15........0
+Priority Route    DeviceType   DeviceID    MsgType     MsgBody
+ 1 бит    1 бит      3 бита      4 бита      4 бита      16 бит
+
+
can_id =
+    ((uint32_t)priority    << 28) |
+    ((uint32_t)route       << 27) |
+    ((uint32_t)device_type << 24) |
+    ((uint32_t)device_id   << 20) |
+    ((uint32_t)msg_type    << 16) |
+    msg_body;
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ПолеЗначенияНазначение
Priority0 critical, 1 standardCAN-арбитраж
Route0 от ПМ, 1 от приборалогическое направление
DeviceType0…7тип прибора
DeviceID0…15номер экземпляра
MsgType0…15тип сообщения
MsgBody0…65535команда, адрес или номер блока
+

Route не является направлением физического трансивера. Ответ прибора +сохраняет адрес DeviceType/DeviceID и устанавливает Route=1.

+

Реестр MsgType

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодИмяОсновное направлениеDLCСтатус
0x0BROADCASTПМ → всезависит от командыstable
0x1DISCRETEоба0…8stable
0x2ANALOGоба0…8stable
0x3GASоба0/2/4/6/8stable
0x4MODBUS_COILоба0…8stable
0x5MODBUS_DISCRETEоба0…8stable
0x6MODBUS_HOLDINGоба0…8stable
0x7MODBUS_INPUTоба0…8stable
0x8ERRORприбор → ПМ0stable
0x9BOOT_CONTROLПМ → прибор0/8draft
0xABOOT_DATA_AПМ → прибор8draft
0xBBOOT_DATA_BПМ → прибор8draft
0xCBOOT_STATUSприбор → ПМ8draft
0xDBOOT_DISCOVERYприбор → ПМ8draft
0xESETTINGSоба0/1/8stable
0xFPULSEприбор → сеть1stable
+

Подробный формат 0x9…0xD находится в BOOTLOADER.md.

+

Разметки MsgBody

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgTypeБиты MsgBody
broadcastкоманда [15:4], параметр [3:0]
discrete/analogподтип [15:12], значение/адрес [11:0]
Modbusначальный адрес [15:4], количество [3:0]
GASадрес первого 16-битного регистра [15:0]
errorдополнительная информация [15:8], код [7:0]
settingsномер сборки [15:8], позиция [7:0]
boot control/statusSessionID[15:8], команда [7:0]
boot dataBlockIndex[15:0]
+

Общие правила обмена

+
    +
  • Многобайтовые значения в DATA передаются little-endian.
  • +
  • Узел игнорирует адресованные кадры с чужим DeviceType/DeviceID.
  • +
  • Прибор принимает команды ПМ с Route=0; ПМ принимает ответы с Route=1.
  • +
  • Стандартные 11-битные CAN ID не являются кадрами ProtoCAN.
  • +
  • RTR для загрузочного сервиса запрещён.
  • +
  • Неописанные комбинации MsgType/MsgBody/DLC должны отвергаться.
  • +
+

Эталон упаковки ID

+
Priority   = 1
+Route      = 0
+DeviceType = 3
+DeviceID   = 5
+MsgType    = 0x9
+MsgBody    = 0x0702
+
+CAN ID = 0x13590702
+
+

Этот пример соответствует ENTER_BOOT, SessionID=7. Машинные варианты +находятся в examples/test-vectors.json.

+
+

ProtoCAN Boot Protocol

+

Статус: Draft
+Версия протокола: 1.0
+Совместимость: classic CAN 2.0B, Extended ID, DLC 0…8
+Реализация: templates/c/protocan-boot

+

Назначение

+

Сервис обновляет адресованный прибор по CAN и поддерживает два логических +слота A/B. Активный слот не стирается: новый образ записывается в неактивный, +проверяется и атомарно назначается кандидатом на запуск.

+

Карта сообщений

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MsgTypeИмяMsgBodyPayload
0x9BOOT_CONTROLSessionID[15:8] \| Command[7:0]параметры команды
0xABOOT_DATA_ABlockIndex[15:0]8 байт слота A
0xBBOOT_DATA_BBlockIndex[15:0]8 байт слота B
0xCBOOT_STATUSSessionID[15:8] \| Command[7:0]статус и прогресс
0xDBOOT_DISCOVERYподтип ответаидентификация
+

Все команды записи адресуются конкретному DeviceType/DeviceID и имеют +Route=0. Ответы сохраняют адрес прибора и имеют Route=1.

+

Адресация образа

+

MsgBody кадра данных — номер 8-байтового блока:

+
offset = (uint32_t)BlockIndex * 8U;
+address = SLOT_X_BASE + offset;
+
+
512 КиБ = 524 288 байт
+524 288 / 8 = 65 536 блоков
+BlockIndex = 0x0000…0xFFFF
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
BlockIndexСмещениеДиапазон байтов
0x00000x000000x00000…0x00007
0x00010x000080x00008…0x0000F
0xFFFF0x7FFF80x7FFF8…0x7FFFF
+

0x80000 является первой позицией за границей слота. Последний кадр +дополняется 0xFF, но CRC32 вычисляется только по ImageSize байтам.

+

Команды BOOT_CONTROL

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодКомандаDLCPayloadДопустимое состояние
0x01IDENTIFY0отсутствуетлюбое
0x02ENTER_BOOT0отсутствуетлюбое; SessionID != 0
0x03BEGIN_IMAGE8размер и CRC32metadata
0x04BEGIN_COMPAT8совместимость и версияmetadata
0x05ERASE0отсутствуетready-to-erase
0x06VERIFY0отсутствуетобраз получен
0x07COMMIT0отсутствуетverified
0x08CONFIRM0отсутствуетзапущенное приложение
0x09REBOOT0отсутствуетактивная сессия
0x0AABORT0отсутствуетактивная сессия
0x0BQUERY_PROGRESS0отсутствуетактивная сессия
+

BEGIN_IMAGE

+
DATA[0..3] ImageSize, uint32 little-endian
+DATA[4..7] ImageCRC32, uint32 little-endian
+
+

BEGIN_COMPAT

+
DATA[0..1] ProductType, uint16 little-endian
+DATA[2]    HardwareRevisionMin
+DATA[3]    HardwareRevisionMax
+DATA[4..7] FirmwareVersion, uint32 little-endian
+
+

До ERASE прибор обязан получить обе части метаданных и проверить размер, +тип изделия, аппаратную ревизию, версию и политику anti-rollback.

+

BOOT_STATUS

+
MsgBody[15..8] SessionID
+MsgBody[7..0]  команда, на которую дан ответ
+
+DATA[0]        Status
+DATA[1]        TargetSlot: 0=A, 1=B, 0xFF=не выбран
+DATA[2..3]     NextBlock, uint16 little-endian
+DATA[4..7]     RunningCRC32, uint32 little-endian
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
КодСтатусПовтор допустим
0x00OK—
0x01BUSYда, после задержки
0x02INVALID_COMMANDпосле исправления
0x03WRONG_DEVICEнет для этого образа
0x04WRONG_HARDWAREнет для этого образа
0x05INVALID_SIZEнет для этого образа
0x06CRC_ERRORновая передача
0x07FLASH_ERRORзависит от платформы
0x08SEQUENCE_ERRORда, с NextBlock
0x09SIGNATURE_ERRORнет
0x0ASESSION_ERRORоткрыть новую сессию
0x0BVOLTAGE_ERRORда после нормализации питания
0x0CINVALID_STATEвыполнить правильный переход
+

State machine

+
IDLE
+  └─ ENTER_BOOT ─> METADATA
+                     ├─ BEGIN_IMAGE
+                     └─ BEGIN_COMPAT
+                            │
+                            v
+                    READY_TO_ERASE
+                            │ ERASE
+                            v
+                      RECEIVING
+                            │ VERIFY
+                            v
+                       VERIFIED
+                            │ COMMIT
+                            v
+                    PENDING + REBOOT
+                            │ CONFIRM
+                            v
+                       CONFIRMED
+
+

Ошибка Flash, CRC, совместимости или подписи переводит сессию в FAILED. +Новая ENTER_BOOT создаёт чистую сессию. ABORT прекращает текущую передачу, +не активируя частично записанный слот.

+

Надёжность и повторы

+
    +
  • Блоки передаются строго по возрастанию BlockIndex.
  • +
  • Дубликат или пропуск возвращает SEQUENCE_ERROR и ожидаемый NextBlock.
  • +
  • Базовый режим подтверждает каждый блок.
  • +
  • Рабочий режим может подтверждать окно из 16 блоков.
  • +
  • После потери связи QUERY_PROGRESS возвращает следующий ожидаемый блок, +пока состояние загрузчика сохранено.
  • +
  • Для продолжения после перезагрузки порт должен сохранять session metadata +и восстановить её при инициализации; ядро версии 1.0 само это не делает.
  • +
+

Безопасность и A/B-обновление

+
active=A -> target=B -> verify -> pending=B
+active=B -> target=A -> verify -> pending=A
+
+

CRC32 защищает только от случайного повреждения. Серийный загрузчик должен +дополнительно проверить подпись контейнера, границы вектора, совместимость и +anti-rollback. Bootloader не обновляется командами BOOT_DATA_A/B.

+

Boot metadata должна атомарно хранить:

+
    +
  • активный слот;
  • +
  • pending-слот;
  • +
  • подтверждение запуска;
  • +
  • число неудачных попыток;
  • +
  • версию и CRC32 образа.
  • +
+

Если приложение не выполняет CONFIRM за установленное число запусков, +загрузчик возвращается к предыдущему подтверждённому слоту.

+

Эталонный сценарий

+
    +
  1. ПМ адресно отправляет IDENTIFY.
  2. +
  3. ПМ открывает ненулевой SessionID командой ENTER_BOOT.
  4. +
  5. ПМ отправляет BEGIN_IMAGE и BEGIN_COMPAT.
  6. +
  7. Прибор сообщает выбранный неактивный слот.
  8. +
  9. ПМ выполняет ERASE и передаёт BOOT_DATA_A либо BOOT_DATA_B.
  10. +
  11. ПМ выполняет VERIFY, затем COMMIT и REBOOT.
  12. +
  13. Новое приложение после самопроверки выполняет CONFIRM.
  14. +
+
+

Общее адресное пространство

+

Статус: Stable, данные ведутся в XLSX
+Порядок значений: 16-битные регистры, little-endian в CAN payload

+

Редактируемый источник реестра: +Протокол CAN и ОАП.xlsx.

+

Просматриваемая большая таблица находится в +Протокол CAN и ОАП.html и +Протокол CAN и ОАП.md.

+

Назначение

+

ОАП связывает 16-битный адрес регистра с его типом, назначением, доступом и +масштабом. В ProtoCAN используется MsgType=0x3, а MsgBody содержит адрес +первого регистра.

+

Обязательные поля реестра

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ПолеТребование
AddressHex0x0000…0xFFFF, уникальное значение
AddressDecдесятичный эквивалент AddressHex
Groupфункциональная группа
Nameоднозначное имя параметра
Typeu16, i16, u32, i32, float32, bitmap или массив
Registersчисло занятых 16-битных регистров
AccessR, W или RW
Unitфизическая единица либо —
Scaleмножитель/делитель представления
Defaultзначение после сброса, если применимо
Descriptionсемантика, диапазон и особые значения
+

Правила ведения

+
    +
  • Адрес не переиспользуется с другим смыслом после выпуска стабильной версии.
  • +
  • Многорегистровое значение занимает непрерывный диапазон.
  • +
  • Порядок 16-битных слов для 32-битного значения фиксируется в строке типа.
  • +
  • Резервные диапазоны явно отмечаются и не используются без изменения версии.
  • +
  • Удалённый параметр помечается deprecated, а не исчезает молча.
  • +
  • Изменение адреса, типа или масштаба отражается в CHANGELOG.md.
  • +
+

Экспорт

+

Для программной генерации каталог следует экспортировать из XLSX в CSV с +UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на:

+
    +
  • уникальность адресов;
  • +
  • пересечение многорегистровых значений;
  • +
  • допустимые типы и права доступа;
  • +
  • равенство шестнадцатеричного и десятичного адреса;
  • +
  • попадание адреса в диапазон 0x0000…0xFFFF.
  • +
+

До появления автоматического экспортёра нормативным источником адресов +остаётся XLSX, а HTML/Markdown считаются представлением.

+
+

История изменений ProtoCAN

+

Формат основан на Keep a Changelog. Версия относится к спецификации, а не к +версии прошивки отдельного прибора.

+

[Unreleased]

+

Added

+
    +
  • Структурированный комплект документации doc/protocan.
  • +
  • Загрузочный сервис MsgType=0x9…0xD.
  • +
  • Два логических слота по 512 КиБ, 65 536 блоков по 8 байт каждый.
  • +
  • Машинные эталоны CAN ID в examples/test-vectors.json.
  • +
+

[1.0] — 2026-08-29

+

Added

+
    +
  • Зафиксирована 29-битная структура ProtoCAN ID.
  • +
  • Зафиксирована адресация 8 типов по 16 экземпляров.
  • +
  • Существующие сообщения 0x0…0x8, 0xE, 0xF сохранены.
  • +
+
+
+

Тестовые векторы

+

Машинные эталоны из examples/test-vectors.json.

+
{
+  "schema_version": 1,
+  "byte_order": "little-endian",
+  "frames": [
+    {
+      "name": "enter_boot_session_7",
+      "direction": "pm_to_device",
+      "priority": 1,
+      "route": 0,
+      "device_type": 3,
+      "device_id": 5,
+      "msg_type": 9,
+      "msg_body": 1794,
+      "can_id_hex": "0x13590702",
+      "dlc": 0,
+      "data_hex": ""
+    },
+    {
+      "name": "slot_b_block_1",
+      "direction": "pm_to_device",
+      "priority": 1,
+      "route": 0,
+      "device_type": 3,
+      "device_id": 5,
+      "msg_type": 11,
+      "msg_body": 1,
+      "can_id_hex": "0x135B0001",
+      "dlc": 8,
+      "data_hex": "1011121314151617"
+    },
+    {
+      "name": "enter_boot_ok",
+      "direction": "device_to_pm",
+      "priority": 1,
+      "route": 1,
+      "device_type": 3,
+      "device_id": 5,
+      "msg_type": 12,
+      "msg_body": 1794,
+      "can_id_hex": "0x1B5C0702",
+      "dlc": 8,
+      "data_hex": "00FF000000000000"
+    }
+  ]
+}
+
+
+
+
+ + +
Сформировано по исходникам и документации SETCAN. Для пересборки запустите doc/build-html.bat. Нормативный приоритет сохраняют PROTOCOL.md, BOOTLOADER.md и реестр ОАП.