Merged i2c-helper in Main

This commit is contained in:
AlexanderHD27
2025-01-12 00:16:00 +01:00
parent f4792de050
commit b5c7e5b4c1
396 changed files with 182143 additions and 14 deletions

View File

@@ -0,0 +1,10 @@
idf_component_register(SRCS
"gobot_rpc_sender.cpp"
"gobot_rpc_receiver.cpp"
"gobot_rpc_statemaschine.cpp"
"gobot_rpc_numberMap.cpp"
"gobot_rpc_transiver.cpp"
REQUIRES mcp2521
REQUIRES mcp2521_hardware_interface
REQUIRES driver
INCLUDE_DIRS "include")

View File

@@ -0,0 +1,19 @@
#include "gobot_rpc.hpp"
#include "protocol_spec.hpp"
#include <string.h>
GobotRPCNumberMap::GobotRPCNumberMap() {
memset(rpc_number_map, 0xffffffff, 16);
}
GobotRPCNumberMap::~GobotRPCNumberMap() {
}
void GobotRPCNumberMap::set(RpcNum rpc_num, uint32_t id) {
rpc_number_map[(int)rpc_num] = id;
}
uint32_t GobotRPCNumberMap::get(RpcNum rpc_num) {
return rpc_number_map[(int)rpc_num];
}

View File

@@ -0,0 +1,43 @@
#include <string.h>
#include "gobot_rpc.hpp"
#include "sm.hpp"
#include "protocol_spec.hpp"
#include "freertos/FreeRTOS.h"
GobotRPCReciver::GobotRPCReciver(MCP2521 * can_interface) {
this->can_interface = can_interface;
this->state_mashine = GobotRPCStateMashine();
can_interface->register_rx0_handler(onRX0_GoboRPC, can_interface);
}
void onRX0_GoboRPC(void *arg) {
GobotRPCReciver *rpc_socket = (GobotRPCReciver *)arg;
rpc_socket->onRX();
}
void GobotRPCReciver::onRX() {
rx_info info = can_interface->get_rx_id(MCP2521_RX_BUFFER::RXB0);
uint8_t data[8];
can_interface->read_rx_buf(MCP2521_RX_BUFFER::RXB0, MCP2521_BUFFER_TYPE::DATA, data, info.length);
RPCFrame frame;
memcpy(((char *)data) + 1, (char *)frame.data, 7);
frame.header = (RPCHeader)(data[0]);
SMResult smResult;
state_mashine.submitFrame(&frame, &smResult);
if(smResult.done) {
}
}
void GobotRPCReciver::registerOnDoneFrameHandler(GobotRPCHandler_t handler, void * arg) {
onDoneFrameHandler = handler;
argOnDoneFrameHandler = arg;
}

View File

@@ -0,0 +1,74 @@
#include "sm.hpp"
#include "protocol_spec.hpp"
#include <string.h>
GobotRPCStateMashine::GobotRPCStateMashine() {
memset(requestDataBuffer, 0, REQUEST_DATA_BUFFER_SIZE*sizeof(uint8_t)*SLOTS);
memset(responseDataBuffer, 0, RESPONSE_DATA_BUFFER_SIZE*sizeof(uint8_t)*SLOTS);
memset(errorDataBuffer, 0, RESPONSE_DATA_BUFFER_SIZE*sizeof(uint8_t)*SLOTS);
memset(requestSegmentArrivedFlags, 0, sizeof(uint8_t)*SLOTS);
memset(responseSegmentArrivedFlags, 0, sizeof(uint8_t)*SLOTS);
memset(errorSegmentArrivedFlags, 0, sizeof(uint8_t)*SLOTS);
slotCounter = 0;
rpc_number_map = GobotRPCNumberMap();
}
void GobotRPCStateMashine::registerRPC(RpcNum rpc_num) {
rpc_number_map.set(rpc_num, slotCounter);
slotCounter = (slotCounter + 1) % SLOTS;
}
void GobotRPCStateMashine::submitFrame(RPCFrame * frame, SMResult * result) {
RpcNum rpcNum = (RpcNum)(frame->header.rpc_num);
result->done = false;
result->rpc_num = rpcNum;
if(rpcNum == RpcNum::INVALID)
return;
size_t slot = rpc_number_map.get(rpcNum);
if (slot == 0xffffffff)
return;
uint8_t segNum = frame->header.rpc_segement;
if(frame->header.error) {
memcpy(result->data, frame->data, 7);
errorSegmentArrivedFlags[slot] |= (1 << segNum);
result->done = true;
result->type = RPCPackageType::ERROR;
} else if(frame->header.response) {
memcpy(responseDataBuffer[slot] + segNum, frame->data, 7);
responseSegmentArrivedFlags[slot] |= (1 << segNum);
uint8_t mask = SEGMENT_MASK_RESPONSE[(int)rpcNum];
if(((responseSegmentArrivedFlags[slot] & mask) ^ mask) == 0) {
responseSegmentArrivedFlags[slot] = 0;
result->done = true;
memcpy(result->data, responseDataBuffer[slot], 7*4);
result->type = RPCPackageType::RESPONSE;
}
} else {
memcpy(requestDataBuffer[slot] + segNum, frame->data, 7);
requestSegmentArrivedFlags[slot] |= (1 << segNum);
uint8_t mask = SEGMENT_MASK_RESPONSE[(int)rpcNum];
if(((requestSegmentArrivedFlags[slot] & mask) ^ mask) == 0) {
requestSegmentArrivedFlags[slot] = 0;
result->done = true;
memcpy(result->data, requestDataBuffer[slot], 7*4);
result->type = RPCPackageType::REQUEST;
}
}
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include "protocol_spec.hpp"
#include "mcp2521.hpp"
#include "sm.hpp"
#include "freertos/FreeRTOS.h"
typedef void (*GobotRPCHandler_t)(void *);
typedef void (*GobotRPCFrameHandler)(void *, RPCFrame *);
class GobotRPCReciver {
protected:
MCP2521 * can_interface;
GobotRPCStateMashine state_mashine;
GobotRPCHandler_t onDoneFrameHandler;
void * argOnDoneFrameHandler;
public:
GobotRPCReciver(MCP2521 * can_interface);
~GobotRPCReciver();
void onRX();
void registerOnDoneFrameHandler(GobotRPCHandler_t handler, void * arg);
};
void onRX0_GoboRPC(void *arg);
class GoboRPCTransiver {
private:
MCP2521 * can_interface;
GobotRPCReciver rx;
GobotRPCHandler_t onRequestHandler;
GobotRPCHandler_t onResponseHandler;
GobotRPCHandler_t onResponseErrorHandler;
void * argOnRequestHandler;
void * argOnResponseHandler;
void * argOnResponseErrorHandler;
public:
GoboRPCTransiver(MCP2521 * can_interface);
~GoboRPCTransiver();
void send(RPCFrame * frame);
void registerOnRequestHandler(GobotRPCHandler_t handler, void * arg);
void registerOnResponseHandler(GobotRPCHandler_t handler, void * arg);
void registerOnResponseErrorHandler(GobotRPCHandler_t handler, void * arg);
};

View File

@@ -0,0 +1,123 @@
#pragma once
#include <stdint.h>
enum RpcNum {
Get_Info = 0x0,
Home = 0x1,
Move_Step = 0x2,
Move_XY = 0x3,
Set_Padding = 0x4,
Release_Motors = 0x5,
Drop_Stones = 0x6,
Get_Stone_Status = 0x7,
Mov_Z_Axis = 0x8,
Set_Vacum = 0x9,
INVALID = 0xF,
};
struct RPCHeader {
unsigned char rpc_num : 4;
unsigned char response : 1;
unsigned char error : 1;
unsigned char rpc_segement : 1;
};
struct RPCFrame {
RPCHeader header;
uint8_t data[7];
};
enum RPC_Node_Type {
NODE_ALL = 0x0,
NODE_CORE_XY = 0x1,
NODE_HEAD = 0x2,
NODE_VACUM = 0x3,
};
// RPC Request and Response structures
struct RPC_RES_Get_Info {
uint32_t can_address;
RPC_Node_Type node_type;
uint32_t status;
uint32_t error;
};
enum RPC_Home_Corner {
HOME_CORNER_0 = 0b00,
HOME_CORNER_1 = 0b01,
HOME_CORNER_2 = 0b10,
HOME_CORNER_3 = 0b11,
};
struct RPC_REQ_Home {
RPC_Home_Corner corner;
};
struct RPC_RES_Home {
uint32_t x;
uint32_t y;
};
struct RPC_REQ_Move_Step {
int32_t x;
int32_t y;
};
struct RPC_RES_Move_Step {
uint32_t x;
uint32_t y;
};
struct RPC_REQ_Set_Padding {
uint32_t c_1x;
uint32_t c_1y;
uint32_t c_2x;
uint32_t c_2y;
uint8_t n_x;
uint8_t n_y;
};
struct RPC_REQ_Move_Z_Axis {
bool up;
};
struct RPC_REQ_Set_Vacum {
bool on;
};
// Segment3, Segment2, Segment1, Segment0
const uint8_t SEGMENT_MASK_REQUEST[16] = {
0b0001, // Get_Info
0b0001, // Home
0b0001, // Move_Step
0b0001, // Move_XY
0b0111, // Set_Padding
0b0001, // Release_Motors
0b0001, // Drop_Stones
0b0001, // Get_Stone_Status
0b0001, // Mov_Z_Axis
0b0001, // Set_Vacum
0b0001, //
0b0001, //
0b0001, //
0b0001, //
0b0001, //
};
const uint8_t SEGMENT_MASK_RESPONSE[16] = {
0b0001, // Get_Info
0b0001, // Home
0b0001, // Move_Step
0b0001, // Move_XY
0b0001, // Set_Padding
0b0001, // Release_Motors
0b0001, // Drop_Stones
0b0001, // Get_Stone_Status
0b0001, // Mov_Z_Axis
0b0001, // Set_Vacum
0b0001, //
0b0001, //
0b0001, //
0b0001, //
0b0001, //
};

View File

@@ -0,0 +1,58 @@
#pragma once
#include <stdint.h>
#include "protocol_spec.hpp"
#include <strings.h>
class GobotRPCNumberMap {
private:
int32_t rpc_number_map[16];
public:
GobotRPCNumberMap();
~GobotRPCNumberMap();
void set(RpcNum rpc_num, uint32_t id);
uint32_t get(RpcNum rpc_num);
};
enum RPCPackageType {
REQUEST,
RESPONSE,
ERROR
};
struct SMResult {
bool done;
uint8_t data[7*4];
RpcNum rpc_num;
RPCPackageType type;
};
class GobotRPCStateMashine {
private:
static const size_t SLOTS = 6;
static const size_t REQUEST_DATA_BUFFER_SIZE = 7*4;
static const size_t RESPONSE_DATA_BUFFER_SIZE = 7*4;
GobotRPCNumberMap rpc_number_map;
size_t slotCounter;
uint8_t requestDataBuffer[REQUEST_DATA_BUFFER_SIZE][SLOTS];
bool requestSegmentArrivedFlags [SLOTS];
uint8_t responseDataBuffer[RESPONSE_DATA_BUFFER_SIZE][SLOTS];
uint8_t responseSegmentArrivedFlags [SLOTS];
uint8_t errorDataBuffer[RESPONSE_DATA_BUFFER_SIZE][SLOTS];
uint8_t errorSegmentArrivedFlags [SLOTS];
public:
GobotRPCStateMashine();
~GobotRPCStateMashine();
void registerRPC(RpcNum rpc_num);
void submitFrame(RPCFrame * frame, SMResult * result);
};

View File

@@ -0,0 +1,8 @@
idf_component_register(SRCS
"interface_commands.cpp"
"interface_interrupts.cpp"
"toplevel_commands.cpp"
INCLUDE_DIRS "include"
REQUIRES driver
REQUIRES mcp2521_hardware_interface
)

View File

View File

@@ -0,0 +1,102 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17">
<diagram name="Page-1" id="FmQN2vLuPXQQGOlHbBG4">
<mxGraphModel dx="1434" dy="838" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="xzzxaMGRirp7Gwq30BhV-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;endArrow=diamondThin;endFill=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-1" target="xzzxaMGRirp7Gwq30BhV-18" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-1" value="«interface»&lt;br&gt;&lt;font face=&quot;Courier New&quot;&gt;&lt;b&gt;I_MCP2521_&lt;/b&gt;&lt;b&gt;HardwareHandle&lt;/b&gt;&lt;/font&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="120" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-9" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_HardwareHandle_ESP&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="230" y="260" width="250" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-11" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_&lt;/font&gt;&lt;/b&gt;&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;HardwareHandle_ESPBus&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="230" y="200" width="250" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-12" value="" style="endArrow=none;dashed=1;html=1;rounded=0;exitX=1;exitY=1;exitDx=0;exitDy=0;strokeWidth=1;dashPattern=1 1;" parent="1" source="xzzxaMGRirp7Gwq30BhV-14" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1060" y="320" as="sourcePoint" />
<mxPoint x="120" y="320" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-14" value="SPI - Hardware Level" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="760" y="280" width="160" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-15" value="" style="endArrow=block;html=1;rounded=0;dashed=1;endFill=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-11" target="xzzxaMGRirp7Gwq30BhV-1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="590" y="290" as="sourcePoint" />
<mxPoint x="640" y="240" as="targetPoint" />
<Array as="points">
<mxPoint x="570" y="220" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-16" value="" style="endArrow=block;html=1;rounded=0;dashed=1;endFill=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-9" target="xzzxaMGRirp7Gwq30BhV-1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="520" y="280" as="sourcePoint" />
<mxPoint x="580" y="250" as="targetPoint" />
<Array as="points">
<mxPoint x="620" y="280" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-17" value="MCP2521 - Device Level" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="760" y="388" width="160" height="32" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-18" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_CommandInterface&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="340" width="200" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-19" value="&lt;b&gt;MCP2521&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="420" width="200" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-20" value="" style="endArrow=block;html=1;rounded=0;endFill=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-19" target="xzzxaMGRirp7Gwq30BhV-18" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="670" y="544" as="sourcePoint" />
<mxPoint x="720" y="494" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.746;entryY=0.064;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-22" target="xzzxaMGRirp7Gwq30BhV-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-24" value="creates" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="xzzxaMGRirp7Gwq30BhV-23" vertex="1" connectable="0">
<mxGeometry x="-0.3135" y="1" relative="1" as="geometry">
<mxPoint x="16" y="1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-22" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_HardwareHandleFactory_ESPBus&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="180" y="120" width="300" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-25" value="" style="endArrow=none;dashed=1;html=1;rounded=0;exitX=1;exitY=1;exitDx=0;exitDy=0;strokeWidth=1;dashPattern=1 1;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="920" y="480" as="sourcePoint" />
<mxPoint x="120" y="480" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-26" value="Network Stack" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="760" y="480" width="160" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-27" value="&lt;b&gt;Socket_CANTP&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="500" width="200" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-28" value="&lt;b&gt;Socket_GoBotRPC&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="580" width="200" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;endArrow=diamondThin;endFill=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" target="xzzxaMGRirp7Gwq30BhV-27" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="619.76" y="460" as="sourcePoint" />
<mxPoint x="640" y="520" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;endArrow=diamondThin;endFill=0;" parent="1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="619.5799999999999" y="540" as="sourcePoint" />
<mxPoint x="619.9699999999999" y="580" as="targetPoint" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,93 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17">
<diagram name="Page-1" id="FmQN2vLuPXQQGOlHbBG4">
<mxGraphModel dx="1195" dy="698" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="xzzxaMGRirp7Gwq30BhV-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;endArrow=diamondThin;endFill=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-1" target="xzzxaMGRirp7Gwq30BhV-18" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-1" value="«interface»&lt;br&gt;&lt;font face=&quot;Courier New&quot;&gt;&lt;b&gt;I_MCP2521_&lt;/b&gt;&lt;b&gt;HardwareHandle&lt;/b&gt;&lt;/font&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="120" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-9" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_HardwareHandle_ESP&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="230" y="260" width="250" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-11" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_&lt;/font&gt;&lt;/b&gt;&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;HardwareHandle_ESPBus&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="230" y="200" width="250" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-12" value="" style="endArrow=none;dashed=1;html=1;rounded=0;exitX=1;exitY=1;exitDx=0;exitDy=0;strokeWidth=1;dashPattern=1 1;" parent="1" source="xzzxaMGRirp7Gwq30BhV-14" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1060" y="320" as="sourcePoint" />
<mxPoint x="120" y="320" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-14" value="SPI - Hardware Level" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="760" y="280" width="160" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-15" value="" style="endArrow=block;html=1;rounded=0;dashed=1;endFill=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-11" target="xzzxaMGRirp7Gwq30BhV-1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="590" y="290" as="sourcePoint" />
<mxPoint x="640" y="240" as="targetPoint" />
<Array as="points">
<mxPoint x="570" y="220" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-16" value="" style="endArrow=block;html=1;rounded=0;dashed=1;endFill=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-9" target="xzzxaMGRirp7Gwq30BhV-1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="520" y="280" as="sourcePoint" />
<mxPoint x="580" y="250" as="targetPoint" />
<Array as="points">
<mxPoint x="620" y="280" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-17" value="MCP2521 - Device Level" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="760" y="388" width="160" height="32" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-18" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_CommandInterface&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="340" width="200" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-19" value="&lt;b&gt;MCP2521&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="420" width="200" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-20" value="" style="endArrow=block;html=1;rounded=0;endFill=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-19" target="xzzxaMGRirp7Gwq30BhV-18" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="670" y="544" as="sourcePoint" />
<mxPoint x="720" y="494" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.746;entryY=0.064;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="xzzxaMGRirp7Gwq30BhV-22" target="xzzxaMGRirp7Gwq30BhV-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-24" value="creates" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="xzzxaMGRirp7Gwq30BhV-23" vertex="1" connectable="0">
<mxGeometry x="-0.3135" y="1" relative="1" as="geometry">
<mxPoint x="16" y="1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-22" value="&lt;b&gt;&lt;font face=&quot;Courier New&quot;&gt;MCP2521_HardwareHandleFactory_ESPBus&lt;/font&gt;&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="180" y="120" width="300" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-25" value="" style="endArrow=none;dashed=1;html=1;rounded=0;exitX=1;exitY=1;exitDx=0;exitDy=0;strokeWidth=1;dashPattern=1 1;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="920" y="480" as="sourcePoint" />
<mxPoint x="120" y="480" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-26" value="Network Stack" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="760" y="480" width="160" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-28" value="&lt;b&gt;Socket_GoBotRPC&lt;/b&gt;" style="html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="520" y="500" width="200" height="40" as="geometry" />
</mxCell>
<mxCell id="xzzxaMGRirp7Gwq30BhV-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;endArrow=diamondThin;endFill=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" target="xzzxaMGRirp7Gwq30BhV-28" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="619.76" y="460" as="sourcePoint" />
<mxPoint x="620" y="500" as="targetPoint" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,177 @@
#pragma once
#include <cstdint>
/**
* @brief RXnBF PIN CONTROL AND STATUS REGISTER (ADDRESS: 0Ch)
*
*/
struct BFPCTRL {
uint8_t B0BFM : 1;
uint8_t B1BFM : 1;
uint8_t B0BFE : 1;
uint8_t B1BFE : 1;
uint8_t B0BFS : 1;
uint8_t B1BFS : 1;
uint8_t : 2;
};
/**
* @brief TXnRTS PIN CONTROL AND STATUS REGISTER
*
*/
struct TXRTSCTRL {
uint8_t B0RTSM : 1;
uint8_t B1RTSM : 1;
uint8_t B2RTSM : 1;
uint8_t B0RTS : 1;
uint8_t B1RTS : 1;
uint8_t B2RTS : 1;
uint8_t : 2;
};
struct CANSTAT {
uint8_t ICOD0 : ;
uint8_t : 1;
uint8_t OPMOD0 : 1;
uint8_t OPMOD1 : 1;
uint8_t OPMOD2 : 1;
uint8_t : 1;
};
struct CANCTRL {
uint8_t CLKPRE0 : 1;
uint8_t CLKPRE1 : 1;
uint8_t CLKEN : 1;
uint8_t OSM : 1;
uint8_t ABAT : 1;
uint8_t REQOP0 : 1;
uint8_t REQOP1 : 1;
uint8_t REQOP2 : 1;
};
struct TEC {
uint8_t TEC;
};
struct REC {
uint8_t REC;
};
struct CNF3 {
uint8_t PHSEG20 : 1;
uint8_t PHSEG21 : 1;
uint8_t PHSEG22 : 1;
uint8_t : 3;
uint8_t WAKFIL : 1;
uint8_t SOF : 1;
};
struct CNF2 {
uint8_t PRSEG0 : 1;
uint8_t PRSEG1 : 1;
uint8_t PRSEG2 : 1;
uint8_t PHSEG10 : 1;
uint8_t PHSEG11 : 1;
uint8_t PHSEG12 : 1;
uint8_t SAM : 1;
uint8_t BTLMODE : 1;
};
struct CNF1 {
uint8_t BRP0 : 1;
uint8_t BRP1 : 1;
uint8_t BRP2 : 1;
uint8_t BRP3 : 1;
uint8_t BRP4 : 1;
uint8_t BRP5 : 1;
uint8_t SJW0 : 1;
uint8_t SJW1 : 1;
};
struct CANINTE {
uint8_t RX0IE : 1;
uint8_t RX1IE : 1;
uint8_t TX0IE : 1;
uint8_t TX1IE : 1;
uint8_t TX2IE : 1;
uint8_t ERRIE : 1;
uint8_t WAKIE : 1;
uint8_t MERRE : 1;
};
struct CANINTF {
uint8_t RX0IF : 1;
uint8_t RX1IF : 1;
uint8_t TX0IF : 1;
uint8_t TX1IF : 1;
uint8_t TX2IF : 1;
uint8_t ERRIF : 1;
uint8_t WAKIF : 1;
uint8_t MERRF : 1;
};
struct EFLG {
uint8_t EWARN : 1;
uint8_t RXWAR : 1;
uint8_t TXWAR : 1;
uint8_t RXEP : 1;
uint8_t TXEP : 1;
uint8_t TXBO : 1;
uint8_t RX0OVR : 1;
uint8_t RX1OVR : 1;
};
struct TXB0CTRL {
uint8_t TXP0 : 1;
uint8_t TXP1 : 1;
uint8_t : 1;
uint8_t TXREQ : 1;
uint8_t TXERR : 1;
uint8_t MLOA : 1;
uint8_t ABTF : 1;
uint8_t : 1;
};
struct TXB1CTRL {
uint8_t TXP0 : 1;
uint8_t TXP1 : 1;
uint8_t : 1;
uint8_t TXREQ : 1;
uint8_t TXERR : 1;
uint8_t MLOA : 1;
uint8_t ABTF : 1;
uint8_t : 1;
};
struct TXB2CTRL {
uint8_t TXP0 : 1;
uint8_t TXP1 : 1;
uint8_t : 1;
uint8_t TXREQ : 1;
uint8_t TXERR : 1;
uint8_t MLOA : 1;
uint8_t ABTF : 1;
uint8_t : 1;
};
struct RXB0CTRL {
uint8_t FILHIT0 : 1;
uint8_t BUKT1 : 1;
uint8_t BUKT : 1;
uint8_t RXRTR : 1;
uint8_t : 1;
uint8_t RXM0 : 1;
uint8_t RXM1 : 1;
uint8_t : 1;
};
struct RXB1CTRL {
uint8_t FILHIT0 : 1;
uint8_t FILHIT1 : 1;
uint8_t FILHIT2 : 1;
uint8_t RXRTR : 1;
uint8_t : 1;
uint8_t RXM0 : 1;
uint8_t RXM1 : 1;
uint8_t : 1;
};

View File

@@ -0,0 +1,7 @@
#pragma once
#include "mcp2521_toplevel.hpp"
#include "mcp2521_command.hpp"
#include "mcp2521_hardware_esp.hpp"
#include "mcp2521_hardware_esp_bus_factory.hpp"
#include "mcp2521_addresses.hpp"

View File

@@ -0,0 +1,192 @@
#pragma once
#include <stdint.h>
#define MCP2521_BFPCTRL 0x0C
#define MCP2521_BFPCTRL_B1BFS (1 << 5)
#define MCP2521_BFPCTRL_B0BFS (1 << 4)
#define MCP2521_BFPCTRL_B1BFE (1 << 3)
#define MCP2521_BFPCTRL_B0BFE (1 << 2)
#define MCP2521_BFPCTRL_B1BFM (1 << 1)
#define MCP2521_BFPCTRL_B0BFM (1 << 0)
#define MCP2521_TXRTSCTRL 0x0D
#define MCP2521_TXRTSCTRL_B2RTS (1 << 5)
#define MCP2521_TXRTSCTRL_B1RTS (1 << 4)
#define MCP2521_TXRTSCTRL_B0RTS (1 << 3)
#define MCP2521_TXRTSCTRL_B2RTSM (1 << 2)
#define MCP2521_TXRTSCTRL_B1RTSM (1 << 1)
#define MCP2521_TXRTSCTRL_B0RTSM (1 << 0)
#define MCP2521_CANSTAT 0x0E
#define MCP2521_CANSTAT_OPMOD2 (1 << 7)
#define MCP2521_CANSTAT_OPMOD1 (1 << 6)
#define MCP2521_CANSTAT_OPMOD0 (1 << 5)
#define MCP2521_CANSTAT_ICOD2 (1 << 2)
#define MCP2521_CANSTAT_ICOD1 (1 << 1)
#define MCP2521_CANSTAT_ICOD0 (1 << 0)
struct CANSTAT_Register {
uint8_t ICOD : 3;
uint8_t : 1; // Unused bit
uint8_t OPMOD : 3;
uint8_t : 1; // Unused bit
};
#define MCP2521_CANCTRL 0x0F
#define MCP2521_CANCTRL_REQOP2 (1 << 7)
#define MCP2521_CANCTRL_REQOP1 (1 << 6)
#define MCP2521_CANCTRL_REQOP0 (1 << 5)
#define MCP2521_CANCTRL_ABAT (1 << 4)
#define MCP2521_CANCTRL_OSM (1 << 3)
#define MCP2521_CANCTRL_CLKEN (1 << 2)
#define MCP2521_CANCTRL_CLKPRE1 (1 << 1)
#define MCP2521_CANCTRL_CLKPRE0 (1 << 0)
#define MCP2521_TEC 0x1C
#define MCP2521_REC 0x1D
#define MCP2521_CNF3 0x28
#define MCP2521_CNF3_SOF (1 << 7)
#define MCP2521_CNF3_WAKFIL (1 << 6)
#define MCP2521_CNF3_PHSEG22 (1 << 2)
#define MCP2521_CNF3_PHSEG21 (1 << 1)
#define MCP2521_CNF3_PHSEG20 (1 << 0)
#define MCP2521_CNF2 0x29
#define MCP2521_CNF2_BTLMODE (1 << 7)
#define MCP2521_CNF2_SAM (1 << 6)
#define MCP2521_CNF2_PHSEG12 (1 << 5)
#define MCP2521_CNF2_PHSEG11 (1 << 4)
#define MCP2521_CNF2_PHSEG10 (1 << 3)
#define MCP2521_CNF2_PRSEG2 (1 << 2)
#define MCP2521_CNF2_PRSEG1 (1 << 1)
#define MCP2521_CNF2_PRSEG0 (1 << 0)
#define MCP2521_CNF1 0x2A
#define MCP2521_CNF1_SJW1 (1 << 7)
#define MCP2521_CNF1_SJW0 (1 << 6)
#define MCP2521_CNF1_BRP5 (1 << 5)
#define MCP2521_CNF1_BRP4 (1 << 4)
#define MCP2521_CNF1_BRP3 (1 << 3)
#define MCP2521_CNF1_BRP2 (1 << 2)
#define MCP2521_CNF1_BRP1 (1 << 1)
#define MCP2521_CNF1_BRP0 (1 << 0)
#define MCP2521_CANINTE 0x2B
#define MCP2521_CANINTE_MERRE (1 << 7)
#define MCP2521_CANINTE_WAKIE (1 << 6)
#define MCP2521_CANINTE_ERRIE (1 << 5)
#define MCP2521_CANINTE_TX2IE (1 << 4)
#define MCP2521_CANINTE_TX1IE (1 << 3)
#define MCP2521_CANINTE_TX0IE (1 << 2)
#define MCP2521_CANINTE_RX1IE (1 << 1)
#define MCP2521_CANINTE_RX0IE (1 << 0)
#define MCP2521_CANINTF 0x2C
#define MCP2521_CANINTF_MERRF (1 << 7)
#define MCP2521_CANINTF_WAKIF (1 << 6)
#define MCP2521_CANINTF_ERRIF (1 << 5)
#define MCP2521_CANINTF_TX2IF (1 << 4)
#define MCP2521_CANINTF_TX1IF (1 << 3)
#define MCP2521_CANINTF_TX0IF (1 << 2)
#define MCP2521_CANINTF_RX1IF (1 << 1)
#define MCP2521_CANINTF_RX0IF (1 << 0)
#define MCP2521_EFLG 0x2D
#define MCP2521_EFLG_RX1OVR (1 << 7)
#define MCP2521_EFLG_RX0OVR (1 << 6)
#define MCP2521_EFLG_TXBO (1 << 5)
#define MCP2521_EFLG_TXEP (1 << 4)
#define MCP2521_EFLG_RXEP (1 << 3)
#define MCP2521_EFLG_TXWAR (1 << 2)
#define MCP2521_EFLG_RXWAR (1 << 1)
#define MCP2521_EFLG_EWARN (1 << 0)
#define MCP2521_TXB0CTRL 0x30
#define MCP2521_TXB0CTRL_ABTF (1 << 6)
#define MCP2521_TXB0CTRL_MLOA (1 << 5)
#define MCP2521_TXB0CTRL_TXERR (1 << 4)
#define MCP2521_TXB0CTRL_TXREQ (1 << 3)
#define MCP2521_TXB0CTRL_TXP1 (1 << 1)
#define MCP2521_TXB0CTRL_TXP0 (1 << 0)
#define MCP2521_TXB0DLC 0x35
#define MCP2521_TXB1DLC 0x45
#define MCP2521_TXB2DLC 0x55
#define MCP2521_TXB1CTRL 0x40
#define MCP2521_TXB1CTRL_ABTF (1 << 6)
#define MCP2521_TXB1CTRL_MLOA (1 << 5)
#define MCP2521_TXB1CTRL_TXERR (1 << 4)
#define MCP2521_TXB1CTRL_TXREQ (1 << 3)
#define MCP2521_TXB1CTRL_TXP1 (1 << 1)
#define MCP2521_TXB1CTRL_TXP0 (1 << 0)
#define MCP2521_TXB2CTRL 0x50
#define MCP2521_TXB2CTRL_ABTF (1 << 6)
#define MCP2521_TXB2CTRL_MLOA (1 << 5)
#define MCP2521_TXB2CTRL_TXERR (1 << 4)
#define MCP2521_TXB2CTRL_TXREQ (1 << 3)
#define MCP2521_TXB2CTRL_TXP1 (1 << 1)
#define MCP2521_TXB2CTRL_TXP0 (1 << 0)
struct TXBnCTRL_Register {
uint8_t TXP : 2;
uint8_t : 1; // Unused bit
uint8_t TXREQ : 1;
uint8_t TXERR : 1;
uint8_t MLOA : 1;
uint8_t ABTF : 1;
uint8_t : 1; // Unused bit
};
#define MCP2521_RXB0CTRL 0x60
#define MCP2521_RXB0CTRL_RXM1 (1 << 6)
#define MCP2521_RXB0CTRL_RXM0 (1 << 5)
#define MCP2521_RXB0CTRL_RXRTR (1 << 3)
#define MCP2521_RXB0CTRL_BUKT (1 << 2)
#define MCP2521_RXB0CTRL_BUKT1 (1 << 1)
#define MCP2521_RXB0CTRL_FILHIT0 (1 << 0)
#define MCP2521_RXB1CTRL 0x70
#define MCP2521_RXB1CTRL_RXM1 (1 << 6)
#define MCP2521_RXB1CTRL_RXM0 (1 << 5)
#define MCP2521_RXB1CTRL_RXRTR (1 << 3)
#define MCP2521_RXB1CTRL_FILHIT2 (1 << 2)
#define MCP2521_RXB1CTRL_FILHIT1 (1 << 1)
#define MCP2521_RXB1CTRL_FILHIT0 (1 << 0)
#define MCP2521_OP_RESET 0b11000000
#define MCP2521_OP_READ 0b00000011
#define MCP2521_OP_READ_RX_BUFFER 0b10010000
#define MCP2521_OP_WRITE 0b00000010
#define MCP2521_OP_LOAD_TX_BUFFER 0b01000000
#define MCP2521_OP_RTS 0b10000000
#define MCP2521_OP_READ_STATUS 0b10100000
#define MCP2521_OP_RX_STATUS 0b10110000
#define MCP2521_OP_BIT_MODIFY 0b00000101
#define MCP2521_TXB0SIDH 0x31
#define MCP2521_TXB1SIDH 0x41
#define MCP2521_TXB2SIDH 0x51
#define MCP2521_TXB0SIDL 0x32
#define MCP2521_TXB1SIDL 0x42
#define MCP2521_TXB2SIDL 0x52
#define MCP2521_RXB0SIDH 0x61
#define MCP2521_RXB1SIDH 0x71
#define MCP2521_RXB0SIDL 0x62
#define MCP2521_RXB1SIDL 0x72
#define MCP2521_RXB0EID8 0x63
#define MCP2521_RXB1EID8 0x73
#define MCP2521_RXB0EID0 0x64
#define MCP2521_RXB1EID0 0x74
#define MCP2521_RXB0DLC 0x65
#define MCP2521_RXB1DLC 0x75

View File

@@ -0,0 +1,102 @@
#pragma once
#include "mcp2521_addresses.hpp"
#include "mcp2521_hardware_handle.hpp"
#include <stdint.h>
enum MCP2521_RX_BUFFER {
RXB0 = 0,
RXB1 = 1
};
enum MCP2521_TX_BUFFER {
TXB0 = 0,
TXB1 = 1,
TXB2 = 2
};
enum MCP2521_BUFFER_TYPE {
ID = 0,
DATA = 1
};
enum MCP2521_OPERATION_MODE {
NORMAL = 0b000,
SLEEP = 0b001,
LOOPBACK = 0b010,
LISTEN_ONLY = 0b011,
CONFIG = 0b100
};
struct rx_info {
bool extended;
uint16_t id;
uint32_t extended_id;
bool rtr;
bool extended_rtr;
uint8_t length;
};
class MCP2521_CommandInterface {
private:
I_MCP2521_HardwareHandle * hardware_handle;
intHandlerFunction_t rx0_handler;
intHandlerFunction_t rx1_handler;
intHandlerFunction_t tx0_handler;
intHandlerFunction_t tx1_handler;
intHandlerFunction_t tx2_handler;
intHandlerFunction_t error_handler;
intHandlerFunction_t wakeup_handler;
intHandlerFunction_t message_error_handler;
void * rx0_handler_arg;
void * rx1_handler_arg;
void * tx0_handler_arg;
void * tx1_handler_arg;
void * tx2_handler_arg;
void * error_handler_arg;
void * wakeup_handler_arg;
void * message_error_handler_arg;
public:
MCP2521_CommandInterface(
I_MCP2521_HardwareHandle * hardware_handle
);
void handleInterrupt();
void reset();
void read_reg(uint8_t address, uint8_t *data, size_t length);
uint8_t read_reg(uint8_t address);
void read_rx_buf(MCP2521_RX_BUFFER buffer, MCP2521_BUFFER_TYPE type, uint8_t *data, size_t length);
void write_reg(uint8_t address, uint8_t *data, size_t length);
void write_reg(uint8_t address, uint8_t data);
void write_tx_buf(MCP2521_TX_BUFFER buffer, MCP2521_BUFFER_TYPE type, uint8_t *data, size_t length);
void request_to_send(bool txb2, bool txb1, bool txb0);
void request_to_send(MCP2521_TX_BUFFER buffer);
uint8_t read_status();
uint8_t read_rx_status();
void bit_modify(uint8_t address, uint8_t mask, uint8_t data);
// Registering Handlers for Interrupts
void register_rx0_handler(intHandlerFunction_t handler, void * arg);
void register_rx1_handler(intHandlerFunction_t handler, void * arg);
void register_tx0_handler(intHandlerFunction_t handler, void * arg);
void register_tx1_handler(intHandlerFunction_t handler, void * arg);
void register_tx2_handler(intHandlerFunction_t handler, void * arg);
void register_error_handler(intHandlerFunction_t handler, void * arg);
void register_wakeup_handler(intHandlerFunction_t handler, void * arg);
void register_message_error_handler(intHandlerFunction_t handler, void * arg);
};

View File

@@ -0,0 +1,38 @@
#pragma once
#include <stdint.h>
#include "mcp2521.hpp"
#include "mcp2521_command.hpp"
#include "mcp2521_addresses.hpp"
class MCP2521 : public MCP2521_CommandInterface {
private:
public:
void set_tx_id(MCP2521_TX_BUFFER buffer, uint16_t id, bool extended);
/**
* @brief Loads the Data Length Code register for the specified buffer
*
* @param buffer What Buffer to load the DLC register for
* @param length How many bytes are in the message (0-8)
* @param rtr: Remote Transmission Request
*/
void set_DLC_reg(MCP2521_TX_BUFFER buffer, uint8_t length, bool rtr);
/**
* @brief Loads the data and id into the specified buffer
*
* @param buffer
* @param id
* @param data
* @param length
*/
void prepare_tx(MCP2521_TX_BUFFER buffer, uint32_t id, uint8_t *data, size_t length, bool rtr, bool extended);
void set_mode_of_operation(MCP2521_OPERATION_MODE mode, bool singleshot);
void set_singleshot_mode(bool enable);
void enable_interrupts(bool MessageError, bool ErrorInterrupt, bool WakeUp, bool TXB0, bool TXB1, bool TXB2, bool RXB0, bool RXB1);
rx_info get_rx_id(MCP2521_RX_BUFFER buffer);
};

View File

@@ -0,0 +1,100 @@
#include <cstring>
#include "mcp2521.hpp"
#include "mcp2521_addresses.hpp"
void runIntHandler(void *arg) {
MCP2521_CommandInterface *command_interface = (MCP2521_CommandInterface *)arg;
command_interface->handleInterrupt();
}
MCP2521_CommandInterface::MCP2521_CommandInterface(
I_MCP2521_HardwareHandle * hardware_handle
) {
this->hardware_handle = hardware_handle;
this->hardware_handle->registerIntHandler(runIntHandler, (void *)this);
rx0_handler = NULL;
rx1_handler = NULL;
tx0_handler = NULL;
tx1_handler = NULL;
tx2_handler = NULL;
error_handler = NULL;
wakeup_handler = NULL;
message_error_handler = NULL;
rx0_handler_arg = NULL;
rx1_handler_arg = NULL;
tx0_handler_arg = NULL;
tx1_handler_arg = NULL;
tx2_handler_arg = NULL;
error_handler_arg = NULL;
wakeup_handler_arg = NULL;
message_error_handler_arg = NULL;
}
void MCP2521_CommandInterface::reset() {
hardware_handle->execute(MCP2521_OP_RESET);
}
void MCP2521_CommandInterface::read_reg(uint8_t address, uint8_t *data, size_t length) {
hardware_handle->read(MCP2521_OP_READ, data, length, address);
}
uint8_t MCP2521_CommandInterface::read_reg(uint8_t address) {
return hardware_handle->read(MCP2521_OP_READ, address);
}
void MCP2521_CommandInterface::read_rx_buf(MCP2521_RX_BUFFER buffer, MCP2521_BUFFER_TYPE type, uint8_t *data, size_t length) {
uint8_t address = (buffer << 1) | (type << 2);
hardware_handle->read(MCP2521_OP_READ_RX_BUFFER | address, data, length);
}
void MCP2521_CommandInterface::write_reg(uint8_t address, uint8_t *data, size_t length) {
hardware_handle->write(MCP2521_OP_WRITE, data, length, address);
}
void MCP2521_CommandInterface::write_reg(uint8_t address, uint8_t data) {
hardware_handle->write(MCP2521_OP_WRITE, data, address);
}
void MCP2521_CommandInterface::write_tx_buf(MCP2521_TX_BUFFER buffer, MCP2521_BUFFER_TYPE type, uint8_t *data, size_t length) {
uint8_t address = (buffer << 1) | (type);
hardware_handle->write(MCP2521_OP_LOAD_TX_BUFFER | address, data, length);
}
void MCP2521_CommandInterface::request_to_send(bool txb2, bool txb1, bool txb0) {
uint8_t data = (txb2 << 2) | (txb1 << 1) | txb0;
hardware_handle->execute(MCP2521_OP_RTS | data);
}
void MCP2521_CommandInterface::request_to_send(MCP2521_TX_BUFFER buffer) {
uint8_t mask = 0;
switch (buffer) {
case MCP2521_TX_BUFFER::TXB0:
mask = 0b001;
break;
case MCP2521_TX_BUFFER::TXB1:
mask = 0b010;
break;
case MCP2521_TX_BUFFER::TXB2:
mask = 0b100;
break;
}
hardware_handle->execute(MCP2521_OP_RTS | mask);
}
uint8_t MCP2521_CommandInterface::read_status() {
return hardware_handle->read(MCP2521_OP_READ_STATUS);
}
uint8_t MCP2521_CommandInterface::read_rx_status() {
return hardware_handle->read(MCP2521_OP_RX_STATUS);
}
void MCP2521_CommandInterface::bit_modify(uint8_t address, uint8_t mask, uint8_t data) {
uint8_t data_array[3] = {address, mask, data};
hardware_handle->write(MCP2521_OP_BIT_MODIFY, data_array, 3);
}

View File

@@ -0,0 +1,113 @@
#include "mcp2521.hpp"
#include "mcp2521_addresses.hpp"
void MCP2521_CommandInterface::register_rx0_handler(intHandlerFunction_t handler, void* args) {
rx0_handler = handler;
rx0_handler_arg = args;
}
void MCP2521_CommandInterface::register_rx1_handler(intHandlerFunction_t handler, void* args) {
rx1_handler = handler;
rx1_handler_arg = args;
}
void MCP2521_CommandInterface::register_tx0_handler(intHandlerFunction_t handler, void* args) {
tx0_handler = handler;
tx0_handler_arg = args;
}
void MCP2521_CommandInterface::register_tx1_handler(intHandlerFunction_t handler, void* args) {
tx1_handler = handler;
tx1_handler_arg = args;
}
void MCP2521_CommandInterface::register_tx2_handler(intHandlerFunction_t handler, void* args) {
tx2_handler = handler;
tx2_handler_arg = args;
}
void MCP2521_CommandInterface::register_error_handler(intHandlerFunction_t handler, void* args) {
error_handler = handler;
error_handler_arg = args;
}
void MCP2521_CommandInterface::register_wakeup_handler(intHandlerFunction_t handler, void* args) {
wakeup_handler = handler;
wakeup_handler_arg = args;
}
void MCP2521_CommandInterface::register_message_error_handler(intHandlerFunction_t handler, void* args) {
message_error_handler = handler;
message_error_handler_arg = args;
}
void MCP2521_CommandInterface::handleInterrupt() {
uint8_t flags = read_reg(MCP2521_CANINTF);
uint8_t clearBits = 0;
if (flags & MCP2521_CANINTF_RX0IF) {
if (rx0_handler) {
rx0_handler(rx0_handler_arg);
}
flags &= ~MCP2521_CANINTF_RX0IF;
clearBits |= MCP2521_CANINTF_RX0IF;
}
if (flags & MCP2521_CANINTF_RX1IF) {
if (rx1_handler) {
rx1_handler(rx1_handler_arg);
}
flags &= ~MCP2521_CANINTF_RX1IF;
clearBits |= MCP2521_CANINTF_RX1IF;
}
if (flags & MCP2521_CANINTF_TX0IF) {
if (tx0_handler) {
tx0_handler(tx0_handler_arg);
}
flags &= ~MCP2521_CANINTF_TX0IF;
clearBits |= MCP2521_CANINTF_TX0IF;
}
if (flags & MCP2521_CANINTF_TX1IF) {
if (tx1_handler) {
tx1_handler(tx1_handler_arg);
}
flags &= ~MCP2521_CANINTF_TX1IF;
clearBits |= MCP2521_CANINTF_TX1IF;
}
if (flags & MCP2521_CANINTF_TX2IF) {
if (tx2_handler) {
tx2_handler(tx2_handler_arg);
}
flags &= ~MCP2521_CANINTF_TX2IF;
clearBits |= MCP2521_CANINTF_TX2IF;
}
if (flags & MCP2521_CANINTF_ERRIF) {
if (error_handler) {
error_handler(error_handler_arg);
}
flags &= ~MCP2521_CANINTF_ERRIF;
clearBits |= MCP2521_CANINTF_ERRIF;
}
if (flags & MCP2521_CANINTF_WAKIF) {
if (wakeup_handler) {
wakeup_handler(wakeup_handler_arg);
}
flags &= ~MCP2521_CANINTF_WAKIF;
clearBits |= MCP2521_CANINTF_WAKIF;
}
if (flags & MCP2521_CANINTF_MERRF) {
if (message_error_handler) {
message_error_handler(message_error_handler_arg);
}
flags &= ~MCP2521_CANINTF_MERRF;
clearBits |= MCP2521_CANINTF_MERRF;
}
bit_modify(MCP2521_CANINTF, clearBits, 0);
}

View File

@@ -0,0 +1,119 @@
#include <cstring>
#include "mcp2521.hpp"
#include "mcp2521_addresses.hpp"
void MCP2521::set_tx_id(MCP2521_TX_BUFFER buffer, uint16_t id, bool extended) {
uint8_t addr_offset = 0;
switch (buffer)
{
case MCP2521_TX_BUFFER::TXB0:
addr_offset = 0x00;
break;
case MCP2521_TX_BUFFER::TXB1:
addr_offset = 0x10;
break;
case MCP2521_TX_BUFFER::TXB2:
addr_offset = 0x20;
break;
}
uint8_t upper_id = (id >> 3) & 0xFF;
uint8_t lower_id = ((id & 0b111) << 5);
if(extended) {
lower_id |= 0b1000;
lower_id |= (id >> 8) & 0b11;
}
write_reg(MCP2521_TXB0SIDH | addr_offset, upper_id);
write_reg(MCP2521_TXB0SIDL | addr_offset, lower_id);
}
void MCP2521::set_DLC_reg(MCP2521_TX_BUFFER buffer, uint8_t length, bool rtr) {
uint8_t data = length;
if (rtr)
data |= 0b01000000;
uint8_t reg_address = 0;
switch (buffer) {
case MCP2521_TX_BUFFER::TXB0:
reg_address = MCP2521_TXB0DLC;
break;
case MCP2521_TX_BUFFER::TXB1:
reg_address = MCP2521_TXB1DLC;
break;
case MCP2521_TX_BUFFER::TXB2:
reg_address = MCP2521_TXB2DLC;
break;
}
write_reg(reg_address, data);
}
void MCP2521::set_mode_of_operation(MCP2521_OPERATION_MODE mode, bool singleshot) {
uint8_t single = singleshot ? 0b00001000 : 0x0;
bit_modify(MCP2521_CANCTRL, 0b11101000 , (mode << 5) | single);
}
void MCP2521::set_singleshot_mode(bool enable) {
uint8_t data = enable ? 0x08 : 0x00;
bit_modify(MCP2521_CANCTRL, 0x08, data);
}
void MCP2521::enable_interrupts(bool MessageError, bool ErrorInterrupt, bool WakeUp, bool TXB0, bool TXB1, bool TXB2, bool RXB0, bool RXB1) {
uint8_t interrupt_flags = 0;
if (MessageError) interrupt_flags |= 0b10000000;
if (WakeUp) interrupt_flags |= 0b01000000;
if (ErrorInterrupt) interrupt_flags |= 0b00100000;
if (TXB2) interrupt_flags |= 0b00010000;
if (TXB1) interrupt_flags |= 0b00001000;
if (TXB0) interrupt_flags |= 0b00000100;
if (RXB1) interrupt_flags |= 0b00000010;
if (RXB0) interrupt_flags |= 0b00000001;
write_reg(MCP2521_CANINTE, interrupt_flags);
}
rx_info MCP2521::get_rx_id(MCP2521_RX_BUFFER buffer) {
uint8_t data[5];
uint8_t addr_offset = MCP2521_RXB0SIDH;
switch (buffer) {
case MCP2521_RX_BUFFER::RXB0:
addr_offset |= 0x00;
break;
case MCP2521_RX_BUFFER::RXB1:
addr_offset |= 0x10;
break;
}
read_reg(addr_offset, data, 5);
rx_info res;
res.extended = data[1] & 0b1000;
res.id = (data[0] << 3) | (data[1] >> 5);
res.extended_id = ((data[1] & 0b11) << 16) | (data[2] << 8) | data[3];
res.rtr = data[1] & 0b10000;
res.extended_rtr = (data[4] & 0b1000000);
res.length = (data[4] & 0b1111);
return res;
}
void MCP2521::prepare_tx(
MCP2521_TX_BUFFER buffer,
uint32_t id,
uint8_t *data,
size_t length,
bool rtr, bool extended) {
set_tx_id(buffer, id, extended);
set_DLC_reg(buffer, length, rtr);
write_tx_buf(buffer, MCP2521_BUFFER_TYPE::DATA, data, length);
}

View File

@@ -0,0 +1,7 @@
idf_component_register(SRCS "esp_implementation_init.cpp"
"esp_implementation_cmd.cpp"
"esp_implementation_int.cpp"
"esp_implementation_bus.cpp"
"esp_implementation_bus_factory.cpp"
INCLUDE_DIRS "include"
REQUIRES driver)

View File

@@ -0,0 +1,58 @@
#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
#include "mcp2521_hardware_esp_bus.hpp"
#include "mcp2521_hardware_esp.hpp"
MCP2521_HardwareHandle_ESPBus::MCP2521_HardwareHandle_ESPBus(
QueueHandle_t send_queue,
spi_host_device_t spi_host,
spi_bus_config_t * bus_config,
gpio_num_t cs,
gpio_num_t int_pin
) : MCP2521_HardwareHandle_ESP(spi_host, bus_config, cs, int_pin) {
this->send_queue = send_queue;
this->receive_queue = xQueueCreate(3, sizeof(spi_message_t));
}
void MCP2521_HardwareHandle_ESPBus::spi_transmit(spi_transaction_t *t) {
spi_message_t message = {
.transaction = t,
.queue = send_queue,
.spi_device_handle = spi_device_handle
};
xQueueSend(send_queue, &message, portMAX_DELAY);
xQueueReceive(receive_queue, &message, portMAX_DELAY);
}
void MCP2521_HardwareHandle_ESPBus::initPins(
gpio_num_t int_pin
) {
canInterruptSemaphore = xSemaphoreCreateBinary();
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = 1 << int_pin;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
gpio_isr_handler_add(int_pin, gpio_isr_can_handler, this);
char taskName[32];
sprintf(taskName, "canInterruptTask_%d", int_pin);
xTaskCreatePinnedToCore(
(TaskFunction_t)&handleInteruptTaskCallerFn,
taskName,
2048,
this,
5,
&canInterruptTaskHandle,
0
);
}
#endif

View File

@@ -0,0 +1,67 @@
#pragma once
#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
#include "mcp2521_hardware_esp_bus_factory.hpp"
#include "mcp2521_hardware_esp_bus.hpp"
#include "mcp2521_hardware_esp.hpp"
void transactionTaskWrapperFn(void *pvParameters) {
MCP2521_HardwareHandleFactory_ESPBus *factory = (MCP2521_HardwareHandleFactory_ESPBus *)pvParameters;
factory->transactionTaskFn();
}
MCP2521_HardwareHandleFactory_ESPBus::MCP2521_HardwareHandleFactory_ESPBus(
spi_host_device_t spi_host,
gpio_num_t mosi,
gpio_num_t miso,
gpio_num_t sclk
) {
this->spi_host = spi_host;
this->mosi = mosi;
this->miso = miso;
this->sclk = sclk;
gpio_install_isr_service(0);
MCP2521_HardwareHandle_ESP::initSPIBus(spi_host, mosi, miso, sclk, &bus_config);
spi_queue = xQueueCreate(12, sizeof(spi_message_t));
xTaskCreatePinnedToCore(
(TaskFunction_t)&transactionTaskWrapperFn,
"transactionTask",
2048,
this,
3,
&transactionTaskHandle,
0
);
}
void MCP2521_HardwareHandleFactory_ESPBus::transactionTaskFn() {
spi_message_t message;
while(true) {
xQueueReceive(spi_queue, &message, portMAX_DELAY);
spi_device_transmit(message.spi_device_handle, message.transaction);
}
}
MCP2521_HardwareHandle_ESPBus MCP2521_HardwareHandleFactory_ESPBus::create(
gpio_num_t int_pin,
gpio_num_t cs
) {
return MCP2521_HardwareHandle_ESPBus(
spi_queue,
spi_host,
&bus_config,
cs,
int_pin
);
}
#endif

View File

@@ -0,0 +1,209 @@
#include "mcp2521_hardware_handle.hpp"
#ifdef ESP_PLATFORM
#include "mcp2521_hardware_esp.hpp"
const uint8_t null_buffer[32] = {0};
void MCP2521_HardwareHandle_ESP::spi_transmit(spi_transaction_t *t) {
xSemaphoreTake(spiMutex, portMAX_DELAY);
spi_device_transmit(this->spi_device_handle, t);
xSemaphoreGive(spiMutex);
}
void MCP2521_HardwareHandle_ESP::execute(uint8_t cmd) {
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = 0,
.length = 0,
.rxlength = 0,
.tx_buffer = NULL,
.rx_buffer = NULL
},
.command_bits = 8,
.address_bits = 0,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
void MCP2521_HardwareHandle_ESP::execute(uint8_t cmd, uint8_t address) {
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = address,
.length = 0,
.rxlength = 0,
.tx_buffer = NULL,
.rx_buffer = NULL
},
.command_bits = 8,
.address_bits = 8,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
void MCP2521_HardwareHandle_ESP::read(uint8_t cmd, uint8_t *data, size_t length, uint8_t address) {
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = address,
.length = 8*length,
.rxlength = 8*length,
.tx_buffer = null_buffer,
.rx_buffer = data
},
.command_bits = 8,
.address_bits = 8,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
void MCP2521_HardwareHandle_ESP::read(uint8_t cmd, uint8_t *data, size_t length) {
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = 0,
.length = 8*length,
.rxlength = 8*length,
.tx_buffer = null_buffer,
.rx_buffer = data
},
.command_bits = 8,
.address_bits = 0,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
uint8_t MCP2521_HardwareHandle_ESP::read(uint8_t cmd, uint8_t address) {
uint8_t result = 0;
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = address,
.length = 8,
.rxlength = 8,
.tx_buffer = null_buffer,
.rx_buffer = &result
},
.command_bits = 8,
.address_bits = 8,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
return result;
}
uint8_t MCP2521_HardwareHandle_ESP::read(uint8_t cmd) {
uint8_t result;
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = 0,
.length = 8,
.rxlength = 8,
.tx_buffer = null_buffer,
.rx_buffer = &result
},
.command_bits = 8,
.address_bits = 0,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
return result;
}
void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t *data, size_t length, uint8_t address) {
uint8_t result;
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = address,
.length = 8*length,
.rxlength = 0,
.tx_buffer = data,
.rx_buffer = NULL
},
.command_bits = 8,
.address_bits = 8,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t *data, size_t length) {
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = 0,
.length = 8*length,
.rxlength = 0,
.tx_buffer = data,
.rx_buffer = NULL
},
.command_bits = 8,
.address_bits = 0,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t data, uint8_t address) {
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = address,
.length = 8,
.rxlength = 0,
.tx_buffer = &data,
.rx_buffer = NULL
},
.command_bits = 8,
.address_bits = 8,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t data) {
spi_transaction_ext_t t = {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = cmd,
.addr = 0,
.length = 8,
.rxlength = 0,
.tx_buffer = &data,
.rx_buffer = NULL
},
.command_bits = 8,
.address_bits = 0,
.dummy_bits = 0,
};
spi_transmit((spi_transaction_t*)(&t));
}
#endif

View File

@@ -0,0 +1,92 @@
#include "mcp2521_hardware_handle.hpp"
#ifdef ESP_PLATFORM
#include "mcp2521_hardware_esp.hpp"
#include "driver/gpio.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
MCP2521_HardwareHandle_ESP::MCP2521_HardwareHandle_ESP(
spi_host_device_t spi_host,
spi_bus_config_t *bus_config,
gpio_num_t mosi,
gpio_num_t miso,
gpio_num_t sclk,
gpio_num_t cs,
gpio_num_t int_pin
) {
initPins(int_pin);
initSPIBus(spi_host, mosi, miso, sclk, bus_config);
this->spi_bus_config = bus_config;
initSPIDevice(spi_host, cs);
}
MCP2521_HardwareHandle_ESP::MCP2521_HardwareHandle_ESP(
spi_host_device_t spi_host,
spi_bus_config_t *bus_config,
gpio_num_t cs,
gpio_num_t int_pin
) {
initPins(int_pin);
this->spi_bus_config = bus_config;
initSPIDevice(spi_host, cs);
}
MCP2521_HardwareHandle_ESP::~MCP2521_HardwareHandle_ESP() {
}
void MCP2521_HardwareHandle_ESP::initSPIBus(
spi_host_device_t spi_host,
gpio_num_t mosi,
gpio_num_t miso,
gpio_num_t sclk,
spi_bus_config_t *bus_config
) {
memset(bus_config, 0, sizeof(spi_bus_config_t));
bus_config->mosi_io_num = mosi;
bus_config->miso_io_num = miso;
bus_config->sclk_io_num = sclk;
bus_config->quadwp_io_num = -1;
bus_config->quadhd_io_num = -1;
bus_config->flags = SPICOMMON_BUSFLAG_MASTER;
spi_bus_initialize(spi_host, bus_config, SPI_DMA_CH_AUTO);
}
void MCP2521_HardwareHandle_ESP::initSPIDevice(
spi_host_device_t spi_host,
gpio_num_t cs
) {
memset(&this->spi_device_config, 0, sizeof(spi_device_interface_config_t));
this->spi_device_config = {
.command_bits = 8,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 128,
// cs_ena_pretrans = 0 and cs_ena_posttrans = 0 need to be set to zero, if not its not compatible with full-duplex mode
// Learned this the hard way
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.clock_speed_hz = 2000,
.spics_io_num = cs,
.flags = SPI_DEVICE_NO_DUMMY,
.queue_size = 5,
};
spi_bus_add_device(spi_host, &this->spi_device_config, &this->spi_device_handle);
spiMutex = xSemaphoreCreateMutex();
}
spi_bus_config_t * MCP2521_HardwareHandle_ESP::getSPI_bus_config() {
return this->spi_bus_config;
}
#endif

View File

@@ -0,0 +1,66 @@
#include "mcp2521_hardware_handle.hpp"
#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "mcp2521_hardware_esp.hpp"
static void IRAM_ATTR gpio_isr_can_handler(void* arg) {
MCP2521_HardwareHandle_ESP * handle = (MCP2521_HardwareHandle_ESP *)arg;
handle->isr_can_interrupt();
}
static void handleInteruptTaskCallerFn(void *arg) {
MCP2521_HardwareHandle_ESP * handle = (MCP2521_HardwareHandle_ESP *)arg;
handle->handleIntteruptTaskFn();
}
void MCP2521_HardwareHandle_ESP::initPins(
gpio_num_t int_pin
) {
canInterruptSemaphore = xSemaphoreCreateBinary();
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = 1 << int_pin;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
gpio_install_isr_service(0);
gpio_isr_handler_add(int_pin, gpio_isr_can_handler, this);
xTaskCreatePinnedToCore(
(TaskFunction_t)&handleInteruptTaskCallerFn,
"canInterruptTask",
2048,
this,
5,
&canInterruptTaskHandle,
0
);
}
void MCP2521_HardwareHandle_ESP::handleIntteruptTaskFn() {
while(true) {
xSemaphoreTake(canInterruptSemaphore, portMAX_DELAY);
intHandler(intHandlerArg);
}
}
void MCP2521_HardwareHandle_ESP::isr_can_interrupt() {
BaseType_t wokenTask = pdFALSE;
xSemaphoreGiveFromISR(canInterruptSemaphore, &wokenTask);
if(wokenTask) {
portYIELD_FROM_ISR();
}
}
void MCP2521_HardwareHandle_ESP::registerIntHandler(intHandlerFunction_t handler, void * arg) {
intHandlerArg = arg;
intHandler = handler;
}
#endif

View File

@@ -0,0 +1,131 @@
/**
* @file mcp2521_hardware_esp.hpp
* @author AlexanderHD27
* @brief
* @version 0.1
* @date 2024-11-16
*
* @copyright Copyright (c) 2024
*
*/
#pragma once
#include "mcp2521_hardware_handle.hpp"
#ifdef ESP_PLATFORM
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static void handleInteruptTaskCallerFn(void *arg);
static void IRAM_ATTR gpio_isr_can_handler(void* arg);
/**
* @brief Hardware handle for MCP2521 over SPI on ESP32
* This is should not be used if multiple MCP2521 are on the same SPI bus
*/
class MCP2521_HardwareHandle_ESP : public I_MCP2521_HardwareHandle {
protected:
void spi_transmit(spi_transaction_t *t);
/**
* @brief Sempahore, that is set every time the MCP2521 triggers an interrupt by the canInterruptTaskHandle
*/
SemaphoreHandle_t canInterruptSemaphore = NULL;
/**
* @brief Handle to task that handles the MCP2521 interrupt
* A Handle can be registered via the registerIntHandler method
*/
TaskHandle_t canInterruptTaskHandle = NULL;
spi_device_handle_t spi_device_handle;
private:
spi_bus_config_t * spi_bus_config;
char spi_tmp_buffer;
spi_device_interface_config_t spi_device_config;
/**
* @brief Sempahore, that protects the SPI bus from being accessed by multiple tasks at the same time
*
*/
SemaphoreHandle_t spiMutex = NULL;
void * intHandlerArg = NULL;
intHandlerFunction_t intHandler = NULL;
public:
MCP2521_HardwareHandle_ESP(
spi_host_device_t spi_host,
spi_bus_config_t *bus_config,
gpio_num_t mosi,
gpio_num_t miso,
gpio_num_t sclk,
gpio_num_t cs,
gpio_num_t int_pin
);
MCP2521_HardwareHandle_ESP(
spi_host_device_t spi_host,
spi_bus_config_t *bus_config,
gpio_num_t cs,
gpio_num_t int_pin
);
static void initSPIBus(
spi_host_device_t spi_host,
gpio_num_t mosi,
gpio_num_t miso,
gpio_num_t sclk,
spi_bus_config_t *bus_config
);
void initSPIDevice(
spi_host_device_t spi_host,
gpio_num_t cs
);
void initPins(
gpio_num_t int_pin
);
~MCP2521_HardwareHandle_ESP();
spi_bus_config_t * getSPI_bus_config();
// ISR Stuff
/**
* @brief This function is called by the ISR, that is triggered by the MCP2521
* This function just set the canInterruptSemaphore, that then unblocks the canInterruptTaskHandle.
* So this function should be as short as possible, let the reset of the work be done in the canInterruptTaskHandle
*/
void isr_can_interrupt();
/**
* This is the methode run as canInterruptTaskHandle.
* It should continously aquire the canInterruptSemaphore and then call the intHandler
*/
void handleIntteruptTaskFn();
// Inherited from MCP2521_Hardware_Handle
void execute(uint8_t cmd);
void execute(uint8_t cmd, uint8_t address);
void read(uint8_t cmd, uint8_t *data, size_t length, uint8_t address);
void read(uint8_t cmd, uint8_t *data, size_t length);
uint8_t read(uint8_t cmd, uint8_t address);
uint8_t read(uint8_t cmd);
void write(uint8_t cmd, uint8_t *data, size_t length, uint8_t address);
void write(uint8_t cmd, uint8_t *data, size_t length);
void write(uint8_t cmd, uint8_t data, uint8_t address);
void write(uint8_t cmd, uint8_t data);
void registerIntHandler(intHandlerFunction_t handler, void * arg);
};
#endif

View File

@@ -0,0 +1,46 @@
#pragma once
#include "mcp2521_hardware_esp.hpp"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
struct spi_message_t {
spi_transaction_t *transaction;
QueueHandle_t queue;
spi_device_handle_t spi_device_handle;
};
/**
* @brief Hardware handle for MCP2521 over SPI in a multi-Bus-Setup on ESP32
* This should not be created directly, use the MCP2521_HardwareHandleFactory_ESPBus instead
*/
class MCP2521_HardwareHandle_ESPBus : public MCP2521_HardwareHandle_ESP {
using MCP2521_HardwareHandle_ESP::MCP2521_HardwareHandle_ESP;
private:
QueueHandle_t send_queue;
QueueHandle_t receive_queue;
/**
* @brief Wrapper around the spi_transmit function, that locks the spiMutex before calling spi_transmit.
* The muxtex is shared with all other MCP2521_HardwareHandle_ESPBus instances created by the same MCP2521_HardwareHandleFactory_ESPBus
* @overload
*
* @param t ESP32 SPI Transaction struct
*/
void spi_transmit(spi_transaction_t *t);
public:
MCP2521_HardwareHandle_ESPBus(
QueueHandle_t send_queue,
spi_host_device_t spi_host,
spi_bus_config_t * bus_config,
gpio_num_t cs,
gpio_num_t int_pin
);
void initPins(
gpio_num_t int_pin
);
};

View File

@@ -0,0 +1,41 @@
#pragma once
#ifdef ESP_PLATFORM
#include "mcp2521_hardware_handle.hpp"
#include "mcp2521_hardware_esp_bus.hpp"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
class MCP2521_HardwareHandleFactory_ESPBus {
private:
spi_bus_config_t bus_config;
spi_host_device_t spi_host;
gpio_num_t mosi;
gpio_num_t miso;
gpio_num_t sclk;
QueueHandle_t spi_queue;
TaskHandle_t transactionTaskHandle;
public:
MCP2521_HardwareHandleFactory_ESPBus(
spi_host_device_t spi_host,
gpio_num_t mosi,
gpio_num_t miso,
gpio_num_t sclk
);
void transactionTaskFn();
MCP2521_HardwareHandle_ESPBus create(
gpio_num_t int_pin,
gpio_num_t cs
);
};
#endif

View File

@@ -0,0 +1,119 @@
#pragma once
#include <cstdint>
#include <strings.h>
/**
* @brief Handler function pointer type
*
*/
typedef void (*intHandlerFunction_t)(void *);
/**
* @brief Hardware handle for MCP2521
* @interface
* This is an abstraction over the sepific hardware setup, eg. SPI@ESP32 or RP2040
*
*/
class I_MCP2521_HardwareHandle {
public:
/**
* @brief Registeres a function that is called when the MCP2521 triggers an interrupt
*
* @param handler This function is called when the MCP2521 triggers an interrupt
* @param arg Arguments passed to the handler-function
*/
virtual void registerIntHandler(intHandlerFunction_t handler, void * arg) = 0;
/**
* @overload
* @brief justed sends a 8bit command to the MCP2521
*
* @param cmd command to send
*/
virtual void execute(uint8_t cmd) = 0;
/**
* @overload
* @brief executes a command (8 bit) with an address (8 bit)
*
* @param cmd 8 bit command
* @param address 8 bit address
*/
virtual void execute(uint8_t cmd, uint8_t address) = 0;
/**
*
* @brief Executes a read from the MCP2521 with command, data buffer, length and address
* @overload
*
* @param cmd Command to MCP2521
* @param data Data buffer to store the read data
* @param length How many bytes to read
* @param address Address to read from
*/
virtual void read(uint8_t cmd, uint8_t *data, size_t length, uint8_t address) = 0;
/**
* @brief Executes a read from the MCP2521 with command, data buffer and length
* @overload
*
* @param cmd Command to MCP2521
* @param data Data buffer to store the read data
* @param length How many bytes to read
*/
virtual void read(uint8_t cmd, uint8_t *data, size_t length) = 0;
/**
* @brief Executes a read from the MCP2521 with command and address, returns just one byte
*
* @param cmd Command to MCP2521
* @param address Address to read from
* @return uint8_t
*/
virtual uint8_t read(uint8_t cmd, uint8_t address) = 0;
/**
* @brief Executes a read from the MCP2521 with command, returns just one byte
*
* @param cmd Command to MCP2521
* @return uint8_t
*/
virtual uint8_t read(uint8_t cmd) = 0;
/**
* @brief Writes data to the MCP2521 with command, data buffer, length and address
*
* @param cmd Command to MCP2521
* @param data Data buffer to write
* @param length Length of the data buffer
* @param address Where to write the data
*/
virtual void write(uint8_t cmd, uint8_t *data, size_t length, uint8_t address) = 0;
/**
* @brief Wirites data to the MCP2521 with command, data buffer and length
*
* @param cmd Command to MCP2521
* @param data Data buffer to write
* @param length Length of the data buffer
*/
virtual void write(uint8_t cmd, uint8_t *data, size_t length) = 0;
/**
* @brief Writes data to the MCP2521 with command, data (on byte) and address
*
* @param cmd Command to MCP2521
* @param data Data byte to write
* @param address Where to write the data
*/
virtual void write(uint8_t cmd, uint8_t data, uint8_t address) = 0;
/**
* @brief Writes to the MCP2521 with command and data (one byte)
*
* @param cmd Command to MCP2521
* @param data Data byte to write
*/
virtual void write(uint8_t cmd, uint8_t data) = 0;
};