164 lines
4.7 KiB
C++
164 lines
4.7 KiB
C++
#include "can.hpp"
|
|
|
|
#include <cstdio>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/sys/printk.h>
|
|
|
|
#include <pb_decode.h>
|
|
|
|
#include "configuration.pb.h"
|
|
#include "ctrl.pb.h"
|
|
#include "temperature.pb.h"
|
|
|
|
const struct device *can_dev = DEVICE_DT_GET(DT_NODELABEL(fdcan1));
|
|
|
|
namespace rims {
|
|
|
|
// External
|
|
CAN_MSGQ_DEFINE(can_engress_queue, 5);
|
|
CAN_MSGQ_DEFINE(can_ingress_queue, 5);
|
|
|
|
// IPC
|
|
K_MSGQ_DEFINE(can_temperature_ingress_queue, temperature_IngressMessage_size, 2, 1);
|
|
K_MSGQ_DEFINE(can_config_ingress_queue, config_IngressMessage_size, 2, 1);
|
|
K_MSGQ_DEFINE(can_ctrl_ingress_queue, ctrl_IngressMessage_size, 2, 1);
|
|
|
|
void CAN_RX::loop() {
|
|
struct can_frame frame;
|
|
int filter_id;
|
|
|
|
/* Set up a filter to receive all CAN messages (example: ID mask 0x000, all pass) */
|
|
struct can_filter filter = {
|
|
.id = 0,
|
|
.mask = CAN_EXT_ID_MASK, /* No filter */
|
|
.flags = CAN_FILTER_IDE,
|
|
};
|
|
|
|
filter_id = can_add_rx_filter_msgq(can_dev, &can_ingress_queue, &filter);
|
|
if (filter_id < 0) {
|
|
printk("Failed to add CAN RX filter (err %d)", filter_id);
|
|
return;
|
|
}
|
|
printk("CAN RX filter added (id: %d)", filter_id);
|
|
|
|
while (1) {
|
|
k_msgq_get(&can_ingress_queue, &frame, K_FOREVER);
|
|
|
|
if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) {
|
|
continue;
|
|
}
|
|
|
|
if (frame.dlc != 2U) {
|
|
printf("Wrong data length: %u\n", frame.dlc);
|
|
continue;
|
|
}
|
|
|
|
printf("CAN received :~%u bytes\n", can_dlc_to_bytes(frame.dlc));
|
|
printf("CAN received id: %u\n", frame.id);
|
|
|
|
bool ok = false;
|
|
auto stream = pb_istream_from_buffer(frame.data, can_dlc_to_bytes(frame.dlc));
|
|
|
|
const auto decodeAndPublish = [&](const pb_msgdesc_t *fields, void *dest, k_msgq &msgq) {
|
|
ok = pb_decode(&stream, fields, &dest);
|
|
if (ok) {
|
|
printf("Decode OK");
|
|
while (k_msgq_put(&msgq, &dest, K_NO_WAIT)) {
|
|
k_msgq_purge(&msgq);
|
|
}
|
|
} else {
|
|
/// TODO loging
|
|
printf("Decode failed");
|
|
}
|
|
};
|
|
|
|
switch (frame.id) {
|
|
case 0x01: { /// TODO temperature endpoint ID
|
|
temperature_IngressMessage msg;
|
|
decodeAndPublish(temperature_IngressMessage_fields, &msg, can_temperature_ingress_queue);
|
|
break;
|
|
}
|
|
case 0x02: /// TODO configuration endpoint ID
|
|
{
|
|
config_IngressMessage msg;
|
|
decodeAndPublish(config_IngressMessage_fields, &msg, can_config_ingress_queue);
|
|
break;
|
|
}
|
|
case 0x03: /// TODO phase controll endpoint ID
|
|
{
|
|
ctrl_IngressMessage msg;
|
|
decodeAndPublish(ctrl_IngressMessage_fields, &msg, can_ctrl_ingress_queue);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (not ok) {
|
|
printk("data broken");
|
|
}
|
|
}
|
|
|
|
/* Remove the filter if the thread exits (unlikely here) */
|
|
can_remove_rx_filter(can_dev, filter_id);
|
|
}
|
|
|
|
void CAN_TX::loop() {
|
|
while (1) {
|
|
can_frame frame;
|
|
// Wait for a message in the FIFO
|
|
auto status = k_msgq_get(&can_engress_queue, &frame, K_SECONDS(1));
|
|
|
|
if (status == 0) {
|
|
int ret = can_send(can_dev, &frame, K_FOREVER, NULL, NULL);
|
|
if (ret == 0) {
|
|
printk("CAN message sent successfully.\n");
|
|
} else {
|
|
printk("Failed to send CAN message, error: %d\n", ret);
|
|
}
|
|
} else if (status == -EAGAIN) {
|
|
printk("Nothing to send, looping");
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CAN_RX::Setup() {
|
|
// CAN device pointer
|
|
|
|
if (!can_dev) {
|
|
printk("Failed to get CAN device binding.\n");
|
|
return false;
|
|
}
|
|
|
|
/// TODO CAN set timing https://docs.zephyrproject.org/latest/hardware/peripherals/can/controller.html
|
|
|
|
// Start CAN device
|
|
int ret = can_start(can_dev);
|
|
if (ret != 0) {
|
|
printk("Failed to start CAN device, error: %d\n", ret);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CAN_TX::send(uint32_t senderId, const void *data, std::size_t messageLength) {
|
|
/// TODO assert proper ID
|
|
/// TODO assert message_length
|
|
can_frame frame;
|
|
|
|
// Populate CAN frame with sample data
|
|
memcpy(frame.data, data, messageLength);
|
|
|
|
frame.flags = CAN_FRAME_FDF | CAN_FRAME_BRS; // use CAN FD
|
|
frame.id = senderId; // ID of given service
|
|
frame.dlc = can_bytes_to_dlc(messageLength); // CAN data length code
|
|
|
|
// put data on outgoing messagesqueue
|
|
|
|
/// TODO fix CANBUS
|
|
// k_msgq_put(&can_engress_queue, &frame, K_MSEC(50));
|
|
/// TODO handle error
|
|
}
|
|
|
|
} // namespace rims
|