Files
canFD_esp32_glm-oh-my-open-/can_handler.cpp
2026-02-20 17:50:40 +00:00

292 lines
7.8 KiB
C++

// can_handler.cpp - CAN FD Handler Implementation
#include <Arduino.h>
#include "can_handler.h"
#include "task_config.h"
#include "rtc_manager.h"
#include "psram_buffer.h"
ACAN2517FD canController(HSPI_CS_PIN, SPI, CAN_INT_PIN);
volatile bool canInitialized = false;
volatile uint32_t canRxCount = 0;
volatile uint32_t canTxCount = 0;
volatile uint32_t canErrorCount = 0;
volatile uint32_t canOverflowCount = 0;
static uint8_t currentCANMode = 0;
static CANFDMessage rxMessage;
static CANFDMessage txMessage;
bool initCAN() {
Serial.println("Initializing CAN FD Controller (MCP2518FD)...");
SPI.begin(HSPI_SCLK_PIN, HSPI_MISO_PIN, HSPI_MOSI_PIN, HSPI_CS_PIN);
ACAN2517FDSettings settings(
ACAN2517FDSettings::OSC_40MHz,
CAN_DEFAULT_ARBITRATION_BAUDRATE,
DataBitRateFactor::x4
);
settings.mISOCRCEnabled = true;
settings.mDriverReceiveFIFOSize = MCP2518FD_RX_FIFO_SIZE;
settings.mDriverTransmitFIFOSize = MCP2518FD_TX_FIFO_SIZE;
switch (currentCANMode) {
case 1:
settings.mRequestedMode = ACAN2517FDSettings::ListenOnly;
break;
case 2:
case 3:
settings.mRequestedMode = ACAN2517FDSettings::InternalLoopBack;
break;
default:
settings.mRequestedMode = ACAN2517FDSettings::NormalFD;
break;
}
const uint32_t errorCode = canController.begin(settings, [] {
onCANInterrupt();
});
if (errorCode == 0) {
canInitialized = true;
Serial.println("CAN FD initialized successfully!");
Serial.printf(" Arbitration: %d bps\n", CAN_DEFAULT_ARBITRATION_BAUDRATE);
Serial.printf(" Data: %d bps\n", CAN_DEFAULT_DATA_BAUDRATE);
Serial.printf(" Mode: %d\n", currentCANMode);
return true;
} else {
Serial.printf("CAN FD initialization failed! Error: 0x%X\n", errorCode);
canInitialized = false;
return false;
}
}
bool setCANMode(uint8_t mode) {
if (mode > 3) return false;
currentCANMode = mode;
if (canInitialized) {
canController.end();
canInitialized = false;
}
return initCAN();
}
uint8_t getCANMode() {
return currentCANMode;
}
void IRAM_ATTR onCANInterrupt() {
// Set flag or notify task - actual handling in task
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// Notify CAN RX task
if (canRxTaskHandle != NULL) {
vTaskNotifyGiveFromISR(canRxTaskHandle, &xHigherPriorityTaskWoken);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void canRxTask(void *pvParameters) {
Serial.println("CAN RX Task started on Core 0");
uint32_t framesProcessed = 0;
uint32_t lastStatusTime = 0;
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
uint8_t batchCount = 0;
while (canController.available() && batchCount < CAN_RX_BATCH_SIZE) {
if (canController.receive(rxMessage)) {
canRxCount++;
batchCount++;
CanFrame frame;
frame.timestamp = getMicrosTimestamp();
frame.id = rxMessage.id;
frame.len = rxMessage.len;
frame.flags = 0;
if (rxMessage.type == CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH) {
frame.flags |= 0x01;
}
if (rxMessage.type == CANFDMessage::CANFD_NO_BIT_RATE_SWITCH) {
frame.flags |= 0x02;
}
memcpy(frame.data, rxMessage.data, rxMessage.len);
if (xQueueSend(canRxQueue, &frame, 0) != pdTRUE) {
if (!canFrameBuffer.push(frame)) {
canErrorCount++;
} else {
canOverflowCount++;
}
}
xQueueSend(graphQueue, &frame, 0);
}
}
framesProcessed += batchCount;
uint32_t now = millis();
if (now - lastStatusTime > 5000) {
Serial.printf("[CAN] RX: %d, Q: %d, PSRAM: %d/%d, Err: %d\n",
canRxCount,
uxQueueMessagesWaiting(canRxQueue),
canFrameBuffer.available(),
canFrameBuffer.capacity(),
canErrorCount);
lastStatusTime = now;
}
}
}
void canTxTask(void *pvParameters) {
Serial.println("CAN TX Task started on Core 0");
CanTxRequest request;
while (1) {
// Wait for transmit request
if (xQueueReceive(canTxQueue, &request, portMAX_DELAY) == pdTRUE) {
// Prepare message
txMessage.id = request.id;
txMessage.len = request.len;
memcpy(txMessage.data, request.data, request.len);
txMessage.type = CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH;
// Handle repeat count
uint32_t repeat = request.repeat_count;
if (repeat == 0) {
repeat = 1; // Send at least once
}
for (uint32_t i = 0; i < repeat; i++) {
if (canController.tryToSend(txMessage)) {
canTxCount++;
} else {
canErrorCount++;
Serial.println("CAN TX failed: buffer full");
}
// Delay between repeats
if (request.delay_ms > 0 && i < repeat - 1) {
vTaskDelay(pdMS_TO_TICKS(request.delay_ms));
}
}
}
}
}
bool sendCANFrame(uint32_t id, uint8_t* data, uint8_t len, bool isFD) {
if (!canInitialized) {
return false;
}
CanTxRequest request;
request.id = id;
request.len = len;
memcpy(request.data, data, len);
request.delay_ms = 0;
request.repeat_count = 1;
return xQueueSend(canTxQueue, &request, pdMS_TO_TICKS(100)) == pdTRUE;
}
bool setCANBaudrate(uint32_t arbitrationBaud, uint32_t dataBaud) {
return setCANBaudrateAndMode(arbitrationBaud, dataBaud, currentCANMode, true);
}
bool setCANBaudrateAndMode(uint32_t arbitrationBaud, uint32_t dataBaud, uint8_t mode, bool enableFD) {
if (canInitialized) {
canController.end();
canInitialized = false;
}
currentCANMode = mode;
DataBitRateFactor dataFactor = DataBitRateFactor::x1;
if (enableFD) {
uint32_t factor = dataBaud / arbitrationBaud;
switch (factor) {
case 1: dataFactor = DataBitRateFactor::x1; break;
case 2: dataFactor = DataBitRateFactor::x2; break;
case 4: dataFactor = DataBitRateFactor::x4; break;
case 5: dataFactor = DataBitRateFactor::x5; break;
case 6: dataFactor = DataBitRateFactor::x6; break;
case 7: dataFactor = DataBitRateFactor::x7; break;
case 8: dataFactor = DataBitRateFactor::x8; break;
case 10: dataFactor = DataBitRateFactor::x10; break;
default: dataFactor = DataBitRateFactor::x4; break;
}
}
ACAN2517FDSettings settings(
ACAN2517FDSettings::OSC_40MHz,
arbitrationBaud,
dataFactor
);
settings.mISOCRCEnabled = enableFD;
settings.mDriverReceiveFIFOSize = MCP2518FD_RX_FIFO_SIZE;
settings.mDriverTransmitFIFOSize = MCP2518FD_TX_FIFO_SIZE;
if (enableFD) {
switch (mode) {
case 1:
settings.mRequestedMode = ACAN2517FDSettings::ListenOnly;
break;
case 2:
case 3:
settings.mRequestedMode = ACAN2517FDSettings::InternalLoopBack;
break;
default:
settings.mRequestedMode = ACAN2517FDSettings::NormalFD;
break;
}
} else {
switch (mode) {
case 1:
settings.mRequestedMode = ACAN2517FDSettings::ListenOnly;
break;
case 2:
case 3:
settings.mRequestedMode = ACAN2517FDSettings::InternalLoopBack;
break;
default:
settings.mRequestedMode = ACAN2517FDSettings::Normal20B;
break;
}
}
const uint32_t errorCode = canController.begin(settings, [] {
onCANInterrupt();
});
canInitialized = (errorCode == 0);
if (canInitialized) {
Serial.printf("CAN configured: Arb=%d, Data=%d, FD=%s, Mode=%d\n",
arbitrationBaud, enableFD ? dataBaud : arbitrationBaud,
enableFD ? "enabled" : "disabled", mode);
}
return canInitialized;
}
void getCANStats(uint32_t& rx, uint32_t& tx, uint32_t& errors) {
rx = canRxCount;
tx = canTxCount;
errors = canErrorCount;
}