mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-09-25 22:23:37 +00:00
Every message send on the device was deterministically rebooting it: send_message() ran the full pipeline (identity recall, message construction, RouterLock-scoped router admission, and LittleFS persistence) synchronously on LVGL's 8 KiB task while holding the LVGL mutex. On this device's degraded filesystem a single save takes ~7s of 400ms-2s per-op gaps, tripping the 5s LVGL deadlock guard and asserting at LVGLLock.h:45 (assert failed: LVGL mutex timeout (5s)). The receive path already carries the fix pattern for exactly this failure class (see on_message_received); the send path never got it. Restructure the send path as a mailbox handoff, following the existing CallStartMailbox / LocationShareCommandMailbox precedent: - send_message() (LVGL task) now only validates and publishes (destination, content, source) into a mutex-guarded single-slot OutgoingSendMailbox. No router lock, no I/O, no message construction. - update() services the mailbox in service_pending_sends() on the main loop, before the big LVGL_LOCK() — the only place in the send path that may take the router lock, block on admission, or wait on LittleFS. - On acceptance, a brief LVGL_LOCK in apply_outbound_result() commits the UI (add_message / clear_composer / compose->chat navigation, route-guarded). The admitted packed form is unpacked for display with incoming/state flags restored. - On rejection (storage error, router busy, queue full) the user's input is retained for retry, matching the old behavior. The 500-char UI cap bounds the mailbox payload. Build tdeck SUCCESS, 170/170 contract tests pass.
76 lines
2.4 KiB
C++
76 lines
2.4 KiB
C++
// Copyright (c) 2024 microReticulum contributors
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#ifndef UI_LXMF_OUTGOINGSENDBOARD_H
|
|
#define UI_LXMF_OUTGOINGSENDBOARD_H
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <mutex>
|
|
#include <string>
|
|
|
|
namespace UI {
|
|
namespace LXMF {
|
|
|
|
// Single-slot handoff for one outgoing message from the LVGL task to the
|
|
// Arduino main loop. The LVGL task only publishes (destination, content,
|
|
// source); the main loop performs identity recall, signing/pack, the
|
|
// RouterLock-scoped router admission, and the LittleFS persistence there, so
|
|
// a multi-second save can never hold the LVGL mutex past the 5s deadlock
|
|
// guard (LVGLLock.h:45) and trip the assert. The user's input is retained on
|
|
// the screen until the main loop confirms acceptance (see
|
|
// UIManager::apply_outbound_result).
|
|
//
|
|
// One producer (LVGL task), one consumer (main loop). The mutex covers a
|
|
// small copy (strings are moved out on take). A second send while one is
|
|
// pending is rejected and its input is retained for retry — the same UX as
|
|
// the router-busy path.
|
|
class OutgoingSendMailbox {
|
|
public:
|
|
enum class Source : uint8_t {
|
|
None,
|
|
Chat,
|
|
Compose,
|
|
};
|
|
|
|
struct Slot {
|
|
Source source = Source::None;
|
|
std::string destination; // raw peer-hash bytes (binary-safe)
|
|
std::string content; // UTF-8 message text
|
|
};
|
|
|
|
// Returns false when a send is already pending (caller retains input).
|
|
bool request(Source source, const void* destination, size_t destinationSize,
|
|
const char* content, size_t contentSize) {
|
|
std::lock_guard<std::mutex> guard(_mutex);
|
|
if (_slot.source != Source::None) return false;
|
|
_slot.source = source;
|
|
_slot.destination.assign(static_cast<const char*>(destination), destinationSize);
|
|
_slot.content.assign(content, contentSize);
|
|
return true;
|
|
}
|
|
|
|
// Returns false when nothing is pending; the slot is consumed on success.
|
|
bool take(Slot& slot) {
|
|
std::lock_guard<std::mutex> guard(_mutex);
|
|
if (_slot.source == Source::None) return false;
|
|
slot = std::move(_slot);
|
|
_slot = Slot{};
|
|
return true;
|
|
}
|
|
|
|
bool hasPending() const {
|
|
std::lock_guard<std::mutex> guard(_mutex);
|
|
return _slot.source != Source::None;
|
|
}
|
|
|
|
private:
|
|
mutable std::mutex _mutex;
|
|
Slot _slot{};
|
|
};
|
|
|
|
} // namespace LXMF
|
|
} // namespace UI
|
|
|
|
#endif // UI_LXMF_OUTGOINGSENDBOARD_H
|