@geastack/core 0.1.23

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.
Files changed (73) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +36 -0
  3. package/app_frame_perf.cpp +77 -0
  4. package/css.d.ts +1 -0
  5. package/events.cpp +67 -0
  6. package/gea_app_entry.cpp +317 -0
  7. package/gea_sources.mjs +126 -0
  8. package/gea_sources.sh +36 -0
  9. package/include/app.h +60 -0
  10. package/include/apps.h +46 -0
  11. package/include/audio.h +90 -0
  12. package/include/ble.h +212 -0
  13. package/include/bluetooth/hid_profile.h +92 -0
  14. package/include/camera.h +107 -0
  15. package/include/canvas.h +290 -0
  16. package/include/display.h +390 -0
  17. package/include/display_present.h +869 -0
  18. package/include/event.h +32 -0
  19. package/include/events.h +116 -0
  20. package/include/gea/embedded.h +13 -0
  21. package/include/gea/reactive_runtime.h +32 -0
  22. package/include/gea.h +14 -0
  23. package/include/gea_perf_config.h +96 -0
  24. package/include/geaos/abi.h +165 -0
  25. package/include/geolocation.h +126 -0
  26. package/include/gpio.h +61 -0
  27. package/include/graphics/font.h +122 -0
  28. package/include/i2c.h +20 -0
  29. package/include/image.h +156 -0
  30. package/include/imu.h +23 -0
  31. package/include/input.h +33 -0
  32. package/include/memory.h +52 -0
  33. package/include/pixel.h +907 -0
  34. package/include/platform/file_cache.h +18 -0
  35. package/include/power.h +11 -0
  36. package/include/runtime.h +83 -0
  37. package/include/services/app_runner.h +10 -0
  38. package/include/services/app_state.h +14 -0
  39. package/include/services/battery_service.h +12 -0
  40. package/include/services/bluetooth_service.h +13 -0
  41. package/include/services/diagnostics.h +76 -0
  42. package/include/services/diagnostics_platform.h +54 -0
  43. package/include/services/frame_scheduler.h +71 -0
  44. package/include/services/mirror.h +49 -0
  45. package/include/services/network_services.h +25 -0
  46. package/include/services/ota.h +32 -0
  47. package/include/services/runtime_log.h +11 -0
  48. package/include/services/storage_service.h +26 -0
  49. package/include/touch.h +38 -0
  50. package/include/ui/signal.h +149 -0
  51. package/include/wifi.h +67 -0
  52. package/index.d.ts +1940 -0
  53. package/jsx.d.ts +1 -0
  54. package/package.json +70 -0
  55. package/runtime/ble.ts +49 -0
  56. package/runtime/color.ts +21 -0
  57. package/runtime/compiler.ts +43 -0
  58. package/runtime/host.ts +1083 -0
  59. package/runtime/images.ts +129 -0
  60. package/runtime/primitives.ts +49 -0
  61. package/runtime-surface.ts +180 -0
  62. package/runtime.cpp +431 -0
  63. package/runtime.ts +34 -0
  64. package/scripts/build-gea-vite-geatsc.mjs +4514 -0
  65. package/scripts/dotenv-defines.mjs +98 -0
  66. package/scripts/gea-bundle-type-hints.mjs +546 -0
  67. package/scripts/gea-embedded-compat-staging.mjs +17 -0
  68. package/scripts/gea-embedded-compat-transform.mjs +427 -0
  69. package/scripts/gea-vite-module-graph-plugin.mjs +578 -0
  70. package/scripts/generate-gea-embedded-assets.mjs +296 -0
  71. package/scripts/generate-gea-embedded-fonts.mjs +1252 -0
  72. package/scripts/generate-installed-app-plan.mjs +55 -0
  73. package/scripts/native-object-cache.sh +244 -0
@@ -0,0 +1,122 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+
5
+ namespace gea::framework::graphics {
6
+
7
+ struct Glyph {
8
+ int codepoint = 0;
9
+ int sourceX = 0;
10
+ int sourceY = 0;
11
+ int width = 0;
12
+ int height = 0;
13
+ int advance = 0;
14
+ int bearingX = 0;
15
+ int bearingY = 0;
16
+ };
17
+
18
+ class Font {
19
+ public:
20
+ virtual ~Font() = default;
21
+
22
+ virtual bool valid() const = 0;
23
+ virtual int sizePx() const = 0;
24
+ virtual int lineHeight() const = 0;
25
+ virtual int ascender() const = 0;
26
+ virtual bool glyph(int codepoint, Glyph *out) const = 0;
27
+ virtual std::uint8_t coverage(const Glyph &glyph, int row, int col) const = 0;
28
+ };
29
+
30
+ class BitmapFont : public Font {
31
+ public:
32
+ static constexpr int kFirstCodepoint = 0x20;
33
+ static constexpr int kLastCodepoint = 0x7e;
34
+ static constexpr int kGlyphCount = kLastCodepoint - kFirstCodepoint + 1;
35
+ static constexpr int kWidth = 8;
36
+ static constexpr int kHeight = 16;
37
+
38
+ bool valid() const final;
39
+ int sizePx() const final;
40
+ int lineHeight() const final;
41
+ int ascender() const final;
42
+ bool glyph(int codepoint, Glyph *out) const final;
43
+ std::uint8_t coverage(const Glyph &glyph, int row, int col) const final;
44
+
45
+ // Takes a CODEPOINT, not a byte. Typed `char` this silently truncated every
46
+ // non-ASCII glyph: a caller decoding UTF-8 properly still narrowed U+2014 to
47
+ // one byte, and a caller not decoding at all handed over three bytes in turn
48
+ // and got three substitution glyphs. `rowsForCodepoint` already substitutes
49
+ // out-of-range codepoints, which is the whole of the fallback policy.
50
+ const std::uint8_t *glyphRows(int codepoint) const;
51
+
52
+ protected:
53
+ virtual const std::uint8_t *rowsForCodepoint(int codepoint) const = 0;
54
+ };
55
+
56
+ class BitmapFont8x16 final : public BitmapFont {
57
+ public:
58
+ static const BitmapFont8x16 &instance();
59
+
60
+ private:
61
+ const std::uint8_t *rowsForCodepoint(int codepoint) const final;
62
+
63
+ static const std::uint8_t glyphs[kGlyphCount][kHeight];
64
+ };
65
+
66
+ struct RasterizedFontData {
67
+ int id = 0;
68
+ int sizePx = 0;
69
+ int lineHeight = 0;
70
+ int ascender = 0;
71
+ int descender = 0;
72
+ int glyphCount = 0;
73
+ const Glyph *glyphs = nullptr;
74
+ int atlasWidth = 0;
75
+ int atlasHeight = 0;
76
+ const std::uint8_t *atlas = nullptr;
77
+ // Bits per atlas pixel. 8 = one coverage byte per pixel (the default, and
78
+ // what runtime-rasterized fonts always produce). 2 = four pixels per byte,
79
+ // baked offline for panels that can only show four gray levels; rows are
80
+ // byte-aligned (stride = (atlasWidth + 3) / 4) and the leftmost pixel of a
81
+ // byte sits in the most significant bit pair.
82
+ int atlasBits = 8;
83
+ };
84
+
85
+ class RasterizedFont final : public Font {
86
+ public:
87
+ RasterizedFont() = default;
88
+ explicit RasterizedFont(const RasterizedFontData *data);
89
+
90
+ bool valid() const final;
91
+ int sizePx() const final;
92
+ int lineHeight() const final;
93
+ int ascender() const final;
94
+ bool glyph(int codepoint, Glyph *out) const final;
95
+ std::uint8_t coverage(const Glyph &glyph, int row, int col) const final;
96
+ const RasterizedFontData *data() const { return data_; }
97
+
98
+ private:
99
+ const RasterizedFontData *data_ = nullptr;
100
+ };
101
+
102
+ class FontRegistry {
103
+ public:
104
+ static RasterizedFont rasterized(int fontId);
105
+ static RasterizedFont rasterizedFamily(int familyId, int sizePx);
106
+ static const BitmapFont8x16 &bitmap8x16();
107
+ static int familyId(const char *family);
108
+ static const char *familyName(int familyId);
109
+ };
110
+
111
+ namespace generated {
112
+
113
+ const RasterizedFontData *lookupFont(int fontId);
114
+ const RasterizedFontData *lookupFontForFamily(int familyId, int sizePx);
115
+ int lookupFontFamily(const char *family);
116
+ const char *lookupFontFamilyName(int familyId);
117
+ const std::uint8_t *lookupRuntimeTtfFontForFamily(int familyId, unsigned long *length);
118
+ void ensureLinked();
119
+
120
+ } // namespace generated
121
+
122
+ } // namespace gea::framework::graphics
package/include/i2c.h ADDED
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ namespace gea::platform::i2c {
4
+
5
+ class Bus {
6
+ public:
7
+ using NativeHandle = void *;
8
+
9
+ static Bus primary();
10
+
11
+ bool available() const { return handle_ != nullptr; }
12
+ NativeHandle nativeHandle() const { return handle_; }
13
+
14
+ private:
15
+ explicit Bus(NativeHandle handle) : handle_(handle) {}
16
+
17
+ NativeHandle handle_ = nullptr;
18
+ };
19
+
20
+ } // namespace gea::platform::i2c
@@ -0,0 +1,156 @@
1
+ #pragma once
2
+
3
+ #include "pixel.h"
4
+
5
+ #include <cstdint>
6
+
7
+ #if GEA_EMBEDDED_SINGLE_THREAD_IMAGE_STORE
8
+ namespace gea::framework::graphics {
9
+ struct ImageStoreMutex {
10
+ void lock() noexcept {}
11
+ void unlock() noexcept {}
12
+ };
13
+ } // namespace gea::framework::graphics
14
+ #else
15
+ #include <mutex>
16
+ #endif
17
+
18
+ namespace gea::framework::graphics {
19
+
20
+ #if !GEA_EMBEDDED_SINGLE_THREAD_IMAGE_STORE
21
+ using ImageStoreMutex = std::mutex;
22
+ #endif
23
+
24
+ // Decoded-image slot pool. Slots are lazy (pixel buffers allocated only on
25
+ // decode), so a larger pool costs almost nothing until filled. 96 lets a
26
+ // tile-grid app (maps) keep ~4 screens of decoded tiles resident in PSRAM for
27
+ // instant pan-back, on top of its persistent SD cache. ~128 KiB/tile (RGB565
28
+ // 256x256) when full → ~12 MiB; the P4 has ample PSRAM.
29
+ inline constexpr int kImageMax = 96;
30
+
31
+ enum class ImageFit {
32
+ Fill = 0,
33
+ Contain = 1,
34
+ Cover = 2,
35
+ None = 3,
36
+ ScaleDown = 4,
37
+ };
38
+
39
+ enum class ImageFormat {
40
+ Unknown = 0,
41
+ Jpeg = 1,
42
+ Png = 2,
43
+ Gif = 3,
44
+ };
45
+
46
+ struct ImageSlot {
47
+ int width = 0;
48
+ int height = 0;
49
+ int frameCount = 0;
50
+ ImageFormat format = ImageFormat::Unknown;
51
+ int loopCount = 0;
52
+ int currentFrame = 0;
53
+ bool playing = false;
54
+ int elapsedMs = 0;
55
+ int currentDelayMs = 0;
56
+
57
+ // Decoded pixels in this target's native framebuffer format (RGB565 on
58
+ // esp32/geaos, RGBA8888 on iOS) — set at compile time by pixel::native_t.
59
+ // Full colour on RGBA8888 targets (the decoder's 8-bit channels are kept, not
60
+ // quantized to 565), so native UIImageView presents stills at full colour.
61
+ pixel::native_t *pixels = nullptr;
62
+ std::uint8_t *alpha = nullptr;
63
+ bool ownsPixels = false;
64
+
65
+ void *gifDecoder = nullptr;
66
+ std::uint8_t *gifData = nullptr;
67
+ int gifDataLength = 0;
68
+
69
+ // Deferred decode (decodeDeferred): the encoded bytes live at a stable
70
+ // address (embedded flash assets); only the header was probed for dims.
71
+ // The first pixel access (record time) materializes the decode.
72
+ const std::uint8_t *deferredData = nullptr;
73
+ int deferredLength = 0;
74
+ // stbi_info reports the encoded channel count while probing dimensions.
75
+ // Preserve whether the source has no alpha channel so materialization can
76
+ // discard the synthetic all-255 alpha plane and use the opaque blit path.
77
+ bool deferredOpaque = false;
78
+ };
79
+
80
+ class ImageStore {
81
+ public:
82
+ static ImageStore &instance();
83
+
84
+ int decode(const std::uint8_t *data, int length, int preferredSlot = -1);
85
+ int decodeOpaque(const std::uint8_t *data, int length, int preferredSlot = -1);
86
+ // Deferred decode for encoded bytes at a STABLE address (embedded flash
87
+ // assets): probes only the header for dimensions (layout needs them at
88
+ // mount) and decodes on first pixel access (record time). Cuts boot-time
89
+ // decoding to the icons actually visible. GIFs decode eagerly.
90
+ int decodeDeferred(const std::uint8_t *data, int length, int preferredSlot = -1);
91
+ // Materialize ONE pending deferred decode (idle-time pre-decode). Returns
92
+ // false when none are pending. Lets the frame loop drain deferred slots
93
+ // during idle frames so a later first-draw (e.g. switching weather cities)
94
+ // doesn't bunch every decode into a single visible hitch.
95
+ bool materializeOneDeferred();
96
+ // Register an externally-owned native-format pixel buffer. `takeOwnership`
97
+ // transfers ownership to the store (freed on dispose) — used by the iOS
98
+ // camera capture, which hands over a freshly-allocated RGBA8888 still.
99
+ int registerBuffer(pixel::native_t *pixels, int width, int height, int preferredSlot = -1, bool takeOwnership = false);
100
+
101
+ int width(int id) const;
102
+ int height(int id) const;
103
+ int frameCount(int id) const;
104
+ bool isAnimated(int id) const;
105
+ ImageFormat format(int id) const;
106
+ void setPlaying(int id, bool playing);
107
+ bool playing(int id) const;
108
+ void seek(int id, int frame);
109
+ int currentFrame(int id) const;
110
+ bool advance(int id, int deltaMs);
111
+ const pixel::native_t *framePixels(int id, int frame) const;
112
+ const pixel::native_t *currentPixels(int id) const;
113
+ const std::uint8_t *currentAlpha(int id) const;
114
+ void dispose(int id);
115
+ void disposeAll();
116
+ ImageFormat detectFormat(const std::uint8_t *data, int length) const;
117
+
118
+ private:
119
+ ImageSlot *slot(int id);
120
+ const ImageSlot *slot(int id) const;
121
+ int findFreeSlot(int preferredSlot) const;
122
+ int decodeWithHint(const std::uint8_t *data, int length, int preferredSlot, bool opaqueHint);
123
+ // Materializes a deferred decode in place (no-op when already decoded).
124
+ void materializeDeferred(int id) const;
125
+ int decodeGif(ImageSlot &image, const std::uint8_t *data, int length);
126
+ int decodeStatic(ImageSlot &image, const std::uint8_t *data, int length, bool opaqueHint);
127
+ #if defined(GEA_EMBEDDED_ROM_TJPGD) && GEA_EMBEDDED_ROM_TJPGD
128
+ // Low-memory JPEG decode via the ESP32 ROM tinyjpeg decompressor (descales
129
+ // large covers so they fit the fragmented PSRAM). Fills `image`, returns 0/-1.
130
+ int decodeJpegTjpgd(ImageSlot &image, const std::uint8_t *data, int length);
131
+ #endif
132
+ int decodeNextGifFrame(ImageSlot &image);
133
+ // dispose() body without taking slotMutex_ (callers hold it).
134
+ void disposeLocked(int id);
135
+
136
+ public:
137
+ // Rotate a SQUARE opaque image 90deg so its pixels match the portrait
138
+ // panel orientation (panel-native landscape rendering: tiles rotate once
139
+ // at decode instead of the display rotating every frame). No-op for
140
+ // non-square or alpha-carrying images.
141
+ bool rotate90(int id);
142
+
143
+ private:
144
+
145
+ ImageSlot images_[kImageMax]{};
146
+ bool used_[kImageMax]{};
147
+ // Guards slot ALLOCATION and DISPOSAL only (reservation-style): the async
148
+ // tile loader decodes on the second core while the frame task blits and
149
+ // evicts. A decode reserves its slot under the lock, then fills it
150
+ // unlocked — the slot id isn't visible to the app until the loader
151
+ // delivers it, so nothing reads a half-decoded slot. Pixel READS of
152
+ // already-delivered slots stay lock-free.
153
+ mutable ImageStoreMutex slotMutex_;
154
+ };
155
+
156
+ } // namespace gea::framework::graphics
package/include/imu.h ADDED
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ #include <stdint.h>
4
+
5
+ namespace gea::platform::sensors {
6
+
7
+ class Accelerometer {
8
+ public:
9
+ static void init();
10
+ static void close();
11
+ static void calibrateBias();
12
+ static int tiltX();
13
+ static int tiltY();
14
+ static double accelerationX();
15
+ static double accelerationY();
16
+ static double accelerationZ();
17
+ static double gyroscopeX();
18
+ static double gyroscopeY();
19
+ static double gyroscopeZ();
20
+ static void setWebTilt(int x, int y);
21
+ };
22
+
23
+ } // namespace gea::platform::sensors
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+
3
+ namespace gea::framework::input {
4
+
5
+ // Sets a one-shot "back button pressed" flag. Called from the platform
6
+ // launcher-button task (BOOT short press on ESP32) and from the per-app
7
+ // application's `_settings_toggle()` entry stub.
8
+ void pressBackButton();
9
+
10
+ // Reads and clears the flag. Returns true if there was a pending press.
11
+ // Polled from the launcher's rAF loop; when true and Settings is visible,
12
+ // the launcher closes Settings.
13
+ bool consumeBackButton();
14
+
15
+ // Adds rotary encoder detents to the pending input delta. Called by platform
16
+ // input tasks; drained by the runtime frame loop and dispatched through the UI
17
+ // tree as a normal bubbling `rotary` event.
18
+ void queueRotaryDelta(int delta);
19
+
20
+ // Reads and clears the pending rotary delta. Returns 0 if there is no pending
21
+ // movement.
22
+ int consumeRotaryDelta();
23
+
24
+ // Queues a key press (web keyCode, e.g. 38/40 for ArrowUp/ArrowDown) from a
25
+ // platform input task — hardware buttons on boards without touch. Drained by
26
+ // the runtime frame loop and dispatched through the UI tree as a bubbling
27
+ // `keydown` event. keyCode 0 is ignored.
28
+ void queueKeyDown(int keyCode);
29
+
30
+ // Reads and clears the oldest pending key press. Returns 0 when none pending.
31
+ int consumeKeyDown();
32
+
33
+ } // namespace gea::framework::input
@@ -0,0 +1,52 @@
1
+ #pragma once
2
+
3
+ #include <cstddef>
4
+ #include <cstdint>
5
+
6
+ namespace gea::framework::memory {
7
+
8
+ class Allocator {
9
+ public:
10
+ static void *allocatePreferSpiram(std::size_t size, std::size_t alignment = alignof(std::max_align_t));
11
+ static void *reallocatePreferSpiram(void *ptr, std::size_t size);
12
+ static void free(void *ptr) noexcept;
13
+ };
14
+
15
+ } // namespace gea::framework::memory
16
+
17
+ namespace gea::platform::memory {
18
+
19
+ class Memory {
20
+ public:
21
+ static std::uint32_t internalFree();
22
+ static std::uint32_t internalLargestFreeBlock();
23
+ static std::uint32_t internalMinimumFree();
24
+ static std::uint32_t psramFree();
25
+ static std::uint32_t currentTaskStackHighWaterMark();
26
+ static std::uint32_t geaMainStackBytes();
27
+ static std::uint32_t geaInitStackBytes();
28
+ static std::uint32_t appFrameStackWords();
29
+ static std::uint32_t appFrameStackBytes();
30
+ static std::uint32_t displayFlushConfiguredRows();
31
+ static std::uint32_t displayFlushConfiguredDepth();
32
+ static std::uint32_t displayFlushBufferMaxBytes();
33
+ static std::uint32_t displayFlushRows();
34
+ static std::uint32_t displayFlushDepth();
35
+ static std::uint32_t displayFlushBufferBytes();
36
+
37
+ // Holds `bytes` of internal, DMA-capable RAM out of the general heap and hands
38
+ // back an opaque reserve, so a later allocation that MUST be internal -- a
39
+ // display bus, a DMA descriptor ring -- still finds a block after code that
40
+ // runs earlier has taken what it wants. nullptr when the reserve could not be
41
+ // taken; releaseInternalDma() gives it back. A platform that does not
42
+ // distinguish internal memory returns nullptr and the caller carries on.
43
+ //
44
+ // Deliberately a real method on the platform API rather than a weak hook: a
45
+ // weak *undefined* reference does not pull the defining object out of a static
46
+ // archive, so the hook-shaped version of this linked to null on every ESP32
47
+ // image and the reserve silently never happened.
48
+ static void *reserveInternalDma(std::size_t bytes);
49
+ static void releaseInternalDma(void *reserve);
50
+ };
51
+
52
+ } // namespace gea::platform::memory