canbus: Move high-level CAN code to new src/generic/canbus.c
Separate out the high-level command processing logic from the low-level transmission code. Place the high-level code in src/generic/canbus.c . This also removes the CAN dependency on serial_irq.c . Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
bee544eaca
commit
d9f6abdb56
|
@ -0,0 +1,227 @@
|
||||||
|
// Generic handling of serial over CAN support
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
|
||||||
|
// Copyright (C) 2020 Pontus Borg <glpontus@gmail.com>
|
||||||
|
// Copyright (C) 2021 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
#include "canbus.h" // canbus_set_uuid
|
||||||
|
#include "command.h" // DECL_CONSTANT
|
||||||
|
#include "sched.h" // sched_wake_task
|
||||||
|
|
||||||
|
static uint32_t canbus_assigned_id;
|
||||||
|
static uint8_t canbus_uuid[CANBUS_UUID_LEN];
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Data transmission over CAN
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
static struct task_wake canbus_tx_wake;
|
||||||
|
static uint8_t transmit_buf[96], transmit_pos, transmit_max;
|
||||||
|
|
||||||
|
void
|
||||||
|
canbus_notify_tx(void)
|
||||||
|
{
|
||||||
|
sched_wake_task(&canbus_tx_wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
canbus_tx_task(void)
|
||||||
|
{
|
||||||
|
if (!sched_check_wake(&canbus_tx_wake))
|
||||||
|
return;
|
||||||
|
uint32_t id = canbus_assigned_id;
|
||||||
|
if (!id) {
|
||||||
|
transmit_pos = transmit_max = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t tpos = transmit_pos, tmax = transmit_max;
|
||||||
|
for (;;) {
|
||||||
|
int avail = tmax - tpos, now = avail > 8 ? 8 : avail;
|
||||||
|
if (avail <= 0)
|
||||||
|
break;
|
||||||
|
int ret = canbus_send(id + 1, now, &transmit_buf[tpos]);
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
tpos += now;
|
||||||
|
}
|
||||||
|
transmit_pos = tpos;
|
||||||
|
}
|
||||||
|
DECL_TASK(canbus_tx_task);
|
||||||
|
|
||||||
|
// Encode and transmit a "response" message
|
||||||
|
void
|
||||||
|
console_sendf(const struct command_encoder *ce, va_list args)
|
||||||
|
{
|
||||||
|
// Verify space for message
|
||||||
|
uint32_t tpos = transmit_pos, tmax = transmit_max;
|
||||||
|
if (tpos >= tmax)
|
||||||
|
transmit_pos = transmit_max = tpos = tmax = 0;
|
||||||
|
uint32_t max_size = ce->max_size;
|
||||||
|
if (tmax + max_size > sizeof(transmit_buf)) {
|
||||||
|
if (tmax + max_size - tpos > sizeof(transmit_buf))
|
||||||
|
// Not enough space for message
|
||||||
|
return;
|
||||||
|
// Move buffer
|
||||||
|
tmax -= tpos;
|
||||||
|
memmove(&transmit_buf[0], &transmit_buf[tpos], tmax);
|
||||||
|
transmit_pos = tpos = 0;
|
||||||
|
transmit_max = tmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate message
|
||||||
|
uint32_t msglen = command_encode_and_frame(&transmit_buf[tmax], ce, args);
|
||||||
|
|
||||||
|
// Start message transmit
|
||||||
|
transmit_max = tmax + msglen;
|
||||||
|
canbus_notify_tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* CAN command handling
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
static uint8_t receive_buf[192], receive_pos;
|
||||||
|
DECL_CONSTANT("RECEIVE_WINDOW", ARRAY_SIZE(receive_buf));
|
||||||
|
|
||||||
|
static void
|
||||||
|
can_process_data(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
|
{
|
||||||
|
int rpos = receive_pos;
|
||||||
|
if (len > sizeof(receive_buf) - rpos)
|
||||||
|
len = sizeof(receive_buf) - rpos;
|
||||||
|
memcpy(&receive_buf[rpos], data, len);
|
||||||
|
receive_pos = rpos + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to retry sending until successful
|
||||||
|
static void
|
||||||
|
canbus_send_blocking(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
int ret = canbus_send(id, len, data);
|
||||||
|
if (ret >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
can_process_ping(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
|
{
|
||||||
|
canbus_send_blocking(canbus_assigned_id + 1, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
can_process_reset(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
|
{
|
||||||
|
uint32_t reset_id = data[0] | (data[1] << 8);
|
||||||
|
if (reset_id == canbus_assigned_id)
|
||||||
|
canbus_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
can_process_uuid(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
|
{
|
||||||
|
if (canbus_assigned_id)
|
||||||
|
return;
|
||||||
|
canbus_send_blocking(CANBUS_ID_UUID_RESP, sizeof(canbus_uuid), canbus_uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
can_process_set_id(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
|
{
|
||||||
|
// compare my UUID with packet to check if this packet mine
|
||||||
|
if (memcmp(&data[2], canbus_uuid, sizeof(canbus_uuid)) == 0) {
|
||||||
|
canbus_assigned_id = data[0] | (data[1] << 8);
|
||||||
|
canbus_set_dataport(canbus_assigned_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
can_process(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
|
{
|
||||||
|
if (id == canbus_assigned_id) {
|
||||||
|
if (len)
|
||||||
|
can_process_data(id, len, data);
|
||||||
|
else
|
||||||
|
can_process_ping(id, len, data);
|
||||||
|
} else if (id == CANBUS_ID_UUID) {
|
||||||
|
if (len)
|
||||||
|
can_process_reset(id, len, data);
|
||||||
|
else
|
||||||
|
can_process_uuid(id, len, data);
|
||||||
|
} else if (id==CANBUS_ID_SET) {
|
||||||
|
can_process_set_id(id, len, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* CAN packet reading
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
static struct task_wake canbus_rx_wake;
|
||||||
|
|
||||||
|
void
|
||||||
|
canbus_notify_rx(void)
|
||||||
|
{
|
||||||
|
sched_wake_task(&canbus_rx_wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
canbus_rx_task(void)
|
||||||
|
{
|
||||||
|
if (!sched_check_wake(&canbus_rx_wake))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Read any pending CAN packets
|
||||||
|
for (;;) {
|
||||||
|
uint8_t data[8];
|
||||||
|
uint32_t id;
|
||||||
|
int ret = canbus_read(&id, data);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
can_process(id, ret, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a complete message block and process it
|
||||||
|
uint_fast8_t rpos = receive_pos, pop_count;
|
||||||
|
int ret = command_find_and_dispatch(receive_buf, rpos, &pop_count);
|
||||||
|
if (ret) {
|
||||||
|
// Move buffer
|
||||||
|
int needcopy = rpos - pop_count;
|
||||||
|
if (needcopy) {
|
||||||
|
memmove(receive_buf, &receive_buf[pop_count], needcopy);
|
||||||
|
canbus_notify_rx();
|
||||||
|
}
|
||||||
|
rpos = needcopy;
|
||||||
|
}
|
||||||
|
receive_pos = rpos;
|
||||||
|
}
|
||||||
|
DECL_TASK(canbus_rx_task);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Setup and shutdown
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
canbus_set_uuid(void *uuid)
|
||||||
|
{
|
||||||
|
memcpy(canbus_uuid, uuid, sizeof(canbus_uuid));
|
||||||
|
|
||||||
|
// Send initial message
|
||||||
|
can_process_uuid(0, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
canbus_shutdown(void)
|
||||||
|
{
|
||||||
|
canbus_notify_tx();
|
||||||
|
canbus_notify_rx();
|
||||||
|
}
|
||||||
|
DECL_SHUTDOWN(canbus_shutdown);
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef __CANBUS_H__
|
||||||
|
#define __CANBUS_H__
|
||||||
|
|
||||||
|
#include <stdint.h> // uint32_t
|
||||||
|
|
||||||
|
#define CANBUS_ID_UUID 0x321
|
||||||
|
#define CANBUS_ID_SET 0x322
|
||||||
|
#define CANBUS_ID_UUID_RESP 0x323
|
||||||
|
#define CANBUS_UUID_LEN 6
|
||||||
|
|
||||||
|
// callbacks provided by board specific code
|
||||||
|
int canbus_read(uint32_t *id, uint8_t *data);
|
||||||
|
int canbus_send(uint32_t id, uint32_t len, uint8_t *data);
|
||||||
|
void canbus_set_dataport(uint32_t id);
|
||||||
|
void canbus_reboot(void);
|
||||||
|
|
||||||
|
// canbus.c
|
||||||
|
void canbus_notify_tx(void);
|
||||||
|
void canbus_notify_rx(void);
|
||||||
|
void canbus_set_uuid(void *data);
|
||||||
|
|
||||||
|
#endif // canbus.h
|
|
@ -176,9 +176,9 @@ config CANSERIAL
|
||||||
bool "Use CAN for communication (instead of serial)"
|
bool "Use CAN for communication (instead of serial)"
|
||||||
depends on !USBSERIAL
|
depends on !USBSERIAL
|
||||||
default n
|
default n
|
||||||
config SERIAL_BAUD
|
config CANBUS_FREQUENCY
|
||||||
int "CAN bus speed" if LOW_LEVEL_OPTIONS && CANSERIAL
|
int "CAN bus speed" if LOW_LEVEL_OPTIONS && CANSERIAL
|
||||||
default 500000 if CANSERIAL
|
default 500000
|
||||||
choice
|
choice
|
||||||
depends on CANSERIAL
|
depends on CANSERIAL
|
||||||
prompt "CAN pins"
|
prompt "CAN pins"
|
||||||
|
|
|
@ -46,8 +46,8 @@ src-$(CONFIG_USBSERIAL) += $(usb-src-y) stm32/chipid.c generic/usb_cdc.c
|
||||||
serial-src-y := stm32/serial.c
|
serial-src-y := stm32/serial.c
|
||||||
serial-src-$(CONFIG_MACH_STM32F0) := stm32/stm32f0_serial.c
|
serial-src-$(CONFIG_MACH_STM32F0) := stm32/stm32f0_serial.c
|
||||||
src-$(CONFIG_SERIAL) += $(serial-src-y) generic/serial_irq.c
|
src-$(CONFIG_SERIAL) += $(serial-src-y) generic/serial_irq.c
|
||||||
can-src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c
|
src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c
|
||||||
src-$(CONFIG_CANSERIAL) += $(can-src-y) generic/serial_irq.c
|
src-$(CONFIG_CANSERIAL) += generic/canbus.c
|
||||||
|
|
||||||
dirs-$(CONFIG_CANSERIAL) += lib/fast-hash
|
dirs-$(CONFIG_CANSERIAL) += lib/fast-hash
|
||||||
|
|
||||||
|
|
247
src/stm32/can.c
247
src/stm32/can.c
|
@ -9,10 +9,10 @@
|
||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
#include "autoconf.h" // CONFIG_MACH_STM32F1
|
#include "autoconf.h" // CONFIG_MACH_STM32F1
|
||||||
#include "board/irq.h" // irq_disable
|
#include "board/irq.h" // irq_disable
|
||||||
#include "can.h" // SHORT_UUID_LEN
|
|
||||||
#include "command.h" // DECL_CONSTANT_STR
|
#include "command.h" // DECL_CONSTANT_STR
|
||||||
#include "fasthash.h" // fasthash64
|
#include "fasthash.h" // fasthash64
|
||||||
#include "generic/armcm_boot.h" // armcm_enable_irq
|
#include "generic/armcm_boot.h" // armcm_enable_irq
|
||||||
|
#include "generic/canbus.h" // canbus_notify_tx
|
||||||
#include "generic/serial_irq.h" // serial_rx_byte
|
#include "generic/serial_irq.h" // serial_rx_byte
|
||||||
#include "internal.h" // enable_pclock
|
#include "internal.h" // enable_pclock
|
||||||
#include "sched.h" // DECL_INIT
|
#include "sched.h" // DECL_INIT
|
||||||
|
@ -87,64 +87,76 @@
|
||||||
#error No known CAN device for configured MCU
|
#error No known CAN device for configured MCU
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint16_t MyCanId = 0;
|
// Read the next CAN packet
|
||||||
|
int
|
||||||
static int
|
canbus_read(uint32_t *id, uint8_t *data)
|
||||||
can_find_empty_tx_mbox(void)
|
|
||||||
{
|
{
|
||||||
uint32_t tsr = SOC_CAN->TSR;
|
if (!(SOC_CAN->RF0R & CAN_RF0R_FMP0)) {
|
||||||
if (tsr & (CAN_TSR_TME0|CAN_TSR_TME1|CAN_TSR_TME2))
|
// All rx mboxes empty, enable wake on rx IRQ
|
||||||
return (tsr & CAN_TSR_CODE) >> CAN_TSR_CODE_Pos;
|
irq_disable();
|
||||||
return -1;
|
SOC_CAN->IER |= CAN_IER_FMPIE0;
|
||||||
|
irq_enable();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and ack packet
|
||||||
|
CAN_FIFOMailBox_TypeDef *mb = &SOC_CAN->sFIFOMailBox[0];
|
||||||
|
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->RF0R = CAN_RF0R_RFOM0;
|
||||||
|
|
||||||
|
// Return packet
|
||||||
|
*id = rir_id;
|
||||||
|
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;
|
||||||
|
return dlc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
// Transmit a packet
|
||||||
can_transmit_mbox(uint32_t id, int mbox, uint32_t dlc, uint8_t *pkt)
|
int
|
||||||
|
canbus_send(uint32_t id, uint32_t len, uint8_t *data)
|
||||||
{
|
{
|
||||||
|
uint32_t tsr = SOC_CAN->TSR;
|
||||||
|
if (!(tsr & (CAN_TSR_TME0|CAN_TSR_TME1|CAN_TSR_TME2))) {
|
||||||
|
// No space in transmit fifo - enable tx irq
|
||||||
|
irq_disable();
|
||||||
|
SOC_CAN->IER |= CAN_IER_TMEIE;
|
||||||
|
irq_enable();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int mbox = (tsr & CAN_TSR_CODE) >> CAN_TSR_CODE_Pos;
|
||||||
CAN_TxMailBox_TypeDef *mb = &SOC_CAN->sTxMailBox[mbox];
|
CAN_TxMailBox_TypeDef *mb = &SOC_CAN->sTxMailBox[mbox];
|
||||||
|
|
||||||
/* Set up the DLC */
|
/* Set up the DLC */
|
||||||
mb->TDTR = (mb->TDTR & 0xFFFFFFF0) | (dlc & 0x0F);
|
mb->TDTR = (mb->TDTR & 0xFFFFFFF0) | (len & 0x0F);
|
||||||
|
|
||||||
/* Set up the data field */
|
/* Set up the data field */
|
||||||
if (pkt) {
|
if (len) {
|
||||||
mb->TDLR = (((uint32_t)pkt[3] << 24)
|
mb->TDLR = (((uint32_t)data[3] << 24)
|
||||||
| ((uint32_t)pkt[2] << 16)
|
| ((uint32_t)data[2] << 16)
|
||||||
| ((uint32_t)pkt[1] << 8)
|
| ((uint32_t)data[1] << 8)
|
||||||
| ((uint32_t)pkt[0] << 0));
|
| ((uint32_t)data[0] << 0));
|
||||||
mb->TDHR = (((uint32_t)pkt[7] << 24)
|
mb->TDHR = (((uint32_t)data[7] << 24)
|
||||||
| ((uint32_t)pkt[6] << 16)
|
| ((uint32_t)data[6] << 16)
|
||||||
| ((uint32_t)pkt[5] << 8)
|
| ((uint32_t)data[5] << 8)
|
||||||
| ((uint32_t)pkt[4] << 0));
|
| ((uint32_t)data[4] << 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request transmission */
|
/* Request transmission */
|
||||||
mb->TIR = (id << CAN_TI0R_STID_Pos) | CAN_TI0R_TXRQ;
|
mb->TIR = (id << CAN_TI0R_STID_Pos) | CAN_TI0R_TXRQ;
|
||||||
}
|
return len;
|
||||||
|
|
||||||
// Blocking transmit function
|
|
||||||
static void
|
|
||||||
can_transmit(uint32_t id, uint32_t dlc, uint8_t *pkt)
|
|
||||||
{
|
|
||||||
int mbox = -1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
mbox = can_find_empty_tx_mbox();
|
|
||||||
} while (mbox < 0);
|
|
||||||
|
|
||||||
can_transmit_mbox(id, mbox, dlc, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Unique 96-bit value into 48 bit representation
|
|
||||||
static void
|
|
||||||
pack_uuid(uint8_t *u)
|
|
||||||
{
|
|
||||||
uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7);
|
|
||||||
memcpy(u, &hash, SHORT_UUID_LEN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CAN_FILTER_NUMBER 0
|
#define CAN_FILTER_NUMBER 0
|
||||||
|
|
||||||
|
// Setup the receive packet filter
|
||||||
static void
|
static void
|
||||||
can_set_filter(uint32_t id1, uint32_t id2)
|
can_set_filter(uint32_t id1, uint32_t id2)
|
||||||
{
|
{
|
||||||
|
@ -172,145 +184,33 @@ can_set_filter(uint32_t id1, uint32_t id2)
|
||||||
SOC_CAN->FMR &= ~CAN_FMR_FINIT;
|
SOC_CAN->FMR &= ~CAN_FMR_FINIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
can_process_data(uint32_t id, uint32_t dlc, uint8_t *data)
|
canbus_set_dataport(uint32_t id)
|
||||||
{
|
{
|
||||||
int i;
|
can_set_filter(CANBUS_ID_UUID, id);
|
||||||
for (i=0; i < dlc; i++)
|
|
||||||
serial_rx_byte(data[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
can_process_ping(uint32_t id, uint32_t dlc, uint8_t *data)
|
|
||||||
{
|
|
||||||
can_transmit(MyCanId+1, 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
can_process_reset(uint32_t id, uint32_t dlc, uint8_t *data)
|
|
||||||
{
|
|
||||||
uint32_t reset_id = data[0] | (data[1] << 8);
|
|
||||||
if (reset_id == MyCanId)
|
|
||||||
NVIC_SystemReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
can_process_uuid(uint32_t id, uint32_t dlc, uint8_t *data)
|
|
||||||
{
|
|
||||||
if (MyCanId)
|
|
||||||
return;
|
|
||||||
uint8_t short_uuid[SHORT_UUID_LEN];
|
|
||||||
pack_uuid(short_uuid);
|
|
||||||
can_transmit(PKT_ID_UUID_RESP, SHORT_UUID_LEN, short_uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
can_process_set_id(uint32_t id, uint32_t dlc, uint8_t *data)
|
|
||||||
{
|
|
||||||
uint8_t short_uuid[SHORT_UUID_LEN];
|
|
||||||
pack_uuid(short_uuid);
|
|
||||||
|
|
||||||
// compare my UUID with packet to check if this packet mine
|
|
||||||
if (memcmp(&data[2], short_uuid, SHORT_UUID_LEN) == 0) {
|
|
||||||
MyCanId = data[0] | (data[1] << 8);
|
|
||||||
can_set_filter(MyCanId, PKT_ID_UUID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
can_process(uint32_t id, uint32_t dlc, uint8_t *data)
|
|
||||||
{
|
|
||||||
if (id == MyCanId) {
|
|
||||||
if (dlc)
|
|
||||||
can_process_data(id, dlc, data);
|
|
||||||
else
|
|
||||||
can_process_ping(id, dlc, data);
|
|
||||||
} else if (id == PKT_ID_UUID) {
|
|
||||||
if (dlc)
|
|
||||||
can_process_reset(id, dlc, data);
|
|
||||||
else
|
|
||||||
can_process_uuid(id, dlc, data);
|
|
||||||
} else if (id==PKT_ID_SET) {
|
|
||||||
can_process_set_id(id, dlc, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct task_wake canbus_wake;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
can_dispatch_task(void)
|
canbus_reboot(void)
|
||||||
{
|
{
|
||||||
if (!sched_check_wake(&canbus_wake))
|
NVIC_SystemReset();
|
||||||
return;
|
|
||||||
|
|
||||||
// Check for rx
|
|
||||||
for (;;) {
|
|
||||||
if (!(SOC_CAN->RF0R & CAN_RF0R_FMP0)) {
|
|
||||||
// All rx mboxes empty, enable wake on rx IRQ
|
|
||||||
irq_disable();
|
|
||||||
SOC_CAN->IER |= CAN_IER_FMPIE0;
|
|
||||||
irq_enable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and ack packet
|
|
||||||
CAN_FIFOMailBox_TypeDef *mb = &SOC_CAN->sFIFOMailBox[0];
|
|
||||||
uint32_t 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->RF0R = CAN_RF0R_RFOM0;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
can_process(id, dlc, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for tx data
|
|
||||||
for (;;) {
|
|
||||||
int mbox = can_find_empty_tx_mbox();
|
|
||||||
if (mbox < 0) {
|
|
||||||
// All tx mboxes full, enable wake on tx IRQ
|
|
||||||
irq_disable();
|
|
||||||
SOC_CAN->IER |= CAN_IER_TMEIE;
|
|
||||||
irq_enable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int i;
|
|
||||||
uint8_t databuf[8];
|
|
||||||
for (i=0; i<8; i++) {
|
|
||||||
if (serial_get_tx_byte(&(databuf[i])) == -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!i)
|
|
||||||
break;
|
|
||||||
can_transmit_mbox(MyCanId+1, mbox, i, databuf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DECL_TASK(can_dispatch_task);
|
|
||||||
|
|
||||||
// This function handles CAN global interrupts
|
// This function handles CAN global interrupts
|
||||||
void
|
void
|
||||||
CAN_IRQHandler(void)
|
CAN_IRQHandler(void)
|
||||||
{
|
{
|
||||||
if (SOC_CAN->RF0R & CAN_RF0R_FMP0) {
|
|
||||||
// Rx
|
|
||||||
SOC_CAN->IER &= ~CAN_IER_FMPIE0;
|
|
||||||
sched_wake_task(&canbus_wake);
|
|
||||||
}
|
|
||||||
uint32_t ier = SOC_CAN->IER;
|
uint32_t ier = SOC_CAN->IER;
|
||||||
|
if (ier & CAN_IER_FMPIE0 && SOC_CAN->RF0R & CAN_RF0R_FMP0) {
|
||||||
|
// Rx
|
||||||
|
SOC_CAN->IER = ier = ier & ~CAN_IER_FMPIE0;
|
||||||
|
canbus_notify_rx();
|
||||||
|
}
|
||||||
if (ier & CAN_IER_TMEIE
|
if (ier & CAN_IER_TMEIE
|
||||||
&& SOC_CAN->TSR & (CAN_TSR_RQCP0|CAN_TSR_RQCP1|CAN_TSR_RQCP2)) {
|
&& SOC_CAN->TSR & (CAN_TSR_RQCP0|CAN_TSR_RQCP1|CAN_TSR_RQCP2)) {
|
||||||
// Tx
|
// Tx
|
||||||
SOC_CAN->IER &= ~CAN_IER_TMEIE;
|
SOC_CAN->IER = ier & ~CAN_IER_TMEIE;
|
||||||
sched_wake_task(&canbus_wake);
|
canbus_notify_tx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +272,7 @@ can_init(void)
|
||||||
|
|
||||||
uint32_t pclock = get_pclock_frequency((uint32_t)SOC_CAN);
|
uint32_t pclock = get_pclock_frequency((uint32_t)SOC_CAN);
|
||||||
|
|
||||||
uint32_t btr = compute_btr(pclock, CONFIG_SERIAL_BAUD);
|
uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_FREQUENCY);
|
||||||
|
|
||||||
/*##-1- Configure the CAN #######################################*/
|
/*##-1- Configure the CAN #######################################*/
|
||||||
|
|
||||||
|
@ -392,7 +292,7 @@ can_init(void)
|
||||||
;
|
;
|
||||||
|
|
||||||
/*##-2- Configure the CAN Filter #######################################*/
|
/*##-2- Configure the CAN Filter #######################################*/
|
||||||
can_set_filter(PKT_ID_UUID, PKT_ID_SET);
|
can_set_filter(CANBUS_ID_UUID, CANBUS_ID_SET);
|
||||||
|
|
||||||
/*##-3- Configure Interrupts #################################*/
|
/*##-3- Configure Interrupts #################################*/
|
||||||
|
|
||||||
|
@ -404,13 +304,8 @@ can_init(void)
|
||||||
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);
|
||||||
|
|
||||||
/*##-4- Say Hello #################################*/
|
// Convert unique 96-bit chip id into 48 bit representation
|
||||||
can_process_uuid(0, 0, NULL);
|
uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7);
|
||||||
|
canbus_set_uuid(&hash);
|
||||||
}
|
}
|
||||||
DECL_INIT(can_init);
|
DECL_INIT(can_init);
|
||||||
|
|
||||||
void
|
|
||||||
serial_enable_tx_irq(void)
|
|
||||||
{
|
|
||||||
sched_wake_task(&canbus_wake);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef __STM32_CAN_H__
|
|
||||||
#define __STM32_CAN_H__
|
|
||||||
|
|
||||||
// Read UUID (6bytes)
|
|
||||||
#define PKT_ID_UUID (0x321)
|
|
||||||
// Set address (2bytes) to UUID (6b)
|
|
||||||
#define PKT_ID_SET (0x322)
|
|
||||||
// UUID response from slave (6bytes)
|
|
||||||
#define PKT_ID_UUID_RESP (0x323)
|
|
||||||
|
|
||||||
#define SHORT_UUID_LEN (6)
|
|
||||||
|
|
||||||
#endif /* __STM32_CAN_H__*/
|
|
Loading…
Reference in New Issue