4
4
*/
5
5
#include < gridcharger/huawei/MCP2515.h>
6
6
#include " MessageOutput.h"
7
- #include " SpiManager.h"
8
7
#include " PinMapping.h"
9
8
#include " Configuration.h"
10
9
11
10
namespace GridCharger ::Huawei {
12
11
12
+ TaskHandle_t sIsrTaskHandle = nullptr ;
13
+
14
+ void mcp2515Isr ()
15
+ {
16
+ if (sIsrTaskHandle == nullptr ) { return ; }
17
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
18
+ vTaskNotifyGiveFromISR (sIsrTaskHandle , &xHigherPriorityTaskWoken);
19
+ // we assume we can wait until the lower-priority task is scheduled
20
+ // anyways, so we ignore xHigherPriorityTaskWoken == pdTRUE.
21
+ }
22
+
23
+ std::optional<uint8_t > MCP2515::_oSpiBus = std::nullopt;
24
+
25
+ MCP2515::~MCP2515 ()
26
+ {
27
+ detachInterrupt (digitalPinToInterrupt (_huaweiIrq));
28
+ sIsrTaskHandle = nullptr ;
29
+ stopLoop ();
30
+ _upCAN.reset (nullptr );
31
+ if (_upSPI) { _upSPI->end (); } // nullptr if init failed or never called
32
+ _upSPI.reset (nullptr );
33
+ }
34
+
13
35
bool MCP2515::init ()
14
36
{
15
37
const PinMapping_t& pin = PinMapping.get ();
@@ -22,51 +44,74 @@ bool MCP2515::init()
22
44
return false ;
23
45
}
24
46
25
- auto spi_bus = SpiManagerInst.claim_bus_arduino ();
26
- if (!spi_bus) { return false ; }
47
+ if (!_oSpiBus) {
48
+ _oSpiBus = SpiManagerInst.claim_bus_arduino ();
49
+ }
50
+
51
+ if (!_oSpiBus) {
52
+ MessageOutput.printf (" [Huawei::MCP2515] no SPI host available\r\n " );
53
+ return false ;
54
+ }
27
55
28
- SPI = new SPIClass (*spi_bus );
56
+ _upSPI = std::make_unique< SPIClass>(*_oSpiBus );
29
57
30
- SPI ->begin (pin.huawei_clk , pin.huawei_miso , pin.huawei_mosi , pin.huawei_cs );
58
+ _upSPI ->begin (pin.huawei_clk , pin.huawei_miso , pin.huawei_mosi , pin.huawei_cs );
31
59
pinMode (pin.huawei_cs , OUTPUT);
32
60
digitalWrite (pin.huawei_cs , HIGH);
33
61
34
- pinMode (pin.huawei_irq , INPUT_PULLUP);
35
- _huaweiIrq = pin.huawei_irq ;
36
-
37
62
auto mcp_frequency = MCP_8MHZ;
38
63
auto frequency = Configuration.get ().Huawei .CAN_Controller_Frequency ;
39
64
if (16000000UL == frequency) { mcp_frequency = MCP_16MHZ; }
40
65
else if (8000000UL != frequency) {
41
66
MessageOutput.printf (" [Huawei::MCP2515] unknown frequency %d Hz, using 8 MHz\r\n " , mcp_frequency);
42
67
}
43
68
44
- _CAN = new MCP_CAN (SPI , pin.huawei_cs );
45
- if (_CAN ->begin (MCP_STDEXT, CAN_125KBPS, mcp_frequency) != CAN_OK) {
69
+ _upCAN = std::make_unique< MCP_CAN>(_upSPI. get () , pin.huawei_cs );
70
+ if (_upCAN ->begin (MCP_STDEXT, CAN_125KBPS, mcp_frequency) != CAN_OK) {
46
71
MessageOutput.printf (" [Huawei::MCP2515] mcp_can begin() failed\r\n " );
47
72
return false ;
48
73
}
49
74
50
75
const uint32_t myMask = 0xFFFFFFFF ; // Look at all incoming bits and...
51
76
const uint32_t myFilter = 0x1081407F ; // filter for this message only
52
- _CAN ->init_Mask (0 , 1 , myMask);
53
- _CAN ->init_Filt (0 , 1 , myFilter);
54
- _CAN ->init_Mask (1 , 1 , myMask);
77
+ _upCAN ->init_Mask (0 , 1 , myMask);
78
+ _upCAN ->init_Filt (0 , 1 , myFilter);
79
+ _upCAN ->init_Mask (1 , 1 , myMask);
55
80
56
81
// Change to normal mode to allow messages to be transmitted
57
- _CAN->setMode (MCP_NORMAL);
82
+ _upCAN->setMode (MCP_NORMAL);
83
+
84
+ if (!startLoop ()) {
85
+ MessageOutput.printf (" [Huawei::MCP2515] failed to start loop task\r\n " );
86
+ return false ;
87
+ }
88
+
89
+ if (sIsrTaskHandle != nullptr ) {
90
+ // make the ISR aware of multiple instances if multiple instances of
91
+ // this driver should be able to co-exist. only one is supported now.
92
+ MessageOutput.printf (" [Huawei::MCP2515] ISR task handle already in use\r\n " );
93
+ stopLoop ();
94
+ return false ;
95
+ }
96
+
97
+ sIsrTaskHandle = getTaskHandle ();
98
+ _huaweiIrq = pin.huawei_irq ;
99
+ pinMode (_huaweiIrq, INPUT_PULLUP);
100
+ attachInterrupt (digitalPinToInterrupt (_huaweiIrq), mcp2515Isr, FALLING);
58
101
59
- return startLoop () ;
102
+ return true ;
60
103
}
61
104
62
105
bool MCP2515::getMessage (HardwareInterface::can_message_t & msg)
63
106
{
107
+ if (!_upCAN) { return false ; }
108
+
64
109
INT32U rxId;
65
110
unsigned char len = 0 ;
66
111
unsigned char rxBuf[8 ];
67
112
68
113
while (!digitalRead (_huaweiIrq)) {
69
- _CAN ->readMsgBuf (&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
114
+ _upCAN ->readMsgBuf (&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
70
115
71
116
// Determine if ID is standard (11 bits) or extended (29 bits)
72
117
if ((rxId & 0x80000000 ) != 0x80000000 ) { continue ; }
@@ -83,12 +128,14 @@ bool MCP2515::getMessage(HardwareInterface::can_message_t& msg)
83
128
return false ;
84
129
}
85
130
86
- bool MCP2515::sendMessage (uint32_t valueId , std::array<uint8_t , 8 > const & data)
131
+ bool MCP2515::sendMessage (uint32_t canId , std::array<uint8_t , 8 > const & data)
87
132
{
133
+ if (!_upCAN) { return false ; }
134
+
88
135
// MCP2515 CAN library requires a non-const pointer to the data
89
136
uint8_t rwData[8 ];
90
137
memcpy (rwData, data.data (), data.size ());
91
- return _CAN ->sendMsgBuf (valueId , 1 , 8 , rwData) == CAN_OK;
138
+ return _upCAN ->sendMsgBuf (canId , 1 , 8 , rwData) == CAN_OK;
92
139
}
93
140
94
141
} // namespace GridCharger::Huawei
0 commit comments