From bb7c94f1b77b926b7663c181d0b4b367675fb585 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 26 Aug 2026 20:13:06 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D1=8B=20SETTINGS=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=B8=D0=B2=D1=8F=D0=B7=D0=BA?= =?UTF-8?q?=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 +}