11#include "isobus/utility/system_timing.hpp"
12#include "isobus/utility/to_string.hpp"
20 transactionHandler(transactionHandler),
67 std::this_thread::sleep_for(std::chrono::milliseconds(10));
83 const std::vector<std::uint8_t> txBuffer = {
static_cast<std::uint8_t
>(MCPInstruction::READ_STATUS), 0x00 };
100 const std::vector<std::uint8_t> txBuffer = {
static_cast<std::uint8_t
>(MCPInstruction::READ),
101 static_cast<std::uint8_t
>(address),
121 std::vector<std::uint8_t> txBuffer(2 + length, 0x00);
122 txBuffer[0] =
static_cast<std::uint8_t
>(MCPInstruction::READ);
123 txBuffer[1] =
static_cast<std::uint8_t
>(address);
141 const std::vector<std::uint8_t> txBuffer = {
static_cast<std::uint8_t
>(MCPInstruction::BITMOD),
142 static_cast<std::uint8_t
>(address),
158 const std::vector<std::uint8_t> txBuffer = {
static_cast<std::uint8_t
>(MCPInstruction::RESET) };
172 const std::vector<std::uint8_t> txBuffer = {
static_cast<std::uint8_t
>(MCPInstruction::WRITE),
173 static_cast<std::uint8_t
>(address),
188 std::vector<std::uint8_t> txBuffer(2 + length, 0x00);
189 txBuffer[0] =
static_cast<std::uint8_t
>(MCPInstruction::WRITE);
190 txBuffer[1] =
static_cast<std::uint8_t
>(address);
191 memcpy(txBuffer.data() + 2, data, length);
204 if (
modify_register(MCPRegister::CANCTRL, 0xE0,
static_cast<std::uint8_t
>(mode)))
207 const auto start = isobus::SystemTiming::get_timestamp_ms();
208 while (isobus::SystemTiming::get_time_elapsed_ms(start) < 10)
210 std::uint8_t newMode;
213 if ((newMode & 0xE0) ==
static_cast<std::uint8_t
>(mode))
227 const std::uint8_t intfMask)
231 std::uint8_t buffer[6];
234 canFrame.
identifier = (buffer[1] << 3) + (buffer[2] >> 5);
236 if (0x08 == (buffer[2] & 0x08))
244 std::uint8_t ctrl = buffer[0];
274 if (status & 0x01 &&
rxIndex == 0)
276 retVal =
read_frame(canFrame, MCPRegister::RXB0CTRL, MCPRegister::RXB0DATA, 0x01);
284 else if (status & 0x02)
286 retVal =
read_frame(canFrame, MCPRegister::RXB1CTRL, MCPRegister::RXB1DATA, 0x02);
291 std::this_thread::sleep_for(std::chrono::milliseconds(6));
307 if ((ctrl & 0x08) == 0)
310 if (0 != (ctrl & (0x40 | 0x10)))
312 LOG_ERROR(
"[MCP2515] Failed to send last message, please verify your connection/setup:");
313 if (0 != (ctrl & 0x40))
315 LOG_ERROR(
"\t- Message was aborted.");
317 if (0 != (ctrl & 0x10))
319 LOG_ERROR(
"\t- A bus error occurred while the message was being transmitted.");
324 std::uint8_t buffer[13];
327 buffer[3] =
static_cast<std::uint8_t
>(canFrame.
identifier & 0xFF);
328 buffer[2] =
static_cast<std::uint8_t
>((canFrame.
identifier >> 8) & 0xFF);
329 buffer[1] =
static_cast<std::uint8_t
>((canFrame.
identifier >> 16) & 0x03);
330 buffer[1] |=
static_cast<std::uint8_t
>((canFrame.
identifier >> 13) & 0xE0);
332 buffer[0] =
static_cast<std::uint8_t
>((canFrame.
identifier >> 21) & 0xFF);
336 buffer[1] =
static_cast<std::uint8_t
>((canFrame.
identifier << 5) & 0xE0);
337 buffer[0] =
static_cast<std::uint8_t
>(canFrame.
identifier >> 3);
353 LOG_WARNING(
"[MCP2515] Failed to send message, buffer is not empty.");
363 std::uint8_t retries = 100;
365 while (!retVal && retries > 0)
368 if (0 == (status & 0x04) &&
txIndex == 0)
370 retVal =
write_frame(canFrame, MCPRegister::TXB0CTRL, MCPRegister::TXB0SIDH);
376 else if (0 == (status & 0x10) &&
txIndex == 1)
378 retVal =
write_frame(canFrame, MCPRegister::TXB1CTRL, MCPRegister::TXB1SIDH);
384 else if (0 == (status & 0x40) &&
txIndex == 2)
386 if (status & (0x10 | 0x04))
400 retVal =
write_frame(canFrame, MCPRegister::TXB2CTRL, MCPRegister::TXB2SIDH);
411 LOG_ERROR(
"[MCP2515] Failed to send message, buffer has been full for too long.");
A class that acts as a logging sink. The intent is that someone could make their own derived class of...
A CAN frame for interfacing with a hardware layer, like socket CAN or other interface.
std::uint8_t dataLength
The length of the data used in the frame.
std::uint32_t identifier
The 32 bit identifier of the frame.
bool isExtendedFrame
Denotes if the frame is extended format.
std::uint8_t data[8]
The data payload of the frame.
std::uint8_t rxIndex
The index of the rx buffer to read from next.
bool reset()
Resets the MCP2515.
bool write_frame(const isobus::CANMessageFrame &canFrame) override
Writes a frame to the bus (synchronous)
bool write_register(const MCPRegister address, const std::uint8_t data)
write a single byte register of the mcp2515
MCPMode
The different modes of the MCP2515 associated with their internal bits.
MCPRegister
Some essential registers of the MCP2515.
const std::uint8_t cfg2
Configuration value for CFG2 register.
void close() override
Closes the socket.
bool write_reset()
Reset the mcp2515 internally.
const std::uint8_t cfg1
Configuration value for CFG1 register.
std::uint8_t txIndex
The index of the tx buffer to write to next, start with 2 as it is the buffer with the highest priori...
std::uint8_t txPriority
The priority of the next tx frame.
bool get_is_valid() const override
Returns if the socket connection is valid.
const std::uint8_t cfg3
Configuration value for CFG3 register.
bool read_register(const MCPRegister address, std::uint8_t &data)
read a single byte register of the mcp2515
bool set_mode(const MCPMode mode)
set the mode of the mcp2515
bool modify_register(const MCPRegister address, const std::uint8_t mask, const std::uint8_t data)
modify a register of the mcp2515
virtual ~MCP2515CANInterface()
The destructor for SocketCANInterface.
bool read_frame(isobus::CANMessageFrame &canFrame) override
Returns a frame from the hardware (synchronous), or false if no frame can be read.
SPIHardwarePlugin * transactionHandler
The SPI transaction handler.
bool get_read_status(std::uint8_t &status)
Read the rx status of the mcp2515.
MCP2515CANInterface(SPIHardwarePlugin *transactionHandler, const std::uint8_t cfg1, const std::uint8_t cfg2, const std::uint8_t cfg3)
Constructor for the socket CAN driver.
void open() override
Connects to the socket.
bool initialized
If the mcp2515 has been initialized and no errors have occurred.
An abstract base class for SPI communication.
virtual void transmit(SPITransactionFrame *frame)=0
Write a frame to the SPI bus. This should only be called after begin_transaction()....
virtual void begin_transaction()
Begin a transaction on the SPI bus. This should be called before any of the read/write operations.
virtual bool end_transaction()=0
End a transaction on the SPI bus. This must be called after all write operations and before any read ...
A class containing the data for a single SPI transaction.
bool read_byte(std::size_t index, std::uint8_t &byte) const
Read a byte from the response buffer.
bool read_bytes(std::size_t index, std::uint8_t *buffer, std::size_t length) const
Read multiple bytes from the response buffer.
An interface for using the MCP2515 can controller.
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...
constexpr std::uint8_t CAN_DATA_LENGTH
The length of a classical CAN frame.