feat(can-sensor): передача ROM датчиков парой CAN-кадров
Перенесён из KONOR_ds18b20/lib/can. 64-битный идентификатор датчика и преамбула не помещаются в восемь байт поля данных, поэтому сообщение идёт двумя кадрами. Сборку на приёме библиотека делает сама: кадр ROM без преамбулы и кадр неверной длины отбрасываются и учитываются в dropped_frames.
This commit is contained in:
53
c/can-sensor/README.md
Normal file
53
c/can-sensor/README.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# can-sensor
|
||||||
|
|
||||||
|
Передача 64-битных идентификаторов датчиков (ROM 1-Wire) по шине CAN.
|
||||||
|
|
||||||
|
Ядро на C99: не включает заголовки периферии, не обращается к регистрам,
|
||||||
|
не пользуется прерываниями. Обмен идёт через таблицу `CanSensor_Io`,
|
||||||
|
которую заполняет порт платы.
|
||||||
|
|
||||||
|
Сообщение состоит из двух классических CAN-кадров — 64-битный идентификатор
|
||||||
|
и преамбула вместе не помещаются в восемь байтов поля данных:
|
||||||
|
|
||||||
|
```
|
||||||
|
кадр 1 — преамбула, DLC = 2 | команда | позиция |
|
||||||
|
кадр 2 — идентификатор, DLC = 8| ROM 8 байт |
|
||||||
|
```
|
||||||
|
|
||||||
|
## Состав
|
||||||
|
|
||||||
|
| Файл | Что делает | Зависимости |
|
||||||
|
|---|---|---|
|
||||||
|
| `can_sensor.h`, `can_sensor.c` | сборка и разбор пары кадров, повторы передачи, счётчики обмена | `stdint.h` |
|
||||||
|
|
||||||
|
Приём собирает сообщение сам: кадр ROM без преамбулы и кадр с неверной
|
||||||
|
длиной отбрасываются и учитываются в `dropped_frames`.
|
||||||
|
|
||||||
|
## Что нужно от платформы
|
||||||
|
|
||||||
|
```c
|
||||||
|
uint8_t send(void *ctx, const CanSensor_Frame *frame); /* 1 — кадр принят */
|
||||||
|
uint8_t receive(void *ctx, CanSensor_Frame *frame); /* 1 — кадр получен */
|
||||||
|
```
|
||||||
|
|
||||||
|
`receive` необязателен: с нулевым полем узел работает только на передачу.
|
||||||
|
|
||||||
|
## Быстрый старт
|
||||||
|
|
||||||
|
```c
|
||||||
|
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_Init(&link, &io, &config);
|
||||||
|
CanSensor_SendId(&link, position, rom);
|
||||||
|
|
||||||
|
CanSensor_Message message;
|
||||||
|
if (CanSensor_Poll(&link, &message)) { /* принят идентификатор */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Проверено в проектах
|
||||||
|
|
||||||
|
`KONOR_ds18b20` — bxCAN на STM32F103C8T6. Естественная пара — [`ds18b20`](../ds18b20):
|
||||||
|
ROM-коды, найденные `DS18B20_Search()`, уходят в шину как есть.
|
||||||
246
c/can-sensor/can_sensor.c
Normal file
246
c/can-sensor/can_sensor.c
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
/**
|
||||||
|
* @file can_sensor.c
|
||||||
|
* @brief Сборка, передача и разбор сообщений «преамбула + идентификатор».
|
||||||
|
*
|
||||||
|
* Реализация не хранит очередей и не пользуется временем: состояние приёма
|
||||||
|
* ограничено признаком принятой преамбулы, поэтому библиотека одинаково
|
||||||
|
* работает и в главном цикле, и в обработчике прерывания порта.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "can_sensor.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Возвращает идентификатор кадра данных для заданных настроек.
|
||||||
|
*
|
||||||
|
* @param config Настройки узла.
|
||||||
|
* @return Идентификатор кадра ROM при передаче.
|
||||||
|
*/
|
||||||
|
static uint32_t can_sensor_tx_data_id(const CanSensor_Config *config)
|
||||||
|
{
|
||||||
|
if (config->tx_data_id != 0U) {
|
||||||
|
return config->tx_data_id;
|
||||||
|
}
|
||||||
|
return config->tx_id + CAN_SENSOR_DATA_ID_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) {
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanSensor_ConfigDefault(CanSensor_Config *config)
|
||||||
|
{
|
||||||
|
if (config == 0) {
|
||||||
|
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->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;
|
||||||
|
} else {
|
||||||
|
CanSensor_ConfigDefault(&link->config);
|
||||||
|
}
|
||||||
|
if (link->config.tx_id == 0U) {
|
||||||
|
link->config.tx_id = CAN_SENSOR_DEFAULT_TX_ID;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
link->dropped_frames = 0U;
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CanSensor_BuildPreamble(const CanSensor_Config *config, CanSensor_Frame *frame,
|
||||||
|
uint8_t command, uint16_t position)
|
||||||
|
{
|
||||||
|
uint8_t index;
|
||||||
|
|
||||||
|
if ((config == 0) || (frame == 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;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
CanSensor_Frame frame;
|
||||||
|
|
||||||
|
if ((link == 0) || (link->io.send == 0)) {
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
(void)CanSensor_BuildPreamble(&link->config, &frame, command, position);
|
||||||
|
if (can_sensor_send_frame(link, &frame) == 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CanSensor_SendId(CanSensor *link, uint16_t position, const uint8_t *id)
|
||||||
|
{
|
||||||
|
if (id == 0) {
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
return CanSensor_Send(link, CAN_SENSOR_CMD_WRITE_POSITION, position, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CanSensor_HandleFrame(CanSensor *link, const CanSensor_Frame *frame,
|
||||||
|
CanSensor_Message *out)
|
||||||
|
{
|
||||||
|
uint8_t index;
|
||||||
|
|
||||||
|
if ((link == 0) || (frame == 0)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CanSensor_Poll(CanSensor *link, CanSensor_Message *out)
|
||||||
|
{
|
||||||
|
CanSensor_Frame frame;
|
||||||
|
|
||||||
|
if ((link == 0) || (link->io.receive == 0)) {
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
while (link->io.receive(link->io.context, &frame) != 0U) {
|
||||||
|
if (CanSensor_HandleFrame(link, &frame, out) != 0U) {
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
217
c/can-sensor/can_sensor.h
Normal file
217
c/can-sensor/can_sensor.h
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/**
|
||||||
|
* @file can_sensor.h
|
||||||
|
* @brief Портируемая передача идентификаторов датчиков по шине CAN.
|
||||||
|
*
|
||||||
|
* Библиотека не привязана к микроконтроллеру: она не включает заголовки
|
||||||
|
* периферии, не обращается к регистрам и не пользуется прерываниями. Обмен
|
||||||
|
* идёт через таблицу обратных вызовов CanSensor_Io, которую заполняет порт
|
||||||
|
* платы (для этой сборки — @c src/can.c поверх bxCAN STM32F103C8T6).
|
||||||
|
*
|
||||||
|
* Сообщение состоит из двух кадров классического CAN, потому что 64-битный
|
||||||
|
* идентификатор датчика и преамбула вместе не помещаются в восемь байтов
|
||||||
|
* поля данных:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* кадр 1 — преамбула, DLC = 2 +---------+----------+
|
||||||
|
* | команда | позиция |
|
||||||
|
* +---------+----------+
|
||||||
|
* кадр 2 — идентификатор, DLC=8 +----------------------------+
|
||||||
|
* | ROM датчика, байты 0..7 |
|
||||||
|
* +----------------------------+
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* Преамбула несёт команду записи датчика в позицию: первый байт — код
|
||||||
|
* команды (@ref CAN_SENSOR_CMD_WRITE_POSITION), второй — номер позиции в
|
||||||
|
* таблице узла-приёмника. Кадр идентификатора передаётся сразу за преамбулой
|
||||||
|
* и без неё считается недействительным, поэтому приёмник не запишет ROM в
|
||||||
|
* позицию, которая ему не была назначена.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CAN_SENSOR_H
|
||||||
|
#define CAN_SENSOR_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** Длина идентификатора датчика (ROM 1-Wire) в байтах. */
|
||||||
|
#define CAN_SENSOR_ID_SIZE 8U
|
||||||
|
|
||||||
|
/** Длина преамбулы: код команды (1 байт) и номер позиции (2 байта, u16 BE). */
|
||||||
|
#define CAN_SENSOR_PREAMBLE_SIZE 3U
|
||||||
|
|
||||||
|
/** Предельная длина поля данных классического кадра CAN. */
|
||||||
|
#define CAN_SENSOR_MAX_DATA 8U
|
||||||
|
|
||||||
|
/** Код команды «записать идентификатор датчика в позицию». */
|
||||||
|
#define CAN_SENSOR_CMD_WRITE_POSITION 0xA1U
|
||||||
|
|
||||||
|
/** Код команды «очистить позицию»; кадр идентификатора передаётся нулевым. */
|
||||||
|
#define CAN_SENSOR_CMD_CLEAR_POSITION 0xA2U
|
||||||
|
|
||||||
|
/** Смещение идентификатора кадра данных относительно кадра преамбулы. */
|
||||||
|
#define CAN_SENSOR_DATA_ID_OFFSET 1U
|
||||||
|
|
||||||
|
/** Число попыток передачи одного кадра по умолчанию. */
|
||||||
|
#define CAN_SENSOR_DEFAULT_RETRIES 3U
|
||||||
|
|
||||||
|
/** Идентификатор кадра преамбулы по умолчанию (стандартный, 11 бит). */
|
||||||
|
#define CAN_SENSOR_DEFAULT_TX_ID 0x200U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Кадр шины CAN в форме, не зависящей от контроллера.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id; /**< Идентификатор кадра, 11 или 29 бит. */
|
||||||
|
uint8_t extended; /**< 1 — расширенный идентификатор. */
|
||||||
|
uint8_t length; /**< Число значащих байтов поля данных. */
|
||||||
|
uint8_t data[CAN_SENSOR_MAX_DATA]; /**< Поле данных кадра. */
|
||||||
|
} CanSensor_Frame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Принятое или собранное сообщение: преамбула и идентификатор датчика.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t command; /**< Код команды из преамбулы. */
|
||||||
|
uint16_t position; /**< Позиция записи из преамбулы. */
|
||||||
|
uint8_t id[CAN_SENSOR_ID_SIZE]; /**< Идентификатор датчика. */
|
||||||
|
} CanSensor_Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Доступ библиотеки к контроллеру CAN.
|
||||||
|
*
|
||||||
|
* Обязателен только @c send; при нулевом @c receive функция CanSensor_Poll()
|
||||||
|
* ничего не делает и узел работает только на передачу.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Ставит кадр в очередь передачи; 1 — кадр принят контроллером. */
|
||||||
|
uint8_t (*send)(void *context, const CanSensor_Frame *frame);
|
||||||
|
/** Забирает принятый кадр; 1 — кадр получен, 0 — очередь пуста. */
|
||||||
|
uint8_t (*receive)(void *context, CanSensor_Frame *frame);
|
||||||
|
void *context; /**< Контекст порта, передаётся вызовам без изменений. */
|
||||||
|
} CanSensor_Io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Идентификаторы кадров и режим передачи.
|
||||||
|
*
|
||||||
|
* Нулевые поля заменяются значениями по умолчанию вызовом
|
||||||
|
* CanSensor_ConfigDefault() или самой CanSensor_Init().
|
||||||
|
*/
|
||||||
|
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 — значение по умолчанию. */
|
||||||
|
} 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 */
|
||||||
Reference in New Issue
Block a user