Hardware: CAN Controller JF0815#
Software Paradigm#
Driver is a bare wrapper around bare hardware
Sending
User registers ISR for IRQ#1001
Drops CAN frame into device buffer
Kick controller (set flag in some device register)
ISR called when frame transmitted (⟶ ready for next transmission)
Receiving
User registers ISR for IRQ#1002
ISR called when device buffer contains received frame
Driver Interface#
#pragma once
#include <why-error.h>
#include <why-fd.h>
#include <jqueue.h>
#include <cstdint>
#include <atomic>
struct CANFrame
{
uint32_t id;
uint8_t dlc;
uint8_t data[8];
};
class CAN_JF0815_HW
{
public:
static const int IRQ_XMIT_DONE = 1001;
static const int IRQ_RECV_READY = 1002;
public:
CAN_JF0815_HW(const std::string& can_iface);
~CAN_JF0815_HW();
void begin_xmit(const CANFrame&);
CANFrame commit_recv();
bool xmit_busy() { return _frame_to_send_valid.load(); }
private:
void _hw_loop();
void _hw_send_requested_func();
void _hw_recv_ready_func();
private:
CANFrame _frame_to_send;
std::atomic<bool> _frame_to_send_valid = false;
CANFrame _frame_received;
std::atomic<bool> _frame_received_valid = false;
Why::FD _can_socket;
Why::FD _send_requested_event;
Why::FD _quit_requested_event;
std::thread _hw_thread;
};
Sample Send Program#
#include "can-jf0815-hw.h"
#include <why-time.h>
#include <why-irq.h>
#include <print>
int main()
{
Why::init();
CAN_JF0815_HW can("my-can");
Why::IRQ::connect(CAN_JF0815_HW::IRQ_XMIT_DONE, [](int irqnum){
std::println("xmit done (IRQ {})", irqnum);
});
can.begin_xmit(CANFrame{/*id*/42, /*dlc*/7, "1234567"});
Why::pause();
return 0;
}
Sample Receive Program#
#include "can-jf0815-hw.h"
#include <why-time.h>
#include <why-irq.h>
#include <print>
int main()
{
Why::init();
CAN_JF0815_HW can("my-can");
Why::IRQ::connect(CAN_JF0815_HW::IRQ_RECV_READY, [&can](int irqnum){
auto frame = can.commit_recv();
std::println("ID {}, dlc {}, data {}", frame.id, frame.dlc, std::string((const char*)frame.data, frame.dlc));
});
Why::pause();
return 0;
}