1
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
+ #include " Configuration.h"
2
3
#include " BatteryCanReceiver.h"
4
+ #include " MqttSettings.h"
3
5
#include " MessageOutput.h"
4
6
#include " PinMapping.h"
5
7
#include < driver/twai.h>
@@ -12,6 +14,24 @@ bool BatteryCanReceiver::init(bool verboseLogging, char const* providerName)
12
14
MessageOutput.printf (" [%s] Initialize interface...\r\n " ,
13
15
_providerName);
14
16
17
+ auto const & config = Configuration.get ();
18
+ _canTopic = config.Battery .MqttCANTopic ;
19
+ _canInterface = static_cast <enum CanInterface>(config.Battery .CanInterface );
20
+ if (_canInterface == kMqtt ) {
21
+ MqttSettings.subscribe (_canTopic, 0 /* QoS*/ ,
22
+ std::bind (&BatteryCanReceiver::onMqttMessageCAN,
23
+ this , std::placeholders::_1, std::placeholders::_2,
24
+ std::placeholders::_3, std::placeholders::_4,
25
+ std::placeholders::_5, std::placeholders::_6)
26
+ );
27
+
28
+ if (_verboseLogging) {
29
+ MessageOutput.printf (" BatteryCanReceiver: Subscribed to '%s' for CAN messages\r\n " ,
30
+ _canTopic.c_str ());
31
+ }
32
+ return true ;
33
+ }
34
+
15
35
const PinMapping_t& pin = PinMapping.get ();
16
36
MessageOutput.printf (" [%s] Interface rx = %d, tx = %d\r\n " ,
17
37
_providerName, pin.battery_rx , pin.battery_tx );
@@ -82,6 +102,11 @@ bool BatteryCanReceiver::init(bool verboseLogging, char const* providerName)
82
102
83
103
void BatteryCanReceiver::deinit ()
84
104
{
105
+ if (_canInterface == kMqtt ) {
106
+ MqttSettings.unsubscribe (_canTopic);
107
+ return ;
108
+ }
109
+
85
110
// Stop TWAI driver
86
111
esp_err_t twaiLastResult = twai_stop ();
87
112
switch (twaiLastResult) {
@@ -111,6 +136,10 @@ void BatteryCanReceiver::deinit()
111
136
112
137
void BatteryCanReceiver::loop ()
113
138
{
139
+ if (_canInterface == kMqtt ) {
140
+ return ; // Mqtt CAN messages are event-driven
141
+ }
142
+
114
143
// Check for messages. twai_receive is blocking when there is no data so we return if there are no frames in the buffer
115
144
twai_status_info_t status_info;
116
145
esp_err_t twaiLastResult = twai_get_status_info (&status_info);
@@ -139,6 +168,80 @@ void BatteryCanReceiver::loop()
139
168
return ;
140
169
}
141
170
171
+ postMessage (std::move (rx_message));
172
+ }
173
+
174
+
175
+ void BatteryCanReceiver::onMqttMessageCAN (espMqttClientTypes::MessageProperties const & properties,
176
+ char const * topic, uint8_t const * payload, size_t len, size_t index, size_t total)
177
+ {
178
+ std::string value (reinterpret_cast <const char *>(payload), len);
179
+ JsonDocument json;
180
+
181
+ auto log = [this , topic](char const * format, auto &&... args) -> void {
182
+ MessageOutput.printf (" [%s] Topic '%s': " , _providerName, topic);
183
+ MessageOutput.printf (format, args...);
184
+ MessageOutput.println ();
185
+ };
186
+
187
+ const DeserializationError error = deserializeJson (json, value);
188
+ if (error) {
189
+ log (" cannot parse payload '%s' as JSON" , value.c_str ());
190
+ return ;
191
+ }
192
+
193
+ if (json.overflowed ()) {
194
+ log (" payload too large to process as JSON" );
195
+ return ;
196
+ }
197
+
198
+ int canID = json[" id" ] | -1 ;
199
+ if (canID == -1 ) {
200
+ log (" JSON is missing message id" );
201
+ return ;
202
+ }
203
+
204
+ twai_message_t rx_message = {};
205
+ rx_message.identifier = canID;
206
+ int maxLen = sizeof (rx_message.data );
207
+
208
+ JsonVariant canData = json[" data" ];
209
+ if (canData.isNull ()) {
210
+ log (" JSON is missing message data" );
211
+ return ;
212
+ }
213
+
214
+ if (canData.is <char const *>()) {
215
+ String strData = canData.as <String>();
216
+ int len = strData.length ();
217
+ if (len > maxLen) {
218
+ log (" JSON data has more than %d elements" , maxLen);
219
+ return ;
220
+ }
221
+
222
+ rx_message.data_length_code = len;
223
+ for (int i = 0 ; i < len; i++) {
224
+ rx_message.data [i] = strData[i];
225
+ }
226
+ } else {
227
+ JsonArray arrayData = canData.as <JsonArray>();
228
+ int len = arrayData.size ();
229
+ if (len > maxLen) {
230
+ log (" JSON data has more than %d elements" , maxLen);
231
+ return ;
232
+ }
233
+
234
+ rx_message.data_length_code = len;
235
+ for (int i = 0 ; i < len; i++) {
236
+ rx_message.data [i] = arrayData[i];
237
+ }
238
+ }
239
+
240
+ postMessage (std::move (rx_message));
241
+ }
242
+
243
+ void BatteryCanReceiver::postMessage (twai_message_t && rx_message)
244
+ {
142
245
if (_verboseLogging) {
143
246
MessageOutput.printf (" [%s] Received CAN message: 0x%04X -" ,
144
247
_providerName, rx_message.identifier );
0 commit comments