19#include "cdc_msg/MessageTransfer.h"
22#include "freertos/FreeRTOS.h"
23#include "freertos/semphr.h"
28namespace msg = cdc::msg;
34constexpr uint8_t MAX_HANDLERS = 8;
37SemaphoreHandle_t s_lock =
nullptr;
38void lock_init() {
if (!s_lock) s_lock = xSemaphoreCreateMutex(); }
41 Guard() {
if (s_lock) held = (xSemaphoreTake(s_lock, portMAX_DELAY) == pdTRUE); }
42 ~Guard() {
if (held) xSemaphoreGive(s_lock); }
48 void* plugin =
nullptr;
50 uint32_t action_id = 0;
52Handler s_handlers[MAX_HANDLERS];
57 void* plugin =
nullptr;
58 uint32_t action_id = 0;
63EXT_RAM_BSS_ATTR Pending s_pending;
67uint32_t s_cur_len = 0;
73 const auto& caps = p->manifest().capabilities;
74 return caps.ble && !caps.message_types.empty();
77int find_handler(
void* plugin,
const char* mime) {
78 for (
int i = 0; i < MAX_HANDLERS; ++i) {
79 if (s_handlers[i].used && s_handlers[i].plugin == plugin &&
88bool on_deliver(
void* plugin, uint32_t action_id,
const uint8_t* data, uint32_t len,
92 if (s_pending.valid)
return false;
93 s_pending.valid =
true;
94 s_pending.plugin = plugin;
95 s_pending.action_id = action_id;
96 std::strncpy(s_pending.mime, mime ? mime :
"",
sizeof(s_pending.mime) - 1);
97 s_pending.mime[
sizeof(s_pending.mime) - 1] =
'\0';
99 std::memcpy(s_pending.buf, data, len);
108 char peerName[msg::kNameBufSize] = {};
112EXT_RAM_BSS_ATTR DeferredMsg s_deferred;
114int find_handler_by_mime(
const char* mime) {
115 for (
int i = 0; i < MAX_HANDLERS; ++i) {
116 if (s_handlers[i].used && std::strncmp(s_handlers[i].mime, mime,
HOST_MSG_MIME_MAX) == 0) {
124bool stash_deferred(
const uint8_t* data, uint32_t len,
const char* mime,
const char* peerName) {
127 if (s_deferred.valid)
return false;
128 s_deferred.valid =
true;
129 std::strncpy(s_deferred.mime, mime ? mime :
"",
sizeof(s_deferred.mime) - 1);
130 s_deferred.mime[
sizeof(s_deferred.mime) - 1] =
'\0';
131 std::strncpy(s_deferred.peerName, peerName ? peerName :
"",
sizeof(s_deferred.peerName) - 1);
132 s_deferred.peerName[
sizeof(s_deferred.peerName) - 1] =
'\0';
133 s_deferred.len = len;
134 std::memcpy(s_deferred.buf, data, len);
140void handle_deferred() {
145 if (!s_deferred.valid)
return;
146 std::memcpy(mime, s_deferred.mime,
sizeof(mime));
147 std::memcpy(s_cur_buf, s_deferred.buf, s_deferred.len);
148 std::memcpy(s_cur_mime, s_deferred.mime,
sizeof(s_cur_mime));
149 len = s_deferred.len;
151 s_deferred.valid =
false;
154 int idx = find_handler_by_mime(mime);
158 static_cast<pm::Plugin*
>(s_handlers[idx].plugin), s_handlers[idx].action_id, 0, len);
162 s_cur_mime[0] =
'\0';
171 if (!mime_type || !mime_type[0] ||
181 for (
int i = 0; i < MAX_HANDLERS; ++i) {
182 if (s_handlers[i].used && s_handlers[i].plugin != plugin &&
188 int idx = find_handler(plugin, mime_type);
190 for (
int i = 0; i < MAX_HANDLERS; ++i) {
191 if (!s_handlers[i].used) { idx = i;
break; }
196 Handler& h = s_handlers[idx];
199 std::strncpy(h.mime, mime_type,
sizeof(h.mime) - 1);
200 h.mime[
sizeof(h.mime) - 1] =
'\0';
201 h.action_id = action_id;
203 const char* descKey =
204 (std::strncmp(mime_type,
"text/", 5) == 0) ?
"core.msg_text" :
"core.msg_data";
205 bool ok = msg::MessageTransfer::instance().registerHandler(
207 [plugin, action_id](
const uint8_t* d, uint32_t l,
const char* m,
const char*) ->
bool {
208 return on_deliver(plugin, action_id, d, l, m);
220 int idx = find_handler(plugin, mime_type);
222 msg::MessageTransfer::instance().unregisterHandler(s_handlers[idx].mime);
223 s_handlers[idx] = Handler{};
229 uint32_t n = s_cur_len;
230 if (n > buf_size) n =
static_cast<uint32_t
>(buf_size);
231 std::memcpy(buf, s_cur_buf, n);
232 if (mime_out && mime_size) {
233 std::strncpy(mime_out, s_cur_mime, mime_size - 1);
234 mime_out[mime_size - 1] =
'\0';
236 return static_cast<int>(n);
242 bool ok = msg::MessageTransfer::instance().beginInteractiveSend(
243 mime_type, data,
static_cast<uint32_t
>(len));
247int host_msg_send(
const uint8_t addr[6], uint8_t addr_type,
const char* mime_type,
248 const uint8_t* data,
size_t len) {
253 bool ok = msg::MessageTransfer::instance().sendTo(
254 addr, addr_type, mime_type, data,
static_cast<uint32_t
>(len));
260 msg::MessageTransfer::instance().setDeferredHandler(
261 [](
const char* mime) ->
bool {
271 void* plugin =
nullptr;
272 uint32_t aid = 0, len = 0;
275 if (!s_pending.valid)
return;
276 plugin = s_pending.plugin;
277 aid = s_pending.action_id;
279 std::memcpy(s_cur_buf, s_pending.buf, len);
280 std::memcpy(s_cur_mime, s_pending.mime,
sizeof(s_cur_mime));
282 s_pending.valid =
false;
286 static_cast<pm::Plugin*
>(plugin), aid, 0, len);
289 s_cur_mime[0] =
'\0';
294 for (
int i = 0; i < MAX_HANDLERS; ++i) {
295 if (s_handlers[i].used && s_handlers[i].plugin == plugin) {
296 msg::MessageTransfer::instance().unregisterHandler(s_handlers[i].mime);
297 s_handlers[i] = Handler{};
301 if (s_pending.valid && s_pending.plugin == plugin) s_pending.valid =
false;
Discovers, loads, runs and unloads WASM plugins on the badge.
Owned WAMR module instance + per-plugin state.
static PluginManager & instance() noexcept
void dispatchActionTo(Plugin *plugin, uint32_t action_id, uint32_t idx, uint32_t user_data)
bool messageTypeInstalled(const char *mime) const
True if any installed plugin's manifest declares this MIME type for message transfer....
int host_msg_send(const uint8_t addr[6], uint8_t addr_type, const char *mime_type, const uint8_t *data, size_t len)
Send a typed payload directly to a known peer address (no picker).
int host_msg_unregister_handler(const char *mime_type)
Drop a previously registered handler.
int host_msg_send_interactive(const char *mime_type, const uint8_t *data, size_t len)
Send a typed payload via the firmware-owned interactive peer picker.
int host_msg_consume(uint8_t *buf, size_t buf_size, char *mime_out, size_t mime_size)
Pull the payload delivered by the most recent inbound message action.
#define HOST_MSG_PAYLOAD_MAX
Maximum payload a plugin may send or receive in one transfer.
int host_msg_register_handler(const char *mime_type, uint32_t action_id)
Register that this plugin handles an incoming MIME type.
#define HOST_MSG_MIME_MAX
Maximum MIME type string length including the NUL.
CDC Badge OS plugin host API - canonical C ABI contract.
#define HOST_ERR_NO_CAPABILITY
#define HOST_ERR_INVALID_ARG
#define HOST_ERR_NO_MEMORY
#define HOST_ERR_NOT_FOUND
void * plg_get_active_plugin(void)
void plg_msg_on_unload(void *plugin)
void * plg_get_active_plugin(void)