Skip to content

Commit 20662ea

Browse files
committed
huawei grid charger: TWAI: asynchronously poll for messages
instead of using a large receive queue and a large stack to handle it all, we now use a mechanism similar to the MCP2515 ISR, which alerts the hardware interface of inbound messages once they are available. this is done by creating another task which blocks on twai_read_alerts() and tests if new messages arrived. if so, the upstream task is notified and can process these messages in time.
1 parent a28192d commit 20662ea

File tree

6 files changed

+63
-18
lines changed

6 files changed

+63
-18
lines changed

include/gridcharger/huawei/TWAI.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// SPDX-License-Identifier: GPL-2.0-or-later
22
#pragma once
33

4+
#include <atomic>
5+
#include <FreeRTOS.h>
6+
#include <freertos/task.h>
47
#include <gridcharger/huawei/HardwareInterface.h>
58

69
namespace GridCharger::Huawei {
@@ -14,6 +17,13 @@ class TWAI : public HardwareInterface {
1417
bool getMessage(HardwareInterface::can_message_t& msg) final;
1518

1619
bool sendMessage(uint32_t canId, std::array<uint8_t, 8> const& data) final;
20+
21+
private:
22+
TaskHandle_t _pollingTaskHandle = nullptr;
23+
std::atomic<bool> _pollingTaskDone = false;
24+
std::atomic<bool> _stopPolling = false;
25+
26+
static void pollAlerts(void* context);
1727
};
1828

1929
} // namespace GridCharger::Huawei

src/WebApi_sysstatus.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
5454
root["flashsize"] = ESP.getFlashChipSize();
5555

5656
JsonArray taskDetails = root["task_details"].to<JsonArray>();
57-
static std::array<char const*, 12> constexpr task_names = {
57+
static std::array<char const*, 13> constexpr task_names = {
5858
"IDLE0", "IDLE1", "wifi", "tiT", "loopTask", "async_tcp", "mqttclient",
59-
"HuaweiHwIfc", "PM:SDM", "PM:HTTP+JSON", "PM:SML", "PM:HTTP+SML"
59+
"HuaweiHwIfc", "HuaweiTwai", "PM:SDM", "PM:HTTP+JSON", "PM:SML", "PM:HTTP+SML"
6060
};
6161
for (char const* task_name : task_names) {
6262
TaskHandle_t const handle = xTaskGetHandle(task_name);

src/gridcharger/huawei/HardwareInterface.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ void HardwareInterface::staticLoopHelper(void* context)
2828

2929
bool HardwareInterface::startLoop()
3030
{
31-
uint32_t constexpr stackSize = 4096;
31+
uint32_t constexpr stackSize = 2048;
3232
return pdPASS == xTaskCreate(HardwareInterface::staticLoopHelper,
33-
"HuaweiHwIfc", stackSize, this, 1/*prio*/, &_taskHandle);
33+
"HuaweiHwIfc", stackSize, this, 10/*prio*/, &_taskHandle);
3434
}
3535

3636
void HardwareInterface::stopLoop()

src/gridcharger/huawei/TWAI.cpp

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ namespace GridCharger::Huawei {
1212

1313
TWAI::~TWAI()
1414
{
15+
if (_pollingTaskHandle != nullptr) {
16+
_pollingTaskDone = false;
17+
_stopPolling = true;
18+
19+
while (!_pollingTaskDone) { delay(10); }
20+
21+
_pollingTaskHandle = nullptr;
22+
}
23+
1524
stopLoop();
1625

1726
if (twai_stop() != ESP_OK) {
@@ -41,7 +50,6 @@ bool TWAI::init()
4150
auto tx = static_cast<gpio_num_t>(pin.huawei_tx);
4251
auto rx = static_cast<gpio_num_t>(pin.huawei_rx);
4352
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(tx, rx, TWAI_MODE_NORMAL);
44-
g_config.rx_queue_len = 16;
4553

4654
// interrupts at level 1 are in high demand, at least on ESP32-S3 boards,
4755
// but only a limited amount can be allocated. failing to allocate an
@@ -65,30 +73,55 @@ bool TWAI::init()
6573
return false;
6674
}
6775

76+
if (!startLoop()) {
77+
MessageOutput.printf("[Huawei::TWAI] failed to start loop task\r\n");
78+
return false;
79+
}
80+
81+
// enable alert on message received
82+
uint32_t alertsToEnable = TWAI_ALERT_RX_DATA;
83+
if (twai_reconfigure_alerts(alertsToEnable, NULL) != ESP_OK) {
84+
MessageOutput.print("[Huawei::TWAI] Failed to configure alerts\r\n");
85+
return false;
86+
}
87+
88+
uint32_t constexpr stackSize = 1536;
89+
return pdPASS == xTaskCreate(TWAI::pollAlerts,
90+
"HuaweiTwai", stackSize, this, 20/*prio*/, &_pollingTaskHandle);
91+
6892
MessageOutput.print("[Huawei::TWAI] driver ready\r\n");
6993

70-
return startLoop();
94+
return true;
7195
}
7296

73-
bool TWAI::getMessage(HardwareInterface::can_message_t& msg)
97+
void TWAI::pollAlerts(void* context)
7498
{
75-
twai_status_info_t status;
99+
auto& instance = *static_cast<TWAI*>(context);
100+
uint32_t alerts;
76101

77-
while (true) {
78-
if (twai_get_status_info(&status) != ESP_OK) {
79-
MessageOutput.print("[Huawei::TWAI] Failed to get status info\r\n");
80-
return false;
102+
while (!instance._stopPolling) {
103+
if (twai_read_alerts(&alerts, pdMS_TO_TICKS(500)) != ESP_OK) { continue; }
104+
105+
if (alerts & TWAI_ALERT_RX_DATA) {
106+
// wake up hardware interface task to actually receive the message
107+
xTaskNotifyGive(instance.getTaskHandle());
81108
}
109+
}
110+
111+
instance._pollingTaskDone = true;
82112

83-
if (status.msgs_to_rx == 0) { return false; }
113+
vTaskDelete(nullptr);
114+
}
84115

116+
bool TWAI::getMessage(HardwareInterface::can_message_t& msg)
117+
{
118+
while (true) {
85119
twai_message_t rxMessage;
86120

87-
// wait for message to be received, function is blocking (for 100ms)
88-
if (twai_receive(&rxMessage, pdMS_TO_TICKS(100)) != ESP_OK) {
89-
MessageOutput.print("[Huawei::TWAI] Failed to receive message\r\n");
90-
return false;
91-
}
121+
// it's okay if we cannot receive a message now, as the hardware
122+
// interface task wakes up for reasons other than a message being
123+
// received, but always checks if a message is available.
124+
if (twai_receive(&rxMessage, pdMS_TO_TICKS(1)) != ESP_OK) { return false; }
92125

93126
if (rxMessage.extd != 1) { continue; } // we only process extended format messages
94127

webapp/src/locales/de.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@
313313
"Task_asynctcp": "Async TCP",
314314
"Task_mqttclient": "MQTT Client",
315315
"Task_huaweihwifc": "Netzladegerät Hardwareschnittstelle",
316+
"Task_huaweitwai": "Netzladegerät TWAI",
316317
"Task_pmsdm": "Stromzähler (SDM)",
317318
"Task_pmhttpjson": "Stromzähler (HTTP+JSON)",
318319
"Task_pmsml": "Stromzähler (Serial SML)",

webapp/src/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@
314314
"Task_asynctcp": "Async TCP",
315315
"Task_mqttclient": "MQTT Client",
316316
"Task_huaweihwifc": "Grid Charger Hardware Interface",
317+
"Task_huaweitwai": "Grid Charger TWAI",
317318
"Task_pmsdm": "PowerMeter (SDM)",
318319
"Task_pmhttpjson": "PowerMeter (HTTP+JSON)",
319320
"Task_pmsml": "PowerMeter (Serial SML)",

0 commit comments

Comments
 (0)