wip hscan common

This commit is contained in:
radex 2024-06-07 14:25:00 +02:00
parent 0ce20cb46f
commit a482444490
Signed by: radex
SSH key fingerprint: SHA256:hvqRXAGG1h89yqnS+cyFTLKQbzjWD4uXIqw7Y+0ws30
9 changed files with 245 additions and 62 deletions

6
can-firmware/.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,6 @@
{
"files.associations": {
"irq.h": "c",
"pio.h": "c"
}
}

View file

@ -0,0 +1,23 @@
#include <assert.h>
#include <string.h>
#include "hscan.h"
void hscan_impl_setup(hscan_bus *bus, hscan_config config);
void hscan_setup(hscan_bus *bus, hscan_config config) {
memset(bus, 0, sizeof(*bus));
assert(config.callback);
if (!config.experimental_bitrate) {
config.experimental_bitrate = HSCAN_BITRATE;
}
hscan_impl_setup(bus, config);
}
void hscan_impl_send(hscan_bus *bus, hscan_msg *msg);
void hscan_send(hscan_bus *bus, hscan_msg *msg) {
hscan_impl_send(bus, msg);
}

View file

@ -0,0 +1,54 @@
#ifndef _HSCAN_H
#define _HSCAN_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "id.h"
#include "impl.h"
typedef struct {
// TBD
hscan_bus_impl *impl;
} hscan_bus;
typedef struct {
/** Identifier (and priority) of the message */
hscan_id id;
/** Number of bytes of data (0-8 bytes), a.k.a. DLC */
uint8_t length;
/** Data bytes */
uint8_t data[8];
/** If `true`, this message is a RTR (Remote Transmission Request) */
bool is_request;
} hscan_msg;
#define HSCAN_BITRATE 500000
typedef enum {
HSCAN_MSG_STATUS_RECEIVED = 1<<20,
HSCAN_MSG_STATUS_TRANSMITTED = 1<<21,
HSCAN_MSG_STATUS_ERROR = 1<<23,
} hscan_msg_status;
typedef void (*hscan_callback_t)(hscan_bus *bus, hscan_msg *msg, hscan_msg_status status);
typedef struct {
hscan_callback_t callback;
hscan_impl_config impl;
// NOTE: Optional, default should be used
uint32_t experimental_bitrate;
} hscan_config;
void hscan_setup(hscan_bus *bus, hscan_config config);
void hscan_send(hscan_bus *bus, hscan_msg *msg);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,6 +1,5 @@
#include <assert.h>
#include "hscan.h"
#include "id.h"
hscan_id hscan_id_make(uint32_t id) {
assert(id < (1 << 29));

View file

@ -1,5 +1,5 @@
#ifndef _HSCAN_H
#define _HSCAN_H
#ifndef _HSCAN_ID_H
#define _HSCAN_ID_H
#include <stdint.h>
#include <stdbool.h>
@ -14,20 +14,6 @@ typedef struct {
bool is_extended;
} hscan_id;
typedef struct {
/** Identifier (and priority) of the message */
hscan_id id;
/** Number of bytes of data (0-8 bytes), a.k.a. DLC */
uint8_t length;
/** Data bytes */
uint8_t data[8];
/** If `true`, this message is a RTR (Remote Transmission Request) */
bool is_request;
} hscan_msg;
#define HSCAN_BAUDRATE 500000
// CAN message IDs
#define HSCAN_ID_DEVICE_SIZE 256
// #define HSCAN_ID_DEVICE_INFRA_MIN 0
// #define HSCAN_ID_DEVICE_INFRA_MAX 31

View file

@ -0,0 +1,11 @@
#ifndef _HSCAN_IMPL_H
#define _HSCAN_IMPL_H
#include "rp2040/rp2040.h"
#include "hscan.h"
typedef hscan_rp2040_config hscan_impl_config;
typedef struct can2040 hscan_bus_impl;
#endif

View file

@ -0,0 +1,83 @@
#include <stdlib.h>
#include "hardware/irq.h"
#include "../hscan.h"
#include "can2040.h"
#include "rp2040.h"
static struct can2040 hscan_rp2040_canbus0;
static struct can2040 hscan_rp2040_canbus1;
static void hscan_rp2040_pio0_irq_handler() {
can2040_pio_irq_handler(&hscan_rp2040_canbus0);
}
static void hscan_rp2040_pio1_irq_handler() {
can2040_pio_irq_handler(&hscan_rp2040_canbus1);
}
struct can2040_msg hscan_rp2040_encode_msg(hscan_msg msg) {
uint32_t id = msg.id.id;
if (msg.id.is_extended) {
id |= CAN2040_ID_EFF;
}
if (msg.is_request) {
id |= CAN2040_ID_RTR;
}
struct can2040_msg can_msg;
can_msg.id = id;
can_msg.dlc = msg.length;
for (int i = 0; i < msg.length; i++) {
can_msg.data[i] = msg.data[i];
}
return can_msg;
}
hscan_msg hscan_rp2040_decode_msg(struct can2040_msg can_msg) {
hscan_msg msg;
msg.id.is_extended = can_msg.id & CAN2040_ID_EFF;
msg.id.id = can_msg.id & 0x1FFFFFFF; // 29-bit mask
msg.is_request = can_msg.id & CAN2040_ID_RTR;
msg.length = can_msg.dlc;
for (int i = 0; i < msg.length; i++) {
msg.data[i] = can_msg.data[i];
}
return msg;
}
void hscan_impl_setup(hscan_bus *bus, hscan_config config) {
// TODO: set up bus->impl
// TODO: Set up callback
uint8_t pio_num = config.impl.pio_num;
assert(pio_num == 0 || pio_num == 1);
// set up can bus
can2040_setup(bus->impl, pio_num);
can2040_callback_config(bus->impl, NULL);
// set up interrupt handler
uint irq_num = pio_num == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
irq_handler_t irq_handler = pio_num == 0 ?
hscan_rp2040_pio0_irq_handler :
hscan_rp2040_pio1_irq_handler;
uint8_t irq_priority = config.impl.irq_priority || 1;
irq_set_exclusive_handler(irq_num, irq_handler);
irq_set_priority(irq_num, irq_priority);
irq_set_enabled(irq_num, true);
// start can bus
can2040_start(bus->impl,
config.impl.sys_clock,
config.experimental_bitrate,
config.impl.gpio_rx,
config.impl.gpio_tx);
}
void hscan_impl_send(hscan_bus *bus, hscan_msg *msg) {
struct can2040_msg encoded = hscan_rp2040_encode_msg(*msg);
can2040_transmit(bus->impl, &encoded);
}

View file

@ -0,0 +1,18 @@
#ifndef _HSCAN_RP2040_IMPL_H
#define _HSCAN_RP2040_IMPL_H
#include <stdint.h>
#include <stdbool.h>
// #include "../hscan.h"
typedef struct {
uint8_t pio_num;
uint32_t sys_clock;
uint8_t gpio_rx;
uint8_t gpio_tx;
// NOTE: Optional, defaults to 1
uint8_t irq_priority;
} hscan_rp2040_config;
#endif

View file

@ -1,51 +1,54 @@
#include <Arduino.h>
extern "C" {
#include "can2040.h"
#include "hscan/hscan.h"
static void can_callback(hscan_bus *bus, hscan_msg *msg, hscan_msg_status status) {
// TODO
}
static struct can2040 cbus;
static hscan_bus bus;
static void can2040_cb(struct can2040 *cd, uint32_t notify, struct can2040_msg *msg) {
printf("cb ntfy status: %d\n", notify);
}
static void PIOx_IRQHandler() {
can2040_pio_irq_handler(&cbus);
}
void canbus_setup()
{
uint32_t pio_num = 0;
uint32_t sys_clock = 125000000, bitrate = 500000;
uint32_t gpio_rx = 16, gpio_tx = 17;
// Setup canbus
can2040_setup(&cbus, pio_num);
can2040_callback_config(&cbus, can2040_cb);
// Enable irqs
irq_set_exclusive_handler(PIO0_IRQ_0, PIOx_IRQHandler);
// NVIC_SetPriority(PIO0_IRQ_0_IRQn, 1);
// NVIC_EnableIRQ(PIO0_IRQ_0_IRQn);
// Start canbus
can2040_start(&cbus, sys_clock, bitrate, gpio_rx, gpio_tx);
}
int main()
{
// stdio_init_all();
canbus_setup();
while (true) {
sleep_ms(1000 + get_rand_32() % 1000);
can2040_msg msg = {
.id = 0x125,
.dlc = 8,
.data = {'P', 'A', 'P', 'I', 'E', 'S', 'Z'}
};
auto status = can2040_transmit(&cbus, &msg);
printf("Transmit status: %d\n", status);
void canbus_setup() {
hscan_setup(&bus, {
.callback = can_callback,
.impl = {
.pio_num = 0,
.sys_clock = 125000000,
.gpio_rx = 16,
.gpio_tx = 17
}
});
}
void setup() {
Serial.begin(115200);
canbus_setup();
}
void canbus_heartbeat_loop();
void loop() {
canbus_heartbeat_loop();
}
unsigned long canbus_last_heartbeat_at = 0;
int canbus_heartbeat_interval = 1000;
void canbus_heartbeat();
void canbus_heartbeat_loop() {
auto now = millis();
if (canbus_last_heartbeat_at + canbus_heartbeat_interval < now) {
canbus_last_heartbeat_at = now;
// add some jitter to reduce collision likelihood
canbus_heartbeat_interval = 1000 + random(-200, 200);
canbus_heartbeat();
}
}
void canbus_heartbeat() {
int experimental_device_id = 1;
hscan_msg msg = {
.id = hscan_id_experimental_device_heartbeat(experimental_device_id)
};
hscan_send(&bus, &msg);
}