Files
pyxis/lib/tdeck_ui/UI/LXMF/OutgoingSendMailbox.h
T
Torlando 3c6275d9e6 chore(diag): gate [SENDT] and [PG] instrumentation behind build flags
[SENDT] send-pipeline timing and the microReticulum [PG] path-store
call-site counters now compile to no-ops unless explicitly enabled:
  - DPYXIS_SEND_DIAG / -DRNS_PATHGET_DIAG added to env:tdeck base flags
  - both removed by env:tdeck-release build_unflags (no-op in release)

So production tdeck/tdeck-release builds are merge-clean, while the
instrumented build stays one env/flag away for the path-request
spammer hunt. Bumps microReticulum pin to 921b3aa (same endpoint
hot-path read gate, counters gated behind RNS_PATHGET_DIAG).

Contract suite: 176/176.
2026-09-06 22:42:16 +00:00

78 lines
2.6 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
uint32_t enqueued_ms = 0; // millis() at request() — queue-wait telemetry (PYXIS_SEND_DIAG)
};
// 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);
_slot.enqueued_ms = millis();
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