Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11d826bdfe | ||
|
|
f49a950e30 | ||
|
|
80b9fd1693 | ||
|
|
2df6f087eb |
No files matched your search
@@ -238,6 +238,7 @@ return app</code></pre>
|
||||
<tr><td>wada.ui.button(text, x, y, w, h, fn)</td><td>A tappable button at <code>x, y</code> sized <code>w × h</code>; <code>fn</code> is called with no arguments.</td></tr>
|
||||
<tr><td>wada.ui.text_w(text [, size])</td><td>Rendered width of <code>text</code> in pixels, for the given size class.</td></tr>
|
||||
<tr><td>wada.ui.text_lines(text, width [, size])</td><td>How many lines <code>text</code> wraps to inside <code>width</code>. Counts explicit newlines too. <b>Use this when you lay out your own rows.</b> <code>label:width()</code> turns wrapping on, so a line longer than the screen becomes two while a fixed <code>y</code> step still advances by one, and the next row is drawn on top of it. This is the single most common way an app's layout goes wrong; it happened to the SDK Test app's channel list.</td></tr>
|
||||
<tr><td>wada.ui.clear()</td><td>Remove every widget from the app's page, leaving the page itself. This is how you build an app with more than one screen: clear, then create the next screen's widgets in the same place you built the first. <b>Any handle you still hold from before the clear is dead</b> — calling a method on it does nothing rather than crashing, but it will not come back, so re-create and re-assign. Older firmware has no <code>ui.clear</code>: write <code>local clear = ui.clear or function() end</code> if you need to run on both.</td></tr>
|
||||
<tr><td>wada.ui.list(x, y, w, h)</td><td>A scrollable list of selectable rows — the "pick one of N" widget. Methods: <code>add(text [, fn])</code> returning the row index, <code>set(i, text)</code>, <code>color(i, c)</code>, <code>select(i)</code> (highlights <i>and</i> scrolls it into view), <code>selected()</code>, <code>count()</code>, <code>clear()</code>, <code>pos(x, y)</code>. Rows are real buttons, so keyboard and trackball navigation walks them on touchless boards without you doing anything.</td></tr>
|
||||
<tr><td>wada.ui.input(title, initial, cb)</td><td>A modal text field. <code>cb(text)</code> on OK, <code>cb(nil)</code> on cancel or on the dialog being closed any other way — exactly one call, always, so an app that disabled itself while waiting always gets to re-enable. Uses the firmware's own dialog and keyboard, so it behaves identically on a touchscreen, on the Tanmatsu's physical keyboard and on a trackball board. One prompt at a time.</td></tr>
|
||||
<tr><td>wada.ui.canvas(w, h)</td><td>A drawing surface. See the canvas methods below.</td></tr>
|
||||
@@ -292,7 +293,8 @@ return app</code></pre>
|
||||
<h2>wada.mesh</h2>
|
||||
<div class="row"><div class="prose">
|
||||
<table class="api">
|
||||
<tr><td>wada.mesh.contacts()</td><td>Array of <code>{name, pubkey, type, ago_s, lat, lon, lat_e6, lon_e6}</code>. <code>pubkey</code> is the first 4 bytes as 8 hex characters — the same short form the rest of the interface uses, and what lines a contact up with a discovery hit.</td></tr>
|
||||
<tr><td>wada.mesh.contacts([offset], [limit])</td><td>Array of <code>{name, pubkey, type, ago_s, lat, lon, lat_e6, lon_e6}</code>. <code>pubkey</code> is the first 4 bytes as 8 hex characters — the same short form the rest of the interface uses, and what lines a contact up with a discovery hit. Returns at most <code>limit</code> entries (default 100, maximum 250) starting at <code>offset</code>, because every entry is an eight-field table and building thousands in one call would exhaust the app heap. On a device with more contacts than that, page through them: ask for 100, then 100 from offset 100, and so on.</td></tr>
|
||||
<tr><td>wada.mesh.contact_count()</td><td>How many contacts the device holds, so you can page through <code>contacts()</code> without calling it repeatedly to find where the list ends.</td></tr>
|
||||
<tr><td>wada.mesh.rx_log()</td><td>Recent packets, newest first: <code>{ago_ms, type, rssi, snr, hops, route, len}</code>, plus whatever identity the frame actually carried — see below. The RF Monitor feed.</td></tr>
|
||||
<tr><td>wada.mesh.stats()</td><td><code>{rssi, noise, rx_air_s, tx_air_s, rx_pkts, rx_err, tx_budget_ms, rx_events, rx_dropped, tx_pkts, freq, bw, sf, duty_pct}</code>.</td></tr>
|
||||
<tr><td>wada.mesh.self()</td><td>This node: <code>{name, pubkey, lat, lon, lat_e6, lon_e6}</code>.</td></tr>
|
||||
@@ -410,7 +412,7 @@ end</code></pre>
|
||||
</table>
|
||||
<p><code>http://</code> only, both of them. On-device TLS is not workable at the heap these boards have left once Wi-Fi has associated, so there is no <code>https</code> to offer; put a proxy in front if you need it. One request in flight at a time per app.</p>
|
||||
<p>The fetch is asynchronous and runs on the firmware's existing network worker, so it does not block the UI. Your callback runs on the UI thread once the body is in memory.</p>
|
||||
<div class="note"><p><b>Plain HTTP only, and that is not an oversight.</b> After Wi-Fi associates there is not enough free internal memory on the smaller boards for a TLS handshake — mbedTLS wants around 30 KB and roughly 5 KB is free. If you need an HTTPS source, put a small proxy in front of it, the way the map tiles do. Responses are capped (64 KB by default).</p></div>
|
||||
<div class="note"><p><b>Plain HTTP only, and that is not an oversight.</b> After Wi-Fi associates there is not enough free internal memory on the smaller boards for a TLS handshake — mbedTLS wants around 30 KB and roughly 5 KB is free. If you need an HTTPS source, put a small proxy in front of it, the way the map tiles do. Responses are capped (192 KB by default).</p></div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# beta_71 - test build. Stable stays beta_65.
|
||||
# One user-facing note per non-blank, non-# line; # lines are section comments.
|
||||
|
||||
# --- For people writing Lua apps ------------------------------------------------------------
|
||||
Apps can clear their page. There was no way to remove the widgets an app had already created, so anything with a second screen drew it on top of the first. wada.ui.clear() takes the page back to empty, and any widget you were still holding from before the clear becomes inert rather than dangerous.
|
||||
Apps can reach all your contacts. The list stopped at 100, and it only ever looked at the first 200 in the first place, so on a device with a lot of contacts most of them were unreachable and nothing said so. wada.mesh.contacts() now takes an offset and a limit, and wada.mesh.contact_count() tells an app how many there are to page through.
|
||||
Apps can be three times larger. The limit was 64 KB, which an ordinary program can reach. It is 192 KB now.
|
||||
|
||||
# --- T-Deck keyboard ---------------------------------------------------------------------------
|
||||
Modifier latching could fail to turn on even with the right keyboard firmware installed. The firmware asked the keyboard what it was capable of exactly once, on the first read after boot, and the first read after boot is the one most likely to come back garbled because the keyboard controller is still starting. One bad answer meant no latching for the rest of the session, and rebooting simply asked again at the same unlucky moment. It now keeps asking for a second and a half before giving up, and says what it actually saw when it does.
|
||||
|
||||
# --- For testers ---------------------------------------------------------------------------------
|
||||
This is a small drop on top of beta_70, which carried the fix for the crash when leaving the known-regions screen. If you have not tried that yet, it is still the thing most worth confirming: add and remove a few regions, leave the screen, check the device stays up.
|
||||
If your screen is not going to sleep, we are still investigating (issue 333) and it is not fixed here.
|
||||
@@ -19,6 +19,11 @@ static uint8_t s_head = 0;
|
||||
static uint8_t s_tail = 0;
|
||||
static bool s_inited = false;
|
||||
enum class KeyboardMode : uint8_t { Probe, Raw, Legacy };
|
||||
// How long to keep asking the C3 for raw frames before settling for legacy mode.
|
||||
// Generous on purpose: getting this wrong costs the user modifier latching for
|
||||
// the entire session, and the only cost of waiting is that the first second of
|
||||
// keystrokes goes through the legacy path, which still works.
|
||||
static const uint32_t kProbeWindowMs = 1500;
|
||||
static KeyboardMode s_mode = KeyboardMode::Probe;
|
||||
static TDeckKeyboardState s_raw_state;
|
||||
static bool s_modifier_input_allowed = true; // guarded by s_keyboard_mux
|
||||
@@ -125,23 +130,46 @@ void tdeckKeyboardPoll() {
|
||||
if (s_mode == KeyboardMode::Probe) {
|
||||
// LilyGO keyboard firmware from June 2025 onward accepts 0x03 and returns
|
||||
// five column-state bytes. Older controllers ignore it and keep returning
|
||||
// one resolved ASCII byte; restore 0x04 key mode immediately in that case.
|
||||
// one resolved ASCII byte; restore 0x04 key mode when that is what we have.
|
||||
//
|
||||
// KEEP RETRYING before concluding "old firmware". This used to decide on a
|
||||
// SINGLE read, and the first I2C read after boot is the least trustworthy
|
||||
// one there is: the C3 is still coming up, so a short or garbled frame is
|
||||
// ordinary. One such frame committed the device to legacy mode for the whole
|
||||
// session, with no recovery short of a reboot -- reported as latching simply
|
||||
// not working on a T-Deck carrying the June 2025 firmware (#332).
|
||||
static uint32_t s_probe_start_ms = 0;
|
||||
const uint32_t now = millis();
|
||||
if (!s_probe_start_ms) s_probe_start_ms = now;
|
||||
|
||||
keyboardCommand(0x03);
|
||||
uint8_t frame[TDeckKeyboardState::COLS] = {};
|
||||
const int count = keyboardRead(frame, sizeof frame);
|
||||
bool valid_raw = count == (int)sizeof frame;
|
||||
for (size_t col = 0; col < sizeof frame && valid_raw; ++col)
|
||||
valid_raw = (frame[col] & 0x80) == 0;
|
||||
size_t bad_col = 0;
|
||||
for (size_t col = 0; col < sizeof frame && valid_raw; ++col) {
|
||||
if (frame[col] & 0x80) { valid_raw = false; bad_col = col; }
|
||||
}
|
||||
if (valid_raw) {
|
||||
s_mode = KeyboardMode::Raw;
|
||||
Serial.println("[keyboard] T-Deck raw mode: modifier latching enabled");
|
||||
processRawFrame(frame, millis());
|
||||
return;
|
||||
}
|
||||
// A legacy controller answers with one resolved byte. Deliver it either way
|
||||
// so nothing typed during the probe window is dropped.
|
||||
if (count == 1) { keyboardCommand(0x04); processLegacyKey(frame[0]); }
|
||||
if ((uint32_t)(now - s_probe_start_ms) < kProbeWindowMs) return; // try again next poll
|
||||
|
||||
keyboardCommand(0x04);
|
||||
s_mode = KeyboardMode::Legacy;
|
||||
Serial.println("[keyboard] T-Deck legacy mode: update keyboard C3 firmware for modifier latching");
|
||||
if (count == 1) processLegacyKey(frame[0]);
|
||||
// Say WHY, so the next report of "latching does not work" is one line to
|
||||
// diagnose instead of a guess about which firmware someone has.
|
||||
Serial.printf("[keyboard] T-Deck legacy mode: update keyboard C3 firmware for modifier "
|
||||
"latching (probe read %d bytes, wanted %d%s)\n",
|
||||
count, (int)sizeof frame,
|
||||
(count == (int)sizeof frame) ? ", high bit set in a column" : "");
|
||||
(void)bad_col;
|
||||
return;
|
||||
}
|
||||
if (s_mode == KeyboardMode::Raw) {
|
||||
|
||||
@@ -170,10 +170,25 @@ void budgetHook(lua_State* L, lua_Debug*) {
|
||||
// host state
|
||||
// ---------------------------------------------------------------------------
|
||||
constexpr size_t kHeapCap = 256 * 1024; // per-app PSRAM cap
|
||||
constexpr size_t kMaxSrc = 64 * 1024; // app source size limit
|
||||
// App source size limit. Was 64 KB, which a real app can reach: reported from a
|
||||
// 2000-contact device whose author hit it writing an ordinary Lua program, not
|
||||
// anything pathological. The source lives in PSRAM only until luaL_loadbuffer
|
||||
// has compiled it, so this is a transient allocation rather than a per-app cost,
|
||||
// and the compiled chunk still has to fit the 256 KB per-app heap below.
|
||||
constexpr size_t kMaxSrc = 192 * 1024; // app source size limit
|
||||
constexpr size_t kStoreMax = 2048; // per-app persisted KV budget (bytes, serialized)
|
||||
constexpr int kMinTickMs = 33; // fastest on_tick cadence (~30 fps)
|
||||
|
||||
// Bumped by wada.ui.clear(). Every widget handle records the generation it was
|
||||
// created in; a handle from an older one has already been destroyed, so the
|
||||
// accessors below null its pointer and the `if (u->obj)` guard that every
|
||||
// method already has does the rest.
|
||||
//
|
||||
// Without this, clear() would be a use-after-free generator: WidgetUd holds a
|
||||
// raw lv_obj_t*, so a Lua variable still referring to a label from the previous
|
||||
// screen would sail past the null check straight into freed memory.
|
||||
static uint32_t s_ui_gen = 1;
|
||||
|
||||
struct Host {
|
||||
lua_State* L = nullptr;
|
||||
LuaHeap heap;
|
||||
@@ -275,7 +290,7 @@ const char* safeUiText(const char* text, size_t length, size_t* safe_length = nu
|
||||
}
|
||||
|
||||
// ---- canvas userdata ----
|
||||
struct CanvasUd { lv_obj_t* obj; lv_color_t* buf; int w, h; };
|
||||
struct CanvasUd { lv_obj_t* obj; lv_color_t* buf; int w, h; uint32_t gen; };
|
||||
|
||||
CanvasUd* checkCanvas(lua_State* L) {
|
||||
return (CanvasUd*)luaL_checkudata(L, 1, "wada.canvas");
|
||||
@@ -368,6 +383,7 @@ int uiCanvas(lua_State* L) {
|
||||
lv_canvas_set_buffer(cv, buf, w, h, LV_IMG_CF_TRUE_COLOR);
|
||||
lv_canvas_fill_bg(cv, lv_color_hex(0x000000), LV_OPA_COVER);
|
||||
CanvasUd* ud = (CanvasUd*)lua_newuserdatauv(L, sizeof(CanvasUd), 0);
|
||||
ud->gen = s_ui_gen;
|
||||
ud->obj = cv; ud->buf = buf; ud->w = w; ud->h = h;
|
||||
luaL_setmetatable(L, "wada.canvas");
|
||||
// Pin the handle in the registry for the app's lifetime. LVGL draws straight
|
||||
@@ -383,8 +399,12 @@ int uiCanvas(lua_State* L) {
|
||||
}
|
||||
|
||||
// ---- label userdata ----
|
||||
struct WidgetUd { lv_obj_t* obj; };
|
||||
WidgetUd* checkLabel(lua_State* L) { return (WidgetUd*)luaL_checkudata(L, 1, "wada.label"); }
|
||||
struct WidgetUd { lv_obj_t* obj; uint32_t gen; };
|
||||
WidgetUd* checkLabel(lua_State* L) {
|
||||
WidgetUd* u = (WidgetUd*)luaL_checkudata(L, 1, "wada.label");
|
||||
if (u->gen != s_ui_gen) u->obj = nullptr; // cleared out from under this handle
|
||||
return u;
|
||||
}
|
||||
|
||||
int lbSet(lua_State* L) {
|
||||
WidgetUd* u = checkLabel(L);
|
||||
@@ -435,14 +455,19 @@ int uiLabel(lua_State* L) {
|
||||
lv_obj_set_style_text_font(l, font, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(l, lv_color_hex(color), LV_PART_MAIN);
|
||||
WidgetUd* ud = (WidgetUd*)lua_newuserdatauv(L, sizeof(WidgetUd), 0);
|
||||
ud->gen = s_ui_gen;
|
||||
ud->obj = l;
|
||||
luaL_setmetatable(L, "wada.label");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---- chart userdata (the primitive the native Monitor/Airtime pages use) ----
|
||||
struct ChartUd { lv_obj_t* obj; lv_chart_series_t* ser[2]; int n_ser; };
|
||||
ChartUd* checkChart(lua_State* L) { return (ChartUd*)luaL_checkudata(L, 1, "wada.chart"); }
|
||||
struct ChartUd { lv_obj_t* obj; lv_chart_series_t* ser[2]; int n_ser; uint32_t gen; };
|
||||
ChartUd* checkChart(lua_State* L) {
|
||||
ChartUd* u = (ChartUd*)luaL_checkudata(L, 1, "wada.chart");
|
||||
if (u->gen != s_ui_gen) { u->obj = nullptr; u->n_ser = 0; }
|
||||
return u;
|
||||
}
|
||||
|
||||
int chPush(lua_State* L) { // chart:push(series_idx, value)
|
||||
ChartUd* c = checkChart(L);
|
||||
@@ -509,6 +534,7 @@ int uiChart(lua_State* L) { // wada.ui.chart(w, h, points, color1 [, color2] [
|
||||
lv_obj_set_style_line_color(ch, lv_color_hex(0x1A1D1F), LV_PART_MAIN); // grid
|
||||
lv_obj_set_style_line_width(ch, 2, LV_PART_ITEMS);
|
||||
ChartUd* ud = (ChartUd*)lua_newuserdatauv(L, sizeof(ChartUd), 0);
|
||||
ud->gen = s_ui_gen;
|
||||
ud->obj = ch;
|
||||
ud->n_ser = 0;
|
||||
ud->ser[0] = lv_chart_add_series(ch, lv_color_hex(argColor(L, 4, 0x15B6A6)), LV_CHART_AXIS_PRIMARY_Y);
|
||||
@@ -557,6 +583,7 @@ int uiButton(lua_State* L) {
|
||||
lv_obj_add_event_cb(b, btnEventCb, LV_EVENT_CLICKED, nullptr);
|
||||
}
|
||||
WidgetUd* ud = (WidgetUd*)lua_newuserdatauv(L, sizeof(WidgetUd), 0);
|
||||
ud->gen = s_ui_gen;
|
||||
ud->obj = b;
|
||||
luaL_setmetatable(L, "wada.label"); // shares set/pos/color methods
|
||||
return 1;
|
||||
@@ -573,8 +600,12 @@ int uiButton(lua_State* L) {
|
||||
// keyboard/trackball focus navigation walks them on touchless boards for free,
|
||||
// and a tap works on the ones with a screen. Per-row callbacks ride the same
|
||||
// button-callback table uiButton uses.
|
||||
struct ListUd { lv_obj_t* obj; int sel; };
|
||||
ListUd* checkList(lua_State* L) { return (ListUd*)luaL_checkudata(L, 1, "wada.list"); }
|
||||
struct ListUd { lv_obj_t* obj; int sel; uint32_t gen; };
|
||||
ListUd* checkList(lua_State* L) {
|
||||
ListUd* u = (ListUd*)luaL_checkudata(L, 1, "wada.list");
|
||||
if (u->gen != s_ui_gen) u->obj = nullptr;
|
||||
return u;
|
||||
}
|
||||
|
||||
lv_obj_t* listRowAt(ListUd* u, int i) { // i is 1-based, as everywhere in Lua
|
||||
if (!u->obj || i < 1) return nullptr;
|
||||
@@ -626,6 +657,24 @@ int uiTextLines(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// wada.ui.clear() -- remove every widget from the app's page.
|
||||
//
|
||||
// The SDK documented building widgets in on_open() and gave no way to take them
|
||||
// down again, so an app with more than one screen drew the second on top of the
|
||||
// first. Reported by pisti87, who had been working around it with buttons.
|
||||
//
|
||||
// Bumping the generation is what makes this safe. A Lua variable still holding a
|
||||
// label from the screen just cleared keeps a raw pointer to freed memory; the
|
||||
// accessors compare generations and null it, so the existing `if (u->obj)` guard
|
||||
// in every method turns a stale call into a no-op instead of a crash.
|
||||
static int uiClear(lua_State* L) {
|
||||
(void)L;
|
||||
if (!s_h || !s_h->body) return 0;
|
||||
lv_obj_clean(s_h->body); // deletes the children, keeps the page itself
|
||||
++s_ui_gen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uiList(lua_State* L) {
|
||||
if (!s_h || !s_h->body) return luaL_error(L, "no app body");
|
||||
const int x = (int)luaL_checkinteger(L, 1), y = (int)luaL_checkinteger(L, 2);
|
||||
@@ -643,6 +692,7 @@ int uiList(lua_State* L) {
|
||||
lv_obj_set_scroll_dir(c, LV_DIR_VER);
|
||||
lv_obj_add_flag(c, LV_OBJ_FLAG_SCROLLABLE);
|
||||
ListUd* ud = (ListUd*)lua_newuserdatauv(L, sizeof(ListUd), 0);
|
||||
ud->gen = s_ui_gen;
|
||||
ud->obj = c; ud->sel = 0;
|
||||
luaL_setmetatable(L, "wada.list");
|
||||
return 1;
|
||||
@@ -1835,10 +1885,35 @@ void pressCb(lv_event_t* e) {
|
||||
}
|
||||
|
||||
// ---- wada.mesh (read-only) ----
|
||||
// wada.mesh.contacts([offset], [limit])
|
||||
//
|
||||
// Used to scan the first 200 contacts and return at most 100, with no way to see
|
||||
// past that and nothing to say it had truncated. On a device with 2000 contacts
|
||||
// an app simply could not reach most of them (reported by Jade).
|
||||
//
|
||||
// It takes an offset and a limit now. The default limit stays 100 because every
|
||||
// entry is an 8-field Lua table and building thousands of them in one call would
|
||||
// blow the per-app heap -- but the window can be moved, so all contacts are
|
||||
// reachable by asking twice. wada.mesh.contact_count() says how many there are.
|
||||
// How many contacts the device holds, so an app can page through them without
|
||||
// calling contacts() repeatedly just to discover where the list ends.
|
||||
static int meshContactCount(lua_State* L) {
|
||||
char name[36], pk[12]; int type; uint32_t ago; double lat, lon; int32_t lat6, lon6;
|
||||
int n = 0;
|
||||
while (n < 4096 && luaHostContactAt(n, name, sizeof name, &type, &ago, &lat, &lon,
|
||||
pk, sizeof pk, &lat6, &lon6)) ++n;
|
||||
lua_pushinteger(L, n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int meshContacts(lua_State* L) {
|
||||
const int offset = (int)luaL_optinteger(L, 1, 0);
|
||||
int limit = (int)luaL_optinteger(L, 2, 100);
|
||||
if (limit < 1) limit = 1;
|
||||
if (limit > 250) limit = 250; // one call still has to fit the app's heap
|
||||
lua_newtable(L);
|
||||
char name[36], pk[12]; int type; uint32_t ago; double lat, lon; int32_t lat6, lon6;
|
||||
for (int i = 0, out = 0; i < 200 && out < 100; i++) {
|
||||
for (int i = (offset > 0 ? offset : 0), out = 0; out < limit; i++) {
|
||||
if (!luaHostContactAt(i, name, sizeof name, &type, &ago, &lat, &lon, pk, sizeof pk,
|
||||
&lat6, &lon6)) break;
|
||||
lua_createtable(L, 0, 8);
|
||||
@@ -2249,6 +2324,7 @@ void openWada(lua_State* L) {
|
||||
lua_setfield(L, -2, "colors");
|
||||
lua_pushcfunction(L, uiInput); lua_setfield(L, -2, "input"); // modal text entry
|
||||
lua_pushcfunction(L, uiList); lua_setfield(L, -2, "list"); // scrollable selectable rows
|
||||
lua_pushcfunction(L, uiClear); lua_setfield(L, -2, "clear"); // wipe the page (#318 / Discord)
|
||||
lua_setfield(L, -2, "ui");
|
||||
|
||||
lua_newtable(L); // wada.sys
|
||||
@@ -2328,6 +2404,7 @@ void openWada(lua_State* L) {
|
||||
|
||||
lua_newtable(L); // wada.mesh (read-only)
|
||||
lua_pushcfunction(L, meshContacts); lua_setfield(L, -2, "contacts");
|
||||
lua_pushcfunction(L, meshContactCount); lua_setfield(L, -2, "contact_count");
|
||||
lua_pushcfunction(L, meshRxLog); lua_setfield(L, -2, "rx_log");
|
||||
lua_pushcfunction(L, meshStats); lua_setfield(L, -2, "stats");
|
||||
lua_pushcfunction(L, meshSelf); lua_setfield(L, -2, "self");
|
||||
|
||||
@@ -26523,7 +26523,7 @@ static bool luaStoreDownloadWorker(WiFiClient& client, HTTPClient& http,
|
||||
luaHostAppPath(appsdir, sizeof appsdir, "/apps");
|
||||
fs->mkdir(appsdir);
|
||||
static const char* const kExt[2] = { "lua", "json" };
|
||||
const size_t kCap[2] = { 64 * 1024, 1024 };
|
||||
const size_t kCap[2] = { 192 * 1024, 1024 }; // must match kMaxSrc in LuaAppHost.cpp
|
||||
for (int e = 0; e < 2; e++) {
|
||||
char* buf = (char*)heap_caps_malloc(kCap[e], MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (!buf) return false;
|
||||
|
||||
Reference in new issue
Block a user