@mikrojs/firmware 0.13.0 → 0.14.0-pr-229.g46bcbe2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,20 +6,19 @@ ESP32 firmware package for Mikro.js. Provides the ESP-IDF integration, build sys
6
6
 
7
7
  - **`project.cmake`** - CMake module that integrates with ESP-IDF. Handles component discovery, SDK config merging, and partition table defaults.
8
8
  - **`components/mikrojs/`** - ESP-IDF component that compiles the Mikro.js runtime, QuickJS engine, and platform-specific C modules.
9
- - **`idf.py` wrapper** - Runs `idf.py` through `eim run`, so you don't need to manually activate ESP-IDF.
10
9
  - **Default configs** - `sdkconfig.defaults` and `partitions.csv` for common setups.
11
10
 
12
11
  ## Usage
13
12
 
14
- A custom firmware project depends on this package and includes `project.cmake`:
13
+ A custom firmware project depends on this package and includes `project.cmake` (resolved via `resolve.js`, see the docs below for the CMakeLists boilerplate):
15
14
 
16
15
  ```
17
16
  my-firmware/
18
17
  ├── package.json # depends on @mikrojs/firmware
19
- ├── CMakeLists.txt # include($ENV{MIKROJS_PROJECT_CMAKE})
20
- └── main/
21
- ├── CMakeLists.txt
22
- └── main.cpp # calls MIK_Main()
18
+ ├── CMakeLists.txt # resolves and includes project.cmake via resolve.js
19
+ └── main/ # optional: omit it and the package's default main
20
+ ├── CMakeLists.txt # (which calls MIK_Main()) is used automatically
21
+ └── main.cpp
23
22
  ```
24
23
 
25
24
  See the [Custom Firmware](https://mikrojs.dev/develop/custom-firmware) docs for details.
@@ -27,4 +26,6 @@ See the [Custom Firmware](https://mikrojs.dev/develop/custom-firmware) docs for
27
26
  ## Requirements
28
27
 
29
28
  - Node.js >= 24
30
- - ESP-IDF >= 6.0.1 (installed via [EIM](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html))
29
+ - ESP-IDF >= 6.0.1 (installed via [EIM](https://docs.espressif.com/projects/idf-im-ui/en/latest/))
30
+
31
+ To build, activate ESP-IDF in your shell first: run `eim select` and source the activation script it prints, then use `idf.py` as usual.
@@ -581,6 +581,14 @@ static JSValue mik__http_request(JSContext* ctx, JSValue this_val, int argc, JSV
581
581
  MIKHttpPending pending = {};
582
582
  pending.id = mik__http_st(mik_rt)->next_id++;
583
583
  JSValue headers_promise = MIK_InitPromise(ctx, &pending.headers_promise);
584
+ if (JS_IsException(headers_promise)) {
585
+ /* OOM building the promise. Nothing is registered yet, so just free the
586
+ * request and propagate. Do NOT register this pending entry: its
587
+ * headers_promise.rfuncs are unwritten on failure, and a later
588
+ * consume/destroy would free dangling values (gc_decref underflow). */
589
+ mik__http_free_request(&req);
590
+ return JS_EXCEPTION;
591
+ }
584
592
 
585
593
  auto* cancelled = new std::atomic<bool>(false);
586
594
  pending.cancelled = cancelled;
@@ -672,6 +680,12 @@ static JSValue mik__http_next_message(JSContext* ctx, JSValue this_val, int argc
672
680
 
673
681
  /* Slow path: wait. Create a new promise stored on the pending entry. */
674
682
  JSValue promise = MIK_InitPromise(ctx, &p->next_promise);
683
+ if (JS_IsException(promise)) {
684
+ /* OOM building the promise. Do NOT mark next_promise_active: rfuncs are
685
+ * unwritten on failure, so a later resolve/destroy would free dangling
686
+ * values (gc_decref underflow). */
687
+ return JS_EXCEPTION;
688
+ }
675
689
  p->next_promise_active = true;
676
690
  return promise;
677
691
  }
@@ -144,6 +144,15 @@ static JSValue mik__sntp_sync(JSContext* ctx, JSValue this_val, int argc, JSValu
144
144
 
145
145
  /* Create and return promise wrapped in result */
146
146
  JSValue promise = MIK_InitPromise(ctx, &state->sync_promise);
147
+ if (JS_IsException(promise)) {
148
+ /* OOM building the promise. Tear down so we don't leave a half-started
149
+ * sync, and crucially do NOT set sync_pending: MIK_InitPromise leaves
150
+ * sync_promise.rfuncs unwritten on failure, so a later consume/destroy
151
+ * would free dangling values (gc_decref refcount underflow). */
152
+ esp_netif_sntp_deinit();
153
+ state->running = false;
154
+ return JS_EXCEPTION;
155
+ }
147
156
  state->sync_pending = true;
148
157
 
149
158
  return mik__result_ok(ctx, promise);
@@ -2,6 +2,7 @@
2
2
  #include <vector>
3
3
 
4
4
  #include "esp_event.h"
5
+ #include "esp_heap_caps.h"
5
6
  #include "esp_log.h"
6
7
  #include "esp_mac.h"
7
8
  #include "esp_netif.h"
@@ -332,6 +333,17 @@ fail_after_init:
332
333
  return err;
333
334
  }
334
335
 
336
+ /* Minimum free internal (DMA-capable) RAM required before bringing up the
337
+ * radio. esp_wifi_start() enables the PHY, which calloc()s its RF
338
+ * calibration data from internal RAM and calls abort() on failure
339
+ * (esp_phy/src/phy_init.c: "failed to allocate memory for RF calibration
340
+ * data"). That hard-abort reboots the device instead of surfacing a
341
+ * catchable error, so we pre-flight the heap here and refuse gracefully
342
+ * when it's too low. The figure covers the PHY cal buffers plus the WiFi
343
+ * driver's start-time internal allocations with margin; it is a heuristic,
344
+ * not an exact bound. Tune if a healthy device ever trips it. */
345
+ static constexpr size_t MIK_WIFI_MIN_INTERNAL_HEAP = 40 * 1024;
346
+
335
347
  /* Start the WiFi radio. Deferred from init so the radio is not active
336
348
  * until connect() or scan() is actually called. */
337
349
  static esp_err_t mik__wifi_ensure_started(JSContext* ctx) {
@@ -339,6 +351,13 @@ static esp_err_t mik__wifi_ensure_started(JSContext* ctx) {
339
351
  if (err != ESP_OK) return err;
340
352
  if (s_wifi_started) return ESP_OK;
341
353
 
354
+ /* Refuse to start under low internal RAM rather than let the PHY init
355
+ * abort() the whole device. The caller turns ESP_ERR_NO_MEM into a
356
+ * catchable StartFailed result. */
357
+ if (heap_caps_get_free_size(MALLOC_CAP_INTERNAL) < MIK_WIFI_MIN_INTERNAL_HEAP) {
358
+ return ESP_ERR_NO_MEM;
359
+ }
360
+
342
361
  err = esp_wifi_start();
343
362
  if (err != ESP_OK) return err;
344
363
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikrojs/firmware",
3
- "version": "0.13.0",
3
+ "version": "0.14.0-pr-229.g46bcbe2",
4
4
  "description": "Mikro.js ESP32 firmware: ESP-IDF component, build tools, and project template",
5
5
  "keywords": [
6
6
  "esp-idf",
@@ -18,9 +18,6 @@
18
18
  "type": "git",
19
19
  "url": "git+https://github.com/mikrojs/mikro.git"
20
20
  },
21
- "bin": {
22
- "idf.py": "./bin/idf.py"
23
- },
24
21
  "files": [
25
22
  "components",
26
23
  "default-app",
@@ -28,7 +25,6 @@
28
25
  "sdkconfig.defaults",
29
26
  "sdkconfig.defaults.*",
30
27
  "partitions.csv",
31
- "bin",
32
28
  "chips.json",
33
29
  "cmake.js",
34
30
  "discover.js",
@@ -51,8 +47,8 @@
51
47
  },
52
48
  "dependencies": {
53
49
  "esbuild": "^0.28.0",
54
- "@mikrojs/native": "0.13.0",
55
- "@mikrojs/quickjs": "0.13.0"
50
+ "@mikrojs/native": "0.14.0-pr-229.g46bcbe2",
51
+ "@mikrojs/quickjs": "0.14.0-pr-229.g46bcbe2"
56
52
  },
57
53
  "engines": {
58
54
  "node": ">=24.0.0"
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -21,11 +21,11 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
21
21
  # Use -Os to reduce code size (less IRAM pressure, smaller function frames)
22
22
  CONFIG_COMPILER_OPTIMIZATION_SIZE=y
23
23
 
24
- # Move system functions from IRAM to flash (IRAM and DRAM share the same
25
- # SRAM on single-core chips like C3/C6, so freeing IRAM also frees DRAM)
24
+ # Move heap functions from IRAM to flash (IRAM and DRAM share the same
25
+ # SRAM on single-core chips like C3/C6, so freeing IRAM also frees DRAM).
26
+ # FreeRTOS and esp_ringbuf functions are placed in flash by default since
27
+ # ESP-IDF 6.0; their *_PLACE_FUNCTIONS_INTO_FLASH options were removed.
26
28
  CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH=y
27
- CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
28
- CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH=y
29
29
 
30
30
  # Trade WiFi throughput for ~15-20KB IRAM savings. Fine for mikrojs
31
31
  # workloads (HTTP requests, small payloads — not high-throughput streaming).
package/bin/idf.py DELETED
@@ -1,7 +0,0 @@
1
- #!/bin/sh
2
- # Thin wrapper: runs idf.py via eim in the activated ESP-IDF environment.
3
- # Usage: idf.py <args>
4
- # idf.py build
5
- # idf.py set-target esp32c6
6
- # idf.py build flash monitor
7
- exec eim run "idf.py $*"