canbus: Move global variables into a struct

Create a single CanData global variable to track the canbus state.
ARM micro-controllers generally produce better code when global
variables are in a struct.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-06-10 12:51:24 -04:00
parent b9e195f098
commit da755c3c1b
1 changed files with 65 additions and 55 deletions

View File

@ -15,44 +15,56 @@
#include "command.h" // DECL_CONSTANT #include "command.h" // DECL_CONSTANT
#include "sched.h" // sched_wake_task #include "sched.h" // sched_wake_task
static uint32_t canbus_assigned_id; // Global storage
static uint8_t canbus_uuid[CANBUS_UUID_LEN]; static struct canbus_data {
uint32_t assigned_id;
uint8_t uuid[CANBUS_UUID_LEN];
// Tx data
struct task_wake tx_wake;
uint8_t transmit_pos, transmit_max;
// Rx data
struct task_wake rx_wake;
uint8_t receive_pos;
// Transfer buffers
uint8_t transmit_buf[96];
uint8_t receive_buf[192];
} CanData;
/**************************************************************** /****************************************************************
* Data transmission over CAN * Data transmission over CAN
****************************************************************/ ****************************************************************/
static struct task_wake canbus_tx_wake;
static uint8_t transmit_buf[96], transmit_pos, transmit_max;
void void
canbus_notify_tx(void) canbus_notify_tx(void)
{ {
sched_wake_task(&canbus_tx_wake); sched_wake_task(&CanData.tx_wake);
} }
void void
canbus_tx_task(void) canbus_tx_task(void)
{ {
if (!sched_check_wake(&canbus_tx_wake)) if (!sched_check_wake(&CanData.tx_wake))
return; return;
uint32_t id = canbus_assigned_id; uint32_t id = CanData.assigned_id;
if (!id) { if (!id) {
transmit_pos = transmit_max = 0; CanData.transmit_pos = CanData.transmit_max = 0;
return; return;
} }
uint32_t tpos = transmit_pos, tmax = transmit_max; uint32_t tpos = CanData.transmit_pos, tmax = CanData.transmit_max;
for (;;) { for (;;) {
int avail = tmax - tpos, now = avail > 8 ? 8 : avail; int avail = tmax - tpos, now = avail > 8 ? 8 : avail;
if (avail <= 0) if (avail <= 0)
break; break;
int ret = canbus_send(id + 1, now, &transmit_buf[tpos]); int ret = canbus_send(id + 1, now, &CanData.transmit_buf[tpos]);
if (ret <= 0) if (ret <= 0)
break; break;
tpos += now; tpos += now;
} }
transmit_pos = tpos; CanData.transmit_pos = tpos;
} }
DECL_TASK(canbus_tx_task); DECL_TASK(canbus_tx_task);
@ -61,26 +73,27 @@ void
console_sendf(const struct command_encoder *ce, va_list args) console_sendf(const struct command_encoder *ce, va_list args)
{ {
// Verify space for message // Verify space for message
uint32_t tpos = transmit_pos, tmax = transmit_max; uint32_t tpos = CanData.transmit_pos, tmax = CanData.transmit_max;
if (tpos >= tmax) if (tpos >= tmax)
transmit_pos = transmit_max = tpos = tmax = 0; CanData.transmit_pos = CanData.transmit_max = tpos = tmax = 0;
uint32_t max_size = ce->max_size; uint32_t max_size = ce->max_size;
if (tmax + max_size > sizeof(transmit_buf)) { if (tmax + max_size > sizeof(CanData.transmit_buf)) {
if (tmax + max_size - tpos > sizeof(transmit_buf)) if (tmax + max_size - tpos > sizeof(CanData.transmit_buf))
// Not enough space for message // Not enough space for message
return; return;
// Move buffer // Move buffer
tmax -= tpos; tmax -= tpos;
memmove(&transmit_buf[0], &transmit_buf[tpos], tmax); memmove(&CanData.transmit_buf[0], &CanData.transmit_buf[tpos], tmax);
transmit_pos = tpos = 0; CanData.transmit_pos = tpos = 0;
transmit_max = tmax; CanData.transmit_max = tmax;
} }
// Generate message // Generate message
uint32_t msglen = command_encode_and_frame(&transmit_buf[tmax], ce, args); uint32_t msglen = command_encode_and_frame(&CanData.transmit_buf[tmax]
, ce, args);
// Start message transmit // Start message transmit
transmit_max = tmax + msglen; CanData.transmit_max = tmax + msglen;
canbus_notify_tx(); canbus_notify_tx();
} }
@ -99,16 +112,16 @@ console_sendf(const struct command_encoder *ce, va_list args)
static int static int
can_check_uuid(uint32_t id, uint32_t len, uint8_t *data) can_check_uuid(uint32_t id, uint32_t len, uint8_t *data)
{ {
return len >= 7 && memcmp(&data[1], canbus_uuid, sizeof(canbus_uuid)) == 0; return len >= 7 && memcmp(&data[1], CanData.uuid, sizeof(CanData.uuid))==0;
} }
// Helpers to encode/decode a CAN identifier to a 1-byte "nodeid" // Helpers to encode/decode a CAN identifier to a 1-byte "nodeid"
static int static int
can_get_nodeid(void) can_get_nodeid(void)
{ {
if (!canbus_assigned_id) if (!CanData.assigned_id)
return 0; return 0;
return (canbus_assigned_id - 0x100) >> 1; return (CanData.assigned_id - 0x100) >> 1;
} }
static uint32_t static uint32_t
can_decode_nodeid(int nodeid) can_decode_nodeid(int nodeid)
@ -119,11 +132,11 @@ can_decode_nodeid(int nodeid)
static void static void
can_process_query_unassigned(uint32_t id, uint32_t len, uint8_t *data) can_process_query_unassigned(uint32_t id, uint32_t len, uint8_t *data)
{ {
if (canbus_assigned_id) if (CanData.assigned_id)
return; return;
uint8_t send[8]; uint8_t send[8];
send[0] = CANBUS_RESP_NEED_NODEID; send[0] = CANBUS_RESP_NEED_NODEID;
memcpy(&send[1], canbus_uuid, sizeof(canbus_uuid)); memcpy(&send[1], CanData.uuid, sizeof(CanData.uuid));
send[7] = CANBUS_CMD_SET_KLIPPER_NODEID; send[7] = CANBUS_CMD_SET_KLIPPER_NODEID;
// Send with retry // Send with retry
for (;;) { for (;;) {
@ -136,8 +149,8 @@ can_process_query_unassigned(uint32_t id, uint32_t len, uint8_t *data)
static void static void
can_id_conflict(void) can_id_conflict(void)
{ {
canbus_assigned_id = 0; CanData.assigned_id = 0;
canbus_set_filter(canbus_assigned_id); canbus_set_filter(CanData.assigned_id);
shutdown("Another CAN node assigned this ID"); shutdown("Another CAN node assigned this ID");
} }
@ -148,11 +161,11 @@ can_process_set_klipper_nodeid(uint32_t id, uint32_t len, uint8_t *data)
return; return;
uint32_t newid = can_decode_nodeid(data[7]); uint32_t newid = can_decode_nodeid(data[7]);
if (can_check_uuid(id, len, data)) { if (can_check_uuid(id, len, data)) {
if (newid != canbus_assigned_id) { if (newid != CanData.assigned_id) {
canbus_assigned_id = newid; CanData.assigned_id = newid;
canbus_set_filter(canbus_assigned_id); canbus_set_filter(CanData.assigned_id);
} }
} else if (newid == canbus_assigned_id) { } else if (newid == CanData.assigned_id) {
can_id_conflict(); can_id_conflict();
} }
} }
@ -189,28 +202,25 @@ can_process(uint32_t id, uint32_t len, uint8_t *data)
* CAN packet reading * CAN packet reading
****************************************************************/ ****************************************************************/
static struct task_wake canbus_rx_wake;
void void
canbus_notify_rx(void) canbus_notify_rx(void)
{ {
sched_wake_task(&canbus_rx_wake); sched_wake_task(&CanData.rx_wake);
} }
static uint8_t receive_buf[192], receive_pos; DECL_CONSTANT("RECEIVE_WINDOW", ARRAY_SIZE(CanData.receive_buf));
DECL_CONSTANT("RECEIVE_WINDOW", ARRAY_SIZE(receive_buf));
// Handle incoming data (called from IRQ handler) // Handle incoming data (called from IRQ handler)
void void
canbus_process_data(uint32_t id, uint32_t len, uint8_t *data) canbus_process_data(uint32_t id, uint32_t len, uint8_t *data)
{ {
if (!id || id != canbus_assigned_id) if (!id || id != CanData.assigned_id)
return; return;
int rpos = receive_pos; int rpos = CanData.receive_pos;
if (len > sizeof(receive_buf) - rpos) if (len > sizeof(CanData.receive_buf) - rpos)
len = sizeof(receive_buf) - rpos; len = sizeof(CanData.receive_buf) - rpos;
memcpy(&receive_buf[rpos], data, len); memcpy(&CanData.receive_buf[rpos], data, len);
receive_pos = rpos + len; CanData.receive_pos = rpos + len;
canbus_notify_rx(); canbus_notify_rx();
} }
@ -220,21 +230,21 @@ console_pop_input(int len)
{ {
int copied = 0; int copied = 0;
for (;;) { for (;;) {
int rpos = readb(&receive_pos); int rpos = readb(&CanData.receive_pos);
int needcopy = rpos - len; int needcopy = rpos - len;
if (needcopy) { if (needcopy) {
memmove(&receive_buf[copied], &receive_buf[copied + len] memmove(&CanData.receive_buf[copied]
, needcopy - copied); , &CanData.receive_buf[copied + len], needcopy - copied);
copied = needcopy; copied = needcopy;
canbus_notify_rx(); canbus_notify_rx();
} }
irqstatus_t flag = irq_save(); irqstatus_t flag = irq_save();
if (rpos != readb(&receive_pos)) { if (rpos != readb(&CanData.receive_pos)) {
// Raced with irq handler - retry // Raced with irq handler - retry
irq_restore(flag); irq_restore(flag);
continue; continue;
} }
receive_pos = needcopy; CanData.receive_pos = needcopy;
irq_restore(flag); irq_restore(flag);
break; break;
} }
@ -244,7 +254,7 @@ console_pop_input(int len)
void void
canbus_rx_task(void) canbus_rx_task(void)
{ {
if (!sched_check_wake(&canbus_rx_wake)) if (!sched_check_wake(&CanData.rx_wake))
return; return;
// Read any pending CAN packets // Read any pending CAN packets
@ -254,17 +264,17 @@ canbus_rx_task(void)
int ret = canbus_read(&id, data); int ret = canbus_read(&id, data);
if (ret < 0) if (ret < 0)
break; break;
if (id && id == canbus_assigned_id + 1) if (id && id == CanData.assigned_id + 1)
can_id_conflict(); can_id_conflict();
else if (id == CANBUS_ID_ADMIN) else if (id == CANBUS_ID_ADMIN)
can_process(id, ret, data); can_process(id, ret, data);
} }
// Check for a complete message block and process it // Check for a complete message block and process it
uint_fast8_t rpos = readb(&receive_pos), pop_count; uint_fast8_t rpos = readb(&CanData.receive_pos), pop_count;
int ret = command_find_block(receive_buf, rpos, &pop_count); int ret = command_find_block(CanData.receive_buf, rpos, &pop_count);
if (ret > 0) if (ret > 0)
command_dispatch(receive_buf, pop_count); command_dispatch(CanData.receive_buf, pop_count);
if (ret) { if (ret) {
console_pop_input(pop_count); console_pop_input(pop_count);
if (ret > 0) if (ret > 0)
@ -282,14 +292,14 @@ void
command_get_canbus_id(uint32_t *args) command_get_canbus_id(uint32_t *args)
{ {
sendf("canbus_id canbus_uuid=%.*s canbus_nodeid=%u" sendf("canbus_id canbus_uuid=%.*s canbus_nodeid=%u"
, sizeof(canbus_uuid), canbus_uuid, can_get_nodeid()); , sizeof(CanData.uuid), CanData.uuid, can_get_nodeid());
} }
DECL_COMMAND_FLAGS(command_get_canbus_id, HF_IN_SHUTDOWN, "get_canbus_id"); DECL_COMMAND_FLAGS(command_get_canbus_id, HF_IN_SHUTDOWN, "get_canbus_id");
void void
canbus_set_uuid(void *uuid) canbus_set_uuid(void *uuid)
{ {
memcpy(canbus_uuid, uuid, sizeof(canbus_uuid)); memcpy(CanData.uuid, uuid, sizeof(CanData.uuid));
canbus_notify_rx(); canbus_notify_rx();
} }