Files
templates/c/set-protocol/src/set_can.c

186 lines
6.6 KiB
C

#include "set_can.h"
#include <string.h>
uint32_t setp_can_id_pack(const setp_can_id_t *value)
{
if (value == NULL) {
return 0U;
}
return ((uint32_t)SETP_CAN_ID_PREFIX << 24)
| ((uint32_t)value->destination << 16)
| ((uint32_t)value->source << 8)
| ((uint32_t)(value->priority & 1U) << 7)
| (uint32_t)(value->channel & 0x7FU);
}
bool setp_can_id_unpack(uint32_t raw, setp_can_id_t *out)
{
if ((out == NULL) || ((raw & ~SETP_CAN_ID_MASK) != 0U)
|| ((raw & SETP_CAN_ID_PREFIX_MASK)
!= ((uint32_t)SETP_CAN_ID_PREFIX << 24))) {
return false;
}
out->destination = (uint8_t)(raw >> 16);
out->source = (uint8_t)(raw >> 8);
out->priority = (uint8_t)((raw >> 7) & 1U);
out->channel = (uint8_t)(raw & 0x7FU);
return true;
}
bool setp_can_segment(const uint8_t *packet, uint16_t length, uint32_t can_id,
setp_can_send_fn send, void *user)
{
setp_can_frame_t frame;
uint16_t offset;
uint8_t sequence = 1U;
if ((packet == NULL) || (send == NULL)
|| (length < SETP_HEADER_SIZE + SETP_CRC_SIZE)
|| (length > SETP_FRAME_MAX)
|| ((can_id & ~SETP_CAN_ID_MASK) != 0U)) {
return false;
}
(void)memset(&frame, 0, sizeof(frame));
frame.id = can_id;
frame.length = 8U;
frame.data[0] = SETP_CAN_PCI_FIRST;
setp_put_u16(&frame.data[1], length);
(void)memcpy(&frame.data[3], packet, SETP_CAN_FIRST_DATA);
if (!send(&frame, user)) {
return false;
}
offset = SETP_CAN_FIRST_DATA;
while (offset < length) {
uint16_t remaining = (uint16_t)(length - offset);
uint8_t chunk = remaining > SETP_CAN_CONSECUTIVE_DATA
? SETP_CAN_CONSECUTIVE_DATA : (uint8_t)remaining;
(void)memset(frame.data, 0, sizeof(frame.data));
frame.data[0] = (uint8_t)(SETP_CAN_PCI_CONSECUTIVE
| (sequence & SETP_CAN_PCI_VALUE_MASK));
(void)memcpy(&frame.data[1], &packet[offset], chunk);
frame.length = (uint8_t)(1U + chunk);
if (!send(&frame, user)) {
return false;
}
offset = (uint16_t)(offset + chunk);
sequence = (uint8_t)((sequence + 1U) & SETP_CAN_PCI_VALUE_MASK);
}
return true;
}
void setp_can_rx_init(setp_can_rx_t *state)
{
if (state != NULL) {
(void)memset(state, 0, sizeof(*state));
}
}
static bool setp_can_expired(const setp_can_rx_t *state, uint32_t now_ms)
{
return state->active && ((int32_t)(now_ms - state->deadline_ms) >= 0);
}
setp_can_rx_result_t setp_can_rx_feed(setp_can_rx_t *state,
const setp_can_frame_t *frame,
uint32_t now_ms, setp_can_packet_t *out)
{
uint8_t pci;
if ((state == NULL) || (frame == NULL) || (out == NULL)
|| (frame->length == 0U) || (frame->length > 8U)) {
return SETP_CAN_RX_FORMAT_ERROR;
}
if (setp_can_expired(state, now_ms)) {
state->active = 0U;
return SETP_CAN_RX_TIMEOUT;
}
pci = (uint8_t)(frame->data[0] & SETP_CAN_PCI_TYPE_MASK);
if (pci == SETP_CAN_PCI_FIRST) {
uint16_t total;
if (frame->length != 8U) {
return SETP_CAN_RX_FORMAT_ERROR;
}
total = setp_get_u16(&frame->data[1]);
if ((total < SETP_HEADER_SIZE + SETP_CRC_SIZE) || (total > SETP_FRAME_MAX)) {
return SETP_CAN_RX_FORMAT_ERROR;
}
(void)memcpy(state->buffer, &frame->data[3], SETP_CAN_FIRST_DATA);
state->expected_length = total;
state->received_length = SETP_CAN_FIRST_DATA;
state->can_id = frame->id;
state->deadline_ms = now_ms + SETP_CAN_REASSEMBLY_TIMEOUT_MS;
state->next_sequence = 1U;
state->active = 1U;
return SETP_CAN_RX_NONE;
}
if (pci == SETP_CAN_PCI_CONSECUTIVE) {
uint8_t sequence = (uint8_t)(frame->data[0] & SETP_CAN_PCI_VALUE_MASK);
uint16_t remaining;
uint8_t chunk;
if (!state->active || (frame->id != state->can_id)
|| (sequence != state->next_sequence) || (frame->length < 2U)) {
state->active = 0U;
return SETP_CAN_RX_SEQUENCE_ERROR;
}
remaining = (uint16_t)(state->expected_length - state->received_length);
chunk = (uint8_t)(frame->length - 1U);
if (chunk > remaining) {
state->active = 0U;
return SETP_CAN_RX_FORMAT_ERROR;
}
(void)memcpy(&state->buffer[state->received_length], &frame->data[1], chunk);
state->received_length = (uint16_t)(state->received_length + chunk);
state->next_sequence = (uint8_t)((state->next_sequence + 1U)
& SETP_CAN_PCI_VALUE_MASK);
state->deadline_ms = now_ms + SETP_CAN_REASSEMBLY_TIMEOUT_MS;
if (state->received_length == state->expected_length) {
setp_can_id_t id;
uint16_t source;
uint16_t destination;
uint8_t priority;
if (!setp_can_id_unpack(state->can_id, &id)
|| (state->expected_length < SETP_HEADER_SIZE + SETP_CRC_SIZE)
|| (state->buffer[0] != SETP_SOF0)
|| (state->buffer[1] != SETP_SOF1)) {
state->active = 0U;
return SETP_CAN_RX_FORMAT_ERROR;
}
source = setp_get_u16(&state->buffer[6]);
destination = setp_get_u16(&state->buffer[8]);
priority = (state->buffer[3] & SETP_FLAG_PRIORITY) != 0U ? 1U : 0U;
if ((source != id.source) || (destination != id.destination)
|| (priority != id.priority)) {
state->active = 0U;
return SETP_CAN_RX_FORMAT_ERROR;
}
out->data = state->buffer;
out->length = state->expected_length;
out->can_id = state->can_id;
state->active = 0U;
return SETP_CAN_RX_COMPLETE;
}
return SETP_CAN_RX_NONE;
}
if (pci == SETP_CAN_PCI_FLOW_CONTROL) {
return SETP_CAN_RX_NONE;
}
return SETP_CAN_RX_FORMAT_ERROR;
}
bool setp_can_flow_control(setp_can_frame_t *out, uint32_t can_id,
uint8_t status, uint8_t block_size, uint8_t st_min_ms)
{
if ((out == NULL) || (status > SETP_CAN_FC_OVERFLOW)
|| (st_min_ms > 0x7FU) || ((can_id & ~SETP_CAN_ID_MASK) != 0U)) {
return false;
}
(void)memset(out, 0, sizeof(*out));
out->id = can_id;
out->length = 3U;
out->data[0] = (uint8_t)(SETP_CAN_PCI_FLOW_CONTROL | status);
out->data[1] = block_size;
out->data[2] = st_min_ms;
return true;
}