From 1345766efb57090ce1512e6731b90289280a043e Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 26 Aug 2026 20:47:59 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20can-sensor=20=D0=B4=D0=BB=D1=8F=20SETCAN=20SETTINGS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/can-sensor/README.md | 20 ++-- c/can-sensor/can_sensor.c | 223 ++++++++++++++--------------------- c/can-sensor/can_sensor.h | 240 ++++++++++++-------------------------- 3 files changed, 175 insertions(+), 308 deletions(-) diff --git a/c/can-sensor/README.md b/c/can-sensor/README.md index e218d38..5b0b05b 100644 --- a/c/can-sensor/README.md +++ b/c/can-sensor/README.md @@ -1,27 +1,27 @@ # can-sensor -Передача 64-битных идентификаторов датчиков (ROM 1-Wire) по шине CAN. +Однокадровый транспорт SETCAN SETTINGS для привязки 64-битного ROM 1-Wire к +локации «номер сборки + позиция» по шине CAN. Ядро на C99: не включает заголовки периферии, не обращается к регистрам, не пользуется прерываниями. Обмен идёт через таблицу `CanSensor_Io`, которую заполняет порт платы. -Сообщение состоит из двух классических CAN-кадров — 64-битный идентификатор -и преамбула вместе не помещаются в восемь байтов поля данных: +Сообщение помещается в один Extended CAN-кадр: локация находится в Body +29-битного ID, а ROM — в восьми байтах payload: ``` - кадр 1 — преамбула, DLC = 2 | команда | позиция | - кадр 2 — идентификатор, DLC = 8| ROM 8 байт | + запрос 0x17FEZZYY: DLC=0 — GET, DLC=8 — WRITE/REPLACE/CLEAR + ответ 0x1FFEZZYY: DLC=8 — текущий ROM, DLC=1 — код ошибки ``` ## Состав | Файл | Что делает | Зависимости | |---|---|---| -| `can_sensor.h`, `can_sensor.c` | сборка и разбор пары кадров, повторы передачи, счётчики обмена | `stdint.h` | +| `can_sensor.h`, `can_sensor.c` | сборка и разбор SETTINGS, повторы передачи, счётчики обмена | `stdint.h` | -Приём собирает сообщение сам: кадр ROM без преамбулы и кадр с неверной -длиной отбрасываются и учитываются в `dropped_frames`. +`ZZ` — номер сборки, `YY` — позиция. Нулевой ROM с DLC=8 очищает локацию. ## Что нужно от платформы @@ -38,10 +38,10 @@ uint8_t receive(void *ctx, CanSensor_Frame *frame); /* 1 — кадр п CanSensor link; CanSensor_Io io = { .send = bxcan_send, .receive = bxcan_receive, .context = &board }; CanSensor_Config config; -CanSensor_ConfigDefault(&config); /* tx_id 0x200, кадр ROM 0x201, 3 попытки */ +CanSensor_ConfigDefault(&config); /* TX 0x1FFE0000, RX 0x17FE0000 */ CanSensor_Init(&link, &io, &config); -CanSensor_SendId(&link, position, rom); +CanSensor_SendId(&link, position, assembly_serial, rom); CanSensor_Message message; if (CanSensor_Poll(&link, &message)) { /* принят идентификатор */ } diff --git a/c/can-sensor/can_sensor.c b/c/can-sensor/can_sensor.c index 348c8e9..e1b6fd4 100644 --- a/c/can-sensor/can_sensor.c +++ b/c/can-sensor/can_sensor.c @@ -1,72 +1,35 @@ /** * @file can_sensor.c - * @brief Сборка, передача и разбор сообщений «преамбула + идентификатор». - * - * Реализация не хранит очередей и не пользуется временем: состояние приёма - * ограничено признаком принятой преамбулы, поэтому библиотека одинаково - * работает и в главном цикле, и в обработчике прерывания порта. + * @brief Однокадровый транспорт SETCAN SETTINGS для локаций DS18B20. */ #include "can_sensor.h" -/** - * @brief Возвращает идентификатор кадра данных для заданных настроек. - * - * @param config Настройки узла. - * @return Идентификатор кадра ROM при передаче. - */ -static uint32_t can_sensor_tx_data_id(const CanSensor_Config *config) +/** Возвращает 1, если все восемь байтов ROM равны нулю. */ +static uint8_t can_sensor_rom_is_zero(const uint8_t *rom) { - if (config->tx_data_id != 0U) { - return config->tx_data_id; + uint8_t index; + + for (index = 0U; index < CAN_SENSOR_ID_SIZE; index++) { + if (rom[index] != 0U) { + return 0U; + } } - return config->tx_id + CAN_SENSOR_DATA_ID_OFFSET; + return 1U; } -/** - * @brief Возвращает ожидаемый идентификатор преамбулы при приёме. - * - * @param config Настройки узла. - * @return Идентификатор кадра преамбулы. - */ -static uint32_t can_sensor_rx_id(const CanSensor_Config *config) -{ - if (config->rx_id != 0U) { - return config->rx_id; - } - return config->tx_id; -} - -/** - * @brief Возвращает ожидаемый идентификатор кадра ROM при приёме. - * - * @param config Настройки узла. - * @return Идентификатор кадра идентификатора датчика. - */ -static uint32_t can_sensor_rx_data_id(const CanSensor_Config *config) -{ - if (config->rx_data_id != 0U) { - return config->rx_data_id; - } - return can_sensor_rx_id(config) + CAN_SENSOR_DATA_ID_OFFSET; -} - -/** - * @brief Передаёт один кадр с повторами при отказе контроллера. - * - * @param link Состояние узла. - * @param frame Передаваемый кадр. - * @return 1, если кадр принят контроллером, иначе 0. - */ +/** Передаёт уже собранный кадр с ограниченным числом повторов. */ static uint8_t can_sensor_send_frame(CanSensor *link, const CanSensor_Frame *frame) { uint8_t attempt; for (attempt = 0U; attempt < link->config.retries; attempt++) { if (link->io.send(link->io.context, frame) != 0U) { + link->sent_messages++; return 1U; } } + link->send_errors++; return 0U; } @@ -76,22 +39,17 @@ void CanSensor_ConfigDefault(CanSensor_Config *config) return; } config->tx_id = CAN_SENSOR_DEFAULT_TX_ID; - config->tx_data_id = CAN_SENSOR_DEFAULT_TX_ID + CAN_SENSOR_DATA_ID_OFFSET; - config->rx_id = CAN_SENSOR_DEFAULT_TX_ID; - config->rx_data_id = CAN_SENSOR_DEFAULT_TX_ID + CAN_SENSOR_DATA_ID_OFFSET; - config->extended = 0U; + config->rx_id = CAN_SENSOR_DEFAULT_RX_ID; + config->extended = 1U; config->retries = CAN_SENSOR_DEFAULT_RETRIES; } uint8_t CanSensor_Init(CanSensor *link, const CanSensor_Io *io, const CanSensor_Config *config) { - uint8_t index; - if ((link == 0) || (io == 0) || (io->send == 0)) { return 0U; } - link->io = *io; if (config != 0) { link->config = *config; @@ -101,16 +59,15 @@ uint8_t CanSensor_Init(CanSensor *link, const CanSensor_Io *io, if (link->config.tx_id == 0U) { link->config.tx_id = CAN_SENSOR_DEFAULT_TX_ID; } + if (link->config.rx_id == 0U) { + link->config.rx_id = CAN_SENSOR_DEFAULT_RX_ID; + } + link->config.tx_id &= CAN_SENSOR_HEADER_MASK; + link->config.rx_id &= CAN_SENSOR_HEADER_MASK; + link->config.extended = 1U; if (link->config.retries == 0U) { link->config.retries = CAN_SENSOR_DEFAULT_RETRIES; } - - link->rx.command = 0U; - link->rx.position = 0U; - for (index = 0U; index < CAN_SENSOR_ID_SIZE; index++) { - link->rx.id[index] = 0U; - } - link->rx_preamble = 0U; link->sent_messages = 0U; link->send_errors = 0U; link->received_messages = 0U; @@ -118,114 +75,114 @@ uint8_t CanSensor_Init(CanSensor *link, const CanSensor_Io *io, return 1U; } -uint8_t CanSensor_BuildPreamble(const CanSensor_Config *config, CanSensor_Frame *frame, - uint8_t command, uint16_t position) +uint8_t CanSensor_BuildFrame(const CanSensor_Config *config, CanSensor_Frame *frame, + uint8_t response, uint8_t position, + uint8_t assembly_serial, const uint8_t *data, + uint8_t length) { uint8_t index; + uint32_t base; - if ((config == 0) || (frame == 0)) { + if ((config == 0) || (frame == 0) || (length > CAN_SENSOR_MAX_DATA) + || ((length != 0U) && (data == 0))) { return 0U; } - frame->id = config->tx_id; - frame->extended = config->extended; - frame->length = CAN_SENSOR_PREAMBLE_SIZE; - frame->data[0] = command; - /* Позиция занимает два байта в порядке от старшего к младшему. */ - frame->data[1] = (uint8_t)((position >> 8U) & 0xFFU); - frame->data[2] = (uint8_t)(position & 0xFFU); - for (index = CAN_SENSOR_PREAMBLE_SIZE; index < CAN_SENSOR_MAX_DATA; index++) { - frame->data[index] = 0U; + base = (response != 0U) ? config->tx_id : config->rx_id; + frame->id = (base & CAN_SENSOR_HEADER_MASK) + | ((uint32_t)assembly_serial << 8U) | (uint32_t)position; + frame->extended = 1U; + frame->length = length; + for (index = 0U; index < CAN_SENSOR_MAX_DATA; index++) { + frame->data[index] = (index < length) ? data[index] : 0U; } return 1U; } -uint8_t CanSensor_BuildIdFrame(const CanSensor_Config *config, CanSensor_Frame *frame, - const uint8_t *id) -{ - uint8_t index; - - if ((config == 0) || (frame == 0)) { - return 0U; - } - frame->id = can_sensor_tx_data_id(config); - frame->extended = config->extended; - frame->length = CAN_SENSOR_ID_SIZE; - for (index = 0U; index < CAN_SENSOR_ID_SIZE; index++) { - frame->data[index] = (id != 0) ? id[index] : 0U; - } - return 1U; -} - -uint8_t CanSensor_Send(CanSensor *link, uint8_t command, uint16_t position, - const uint8_t *id) +uint8_t CanSensor_SendId(CanSensor *link, uint8_t position, + uint8_t assembly_serial, const uint8_t *id) { CanSensor_Frame frame; - if ((link == 0) || (link->io.send == 0)) { + if ((link == 0) || (id == 0) || (link->io.send == 0)) { return 0U; } - (void)CanSensor_BuildPreamble(&link->config, &frame, command, position); - if (can_sensor_send_frame(link, &frame) == 0U) { + if (CanSensor_BuildFrame(&link->config, &frame, 1U, position, + assembly_serial, id, CAN_SENSOR_ID_SIZE) == 0U) { link->send_errors++; return 0U; } - (void)CanSensor_BuildIdFrame(&link->config, &frame, id); - if (can_sensor_send_frame(link, &frame) == 0U) { - /* Одиночная преамбула приёмником отбрасывается, позиция не изменится. */ - link->send_errors++; - return 0U; - } - link->sent_messages++; - return 1U; + return can_sensor_send_frame(link, &frame); } -uint8_t CanSensor_SendId(CanSensor *link, uint16_t position, const uint8_t *id) +uint8_t CanSensor_SendError(CanSensor *link, uint8_t position, + uint8_t assembly_serial, uint8_t result) { - if (id == 0) { + CanSensor_Frame frame; + + if ((link == 0) || (link->io.send == 0) || (result == CAN_SENSOR_RESULT_OK)) { return 0U; } - return CanSensor_Send(link, CAN_SENSOR_CMD_WRITE_POSITION, position, id); + if (CanSensor_BuildFrame(&link->config, &frame, 1U, position, + assembly_serial, &result, 1U) == 0U) { + link->send_errors++; + return 0U; + } + return can_sensor_send_frame(link, &frame); } uint8_t CanSensor_HandleFrame(CanSensor *link, const CanSensor_Frame *frame, CanSensor_Message *out) { + CanSensor_Message message; + uint32_t header; uint8_t index; if ((link == 0) || (frame == 0)) { return 0U; } + if (frame->extended == 0U) { + return 0U; + } + header = frame->id & CAN_SENSOR_HEADER_MASK; + if (header == (link->config.rx_id & CAN_SENSOR_HEADER_MASK)) { + message.request = 1U; + } else if (header == (link->config.tx_id & CAN_SENSOR_HEADER_MASK)) { + message.request = 0U; + } else { + return 0U; + } - if ((frame->id == can_sensor_rx_id(&link->config)) - && (frame->extended == link->config.extended)) { - if (frame->length < CAN_SENSOR_PREAMBLE_SIZE) { - link->dropped_frames++; - return 0U; + message.assembly_serial = (uint8_t)((frame->id >> 8U) & 0xFFU); + message.position = (uint8_t)(frame->id & 0xFFU); + message.result = CAN_SENSOR_RESULT_OK; + for (index = 0U; index < CAN_SENSOR_ID_SIZE; index++) { + message.id[index] = (index < frame->length) ? frame->data[index] : 0U; + } + + if (message.request != 0U) { + if (frame->length == 0U) { + message.operation = CAN_SENSOR_OPERATION_GET; + } else if (frame->length == CAN_SENSOR_ID_SIZE) { + message.operation = (can_sensor_rom_is_zero(message.id) != 0U) + ? CAN_SENSOR_OPERATION_CLEAR + : CAN_SENSOR_OPERATION_WRITE; + } else { + message.operation = CAN_SENSOR_OPERATION_INVALID; + message.result = CAN_SENSOR_RESULT_INVALID_DLC; } - link->rx.command = frame->data[0]; - link->rx.position = (uint16_t)(((uint16_t)frame->data[1] << 8U) - | frame->data[2]); - link->rx_preamble = 1U; - return 0U; - } - - if ((frame->id != can_sensor_rx_data_id(&link->config)) - || (frame->extended != link->config.extended)) { - return 0U; - } - if ((link->rx_preamble == 0U) || (frame->length < CAN_SENSOR_ID_SIZE)) { - /* Идентификатор без преамбулы не говорит, в какую позицию его писать. */ - link->rx_preamble = 0U; + } else if (frame->length == CAN_SENSOR_ID_SIZE) { + message.operation = CAN_SENSOR_OPERATION_RESPONSE; + } else if (frame->length == 1U) { + message.operation = CAN_SENSOR_OPERATION_ERROR; + message.result = frame->data[0]; + } else { link->dropped_frames++; return 0U; } - for (index = 0U; index < CAN_SENSOR_ID_SIZE; index++) { - link->rx.id[index] = frame->data[index]; - } - link->rx_preamble = 0U; + link->received_messages++; if (out != 0) { - *out = link->rx; + *out = message; } return 1U; } diff --git a/c/can-sensor/can_sensor.h b/c/can-sensor/can_sensor.h index eb10d15..d6a5ebf 100644 --- a/c/can-sensor/can_sensor.h +++ b/c/can-sensor/can_sensor.h @@ -1,30 +1,19 @@ /** * @file can_sensor.h - * @brief Портируемая передача идентификаторов датчиков по шине CAN. + * @brief Портируемый транспорт SETTINGS для привязки DS18B20 к локации. * - * Библиотека не привязана к микроконтроллеру: она не включает заголовки - * периферии, не обращается к регистрам и не пользуется прерываниями. Обмен - * идёт через таблицу обратных вызовов CanSensor_Io, которую заполняет порт - * платы (для этой сборки — @c src/can.c поверх bxCAN STM32F103C8T6). - * - * Сообщение состоит из двух кадров классического CAN, потому что 64-битный - * идентификатор датчика и преамбула вместе не помещаются в восемь байтов - * поля данных: + * Один Extended CAN-кадр содержит полную операцию. Поля локации находятся в + * Body идентификатора SETCAN, а восьмибайтовый ROM — в payload: * * @code - * кадр 1 — преамбула, DLC = 2 +---------+----------+ - * | команда | позиция | - * +---------+----------+ - * кадр 2 — идентификатор, DLC=8 +----------------------------+ - * | ROM датчика, байты 0..7 | - * +----------------------------+ + * Priority=1, DeviceType=0x7, DeviceID=0xF, MsgType=0xE (SETTINGS) + * Body[15:8] = номер сборки, Body[7:0] = позиция * @endcode * - * Преамбула несёт команду записи датчика в позицию: первый байт — код - * команды (@ref CAN_SENSOR_CMD_WRITE_POSITION), второй — номер позиции в - * таблице узла-приёмника. Кадр идентификатора передаётся сразу за преамбулой - * и без неё считается недействительным, поэтому приёмник не запишет ROM в - * позицию, которая ему не была назначена. + * Запрос ПМ использует Route=0 (0x17FEZZYY), ответ прибора — Route=1 + * (0x1FFEZZYY). DLC=0 означает GET, DLC=8 с ненулевым ROM — SET/REPLACE, + * DLC=8 с нулевым ROM — CLEAR. Успешный ответ возвращает текущий ROM с DLC=8, + * ошибка — однобайтовый код с DLC=1. */ #ifndef CAN_SENSOR_H @@ -32,186 +21,107 @@ #include -/** Длина идентификатора датчика (ROM 1-Wire) в байтах. */ -#define CAN_SENSOR_ID_SIZE 8U +/** Длина ROM 1-Wire и максимального payload classic CAN. */ +#define CAN_SENSOR_ID_SIZE 8U +#define CAN_SENSOR_MAX_DATA 8U -/** Длина преамбулы: код команды (1 байт) и номер позиции (2 байта, u16 BE). */ -#define CAN_SENSOR_PREAMBLE_SIZE 3U +/** Назначенный проекту тип сообщения SETCAN SETTINGS. */ +#define CAN_SENSOR_MSGTYPE_SETTINGS 0xEU -/** Предельная длина поля данных классического кадра CAN. */ -#define CAN_SENSOR_MAX_DATA 8U +/** Маска полей SETCAN от Priority до MsgType; Body под маской не находится. */ +#define CAN_SENSOR_HEADER_MASK 0x1FFF0000UL +#define CAN_SENSOR_BODY_MASK 0x0000FFFFUL -/** Код команды «записать идентификатор датчика в позицию». */ -#define CAN_SENSOR_CMD_WRITE_POSITION 0xA1U +/** Базовые ID SETTINGS для выбранных DeviceType=0x7 и DeviceID=0xF. */ +#define CAN_SENSOR_DEFAULT_TX_ID 0x1FFE0000UL +#define CAN_SENSOR_DEFAULT_RX_ID 0x17FE0000UL -/** Код команды «очистить позицию»; кадр идентификатора передаётся нулевым. */ -#define CAN_SENSOR_CMD_CLEAR_POSITION 0xA2U +/** Число попыток помещения кадра в почтовый ящик. */ +#define CAN_SENSOR_DEFAULT_RETRIES 3U -/** Смещение идентификатора кадра данных относительно кадра преамбулы. */ -#define CAN_SENSOR_DATA_ID_OFFSET 1U +/** Операции, полученные из направления, DLC и payload кадра. */ +#define CAN_SENSOR_OPERATION_GET 0U +#define CAN_SENSOR_OPERATION_WRITE 1U +#define CAN_SENSOR_OPERATION_CLEAR 2U +#define CAN_SENSOR_OPERATION_RESPONSE 3U +#define CAN_SENSOR_OPERATION_ERROR 4U +#define CAN_SENSOR_OPERATION_INVALID 5U -/** Число попыток передачи одного кадра по умолчанию. */ -#define CAN_SENSOR_DEFAULT_RETRIES 3U +/** Коды результата SETTINGS, передаваемые ответом с DLC=1. */ +#define CAN_SENSOR_RESULT_OK 0x00U +#define CAN_SENSOR_RESULT_INVALID_DLC 0x01U +#define CAN_SENSOR_RESULT_INVALID_ROM_CRC 0x02U +#define CAN_SENSOR_RESULT_NOT_FOUND 0x03U +#define CAN_SENSOR_RESULT_ALREADY_ASSIGNED 0x04U +#define CAN_SENSOR_RESULT_EEPROM_ERROR 0x05U +#define CAN_SENSOR_RESULT_INVALID_LOCATION 0x06U +#define CAN_SENSOR_RESULT_BUSY 0x07U -/** Идентификатор кадра преамбулы по умолчанию (стандартный, 11 бит). */ -#define CAN_SENSOR_DEFAULT_TX_ID 0x200U - -/** - * @brief Кадр шины CAN в форме, не зависящей от контроллера. - */ +/** Кадр CAN в форме, не зависящей от периферийного контроллера. */ typedef struct { - uint32_t id; /**< Идентификатор кадра, 11 или 29 бит. */ - uint8_t extended; /**< 1 — расширенный идентификатор. */ - uint8_t length; /**< Число значащих байтов поля данных. */ - uint8_t data[CAN_SENSOR_MAX_DATA]; /**< Поле данных кадра. */ + uint32_t id; /**< Расширенный идентификатор, 29 бит. */ + uint8_t extended; /**< Для SETTINGS всегда 1. */ + uint8_t length; /**< DLC, 0..8. */ + uint8_t data[CAN_SENSOR_MAX_DATA]; /**< Payload. */ } CanSensor_Frame; -/** - * @brief Принятое или собранное сообщение: преамбула и идентификатор датчика. - */ +/** Разобранная команда или ответ SETTINGS. */ typedef struct { - uint8_t command; /**< Код команды из преамбулы. */ - uint16_t position; /**< Позиция записи из преамбулы. */ - uint8_t id[CAN_SENSOR_ID_SIZE]; /**< Идентификатор датчика. */ + uint8_t operation; /**< CAN_SENSOR_OPERATION_*. */ + uint8_t request; /**< 1 — запрос Route=0, 0 — ответ Route=1. */ + uint8_t assembly_serial; /**< Body[15:8], номер сборки Z. */ + uint8_t position; /**< Body[7:0], позиция Y. */ + uint8_t result; /**< Код ошибки для ERROR/INVALID. */ + uint8_t id[CAN_SENSOR_ID_SIZE]; /**< ROM для WRITE/RESPONSE, нули для CLEAR. */ } CanSensor_Message; -/** - * @brief Доступ библиотеки к контроллеру CAN. - * - * Обязателен только @c send; при нулевом @c receive функция CanSensor_Poll() - * ничего не делает и узел работает только на передачу. - */ +/** Доступ переносимой части к CAN-контроллеру. */ typedef struct { - /** Ставит кадр в очередь передачи; 1 — кадр принят контроллером. */ uint8_t (*send)(void *context, const CanSensor_Frame *frame); - /** Забирает принятый кадр; 1 — кадр получен, 0 — очередь пуста. */ uint8_t (*receive)(void *context, CanSensor_Frame *frame); - void *context; /**< Контекст порта, передаётся вызовам без изменений. */ + void *context; } CanSensor_Io; -/** - * @brief Идентификаторы кадров и режим передачи. - * - * Нулевые поля заменяются значениями по умолчанию вызовом - * CanSensor_ConfigDefault() или самой CanSensor_Init(). - */ +/** Базовые идентификаторы SETTINGS и режим транспорта. */ typedef struct { - uint32_t tx_id; /**< Идентификатор кадра преамбулы при передаче. */ - uint32_t tx_data_id; /**< Идентификатор кадра ROM; 0 — @c tx_id + 1. */ - uint32_t rx_id; /**< Ожидаемая преамбула при приёме; 0 — @c tx_id. */ - uint32_t rx_data_id; /**< Ожидаемый кадр ROM; 0 — @c rx_id + 1. */ - uint8_t extended; /**< 1 — расширенные идентификаторы 29 бит. */ - uint8_t retries; /**< Попыток передачи кадра; 0 — значение по умолчанию. */ + uint32_t tx_id; /**< База ответа 0x1FFE0000, Body должен быть нулевым. */ + uint32_t rx_id; /**< База запроса 0x17FE0000, Body должен быть нулевым. */ + uint8_t extended; /**< 1 — Extended CAN ID. */ + uint8_t retries; /**< Число попыток передачи. */ } CanSensor_Config; -/** - * @brief Состояние узла: настройки, счётчики и сборка принимаемого сообщения. - */ +/** Состояние транспорта и диагностические счётчики. */ typedef struct { - CanSensor_Io io; /**< Обратные вызовы порта. */ - CanSensor_Config config; /**< Идентификаторы кадров и режим передачи. */ - CanSensor_Message rx; /**< Собираемое сообщение приёма. */ - uint8_t rx_preamble; /**< 1 — преамбула принята, ожидается кадр ROM. */ - uint32_t sent_messages; /**< Полностью переданные сообщения. */ - uint32_t send_errors; /**< Сообщения, не ушедшие в шину. */ - uint32_t received_messages; /**< Полностью принятые сообщения. */ - uint32_t dropped_frames; /**< Кадры без преамбулы или с неверной длиной. */ + CanSensor_Io io; + CanSensor_Config config; + uint32_t sent_messages; + uint32_t send_errors; + uint32_t received_messages; + uint32_t dropped_frames; } CanSensor; -/** - * @brief Заполняет настройки значениями по умолчанию. - * - * Идентификатор преамбулы — @ref CAN_SENSOR_DEFAULT_TX_ID, кадр ROM идёт - * следующим идентификатором, приём настроен на те же значения. - * - * @param config Настройки, принадлежащие вызывающему коду. - */ void CanSensor_ConfigDefault(CanSensor_Config *config); -/** - * @brief Готовит узел к работе. - * - * @param link Состояние узла, принадлежащее вызывающему коду. - * @param io Обратные вызовы порта; копируются внутрь состояния. - * @param config Настройки либо 0 для значений по умолчанию. - * @return 1 при успешной настройке, 0 при неполных аргументах. - */ uint8_t CanSensor_Init(CanSensor *link, const CanSensor_Io *io, const CanSensor_Config *config); -/** - * @brief Собирает кадр преамбулы. - * - * @param config Настройки узла. - * @param frame Кадр приёмника. - * @param command Код команды, например @ref CAN_SENSOR_CMD_WRITE_POSITION. - * @param position Номер позиции записи датчика. - * @return 1 при успешной сборке, иначе 0. - */ -uint8_t CanSensor_BuildPreamble(const CanSensor_Config *config, CanSensor_Frame *frame, - uint8_t command, uint16_t position); +/** Собирает SETTINGS-кадр на базе tx_id или rx_id. */ +uint8_t CanSensor_BuildFrame(const CanSensor_Config *config, CanSensor_Frame *frame, + uint8_t response, uint8_t position, + uint8_t assembly_serial, const uint8_t *data, + uint8_t length); -/** - * @brief Собирает кадр идентификатора датчика. - * - * @param config Настройки узла. - * @param frame Кадр приёмника. - * @param id Идентификатор датчика длиной @ref CAN_SENSOR_ID_SIZE либо 0 для - * нулевого кадра команды очистки. - * @return 1 при успешной сборке, иначе 0. - */ -uint8_t CanSensor_BuildIdFrame(const CanSensor_Config *config, CanSensor_Frame *frame, - const uint8_t *id); +/** Передаёт успешный ответ с текущим ROM (DLC=8). */ +uint8_t CanSensor_SendId(CanSensor *link, uint8_t position, + uint8_t assembly_serial, const uint8_t *id); -/** - * @brief Передаёт преамбулу и идентификатор датчика. - * - * Кадры уходят подряд; при отказе контроллера передача повторяется - * @c retries раз. Если преамбула ушла, а кадр ROM — нет, сообщение считается - * несостоявшимся: приёмник отбросит одиночную преамбулу. - * - * @param link Состояние узла. - * @param command Код команды преамбулы. - * @param position Номер позиции записи датчика. - * @param id Идентификатор датчика либо 0 для команды очистки позиции. - * @return 1, если оба кадра приняты контроллером, иначе 0. - */ -uint8_t CanSensor_Send(CanSensor *link, uint8_t command, uint16_t position, - const uint8_t *id); +/** Передаёт ошибку SETTINGS (DLC=1). */ +uint8_t CanSensor_SendError(CanSensor *link, uint8_t position, + uint8_t assembly_serial, uint8_t result); -/** - * @brief Передаёт команду записи датчика в позицию. - * - * Краткая форма CanSensor_Send() с кодом @ref CAN_SENSOR_CMD_WRITE_POSITION. - * - * @param link Состояние узла. - * @param position Номер позиции записи датчика. - * @param id Идентификатор датчика длиной @ref CAN_SENSOR_ID_SIZE. - * @return 1, если оба кадра приняты контроллером, иначе 0. - */ -uint8_t CanSensor_SendId(CanSensor *link, uint16_t position, const uint8_t *id); - -/** - * @brief Разбирает принятый кадр и собирает из пары кадров сообщение. - * - * Кадр идентификатора без предшествующей преамбулы отбрасывается, а новая - * преамбула заменяет незавершённую: сборка не требует таймера. - * - * @param link Состояние узла. - * @param frame Принятый кадр. - * @param out Приёмник готового сообщения либо 0. - * @return 1, если сообщение собрано полностью, иначе 0. - */ uint8_t CanSensor_HandleFrame(CanSensor *link, const CanSensor_Frame *frame, CanSensor_Message *out); -/** - * @brief Забирает кадры у порта и возвращает первое собранное сообщение. - * - * @param link Состояние узла. - * @param out Приёмник сообщения либо 0. - * @return 1, если сообщение собрано, иначе 0. - */ uint8_t CanSensor_Poll(CanSensor *link, CanSensor_Message *out); #endif /* CAN_SENSOR_H */