reworked CAN Stack

This commit is contained in:
2025-08-24 21:49:09 +02:00
parent 3e69485696
commit c6d65f50bf
11 changed files with 721 additions and 447 deletions

240
Software/src/can_hal.cpp Normal file
View File

@@ -0,0 +1,240 @@
#include "can_hal.h"
#include "dtc.h"
// #include "debugger.h" // optional für Logs
// ==== Interner Zustand/Helper ====
MCP_CAN CAN0(GPIO_CS_CAN);
static bool s_ready = false;
static uint8_t s_nextFiltSlot = 0; // 0..5 (MCP2515 hat 6 Filter-Slots)
static uint16_t s_modeSettleMs = 10; // Default aus Config
// 11-bit: Lib erwartet (value << 16)
static inline uint32_t _std_to_hw(uint16_t v11) { return ((uint32_t)v11) << 16; }
// „Bestätigter“ Mode-Wechsel mithilfe der Lib-Funktion setMode(newMode)
// Viele Forks nutzen intern mcp2515_requestNewMode(); wir retryen kurz.
static bool _trySetMode(uint8_t mode, uint16_t settleMs)
{
const uint32_t t0 = millis();
do {
if (CAN0.setMode(mode) == CAN_OK) return true;
delay(1);
} while ((millis() - t0) < settleMs);
return false;
}
// LOOPBACK-Selftest (ohne Bus)
static bool _selftest_loopback(uint16_t windowMs)
{
if (!_trySetMode(MCP_LOOPBACK, s_modeSettleMs)) return false;
const unsigned long tid = 0x123;
uint8_t tx[8] = {0xA5, 0x5A, 0x11, 0x22, 0x33, 0x44, 0x77, 0x88};
if (CAN0.sendMsgBuf(tid, 0, 8, tx) != CAN_OK) {
(void)_trySetMode(MCP_NORMAL, s_modeSettleMs);
return false;
}
bool got = false;
const uint32_t t0 = millis();
while ((millis() - t0) < windowMs) {
if (CAN0.checkReceive() == CAN_MSGAVAIL) {
unsigned long rid; uint8_t len, rx[8];
if (CAN0.readMsgBuf(&rid, &len, rx) == CAN_OK) {
if (rid == tid && len == 8 && memcmp(tx, rx, 8) == 0) { got = true; break; }
}
}
delay(1);
}
(void)_trySetMode(MCP_NORMAL, s_modeSettleMs);
return got;
}
// Optional: kurzer ListenOnly-Hörtest (nur Heuristik, keine DTC-Änderung)
static void _probe_listen_only(uint16_t ms)
{
if (ms == 0) return;
if (!_trySetMode(MCP_LISTENONLY, s_modeSettleMs)) return;
const uint32_t t0 = millis();
while ((millis() - t0) < ms) {
if (CAN0.checkReceive() == CAN_MSGAVAIL) break;
delay(1);
}
(void)_trySetMode(MCP_NORMAL, s_modeSettleMs);
}
// ==== Öffentliche API ====
bool CAN_HAL_Init(const CanHalConfig& cfg)
{
s_ready = false;
s_modeSettleMs = cfg.modeSettleMs ? cfg.modeSettleMs : 10;
// 1) SPI/MCP starten
// HIER: MCP_STDEXT statt MCP_STD, damit die Lib nicht ins default/Failure läuft
if (CAN0.begin(MCP_STDEXT, cfg.baud, cfg.clock) != CAN_OK) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
// 2) LoopbackSelftest (ohne Bus)
if (!_selftest_loopback(20)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
// 3) Optional ListenOnlyProbe (nur Info)
_probe_listen_only(cfg.listenOnlyProbeMs);
// 4) Default: Filter/Masks neutral, Mode NORMAL
// -> Für Masken/Filter müssen wir in CONFIG sein (hier: MODE_CONFIG laut deiner Lib)
if (!_trySetMode(MODE_CONFIG, s_modeSettleMs)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
// weit offen (STD)
CAN0.init_Mask(0, 0, _std_to_hw(0x000));
CAN0.init_Mask(1, 0, _std_to_hw(0x000));
for (uint8_t i = 0; i < 6; ++i) {
CAN0.init_Filt(i, 0, _std_to_hw(0x000));
}
s_nextFiltSlot = 0;
if (!_trySetMode(MCP_NORMAL, s_modeSettleMs)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
// Erfolgreich
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, false);
s_ready = true;
return true;
}
bool CAN_HAL_IsReady() { return s_ready; }
bool CAN_HAL_SetMode(uint8_t mode)
{
const bool ok = _trySetMode(mode, s_modeSettleMs);
if (!ok) MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return ok;
}
bool CAN_HAL_SetMask(uint8_t bank, bool ext, uint32_t rawMask)
{
if (bank > 1) return false;
if (!CAN_HAL_SetMode(MODE_CONFIG)) return false;
const bool ok = (CAN0.init_Mask(bank, ext ? 1 : 0, rawMask) == CAN_OK);
if (!CAN_HAL_SetMode(MCP_NORMAL)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
return ok;
}
bool CAN_HAL_SetStdMask11(uint8_t bank, uint16_t mask11)
{
return CAN_HAL_SetMask(bank, false, _std_to_hw(mask11));
}
void CAN_HAL_ClearFilters()
{
if (!CAN_HAL_SetMode(MODE_CONFIG)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return;
}
CAN0.init_Mask(0, 0, _std_to_hw(0x000));
CAN0.init_Mask(1, 0, _std_to_hw(0x000));
for (uint8_t i = 0; i < 6; ++i) {
CAN0.init_Filt(i, 0, _std_to_hw(0x000));
}
s_nextFiltSlot = 0;
if (!CAN_HAL_SetMode(MCP_NORMAL)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
}
}
bool CAN_HAL_AddFilter(const CanFilter& f)
{
if (s_nextFiltSlot >= 6) return false;
if (!CAN_HAL_SetMode(MODE_CONFIG)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
const uint32_t hwId = f.ext ? f.id : _std_to_hw((uint16_t)f.id);
const uint8_t slot = s_nextFiltSlot++;
const bool ok = (CAN0.init_Filt(slot, f.ext ? 1 : 0, hwId) == CAN_OK);
if (!CAN_HAL_SetMode(MCP_NORMAL)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
return ok;
}
bool CAN_HAL_SetFilters(const CanFilter* list, size_t count)
{
if (!CAN_HAL_SetMode(MODE_CONFIG)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
// Slots zurücksetzen
s_nextFiltSlot = 0;
for (uint8_t i = 0; i < 6; ++i) {
CAN0.init_Filt(i, 0, _std_to_hw(0x000));
}
// Setzen
for (size_t i = 0; i < count && s_nextFiltSlot < 6; ++i) {
const auto& f = list[i];
const uint32_t hwId = f.ext ? f.id : _std_to_hw((uint16_t)f.id);
CAN0.init_Filt(s_nextFiltSlot++, f.ext ? 1 : 0, hwId);
}
if (!CAN_HAL_SetMode(MCP_NORMAL)) {
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
return true;
}
bool CAN_HAL_Read(unsigned long& id, uint8_t& len, uint8_t data[8])
{
if (CAN0.checkReceive() != CAN_MSGAVAIL) return false;
if (CAN0.readMsgBuf(&id, &len, data) != CAN_OK) {
// Echte Lese-Fehler -> vermutlich SPI/Controller-Problem
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
return false;
}
return true;
}
uint8_t CAN_HAL_Send(unsigned long id, bool ext, uint8_t len, const uint8_t* data)
{
// Sende-Fehler (CAN_FAILTX) müssen nicht zwingend Transceiver-Defekte sein (z. B. Bus-Off).
// Höhere Ebene kann bei Bedarf DTCs setzen. Hier nur durchreichen.
return CAN0.sendMsgBuf(id, ext ? 1 : 0, len, const_cast<uint8_t*>(data));
}
// ==== Diagnose/Utilities ====
uint8_t CAN_HAL_GetErrorFlags()
{
// getError() liefert MCP_EFLG Snapshot (Lib-abhängig)
return CAN0.getError();
}
void CAN_HAL_GetErrorCounters(uint8_t& tec, uint8_t& rec)
{
tec = CAN0.errorCountTX();
rec = CAN0.errorCountRX();
}