Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 33 additions & 37 deletions libs/can/can.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,81 @@
#include <string.h>

void can_frame_init(can_frame_t *f, can_priority_t prio, can_source_t src,
uint8_t type, uint8_t dlc)
{
uint8_t type, uint8_t dlc) {
memset(f, 0, sizeof(*f));
f->id = can_make_id(prio, src, type);
f->id = can_make_id(prio, src, type);
f->dlc = (dlc > CAN_MAX_DLC) ? (uint8_t)CAN_MAX_DLC : dlc;
}

void can_put_u16(uint8_t *buf, uint16_t v)
{
void can_put_u16(uint8_t *buf, uint16_t v) {
buf[0] = (uint8_t)(v & 0xFFu);
buf[1] = (uint8_t)(v >> 8);
}

void can_put_i16(uint8_t *buf, int16_t v) { can_put_u16(buf, (uint16_t)v); }

void can_put_u32(uint8_t *buf, uint32_t v)
{
void can_put_u32(uint8_t *buf, uint32_t v) {
buf[0] = (uint8_t)(v & 0xFFu);
buf[1] = (uint8_t)((v >> 8) & 0xFFu);
buf[2] = (uint8_t)((v >> 16) & 0xFFu);
buf[3] = (uint8_t)(v >> 24);
}

uint16_t can_get_u16(const uint8_t *buf)
{
uint16_t can_get_u16(const uint8_t *buf) {
return (uint16_t)((uint16_t)buf[0] | (uint16_t)((uint16_t)buf[1] << 8));
}

int16_t can_get_i16(const uint8_t *buf) { return (int16_t)can_get_u16(buf); }

uint32_t can_get_u32(const uint8_t *buf)
{
return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) |
((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24);
uint32_t can_get_u32(const uint8_t *buf) {
return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24);
}

#define HEARTBEAT_DLC 5u

void can_encode_heartbeat(can_frame_t *f, const can_heartbeat_t *hb)
{
void can_encode_heartbeat(can_frame_t *f, const can_heartbeat_t *hb) {
can_frame_init(f, CAN_PRIO_INFO, hb->source, CAN_MSG_HEARTBEAT, HEARTBEAT_DLC);
f->data[0] = hb->state;
can_put_u32(&f->data[1], hb->uptime_s);
}

bool can_decode_heartbeat(const can_frame_t *f, can_heartbeat_t *out)
{
if (f == NULL || out == NULL) return false;
bool can_decode_heartbeat(const can_frame_t *f, can_heartbeat_t *out) {
if (f == NULL || out == NULL)
return false;

can_source_t src = can_id_source(f->id);
if (can_id_priority(f->id) != CAN_PRIO_INFO) return false;
if (can_id_type(f->id) != CAN_MSG_HEARTBEAT) return false;
if (src == CAN_SRC_GROUND || src == CAN_SRC_BROADCAST) return false;
if (f->dlc < HEARTBEAT_DLC) return false;

out->source = src;
out->state = f->data[0];
if (can_id_priority(f->id) != CAN_PRIO_INFO)
return false;
if (can_id_type(f->id) != CAN_MSG_HEARTBEAT)
return false;
if (src == CAN_SRC_GROUND || src == CAN_SRC_BROADCAST)
return false;
if (f->dlc < HEARTBEAT_DLC)
return false;

out->source = src;
out->state = f->data[0];
out->uptime_s = can_get_u32(&f->data[1]);
return true;
}

typedef struct {
can_priority_t prio;
uint8_t all_type;
uint8_t node_type;
uint8_t all_type;
uint8_t node_type;
} sys_cmd_def_t;

static const sys_cmd_def_t SYS_CMDS[] = {
[CAN_SYS_UNLOCK] = { CAN_PRIO_IMPORTANT, CAN_CMD_UNLOCK_ALL, CAN_CMD_UNLOCK_NODE },
[CAN_SYS_SLEEP] = { CAN_PRIO_IMPORTANT, CAN_CMD_SLEEP_ALL, CAN_CMD_SLEEP_NODE },
[CAN_SYS_RESET] = { CAN_PRIO_CRITICAL, CAN_CMD_RESET_ALL, CAN_CMD_RESET_NODE },
[CAN_SYS_SLEEP] = { CAN_PRIO_IMPORTANT, CAN_CMD_SLEEP_ALL, CAN_CMD_SLEEP_NODE },
[CAN_SYS_RESET] = { CAN_PRIO_CRITICAL, CAN_CMD_RESET_ALL, CAN_CMD_RESET_NODE },
};

#define SYS_CMD_COUNT (sizeof(SYS_CMDS) / sizeof(SYS_CMDS[0]))

bool can_encode_sys_cmd(can_frame_t *f, can_sys_cmd_t cmd, can_source_t target)
{
if (cmd <= CAN_SYS_NONE || (size_t)cmd >= SYS_CMD_COUNT) return false;
bool can_encode_sys_cmd(can_frame_t *f, can_sys_cmd_t cmd, can_source_t target) {
if (cmd <= CAN_SYS_NONE || (size_t)cmd >= SYS_CMD_COUNT)
return false;
const sys_cmd_def_t *d = &SYS_CMDS[cmd];

if (target == CAN_SRC_BROADCAST) {
Expand All @@ -91,18 +88,17 @@ bool can_encode_sys_cmd(can_frame_t *f, can_sys_cmd_t cmd, can_source_t target)
return true;
}

can_sys_cmd_t can_decode_sys_cmd(const can_frame_t *f, can_source_t me)
{
if (f == NULL) return CAN_SYS_NONE;
can_sys_cmd_t can_decode_sys_cmd(const can_frame_t *f, can_source_t me) {
if (f == NULL)
return CAN_SYS_NONE;

for (size_t i = 1; i < SYS_CMD_COUNT; i++) {
const sys_cmd_def_t *d = &SYS_CMDS[i];

if (f->id == can_make_id(d->prio, CAN_SRC_BROADCAST, d->all_type)) {
return (can_sys_cmd_t)i;
}
if (f->id == can_make_id(d->prio, CAN_SRC_MASTER, d->node_type) &&
f->dlc >= 1 && f->data[0] == (uint8_t)me) {
if (f->id == can_make_id(d->prio, CAN_SRC_MASTER, d->node_type) && f->dlc >= 1 && f->data[0] == (uint8_t)me) {
return (can_sys_cmd_t)i;
}
}
Expand Down
24 changes: 12 additions & 12 deletions libs/can/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,33 @@ extern "C" {

/** @brief Abstract CAN frame without any driver shit (Standard CAN; not FD)*/
typedef struct {
uint32_t id; /**< 11-bit ID, see can_make_id() */
uint8_t dlc; /**< Payload length, 0-8 */
uint8_t data[CAN_MAX_DLC];
uint32_t id; /**< 11-bit ID, see can_make_id() */
uint8_t dlc; /**< Payload length, 0-8 */
uint8_t data[CAN_MAX_DLC];
} can_frame_t;

/**
* @brief Start a frame: sets the ID and length, zeroes the payload
* @param dlc Payload length; values above 8 are clamped to 8
*/
void can_frame_init(can_frame_t *f, can_priority_t prio, can_source_t src,
uint8_t type, uint8_t dlc);
uint8_t type, uint8_t dlc);

/** @name Utility functions for little endian byte packing */
/**@{*/
void can_put_u16(uint8_t *buf, uint16_t v);
void can_put_i16(uint8_t *buf, int16_t v);
void can_put_u32(uint8_t *buf, uint32_t v);
void can_put_u16(uint8_t *buf, uint16_t v);
void can_put_i16(uint8_t *buf, int16_t v);
void can_put_u32(uint8_t *buf, uint32_t v);
uint16_t can_get_u16(const uint8_t *buf);
int16_t can_get_i16(const uint8_t *buf);
int16_t can_get_i16(const uint8_t *buf);
uint32_t can_get_u32(const uint8_t *buf);
/**@}*/

/** @brief Heartbeat contents, Payload: [state u8][uptime_s u32] = 5 bytes. */
typedef struct {
can_source_t source; /**< Which node sent it (from the ID) */
uint8_t state; /**< Sender's fsm_state_t, as a byte */
uint32_t uptime_s; /**< Seconds since boot, if this is lower than the prior log it means the node rebooted! */
can_source_t source; /**< Which node sent it (from the ID) */
uint8_t state; /**< Sender's fsm_state_t, as a byte */
uint32_t uptime_s; /**< Seconds since boot, if this is lower than the prior log it means the node rebooted! */
} can_heartbeat_t;

/** @brief Build a heartbeat frame (INFO priority, type 0x00) */
Expand All @@ -55,7 +55,7 @@ void can_encode_heartbeat(can_frame_t *f, const can_heartbeat_t *hb);
/**
* @brief Decode a heartbeat
* @return false if the frame is not a well-formed heartbeat (wrong priority,
* wrong type, command-only source, or too short, etc
* wrong type, command-only source, or too short, etc
* @p out is usuallyuntouched
*/
bool can_decode_heartbeat(const can_frame_t *f, can_heartbeat_t *out);
Expand Down
19 changes: 10 additions & 9 deletions libs/can/can_eps.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@

#define STATUS_DLC 6u

void can_encode_eps_status(can_frame_t *f, const can_eps_status_t *s)
{
void can_encode_eps_status(can_frame_t *f, const can_eps_status_t *s) {
can_frame_init(f, CAN_PRIO_INFO, CAN_SRC_EPS, CAN_EPS_STATUS, STATUS_DLC);
can_put_i16(&f->data[0], s->current_ma);
can_put_i16(&f->data[2], s->shunt_mv_x100);
can_put_i16(&f->data[4], s->temp_c_x10);
}

bool can_decode_eps_status(const can_frame_t *f, can_eps_status_t *out)
{
if (f == NULL || out == NULL) return false;
if (f->id != can_make_id(CAN_PRIO_INFO, CAN_SRC_EPS, CAN_EPS_STATUS)) return false;
if (f->dlc < STATUS_DLC) return false;
bool can_decode_eps_status(const can_frame_t *f, can_eps_status_t *out) {
if (f == NULL || out == NULL)
return false;
if (f->id != can_make_id(CAN_PRIO_INFO, CAN_SRC_EPS, CAN_EPS_STATUS))
return false;
if (f->dlc < STATUS_DLC)
return false;

out->current_ma = can_get_i16(&f->data[0]);
out->current_ma = can_get_i16(&f->data[0]);
out->shunt_mv_x100 = can_get_i16(&f->data[2]);
out->temp_c_x10 = can_get_i16(&f->data[4]);
out->temp_c_x10 = can_get_i16(&f->data[4]);
return true;
}
Loading