Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow registration of callbacks for CAN bus errors/warnings. #87

Merged
merged 13 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/MCP2515-CAN-Sniffer/MCP2515-CAN-Sniffer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ ArduinoMCP2515 mcp2515([]() { digitalWrite(MKRCAN_MCP2515_CS_PIN, LOW); },
[](uint8_t const d) { return SPI.transfer(d); },
micros,
onReceiveBufferFull,
nullptr);
nullptr,
[](MCP2515::EFLG const err_flag) { Serial.print("MCP2515::OnError, error code = "); Serial.println(MCP2515::toStr(err_flag)); },
[](MCP2515::EFLG const err_flag) { Serial.print("MCP2515::OnError, error code = "); Serial.println(MCP2515::toStr(err_flag)); });

/**************************************************************************************
* SETUP/LOOP
Expand Down
2 changes: 2 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
ArduinoMCP2515 KEYWORD1
CanBitRate KEYWORD1
MCP2515 KEYWORD1
EFLG KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
Expand All @@ -24,6 +25,7 @@ setConfigMode KEYWORD2
enableFilter KEYWORD2
transmit KEYWORD2
onExternalEventHandler KEYWORD2
toStr KEYWORD2

#######################################
# Constants (LITERAL1)
Expand Down
56 changes: 55 additions & 1 deletion src/ArduinoMCP2515.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,17 @@ ArduinoMCP2515::ArduinoMCP2515(SpiSelectFunc select,
SpiTransferFunc transfer,
MicroSecondFunc micros,
OnReceiveBufferFullFunc on_rx_buf_full,
OnTransmitBufferEmptyFunc on_tx_buf_empty)
OnTransmitBufferEmptyFunc on_tx_buf_empty,
OnCanErrorFunc on_error,
OnCanWarningFunc on_warning)
: _io{select, deselect, transfer}
, _cfg{_io}
, _ctrl{_io}
, _micros{micros}
, _on_rx_buf_full{on_rx_buf_full}
, _on_tx_buf_empty{on_tx_buf_empty}
, _on_error{on_error}
, _on_warning{on_warning}
{

}
Expand Down Expand Up @@ -121,6 +125,13 @@ void ArduinoMCP2515::begin()
_cfg.enableIntFlag(CANINTE::RX0IE);
_cfg.enableIntFlag(CANINTE::RX1IE);
}

/* Conditionally enable error interrupt
* only if we have error callbacks
* registered.
*/
if (_on_error || _on_warning)
_cfg.enableIntFlag(CANINTE::ERRIE);
}

void ArduinoMCP2515::setBitRate(CanBitRate const bit_rate)
Expand Down Expand Up @@ -164,13 +175,56 @@ bool ArduinoMCP2515::transmit(uint32_t const id, uint8_t const * data, uint8_t c

void ArduinoMCP2515::onExternalEventHandler()
{
/* Obtain current status and call the appropriate callback
* handlers to facilitate the necessary actions.
*/
uint8_t const status = _ctrl.status();

if(isBitSet(status, bp(STATUS::RX0IF))) onReceiveBuffer_0_Full();
if(isBitSet(status, bp(STATUS::RX1IF))) onReceiveBuffer_1_Full();
if(isBitSet(status, bp(STATUS::TX0IF))) onTransmitBuffer_0_Empty();
if(isBitSet(status, bp(STATUS::TX1IF))) onTransmitBuffer_1_Empty();
if(isBitSet(status, bp(STATUS::TX2IF))) onTransmitBuffer_2_Empty();


/* Only perform error checks if a callback has been
* registered. Otherwise, it's an unnecessary SPI
* transaction which consumes valuable processing
* time.
*/
if (!_on_error && !_on_warning)
return;

/* Check if an error flag is set and - should an error flag
* be set - deal with it.
*/
uint8_t const error_flag = _ctrl.error();

bool const is_error = (error_flag > EFLG_ERR_MASK) > 0;
if (is_error && _on_error)
{
_on_error(static_cast<EFLG>(error_flag & EFLG_ERR_MASK));

/* RX0OVR and RX1OVR need to be cleared manually,
* otherwise the error will persist and we will
* not be able to ever again obtain received
* CAN frames.
*/
if (isBitSet(error_flag, bp(EFLG::RX0OVR)))
_ctrl.clearErrFlag(EFLG::RX0OVR);

if (isBitSet(error_flag, bp(EFLG::RX1OVR)))
_ctrl.clearErrFlag(EFLG::RX1OVR);
}

bool const is_warning = (error_flag > EFLG_WAR_MASK) > 0;
if (is_warning && _on_warning)
_on_warning(static_cast<EFLG>(error_flag & EFLG_WAR_MASK));

/* Finally clear the error interrupt flag so that we are not
* continuously caught in the ERROR handling loop.
*/
_ctrl.clearIntFlag(CANINTF::ERRIF);
}

/**************************************************************************************
Expand Down
17 changes: 16 additions & 1 deletion src/ArduinoMCP2515.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ typedef std::function<void(uint32_t const, uint32_t const, uint8_t const *, uint
#endif
class ArduinoMCP2515;
typedef std::function<void(ArduinoMCP2515 *)> OnTransmitBufferEmptyFunc;
typedef std::function<void(MCP2515::EFLG const)> OnCanErrorFunc;
typedef std::function<void(MCP2515::EFLG const)> OnCanWarningFunc;

/**************************************************************************************
* CLASS DECLARATION
Expand All @@ -105,7 +107,18 @@ class ArduinoMCP2515
MCP2515::SpiTransferFunc transfer,
MicroSecondFunc micros,
OnReceiveBufferFullFunc on_rx_buf_full,
OnTransmitBufferEmptyFunc on_tx_buf_empty);
OnTransmitBufferEmptyFunc on_tx_buf_empty,
OnCanErrorFunc on_error,
OnCanWarningFunc on_warning);

ArduinoMCP2515(MCP2515::SpiSelectFunc select,
MCP2515::SpiDeselectFunc deselect,
MCP2515::SpiTransferFunc transfer,
MicroSecondFunc micros,
OnReceiveBufferFullFunc on_rx_buf_full,
OnTransmitBufferEmptyFunc on_tx_buf_empty)
: ArduinoMCP2515{select, deselect, transfer, micros, on_rx_buf_full, on_tx_buf_empty, nullptr, nullptr}
{ }


void begin();
Expand Down Expand Up @@ -137,6 +150,8 @@ class ArduinoMCP2515
MicroSecondFunc _micros;
OnReceiveBufferFullFunc _on_rx_buf_full;
OnTransmitBufferEmptyFunc _on_tx_buf_empty;
OnCanErrorFunc _on_error;
OnCanWarningFunc _on_warning;

bool transmitCANFrame (uint32_t const id, uint8_t const * data, uint8_t const len);
void onReceiveBuffer_0_Full ();
Expand Down
45 changes: 45 additions & 0 deletions src/MCP2515/MCP2515_Const.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* This software is distributed under the terms of the MIT License.
* Copyright (c) 2020 LXRobotics.
* Author: Alexander Entinger <[email protected]>
* Contributors: https://github.com/107-systems/107-Arduino-MCP2515/graphs/contributors.
*/

/**************************************************************************************
* INCLUDE
**************************************************************************************/

#include "MCP2515_Const.h"

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

namespace MCP2515
{

/**************************************************************************************
* FUNCTION DEFINITION
**************************************************************************************/

const char * toStr(EFLG const err_flag)
{
switch(err_flag)
{
case EFLG::RX1OVR: return "RX1OVR"; break;
case EFLG::RX0OVR: return "RX0OVR"; break;
case EFLG::TXBO : return "TXBO"; break;
case EFLG::TXEP : return "TXEP"; break;
case EFLG::RXEP : return "RXEP"; break;
case EFLG::TXWAR : return "TXWAR"; break;
case EFLG::RXWAR : return "RXWAR"; break;
case EFLG::EWARN : return "EWARN"; break;
default: __builtin_unreachable(); return ""; break;
}
}

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

} /* MCP2515 */
22 changes: 22 additions & 0 deletions src/MCP2515/MCP2515_Const.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ enum class STATUS : uint8_t

enum class CANINTE : uint8_t
{
ERRIE = 5,
TX2IE = 4,
TX1IE = 3,
TX0IE = 2,
Expand Down Expand Up @@ -222,6 +223,18 @@ enum class TXBnCTRL : uint8_t
TXREQ = 3,
};

enum class EFLG : uint8_t
{
RX1OVR = 7,
RX0OVR = 6,
TXBO = 5,
TXEP = 4,
RXEP = 3,
TXWAR = 2,
RXWAR = 1,
EWARN = 0,
};

/**************************************************************************************
* CONVERSION FUNCTIONS
**************************************************************************************/
Expand All @@ -238,6 +251,12 @@ constexpr auto bm(Enumeration const value) -> typename std::underlying_type<Enum
return (1 << bp(value));
}

/**************************************************************************************
* FUNCTION DECLARATION
**************************************************************************************/

const char * toStr(EFLG const err_flag);

/**************************************************************************************
* CONSTANTS
**************************************************************************************/
Expand All @@ -247,6 +266,9 @@ static uint8_t constexpr CANSTAT_OP_MASK = bm(CANSTAT::OPMOD2) | bm(CANSTAT::
static uint8_t constexpr RXB0CTRL_RXM_MASK = bm(RXB0CTRL::RXM1) | bm(RXB0CTRL::RXM0);
static uint8_t constexpr RXB1CTRL_RXM_MASK = bm(RXB1CTRL::RXM1) | bm(RXB1CTRL::RXM0);

static uint8_t constexpr EFLG_ERR_MASK = bm(EFLG::RX1OVR) | bm(EFLG::RX0OVR) | bm(EFLG::TXBO) | bm(EFLG::TXEP) | bm(EFLG::RXEP);
static uint8_t constexpr EFLG_WAR_MASK = bm(EFLG::TXWAR) | bm(EFLG::RXWAR) | bm(EFLG::EWARN);

static uint32_t constexpr CAN_EFF_BITMASK = 0x80000000;
static uint32_t constexpr CAN_RTR_BITMASK = 0x40000000;
static uint32_t constexpr CAN_ERR_BITMASK = 0x20000000;
Expand Down
4 changes: 4 additions & 0 deletions src/MCP2515/MCP2515_Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ void MCP2515_Control::receive(RxB const rxb, uint32_t & id, uint8_t * data, uint
memcpy(data, rx_buffer.reg.data, std::min<uint8_t>(len, 8));
}

uint8_t MCP2515_Control::error()
{
return _io.readRegister(Register::EFLG);
}

/**************************************************************************************
* NAMESPACE
Expand Down
10 changes: 6 additions & 4 deletions src/MCP2515/MCP2515_Control.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ class MCP2515_Control
MCP2515_Control(MCP2515_Io & io);


void transmit (TxB const txb, uint32_t const id, uint8_t const * data, uint8_t const len);
void receive (RxB const rxb, uint32_t & id, uint8_t * data, uint8_t & len);
void transmit(TxB const txb, uint32_t const id, uint8_t const * data, uint8_t const len);
void receive (RxB const rxb, uint32_t & id, uint8_t * data, uint8_t & len);

uint8_t error();

inline void reset () { _io.reset(); }
inline uint8_t status () { return _io.status(); }
inline void clearIntFlag(CANINTF const int_flag) { _io.clrBit(Register::CANINTF, bp(int_flag)); }

inline void clearIntFlag(CANINTF const int_flag) { _io.clrBit(Register::CANINTF, bp(int_flag)); }
inline void clearErrFlag(EFLG const err_flag) { _io.clrBit(Register::EFLG, bp(err_flag)); }

private:

Expand Down