Fix gui semaphore and dynamic mqtt msg queue #174

This commit is contained in:
fvanroie 2022-12-01 20:08:51 +01:00
parent 8ec8de6980
commit 5ea9e1c373
4 changed files with 170 additions and 47 deletions

View File

@ -230,15 +230,6 @@ static inline void gui_init_filesystems()
void guiSetup() void guiSetup()
{ {
#if ESP32
g_lvgl_task_handle = xTaskGetCurrentTaskHandle();
xGuiSemaphore = xSemaphoreCreateMutex();
if(!xGuiSemaphore) {
LOG_FATAL(TAG_GUI, "Create mutex for LVGL failed");
}
#endif
// Initialize hardware drivers // Initialize hardware drivers
gui_init_tft(); gui_init_tft();
haspDevice.show_info(); // debug info + preload app flash size haspDevice.show_info(); // debug info + preload app flash size
@ -366,19 +357,23 @@ void guiSetup()
lv_obj_set_style_local_bg_color(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_bg_color(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_bg_opa(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); lv_obj_set_style_local_bg_opa(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
xGuiSemaphore = xSemaphoreCreateMutex();
if(!xGuiSemaphore) {
LOG_FATAL(TAG_GUI, "Create mutex for LVGL failed");
}
gui_acquire(); // Block LVGL until plate is fully booted
#if HASP_USE_LVGL_TASK
gui_setup_lvgl_task();
#endif // HASP_USE_LVGL_TASK
#endif // ESP32 && HASP_USE_ESP_MQTT
LOG_INFO(TAG_LVGL, F(D_SERVICE_STARTED)); LOG_INFO(TAG_LVGL, F(D_SERVICE_STARTED));
} }
IRAM_ATTR void guiLoop(void) IRAM_ATTR void guiLoop(void)
{ {
#if ESP32
if(pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
lv_task_handler();
xSemaphoreGive(xGuiSemaphore);
}
#else
lv_task_handler(); // process animations lv_task_handler(); // process animations
#endif
#if defined(STM32F4xx) #if defined(STM32F4xx)
// tick.update(); // tick.update();
@ -394,22 +389,64 @@ void guiEverySecond(void)
// nothing // nothing
} }
void gui_acquire(void) #if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
#if HASP_USE_LVGL_TASK == 1
static void gui_task(void* args)
{ {
LOG_TRACE(TAG_GUI, "Start to run LVGL");
while(1) {
vTaskDelay(pdMS_TO_TICKS(10));
/* Try to take the semaphore, call lvgl related function on success */
if(pdTRUE == xSemaphoreTake(xGuiSemaphore, pdMS_TO_TICKS(10))) {
lv_task_handler();
xSemaphoreGive(xGuiSemaphore);
}
}
}
esp_err_t gui_setup_lvgl_task()
{
#if CONFIG_FREERTOS_UNICORE == 0
int err = xTaskCreatePinnedToCore(gui_task, "lvglTask", 1024 * 8, NULL, 5, &g_lvgl_task_handle, 1);
#else
int err = xTaskCreatePinnedToCore(gui_task, "lvglTask", 1024 * 8, NULL, 5, &g_lvgl_task_handle, 0);
#endif
if(!err) {
LOG_FATAL(TAG_GUI, "Create task for LVGL failed");
return ESP_FAIL;
}
return ESP_OK;
}
#endif // HASP_USE_LVGL_TASK
bool gui_acquire(void)
{
#if ESP32
TaskHandle_t task = xTaskGetCurrentTaskHandle(); TaskHandle_t task = xTaskGetCurrentTaskHandle();
if(g_lvgl_task_handle != task) { if(g_lvgl_task_handle != task) {
xSemaphoreTake(xGuiSemaphore, portMAX_DELAY); if(xSemaphoreTake(xGuiSemaphore, pdMS_TO_TICKS(30)) != pdTRUE) {
return false;
}
} }
#endif
return true;
} }
void gui_release(void) void gui_release(void)
{ {
#if ESP32
TaskHandle_t task = xTaskGetCurrentTaskHandle(); TaskHandle_t task = xTaskGetCurrentTaskHandle();
if(g_lvgl_task_handle != task) { if(g_lvgl_task_handle != task) {
xSemaphoreGive(xGuiSemaphore); xSemaphoreGive(xGuiSemaphore);
// LOG_VERBOSE(TAG_TFT, F("GIVE"));
} }
#endif
} }
#endif // ESP32 && HASP_USE_ESP_MQTT
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
#if HASP_USE_CONFIG > 0 #if HASP_USE_CONFIG > 0
bool guiGetConfig(const JsonObject& settings) bool guiGetConfig(const JsonObject& settings)

View File

@ -61,8 +61,9 @@ void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_
void gui_antiburn_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); void gui_antiburn_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p);
/* ===== Locks ===== */ /* ===== Locks ===== */
void gui_acquire(void); bool gui_acquire(void);
void gui_release(void); void gui_release(void);
esp_err_t gui_setup_lvgl_task();
/* ===== Read/Write Configuration ===== */ /* ===== Read/Write Configuration ===== */
#if HASP_USE_CONFIG > 0 #if HASP_USE_CONFIG > 0

View File

@ -3,6 +3,16 @@
#if !(defined(WINDOWS) || defined(POSIX)) #if !(defined(WINDOWS) || defined(POSIX))
/*
#ifdef CORE_DEBUG_LEVEL
#undef CORE_DEBUG_LEVEL
#endif
#define CORE_DEBUG_LEVEL 3
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
*/
#include "hasplib.h" #include "hasplib.h"
#include "hasp_oobe.h" #include "hasp_oobe.h"
#include "sys/net/hasp_network.h" #include "sys/net/hasp_network.h"
@ -31,6 +41,11 @@ void setup()
{ {
// hal_setup(); // hal_setup();
esp_log_level_set("*", ESP_LOG_NONE); // set all components to ERROR level
// esp_log_level_set("wifi", ESP_LOG_NONE); // enable WARN logs from WiFi stack
// esp_log_level_set("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client
// esp_log_level_set("esp_crt_bundle", ESP_LOG_VERBOSE); // enable WARN logs from WiFi stack
// esp_log_level_set("esp_tls", ESP_LOG_VERBOSE); // enable WARN logs from WiFi stack
haspDevice.init(); haspDevice.init();
/**************************** /****************************
@ -75,16 +90,14 @@ void setup()
* Apply User Configuration * Apply User Configuration
***************************/ ***************************/
#if HASP_USE_MQTT > 0 // #if HASP_USE_MQTT > 0
mqttSetup(); // Load Hostname before starting WiFi // mqttSetup(); // Load Hostname before starting WiFi
#endif // #endif
#if HASP_USE_GPIO > 0 #if HASP_USE_GPIO > 0
gpioSetup(); gpioSetup();
#endif #endif
#if HASP_USE_MDNS > 0 #if HASP_USE_MDNS > 0
mdnsSetup(); mdnsSetup();
#endif #endif
@ -120,21 +133,38 @@ void setup()
// guiStart(); // guiStart();
delay(20); delay(20);
if(!oobe) { if(!oobe) {
dispatch_exec(NULL, "L:/boot.cmd", TAG_HASP); dispatch_run_script(NULL, "L:/boot.cmd", TAG_HASP);
#if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0 #if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0
network_run_scripts(); network_run_scripts();
#endif #endif
} }
#if HASP_USE_MQTT > 0
mqttSetup();
#endif
mainLastLoopTime = -1000; // reset loop counter mainLastLoopTime = -1000; // reset loop counter
gui_release();
} }
IRAM_ATTR void loop() IRAM_ATTR void loop()
{ {
#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
if(!gui_acquire()) {
// LOG_ERROR(TAG_MAIN, F("TAKE Mutex"));
delay(10); // ms
return;
}
#endif
#if HASP_USE_LVGL_TASK == 0
guiLoop(); guiLoop();
#endif
#if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0 #if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0
networkLoop(); networkLoop();
#endif #endif
#if HASP_USE_GPIO > 0 #if HASP_USE_GPIO > 0
@ -222,11 +252,19 @@ IRAM_ATTR void loop()
} }
} }
#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
gui_release();
#endif
// allow the cpu to switch to other tasks // allow the cpu to switch to other tasks
#if HASP_USE_LVGL_TASK == 0
#ifdef ARDUINO_ARCH_ESP8266 #ifdef ARDUINO_ARCH_ESP8266
delay(2); // ms delay(2); // ms
#else #else
delay(3); // ms delay(5); // ms
#endif
#else // HASP_USE_LVGL_TASK != 0
delay(10); // ms
#endif #endif
} }

View File

@ -19,14 +19,14 @@
#include "hasp_gui.h" #include "hasp_gui.h"
#include "../hasp/hasp_dispatch.h" #include "../hasp/hasp_dispatch.h"
/* #include "freertos/queue.h" #include "freertos/queue.h"
QueueHandle_t queue; QueueHandle_t queue;
typedef struct typedef struct
{ {
char topic[64]; char* topic; //[64];
char payload[512]; char* payload; //[512];
} mqtt_message_t; */ } mqtt_message_t;
char mqttLwtTopic[28]; char mqttLwtTopic[28];
char mqttNodeTopic[24]; char mqttNodeTopic[24];
@ -74,6 +74,12 @@ void mqtt_run_scripts()
// attempt++; // attempt++;
// }; // };
if(current_mqtt_state) {
dispatch_run_script(NULL, "L:/mqtt_on.cmd", TAG_HASP);
} else {
dispatch_run_script(NULL, "L:/mqtt_off.cmd", TAG_HASP);
}
last_mqtt_state = current_mqtt_state; last_mqtt_state = current_mqtt_state;
} }
} }
@ -101,6 +107,10 @@ int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
// Write directly to the client, don't use the buffer // Write directly to the client, don't use the buffer
if(current_mqtt_state && esp_mqtt_client_publish(mqttClient, topic, payload, len, 0, retain) != ESP_FAIL) { if(current_mqtt_state && esp_mqtt_client_publish(mqttClient, topic, payload, len, 0, retain) != ESP_FAIL) {
// Enqueue a message to the outbox, to be sent later
// if(current_mqtt_state && esp_mqtt_client_enqueue(mqttClient, topic, payload, len, 0, retain, true) !=
// ESP_FAIL) {
mqttPublishCount++; mqttPublishCount++;
return MQTT_ERR_OK; return MQTT_ERR_OK;
} }
@ -158,12 +168,52 @@ int mqtt_send_discovery(const char* payload, size_t len)
return mqttPublish(tmp_topic, payload, len, false); return mqttPublish(tmp_topic, payload, len, false);
} }
static inline size_t mqtt_msg_length(size_t len)
{
return (len / 64) * 64 + 64;
}
void mqtt_process_topic_payload(const char* topic, const char* payload, unsigned int length)
{
if(gui_acquire()) {
mqttLoop(); // First empty the MQTT queue
LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, payload);
dispatch_topic_payload(topic, payload, length > 0, TAG_MQTT);
gui_release();
} else {
// Add new message to the queue
mqtt_message_t data;
size_t topic_len = strlen(topic);
size_t payload_len = length;
data.topic = (char*)hasp_calloc(sizeof(char), mqtt_msg_length(topic_len + 1));
data.payload = (char*)hasp_calloc(sizeof(char), mqtt_msg_length(payload_len + 1));
if(!data.topic || !data.payload) {
LOG_ERROR(TAG_MQTT_RCV, D_ERROR_OUT_OF_MEMORY);
hasp_free(data.topic);
hasp_free(data.payload);
return;
}
memcpy(data.topic, topic, topic_len);
memcpy(data.payload, payload, payload_len);
{
size_t attempt = 0;
while(xQueueSend(queue, &data, (TickType_t)0) == errQUEUE_FULL && attempt < 100) {
delay(5);
attempt++;
};
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Receive incoming messages // Receive incoming messages
static void mqtt_message_cb(const char* topic, byte* payload, unsigned int length) static void mqtt_message_cb(const char* topic, byte* payload, unsigned int length)
{ // Handle incoming commands from MQTT { // Handle incoming commands from MQTT
mqttReceiveCount++; mqttReceiveCount++;
LOG_TRACE(TAG_MQTT_RCV, F("[%s] %s = %s"), pcTaskGetTaskName(NULL), topic, (char*)payload); // LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload);
if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic
@ -174,16 +224,12 @@ static void mqtt_message_cb(const char* topic, byte* payload, unsigned int lengt
// Group topic // Group topic
topic += strlen(mqttGroupTopic); // shorten topic topic += strlen(mqttGroupTopic); // shorten topic
// dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
// return;
#ifdef HASP_USE_BROADCAST #ifdef HASP_USE_BROADCAST
} else if(topic == strstr_P(topic, PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/"))) { // broadcast topic } else if(topic == strstr_P(topic, PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/"))) { // broadcast topic
// Broadcast topic // Broadcast topic
topic += strlen_P(PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/")); // shorten topic topic += strlen_P(PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/")); // shorten topic
// dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
// return;
#endif #endif
#ifdef HASP_USE_HA #ifdef HASP_USE_HA
@ -223,9 +269,7 @@ static void mqtt_message_cb(const char* topic, byte* payload, unsigned int lengt
else */ else */
{ {
gui_acquire(); mqtt_process_topic_payload(topic, (const char*)payload, length);
dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
gui_release();
} }
/* { /* {
@ -326,8 +370,8 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
int msg_id; int msg_id;
switch(event->event_id) { switch(event->event_id) {
case MQTT_EVENT_DISCONNECTED: case MQTT_EVENT_DISCONNECTED:
mqtt_disconnected();
LOG_WARNING(TAG_MQTT, F(D_MQTT_DISCONNECTED)); LOG_WARNING(TAG_MQTT, F(D_MQTT_DISCONNECTED));
mqtt_disconnected();
break; break;
case MQTT_EVENT_BEFORE_CONNECT: case MQTT_EVENT_BEFORE_CONNECT:
// LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTING)); // LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTING));
@ -338,7 +382,7 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
onMqttConnect(event->client); onMqttConnect(event->client);
break; break;
case MQTT_EVENT_SUBSCRIBED: case MQTT_EVENT_SUBSCRIBED:
// onMqttSubscribed(event); onMqttSubscribed(event);
break; break;
case MQTT_EVENT_DATA: case MQTT_EVENT_DATA:
onMqttData(event); onMqttData(event);
@ -385,8 +429,7 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
void mqttSetup() void mqttSetup()
{ {
/*queue = xQueueCreate(20, sizeof(mqtt_message_t)); */ queue = xQueueCreate(64, sizeof(mqtt_message_t));
esp_crt_bundle_set(rootca_crt_bundle_start); esp_crt_bundle_set(rootca_crt_bundle_start);
mqttStart(); mqttStart();
} }
@ -395,15 +438,17 @@ IRAM_ATTR void mqttLoop(void)
{ {
// mqttClient.loop(); // mqttClient.loop();
/* if(!uxQueueMessagesWaiting(queue)) return;
mqtt_message_t data; mqtt_message_t data;
while(xQueueReceive(queue, &data, (TickType_t)0)) { while(xQueueReceive(queue, &data, (TickType_t)0)) {
LOG_DEBUG(TAG_MQTT, F("[%s] Received data from queue == %s\n"), pcTaskGetTaskName(NULL), data.topic); LOG_WARNING(TAG_MQTT, F("[%d] QUE %s => %s"), uxQueueMessagesWaiting(queue), data.topic, data.payload);
size_t length = strlen(data.payload); size_t length = strlen(data.payload);
dispatch_topic_payload(data.topic, data.payload, length > 0, TAG_MQTT); dispatch_topic_payload(data.topic, data.payload, length > 0, TAG_MQTT);
delay(1); hasp_free(data.topic);
hasp_free(data.payload);
// delay(1);
} }
*/
} }
void mqttEvery5Seconds(bool networkIsConnected) void mqttEvery5Seconds(bool networkIsConnected)
@ -461,6 +506,8 @@ void mqttStart()
mqtt_cfg.lwt_topic = mqttLwtTopic; mqtt_cfg.lwt_topic = mqttLwtTopic;
mqtt_cfg.lwt_qos = 1; mqtt_cfg.lwt_qos = 1;
mqtt_cfg.task_prio = 1;
// mqtt_cfg.crt_bundle_attach = esp_crt_bundle_attach; // mqtt_cfg.crt_bundle_attach = esp_crt_bundle_attach;
// test Mosquitto doesn't need a user/pwd // test Mosquitto doesn't need a user/pwd