/** * @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; }