Skip to content

Commit bfc56df

Browse files
committed
2 parents 2d5ce46 + 8234d1d commit bfc56df

9 files changed

Lines changed: 108 additions & 27 deletions

File tree

src/hasp/hasp_attribute.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,17 +197,26 @@ static bool my_line_set_points(lv_obj_t* obj, const char* payload)
197197
{
198198
my_line_clear_points(obj); // delete pointmap
199199

200-
// Create new points
201-
// Reserve memory for JsonDocument
202-
// StaticJsonDocument<1024> doc;
203-
size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 256;
200+
// count LEFT SQUARE BRACKET => nb points +1
201+
uint16_t count = 0;
202+
for (const char* p = payload; *p; p++)
203+
if (*p == '[') count++;
204+
count--;
205+
206+
// Reserve memory for JsonDocument rounded to upper 128 bytes
207+
uint16_t maxsize = 128u * (3*JSON_ARRAY_SIZE(1)*count / 128+1) ;
208+
209+
LOG_VERBOSE(TAG_ATTR,"payload: %s",payload);
210+
LOG_TRACE(TAG_ATTR,"count: %u maxsize: %u taille brut %u",count,maxsize,(uint32_t)(3*JSON_ARRAY_SIZE(1)*count));
211+
204212
DynamicJsonDocument doc(maxsize);
205213
DeserializationError jsonError = deserializeJson(doc, payload);
206214

207215
if(jsonError) { // Couldn't parse incoming JSON payload
208216
dispatch_json_error(TAG_ATTR, jsonError);
209217
return false;
210218
}
219+
LOG_VERBOSE(TAG_ATTR,"Memory usage: %u",(uint32_t)doc.memoryUsage());
211220

212221
JsonArray arr = doc.as<JsonArray>(); // Parse payload
213222
size_t tot_len = sizeof(lv_point_t*) * (arr.size());

src/hasp/hasp_dispatch.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@
2020
#include <iostream>
2121
#include <fstream>
2222
#include <sstream>
23+
#include <queue>
24+
#include <mutex>
25+
#include <string>
2326
#include "../mqtt/hasp_mqtt.h"
27+
28+
/* Deferred command queue: MQTT callback runs on Paho thread; jsonl/json handlers call LVGL
29+
* (hasp_new_object) which is not thread-safe. Queue jsonl/json for processing on main thread.
30+
* 64 is enough for burst layout + state; PC has plenty of memory. */
31+
#define DISPATCH_DEFERRED_QUEUE_MAX 64
32+
static std::queue<std::pair<std::string, std::string>> deferred_queue;
33+
static std::mutex deferred_mutex;
2434
#else
2535
#include "StringStream.h"
2636
#include "StreamUtils.h" // for exec ReadBufferingStream
@@ -463,6 +473,33 @@ void dispatch_topic_payload(const char* topic, const char* payload, bool update,
463473
dispatch_command(topic, (char*)payload, update, source); // dispatch as is
464474
}
465475

476+
#if HASP_TARGET_PC
477+
void dispatch_defer_command(const char* topic, const char* payload)
478+
{
479+
std::lock_guard<std::mutex> lock(deferred_mutex);
480+
if(deferred_queue.size() >= DISPATCH_DEFERRED_QUEUE_MAX) {
481+
(void)deferred_queue.front();
482+
deferred_queue.pop(); // drop oldest
483+
}
484+
deferred_queue.push({std::string(topic), std::string(payload)});
485+
}
486+
487+
void dispatch_process_deferred(void)
488+
{
489+
std::pair<std::string, std::string> item;
490+
for(;;) {
491+
{
492+
std::lock_guard<std::mutex> lock(deferred_mutex);
493+
if(deferred_queue.empty()) break;
494+
item = deferred_queue.front();
495+
deferred_queue.pop();
496+
}
497+
bool update = item.second.size() > 0;
498+
dispatch_topic_payload(item.first.c_str(), item.second.c_str(), update, TAG_MQTT);
499+
}
500+
}
501+
#endif
502+
466503
// void dispatch_output_group_state(uint8_t groupid, uint16_t state)
467504
// {
468505
// char payload[64];

src/hasp/hasp_dispatch.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source);
9393

9494
void dispatch_normalized_group_values(hasp_update_value_t& value);
9595

96+
#if HASP_TARGET_PC
97+
/* Defer json/jsonl from MQTT thread to main (LVGL) thread to avoid segfault (PC/SDL2 only). */
98+
void dispatch_defer_command(const char* topic, const char* payload);
99+
void dispatch_process_deferred(void);
100+
#endif
101+
96102
void dispatch_state_subtopic(const char* subtopic, const char* payload);
97103
void dispatch_state_eventid(const char* topic, hasp_event_t eventid);
98104
void dispatch_state_brightness(const char* topic, hasp_event_t eventid, int32_t val);

src/main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ IRAM_ATTR void loop()
172172
}
173173
#endif
174174

175+
#if HASP_TARGET_PC
176+
/* Process jsonl/json commands deferred from MQTT thread (LVGL not thread-safe on PC). */
177+
dispatch_process_deferred();
178+
#endif
179+
175180
#if HASP_USE_LVGL_TASK == 0
176181
guiLoop();
177182
#endif

src/mqtt/hasp_mqtt_paho_async.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const char FP_CONFIG_GROUP[] PROGMEM = "group";
4444

4545
#include "hasp_mqtt.h" // functions to implement here
4646

47-
#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload
47+
#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload, dispatch_defer_command
4848
#include "hasp_debug.h" // for logging
4949

5050
#if !defined(_WIN32)
@@ -83,6 +83,7 @@ uint16_t mqttPort = MQTT_PORT;
8383

8484
MQTTAsync mqtt_client;
8585

86+
static bool mqttClientCreated = false;
8687
static bool mqttConnecting = false;
8788
static bool mqttConnected = false;
8889

@@ -206,6 +207,11 @@ static void mqtt_message_cb(char* topic, char* payload, size_t length)
206207
// LOG_TRACE(TAG_MQTT, F("ignoring LWT = online"));
207208
}
208209
} else {
210+
// On PC, jsonl/json handlers call LVGL from MQTT thread -> segfault. Defer to main thread.
211+
if(!strcmp(topic, "command/jsonl") || !strcmp(topic, "command/json")) {
212+
dispatch_defer_command(topic, payload);
213+
return;
214+
}
209215
dispatch_mtx.lock();
210216
dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
211217
dispatch_mtx.unlock();
@@ -361,18 +367,21 @@ void mqttStart()
361367
int rc;
362368
int ch;
363369

364-
if((rc = MQTTAsync_create(&mqtt_client, mqttServer.c_str(), haspDevice.get_hostname(), MQTTCLIENT_PERSISTENCE_NONE,
365-
NULL)) != MQTTASYNC_SUCCESS) {
366-
LOG_ERROR(TAG_MQTT, "Failed to create client, return code %d", rc);
367-
rc = EXIT_FAILURE;
368-
return;
369-
}
370+
if(!mqttClientCreated) {
371+
if((rc = MQTTAsync_create(&mqtt_client, mqttServer.c_str(), haspDevice.get_hostname(), MQTTCLIENT_PERSISTENCE_NONE,
372+
NULL)) != MQTTASYNC_SUCCESS) {
373+
LOG_ERROR(TAG_MQTT, "Failed to create client, return code %d", rc);
374+
rc = EXIT_FAILURE;
375+
return;
376+
}
370377

371-
if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, mqtt_message_arrived, NULL)) !=
372-
MQTTASYNC_SUCCESS) {
373-
LOG_ERROR(TAG_MQTT, "Failed to set callbacks, return code %d", rc);
374-
rc = EXIT_FAILURE;
375-
return;
378+
if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, mqtt_message_arrived, NULL)) !=
379+
MQTTASYNC_SUCCESS) {
380+
LOG_ERROR(TAG_MQTT, "Failed to set callbacks, return code %d", rc);
381+
rc = EXIT_FAILURE;
382+
return;
383+
}
384+
mqttClientCreated = true;
376385
}
377386

378387
mqttEnabled = mqttServer.length() > 0 && mqttPort > 0;
@@ -410,6 +419,8 @@ void mqttStart()
410419

411420
void mqttStop()
412421
{
422+
if(!mqttClientCreated) return;
423+
413424
int rc;
414425
MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer;
415426
disc_opts.onSuccess = onDisconnect;
@@ -418,6 +429,8 @@ void mqttStop()
418429
LOG_ERROR(TAG_MQTT, "Failed to disconnect, return code %d", rc);
419430
rc = EXIT_FAILURE;
420431
}
432+
MQTTAsync_destroy(&mqtt_client);
433+
mqttClientCreated = false;
421434
}
422435

423436
void mqttSetup()

src/mqtt/hasp_mqtt_paho_single.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ uint16_t mqttPort = MQTT_PORT;
8080

8181
MQTTClient mqtt_client;
8282

83+
static bool mqttClientCreated = false;
8384
int disc_finished = 0;
8485
int subscribed = 0;
8586
int connected = 0;
@@ -300,18 +301,21 @@ void mqttStart()
300301
int ch;
301302

302303
LOG_DEBUG(TAG_MQTT, "%s %d", __FILE__, __LINE__);
303-
if((rc = MQTTClient_create(&mqtt_client, mqttServer.c_str(), haspDevice.get_hostname(), MQTTCLIENT_PERSISTENCE_NONE,
304-
NULL)) != MQTTCLIENT_SUCCESS) {
305-
LOG_ERROR(TAG_MQTT, "Failed to create client, return code %d", rc);
306-
rc = EXIT_FAILURE;
307-
return;
308-
}
304+
if(!mqttClientCreated) {
305+
if((rc = MQTTClient_create(&mqtt_client, mqttServer.c_str(), haspDevice.get_hostname(), MQTTCLIENT_PERSISTENCE_NONE,
306+
NULL)) != MQTTCLIENT_SUCCESS) {
307+
LOG_ERROR(TAG_MQTT, "Failed to create client, return code %d", rc);
308+
rc = EXIT_FAILURE;
309+
return;
310+
}
309311

310-
if((rc = MQTTClient_setCallbacks(mqtt_client, mqtt_client, connlost, mqtt_message_arrived, NULL)) !=
311-
MQTTCLIENT_SUCCESS) {
312-
LOG_ERROR(TAG_MQTT, "Failed to set callbacks, return code %d", rc);
313-
rc = EXIT_FAILURE;
314-
return;
312+
if((rc = MQTTClient_setCallbacks(mqtt_client, mqtt_client, connlost, mqtt_message_arrived, NULL)) !=
313+
MQTTCLIENT_SUCCESS) {
314+
LOG_ERROR(TAG_MQTT, "Failed to set callbacks, return code %d", rc);
315+
rc = EXIT_FAILURE;
316+
return;
317+
}
318+
mqttClientCreated = true;
315319
}
316320

317321
LOG_DEBUG(TAG_MQTT, "%s %d", __FILE__, __LINE__);
@@ -350,6 +354,8 @@ void mqttStart()
350354

351355
void mqttStop()
352356
{
357+
if(!mqttClientCreated) return;
358+
353359
int rc;
354360
// MQTTClient_disconnectOptions disc_opts = MQTTClient_disconnectOptions_initializer;
355361
// disc_opts.onSuccess = onDisconnect;
@@ -358,6 +364,8 @@ void mqttStop()
358364
LOG_ERROR(TAG_MQTT, "Failed to disconnect, return code %d", rc);
359365
rc = EXIT_FAILURE;
360366
}
367+
MQTTClient_destroy(&mqtt_client);
368+
mqttClientCreated = false;
361369
}
362370

363371
void mqttSetup()

user_setups/darwin/darwin_headless.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extra_scripts =
66
tools/linux_build_extra.py
77
build_flags =
88
${env.build_flags}
9+
-std=c++14
910
-D HASP_MODEL="MacOS Headless"
1011
-D HASP_TARGET_PC=1
1112

user_setups/linux/linux_fbdev.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extra_scripts =
44
tools/linux_build_extra.py
55
build_flags =
66
${env.build_flags}
7+
-std=c++14
78
-D HASP_MODEL="Linux App"
89
-D HASP_TARGET_PC=1
910

user_setups/linux/linux_headless.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extra_scripts =
44
tools/linux_build_extra.py
55
build_flags =
66
${env.build_flags}
7+
-std=c++14
78
-D HASP_MODEL="Linux Headless"
89
-D HASP_TARGET_PC=1
910

0 commit comments

Comments
 (0)