204 lines
6.1 KiB
C
204 lines
6.1 KiB
C
/**
|
||
* @file can_sensor.c
|
||
* @brief Однокадровый транспорт SETCAN SETTINGS для локаций DS18B20.
|
||
*/
|
||
|
||
#include "can_sensor.h"
|
||
|
||
/** Возвращает 1, если все восемь байтов ROM равны нулю. */
|
||
static uint8_t can_sensor_rom_is_zero(const uint8_t *rom)
|
||
{
|
||
uint8_t index;
|
||
|
||
for (index = 0U; index < CAN_SENSOR_ID_SIZE; index++) {
|
||
if (rom[index] != 0U) {
|
||
return 0U;
|
||
}
|
||
}
|
||
return 1U;
|
||
}
|
||
|
||
/** Передаёт уже собранный кадр с ограниченным числом повторов. */
|
||
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;
|
||
}
|
||
|
||
void CanSensor_ConfigDefault(CanSensor_Config *config)
|
||
{
|
||
if (config == 0) {
|
||
return;
|
||
}
|
||
config->tx_id = CAN_SENSOR_DEFAULT_TX_ID;
|
||
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)
|
||
{
|
||
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.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->sent_messages = 0U;
|
||
link->send_errors = 0U;
|
||
link->received_messages = 0U;
|
||
link->dropped_frames = 0U;
|
||
return 1U;
|
||
}
|
||
|
||
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) || (length > CAN_SENSOR_MAX_DATA)
|
||
|| ((length != 0U) && (data == 0))) {
|
||
return 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_SendId(CanSensor *link, uint8_t position,
|
||
uint8_t assembly_serial, const uint8_t *id)
|
||
{
|
||
CanSensor_Frame frame;
|
||
|
||
if ((link == 0) || (id == 0) || (link->io.send == 0)) {
|
||
return 0U;
|
||
}
|
||
if (CanSensor_BuildFrame(&link->config, &frame, 1U, position,
|
||
assembly_serial, id, CAN_SENSOR_ID_SIZE) == 0U) {
|
||
link->send_errors++;
|
||
return 0U;
|
||
}
|
||
return can_sensor_send_frame(link, &frame);
|
||
}
|
||
|
||
uint8_t CanSensor_SendError(CanSensor *link, uint8_t position,
|
||
uint8_t assembly_serial, uint8_t result)
|
||
{
|
||
CanSensor_Frame frame;
|
||
|
||
if ((link == 0) || (link->io.send == 0) || (result == CAN_SENSOR_RESULT_OK)) {
|
||
return 0U;
|
||
}
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
} 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;
|
||
}
|
||
|
||
link->received_messages++;
|
||
if (out != 0) {
|
||
*out = message;
|
||
}
|
||
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;
|
||
}
|