canbus: Support reading CAN packets directly from IRQ handler
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
d5a3ef6c40
commit
fee84c2afb
|
@ -9,6 +9,8 @@
|
||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
#include "canbus.h" // canbus_set_uuid
|
#include "canbus.h" // canbus_set_uuid
|
||||||
#include "command.h" // DECL_CONSTANT
|
#include "command.h" // DECL_CONSTANT
|
||||||
|
#include "generic/io.h" // readb
|
||||||
|
#include "generic/irq.h" // irq_disable
|
||||||
#include "sched.h" // sched_wake_task
|
#include "sched.h" // sched_wake_task
|
||||||
|
|
||||||
static uint32_t canbus_assigned_id;
|
static uint32_t canbus_assigned_id;
|
||||||
|
@ -183,16 +185,47 @@ canbus_notify_rx(void)
|
||||||
static uint8_t receive_buf[192], receive_pos;
|
static uint8_t receive_buf[192], receive_pos;
|
||||||
DECL_CONSTANT("RECEIVE_WINDOW", ARRAY_SIZE(receive_buf));
|
DECL_CONSTANT("RECEIVE_WINDOW", ARRAY_SIZE(receive_buf));
|
||||||
|
|
||||||
static void
|
// Handle incoming data (called from IRQ handler)
|
||||||
can_process_data(uint32_t id, uint32_t len, uint8_t *data)
|
void
|
||||||
|
canbus_process_data(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
{
|
{
|
||||||
|
if (!id || id != canbus_assigned_id)
|
||||||
|
return;
|
||||||
int rpos = receive_pos;
|
int rpos = receive_pos;
|
||||||
if (len > sizeof(receive_buf) - rpos)
|
if (len > sizeof(receive_buf) - rpos)
|
||||||
len = sizeof(receive_buf) - rpos;
|
len = sizeof(receive_buf) - rpos;
|
||||||
memcpy(&receive_buf[rpos], data, len);
|
memcpy(&receive_buf[rpos], data, len);
|
||||||
receive_pos = rpos + len;
|
receive_pos = rpos + len;
|
||||||
|
canbus_notify_rx();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove from the receive buffer the given number of bytes
|
||||||
|
static void
|
||||||
|
console_pop_input(int len)
|
||||||
|
{
|
||||||
|
int copied = 0;
|
||||||
|
for (;;) {
|
||||||
|
int rpos = readb(&receive_pos);
|
||||||
|
int needcopy = rpos - len;
|
||||||
|
if (needcopy) {
|
||||||
|
memmove(&receive_buf[copied], &receive_buf[copied + len]
|
||||||
|
, needcopy - copied);
|
||||||
|
copied = needcopy;
|
||||||
|
canbus_notify_rx();
|
||||||
|
}
|
||||||
|
irqstatus_t flag = irq_save();
|
||||||
|
if (rpos != readb(&receive_pos)) {
|
||||||
|
// Raced with irq handler - retry
|
||||||
|
irq_restore(flag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
receive_pos = needcopy;
|
||||||
|
irq_restore(flag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task to process incoming commands and admin messages
|
||||||
void
|
void
|
||||||
canbus_rx_task(void)
|
canbus_rx_task(void)
|
||||||
{
|
{
|
||||||
|
@ -206,8 +239,6 @@ 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)
|
|
||||||
can_process_data(id, ret, data);
|
|
||||||
if (id && id == canbus_assigned_id + 1)
|
if (id && id == canbus_assigned_id + 1)
|
||||||
can_id_conflict();
|
can_id_conflict();
|
||||||
else if (id == CANBUS_ID_ADMIN)
|
else if (id == CANBUS_ID_ADMIN)
|
||||||
|
@ -215,18 +246,15 @@ canbus_rx_task(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a complete message block and process it
|
// Check for a complete message block and process it
|
||||||
uint_fast8_t rpos = receive_pos, pop_count;
|
uint_fast8_t rpos = readb(&receive_pos), pop_count;
|
||||||
int ret = command_find_and_dispatch(receive_buf, rpos, &pop_count);
|
int ret = command_find_block(receive_buf, rpos, &pop_count);
|
||||||
|
if (ret > 0)
|
||||||
|
command_dispatch(receive_buf, pop_count);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
// Move buffer
|
console_pop_input(pop_count);
|
||||||
int needcopy = rpos - pop_count;
|
if (ret > 0)
|
||||||
if (needcopy) {
|
command_send_ack();
|
||||||
memmove(receive_buf, &receive_buf[pop_count], needcopy);
|
|
||||||
canbus_notify_rx();
|
|
||||||
}
|
}
|
||||||
rpos = needcopy;
|
|
||||||
}
|
|
||||||
receive_pos = rpos;
|
|
||||||
}
|
}
|
||||||
DECL_TASK(canbus_rx_task);
|
DECL_TASK(canbus_rx_task);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ void canbus_set_filter(uint32_t id);
|
||||||
// canbus.c
|
// canbus.c
|
||||||
void canbus_notify_tx(void);
|
void canbus_notify_tx(void);
|
||||||
void canbus_notify_rx(void);
|
void canbus_notify_rx(void);
|
||||||
|
void canbus_process_data(uint32_t id, uint32_t len, uint8_t *data);
|
||||||
void canbus_set_uuid(void *data);
|
void canbus_set_uuid(void *data);
|
||||||
|
|
||||||
#endif // canbus.h
|
#endif // canbus.h
|
||||||
|
|
|
@ -179,8 +179,8 @@ canbus_set_filter(uint32_t id)
|
||||||
/* 32-bit scale for the filter */
|
/* 32-bit scale for the filter */
|
||||||
SOC_CAN->FS1R = (1<<0) | (1<<1) | (1<<2);
|
SOC_CAN->FS1R = (1<<0) | (1<<1) | (1<<2);
|
||||||
|
|
||||||
/* FIFO 0 assigned for the filter */
|
/* FIFO 1 assigned to 'id' */
|
||||||
SOC_CAN->FFA1R = 0;
|
SOC_CAN->FFA1R = (1<<2);
|
||||||
|
|
||||||
/* Filter activation */
|
/* Filter activation */
|
||||||
SOC_CAN->FA1R = (1<<0) | (id ? (1<<1) | (1<<2) : 0);
|
SOC_CAN->FA1R = (1<<0) | (id ? (1<<1) | (1<<2) : 0);
|
||||||
|
@ -192,9 +192,29 @@ canbus_set_filter(uint32_t id)
|
||||||
void
|
void
|
||||||
CAN_IRQHandler(void)
|
CAN_IRQHandler(void)
|
||||||
{
|
{
|
||||||
|
if (SOC_CAN->RF1R & CAN_RF1R_FMP1) {
|
||||||
|
// Read and ack data packet
|
||||||
|
CAN_FIFOMailBox_TypeDef *mb = &SOC_CAN->sFIFOMailBox[1];
|
||||||
|
uint32_t rir_id = (mb->RIR >> CAN_RI0R_STID_Pos) & 0x7FF;
|
||||||
|
uint32_t dlc = mb->RDTR & CAN_RDT0R_DLC;
|
||||||
|
uint32_t rdlr = mb->RDLR, rdhr = mb->RDHR;
|
||||||
|
SOC_CAN->RF1R = CAN_RF1R_RFOM1;
|
||||||
|
|
||||||
|
// Process packet
|
||||||
|
uint8_t data[8];
|
||||||
|
data[0] = (rdlr >> 0) & 0xff;
|
||||||
|
data[1] = (rdlr >> 8) & 0xff;
|
||||||
|
data[2] = (rdlr >> 16) & 0xff;
|
||||||
|
data[3] = (rdlr >> 24) & 0xff;
|
||||||
|
data[4] = (rdhr >> 0) & 0xff;
|
||||||
|
data[5] = (rdhr >> 8) & 0xff;
|
||||||
|
data[6] = (rdhr >> 16) & 0xff;
|
||||||
|
data[7] = (rdhr >> 24) & 0xff;
|
||||||
|
canbus_process_data(rir_id, dlc, data);
|
||||||
|
}
|
||||||
uint32_t ier = SOC_CAN->IER;
|
uint32_t ier = SOC_CAN->IER;
|
||||||
if (ier & CAN_IER_FMPIE0 && SOC_CAN->RF0R & CAN_RF0R_FMP0) {
|
if (ier & CAN_IER_FMPIE0 && SOC_CAN->RF0R & CAN_RF0R_FMP0) {
|
||||||
// Rx
|
// Admin Rx
|
||||||
SOC_CAN->IER = ier = ier & ~CAN_IER_FMPIE0;
|
SOC_CAN->IER = ier = ier & ~CAN_IER_FMPIE0;
|
||||||
canbus_notify_rx();
|
canbus_notify_rx();
|
||||||
}
|
}
|
||||||
|
@ -292,6 +312,7 @@ can_init(void)
|
||||||
armcm_enable_irq(CAN_IRQHandler, CAN_RX1_IRQn, 0);
|
armcm_enable_irq(CAN_IRQHandler, CAN_RX1_IRQn, 0);
|
||||||
if (CAN_RX0_IRQn != CAN_TX_IRQn)
|
if (CAN_RX0_IRQn != CAN_TX_IRQn)
|
||||||
armcm_enable_irq(CAN_IRQHandler, CAN_TX_IRQn, 0);
|
armcm_enable_irq(CAN_IRQHandler, CAN_TX_IRQn, 0);
|
||||||
|
SOC_CAN->IER = CAN_IER_FMPIE1;
|
||||||
|
|
||||||
// Convert unique 96-bit chip id into 48 bit representation
|
// Convert unique 96-bit chip id into 48 bit representation
|
||||||
uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7);
|
uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7);
|
||||||
|
|
Loading…
Reference in New Issue