444d87de82633f06a9e8b30ec44b473fd0db8d3a
25
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
243ae8b408 |
feat: show crash reason on boot (#1453)
## Summary If the system reboots from crash, display the reason and tell user to include `crash_report.txt` file. To test this, simply add an `assert(false)` somewhere inside the code.  --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
526c8a5e7a |
fix: use sleep routine from the original firmware (#1298)
## Summary Fixes #1263 I spent half of my day(-off) reverse engineering the stock english firmware V3.1.1, it's more or less like solving a sudoku with some known pieces (like debug strings, known static addresses, known compiled function, etc) and then the task is to guess the rest. Long story short, this is the sleep routine that they use: <img width="674" height="604" alt="image" src="https://github.com/user-attachments/assets/6d53ce44-7bae-40c7-b4fb-24f898dbcc05" /> From the code above: - They pull down GPIO13 (value = 0xd) before sleep - They verify that power button is released by doing a delay loop of 50ms, similar to what we're doing - `esp_sleep_config_gpio_isolate` is called but I'm not 100% sure why - Pull up power button, note that it's likely redundant because power button should already pulled up by `InputManager` - `param1` and `param2` means enabling front/side buttons for wake up, but it doesn't used in the code in reality. But I think it's physically impossible, see the explanation below - `param3` means "wake up from power button" - `esp_sleep_start` is used; there is a logic to handle if it fails to sleep, then retry recursively (no idea why!) My observation is that they use GPIO13 so that it will be on HIGH state when the chip is powered on, without any user space code to keep it on that state. And once going to deep sleep, it goes into FLOATING by default. That may explain why it need to be in LOW state before going to sleep. (Nice trick btw) Looking again at the circuit diagram provided [here](https://github.com/sunwoods/Xteink-X4/blob/main/readme-img/sch.jpg) (note: it's not official): <img width="705" height="384" alt="image" src="https://github.com/user-attachments/assets/b98d59fd-47ca-4d3d-a24a-94bf999e957b" /> It kinda make sense as the GPIO13 and VBUS (USB VCC) have the same role, they are part of a simple "battery protection" cirtuit Now, we may wonder, how the device wake up when there is no battery at all? <img width="440" height="323" alt="image" src="https://github.com/user-attachments/assets/2981c411-239b-49a7-b9f7-9a75b6c1b6d3" /> It seems like power button is not just a simple switch between GPIO3 and ground, but it also linked the POWER_CTRL, which leads to nowhere on the diagram, but I suppose it connects the battery back for a short amount of time, just enough for the MCU to wake up, and GPIO13 goes HIGH again. It may also explain why power button becomes non-responsive for ~1 second after power on, as it's being pulled up by the current from battery (remind: high = not pressed, low = pressed) To test the theory above, I simply **comment out** the `esp_deep_sleep_enable_gpio_wakeup`: - On battery, power button works as nothing happen - On USB, it doesn't wake up, I need to press RST --- Important things about my analysis: 1. I had to name every function on the code above **manually**, but I'm 99% confident about it. The only function that I'm not sure is `esp_wifi_bt_power_domain_off` ; Edit: it was indeed mislabeled, see https://github.com/crosspoint-reader/crosspoint-reader/pull/1298#discussion_r2879670852 2. Some logic inside the stock firmware looks very strange, there is almost no mention to "arduino" in the hardware, suggesting that they may just call esp-idf functions directly, bypassing the arduino abstraction. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** --------- Co-authored-by: Zach Nelson <zach@zdnelson.com> |
||
|
|
c40e92e4d1 |
fix: dump crash log without usb plugged, bump release log to INFO (#1332)
## Summary Follow-up https://github.com/crosspoint-reader/crosspoint-reader/pull/1145 - Fix log not being record without USB connected - Bump release log to INFO for more logging details --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> |
||
|
|
18b36efbae |
feat: dump crash report to sdcard (#1145)
## Summary This allow dumping crash message (i.e. assertion fail) and stack trace to `crash_report.txt` file on sdcard. The stack trace can then be decoded using https://esphome.github.io/esp-stacktrace-decoder/ Could be useful to debug things like https://github.com/crosspoint-reader/crosspoint-reader/issues/1137 where error doesn't always happen. May also be useful to show a screen to tell what happen (show on next boot after crash), similar to [flipper zero crash message](https://www.reddit.com/r/flipperzero/comments/10f8m3f/anyone_who_can_tell_me_why_this_message_pops_up/) , but this is better to be a dedicated PR (I'm missing the `drawTextWrapped` function, too lazy to code it ; update: exactly what I need in https://github.com/crosspoint-reader/crosspoint-reader/pull/1141) To test this: - Option 1: add an `assert(false)` somewhere in the code - Option 2: try dereferencing a nullptr - Option 3: try `throw` an exception Example of a crash report: ``` CrossPoint version: 1.1.0-dev Panic reason: abort() was called at PC 0x4214585b on core 0 Recent logs: [196] [DBG] [GFX] Time = 2 ms from clearScreen to displayBuffer [1831] [DBG] [RBS] Recent books loaded from file (7 entries) [1832] [DBG] [ACT] Exiting activity: Boot [1832] [DBG] [ACT] Entering activity: Home [1891] [DBG] [GFX] Time = 54 ms from clearScreen to displayBuffer [2521] [DBG] [GFX] Time = 46 ms from clearScreen to displayBuffer [4839] [DBG] [PWR] Going to low-power mode [10048] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes [20060] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes [30072] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes [34453] [DBG] [PWR] Restoring normal CPU frequency [34485] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer [35182] [DBG] [GFX] Time = 31 ms from clearScreen to displayBuffer [36675] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer [38800] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer [40079] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes Stack memory: 0x3FCB0650: 0x00000000 0x00000000 0x3FCB0668 0x4038DBB6 0x00000000 0x00000000 0x3FCA0030 0x3FC936D0 0x3FCB0670: 0x3FCB067C 0x3FC936EC 0x3FCB0668 0x34313234 0x62353835 0x00000000 0x726F6261 0x20292874 0x3FCB0690: 0x20736177 0x6C6C6163 0x61206465 0x43502074 0x34783020 0x35343132 0x20623538 0x63206E6F 0x3FCB06B0: 0x2065726F 0x00000030 0x3FCA0000 0xB37A603F 0x00000001 0x3FCA7000 0x3FCABCDC 0x4214585E 0x3FCB06D0: 0x3FCA7000 0x3FCA7000 0x3FCABCDC 0x421458AA 0x3FCABCDC 0x3FCA7000 0x3FCABCDC 0x421459CC 0x3FCB06F0: 0x3FCA7000 0x3FCA7000 0x42145D5A 0x3C205624 0x40388560 0x3FCA7000 0x3FCABCFC 0x42079866 0x3FCB0710: 0x3FCA7000 0x3FCA7000 0x00009C9A 0x4207B7F6 0x3FCA7000 0x42090000 0x001B7740 0x00000001 0x3FCB0730: 0x3FCA7000 0x3FCA7000 0x00000001 0x600C0028 0x00000001 0x3FCA1000 0x00000000 0x00000000 0x3FCB0750: 0x00000000 0x00000000 0x00000000 0xB37A603F 0x00000000 0x00000000 0x00000000 0x00000000 0x3FCB0770: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x42090000 0x3FCA7000 0x4208F9C4 0x3FCB0790: 0x00000000 0x00000000 0x00000000 0x40388368 0x00000000 0x00000000 0x00000000 0x00000000 0x3FCB07B0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0x3FCB07D0: 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0xBAAD5678 0xDA6D3601 0x5EB5B9C5 0x2602E480 0x3FCB07F0: 0x2BCDD33F 0x15556D4A 0x1F2140A0 0x5D59BEE3 0x8E76449F 0x6FB2D0CE 0xF5F46FAC 0x0112946A 0x3FCB0810: 0x3B0B32E0 0x7A52B537 0x46801DB4 0xDA85DF9F 0x37E83D20 0x12861028 0x47A702BB 0x287A3C8A 0x3FCB0830: 0x03632209 0xD44C5489 0x5E258453 0xFDA77529 0xE6748E23 0xADCF1394 0x67AD6778 0x2C208663 0x3FCB0850: 0xC7985786 0xD4AA3AB2 0x312E1760 0xEC7AEAAE 0x1857020E 0x48003E7E 0xD6CB8763 0x9B4A3F66 0x3FCB0870: 0x4B79E9F6 0xCBF739F0 0x3794C641 0xD0DBA3CB 0x95B9BE15 0x581C9983 0xDE62EFB6 0x20C67C5B 0x3FCB0890: 0x1E4A3DF3 0xFB317C74 0xC0D86103 0x1D79ED56 0x72FE0862 0x3D38B0C8 0xD27EB587 0x0E0A4C40 0x3FCB08B0: 0xF643ADC0 0x56D114D7 0x703AF879 0xAC7F3075 0x89C78C23 0xEDA86814 0xF767B3E3 0x0528838F 0x3FCB08D0: 0x50ED4662 0x11FD38E7 0x8A5A83BB 0x658159BD 0x781AF696 0x8A700F79 0x526DDE23 0xC8472505 0x3FCB08F0: 0x21AACC02 0xCB89369E 0xB82E5BE2 0x4C6C9D7D 0x9E724D9B 0xDC1067F7 0x84478FBC 0x4E89C444 0x3FCB0910: 0x973F4229 0x49F93DA8 0xE30200F6 0xD1B5C391 0x8363A89F 0x2409E74C 0x3AFF7B52 0xCBEC2349 0x3FCB0930: 0xD38F6695 0xBC3EA980 0xF067EBB1 0x7F87D167 0x92B3823B 0x9F0617D7 0xA7537C57 0x12CAB3D4 0x3FCB0950: 0xC82EEE37 0x84D4B4BC 0xE1E2261C 0x488F0ADA 0x96EAF2FF 0x0BC493A0 0xCE614467 0x3829053D 0x3FCB0970: 0xA41156BE 0x2747B77D 0x64DEA90B 0xE704AB0A 0xE4B01006 0x8D51903C 0x56CD3CF2 0x07E0A8E8 0x3FCB0990: 0xD1DE05CE 0x33368522 0xD1889988 0x3A3097F4 0xB0796D09 0xC78948AA 0x6DEFC56E 0xD5C2E1D9 0x3FCB09B0: 0xFD6DD8FA 0xA957B675 0xC202D80D 0x733FF8F4 0xA1484913 0x0B9AFBA6 0x330C07EA 0x2C09AD4C 0x3FCB09D0: 0x3B1E08F7 0x3FCAE7D0 0x00000170 0xABBA1234 0x0000015C 0x3FCB00E0 0x00009C93 0x3FCA13C4 0x3FCB09F0: 0x3FCA13C4 0x3FCB09E4 0x3FCA13BC 0x00000018 0x00000000 0x00000000 0x3FCB09E4 0x00000000 0x3FCB0A10: 0x00000001 0x3FCAE7E0 0x706F6F6C 0x6B736154 0x00000000 0x00000000 0x3FCB07D0 0x00000005 0x3FCB0A30: 0x00000000 0x00000001 0x00000000 0x3FCAB444 0x4209AFF0 0x0017E38F 0x00000000 0x3FCA7BD0 ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> |
||
|
|
307a6608f0 |
chore: remove rendundant xTaskCreate (#1264)
## Summary Ref discussion: https://github.com/crosspoint-reader/crosspoint-reader/pull/1222#discussion_r2865402110 Important note that this is a bug-for-bug fix. In reality, this branch `WiFi.status() == WL_CONNECTED` is pretty much a dead code because the entry point of these 2 activities don't use wifi. It is better to refactor the management of network though, but it's better to be a dedicated PR. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
a57c62f0b4 |
fix: properly implement requestUpdateAndWait() (#1218)
## Summary Properly implement `requestUpdateAndWait()` using freeRTOS direct task notification. FWIW, I think most of the current use cases of `requestUpdateAndWait()` are redundant, better to be replaced by `requestUpdate(true)`. But just keeping them in case we can find a proper use case for it in the future. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **YES**, it's trivial, so I asked an AI to write the code --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> |
||
|
|
6ff5fcd9a7 |
fix: make file system operations thread-safe (HalFile) (#1212)
## Summary Fix https://github.com/crosspoint-reader/crosspoint-reader/issues/1137 Introducing `HalFile`, a thin wrapper around `FsFile` that uses a global mutex to protect file operations. To test this PR, place the code below somewhere in the code base (I placed it in `onGoToRecentBooks`) ```cpp static auto testTask = [](void* param) { for (int i = 0; i < 10; i++) { String json = Storage.readFile("/.crosspoint/settings.json"); LOG_DBG("TEST_TASK", "Read settings.json, bytes read: %u", json.length()); } vTaskDelete(nullptr); }; xTaskCreate(testTask, "test0", 8192, nullptr, 1, nullptr); xTaskCreate(testTask, "test1", 8192, nullptr, 1, nullptr); xTaskCreate(testTask, "test2", 8192, nullptr, 1, nullptr); xTaskCreate(testTask, "test3", 8192, nullptr, 1, nullptr); delay(1000); ``` It will reliably lead to crash on `master`, but will function correctly with this PR. A macro renaming trick is used to avoid changing too many downstream code files. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **PARTIALLY**, only to help with tedious copy-paste tasks --------- Co-authored-by: Zach Nelson <zach@zdnelson.com> |
||
|
|
c4fc4effbd |
refactor: implement ActivityManager (#1016)
## Summary Ref comment: https://github.com/crosspoint-reader/crosspoint-reader/pull/1010#pullrequestreview-3828854640 This PR introduces `ActivityManager`, which mirrors the same concept of Activity in Android, where an activity represents a single screen of the UI. The manager is responsible for launching activities, and ensuring that only one activity is active at a time. Main differences from Android's ActivityManager: - No concept of Bundle or Intent extras - No onPause/onResume, since we don't have a concept of background activities - onActivityResult is implemented via a callback instead of a separate method, for simplicity ## Key changes - Single `renderTask` shared across all activities - No more sub-activity, we manage them using a stack; Results can be passed via `startActivityForResult` and `setResult` - Activity can call `finish()` to destroy themself, but the actual deletion will be handled by `ActivityManager` to avoid `delete this` pattern As a bonus: the manager will automatically call `requestUpdate()` when returning from another activity ## Example usage **BEFORE**: ```cpp // caller enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, [this](const bool connected) { onWifiSelectionComplete(connected); })); // subactivity onComplete(true); // will eventually call exitActivity(), which deletes the caller instance (dangerous behavior) ``` **AFTER**: (mirrors the `startActivityForResult` and `setResult` from android) ```cpp // caller startActivityForResult(new NetworkModeSelectionActivity(renderer, mappedInput), [this](const ActivityResult& result) { onNetworkModeSelected(result.selectedNetworkMode); }); // subactivity ActivityResult result; result.isCancelled = false; result.selectedNetworkMode = mode; setResult(result); finish(); // signals to ActivityManager to go back to last activity AFTER this function returns ``` TODO: - [x] Reconsider if the `Intent` is really necessary or it should be removed (note: it's inspired by [Intent](https://developer.android.com/guide/components/intents-common) from Android API) ==> I decided to keep this pattern fr clarity - [x] Verify if behavior is still correct (i.e. back from sub-activity) - [x] Refactor the `ActivityWithSubactivity` to just simple `Activity` --> We are using a stack for keeping track of sub-activity now - [x] Use single task for rendering --> avoid allocating 8KB stack per activity - [x] Implement the idea of [Activity result](https://developer.android.com/training/basics/intents/result) --> Allow sub-activity like Wifi to report back the status (connected, failed, etc) --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **PARTIALLY**, some repetitive migrations are done by Claude, but I'm the one how ultimately approve it --------- Co-authored-by: Zach Nelson <zach@zdnelson.com> |
||
|
|
ae94e97fb8 |
fix: sdfat warning about redefinition of macro (#1135)
## Summary
Fix redefinition of `FILE_*` macro.
Note that there will still be 2 warning:
```
.pio/libdeps/default/WebSockets/src/WebSocketsClient.cpp: In member function 'void WebSocketsClient::clientDisconnect(WSclient_t*, const char*)':
.pio/libdeps/default/WebSockets/src/WebSocketsClient.cpp:573:31: warning: 'virtual void NetworkClient::flush()' is deprecated: Use clear() instead. [-Wdeprecated-declarations]
573 | client->tcp->flush();
| ~~~~~~~~~~~~~~~~~~^~
```
--> I assume the upstream library need to fix it
And:
```
src/activities/Activity.cpp:8:1: warning: 'noreturn' function does return
8 | }
| ^
```
Will be fixed in #1016
---
### AI Usage
While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.
Did you use AI tools to help write this code? **NO**
|
||
|
|
7761ced0ed |
fix: acquire power lock before sleeping (#1125)
## Summary Ref: https://github.com/crosspoint-reader/crosspoint-reader/issues/1110 Power lock is automatically acquired on `render()`. However, instead of using `render()`, sleep activity render everything right inside `onEnter()`, so no power lock was acquired. After https://github.com/crosspoint-reader/crosspoint-reader/pull/1016 , the power lock will also be acquired on activity transition. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
75ff7b25ab |
fix: double free WebDAVHandler (#1093)
## Summary Ref: https://github.com/crosspoint-reader/crosspoint-reader/pull/1047#discussion_r2838439305 To reproduce: 1. Open file transfer 2. Join a network 3. Once it's connected, press (hold) back --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
840e8c38f1 |
feat: add script for listing objects in flash (#880)
## Summary Adding a simple script to list objects and its size. I know `pio` already had the "analyze" function but it never works in my case. Ref discussion: https://github.com/crosspoint-reader/crosspoint-reader/discussions/862 To use it: ```sh scripts/script_profile_mem.sh ``` Example: ``` ============================================ Top 10 largest symbols in section: .dram0.bss Total section size: 85976 bytes (83.96 KB) ============================================ 0000bb98 ( 46.90 KB) display 00000ed8 ( 3.71 KB) g_cnxMgr 00000ad8 ( 2.71 KB) ftm_initiator 00000830 ( 2.05 KB) xIsrStack 000005b4 ( 1.43 KB) packet.8427 000004e0 ( 1.22 KB) _ZN12_GLOBAL__N_17ctype_wE 000004a0 ( 1.16 KB) dns_table 0000049c ( 1.15 KB) s_wifi_nvs 00000464 ( 1.10 KB) s_coredump_stack 0000034c ( 0.82 KB) gWpaSm ============================================ Top 10 largest symbols in section: .dram0.data Total section size: 13037 bytes (12.73 KB) ============================================ 000003c0 ( 0.94 KB) TxRxCxt 00000328 ( 0.79 KB) phy_param 000001d0 ( 0.45 KB) g_wifi_osi_funcs 0000011b ( 0.28 KB) _ZN18CrossPointSettings8instanceE 000000e6 ( 0.22 KB) country_info_24ghz 000000dc ( 0.21 KB) g_eb_list_desc 000000c0 ( 0.19 KB) s_fd_table 000000b8 ( 0.18 KB) g_timer_info 000000a8 ( 0.16 KB) rc11NSchedTbl 000000a0 ( 0.16 KB) g_rmt_objects ============================================ Top 200 largest symbols in section: .flash.rodata Total section size: 4564375 bytes (4457.40 KB) ============================================ 000325b7 ( 201.43 KB) _ZL12de_trie_data 0001cbd8 ( 114.96 KB) _ZL29notosans_18_bolditalicBitmaps 0001ca38 ( 114.55 KB) _ZL29bookerly_18_bolditalicBitmaps 0001bd3f ( 111.31 KB) _ZL23bookerly_18_boldBitmaps 0001af54 ( 107.83 KB) _ZL23notosans_18_boldBitmaps 0001abcc ( 106.95 KB) _ZL25bookerly_18_italicBitmaps 0001a341 ( 104.81 KB) _ZL25notosans_18_italicBitmaps 0001a0a5 ( 104.16 KB) _ZL26bookerly_18_regularBitmaps 0001890c ( 98.26 KB) _ZL26notosans_18_regularBitmaps 000188cc ( 98.20 KB) _ZL33opendyslexic_14_bolditalicBitmaps 000170ca ( 92.20 KB) _ZL29notosans_16_bolditalicBitmaps 00015e7f ( 87.62 KB) _ZL29bookerly_16_bolditalicBitmaps 00015acb ( 86.70 KB) _ZL23notosans_16_boldBitmaps 00015140 ( 84.31 KB) _ZL23bookerly_16_boldBitmaps 00014f0c ( 83.76 KB) _ZL25notosans_16_italicBitmaps 00014d54 ( 83.33 KB) _ZL29opendyslexic_14_italicBitmaps 00014766 ( 81.85 KB) _ZL27opendyslexic_14_boldBitmaps 0001467f ( 81.62 KB) _ZL25bookerly_16_italicBitmaps 00013c46 ( 79.07 KB) _ZL26bookerly_16_regularBitmaps 00013934 ( 78.30 KB) _ZL26notosans_16_regularBitmaps 00012572 ( 73.36 KB) _ZL33opendyslexic_12_bolditalicBitmaps 00011cee ( 71.23 KB) _ZL29notosans_14_bolditalicBitmaps 00011547 ( 69.32 KB) _ZL30opendyslexic_14_regularBitmaps 0001153c ( 69.31 KB) _ZL29bookerly_14_bolditalicBitmaps 00010c2e ( 67.04 KB) _ZL23notosans_14_boldBitmaps 0001096e ( 66.36 KB) _ZL23bookerly_14_boldBitmaps 000103d2 ( 64.96 KB) _ZL25notosans_14_italicBitmaps 000100d5 ( 64.21 KB) _ZL25bookerly_14_italicBitmaps 0000f83e ( 62.06 KB) _ZL26bookerly_14_regularBitmaps 0000f7fc ( 62.00 KB) _ZL29opendyslexic_12_italicBitmaps 0000f42b ( 61.04 KB) _ZL26notosans_14_regularBitmaps 0000f229 ( 60.54 KB) _ZL27opendyslexic_12_boldBitmaps 0000d301 ( 52.75 KB) _ZL29notosans_12_bolditalicBitmaps 0000d22f ( 52.55 KB) _ZL30opendyslexic_12_regularBitmaps 0000cff4 ( 51.99 KB) _ZL29bookerly_12_bolditalicBitmaps 0000cd12 ( 51.27 KB) _ZL33opendyslexic_10_bolditalicBitmaps 0000cad2 ( 50.71 KB) _ZL23bookerly_12_boldBitmaps 0000c60a ( 49.51 KB) _ZL23notosans_12_boldBitmaps 0000c147 ( 48.32 KB) _ZL25bookerly_12_italicBitmaps 0000c120 ( 48.28 KB) _ZL25notosans_12_italicBitmaps 0000ba7e ( 46.62 KB) _ZL26bookerly_12_regularBitmaps 0000b454 ( 45.08 KB) _ZL26notosans_12_regularBitmaps 0000b1e0 ( 44.47 KB) _ZL29opendyslexic_10_italicBitmaps 0000a939 ( 42.31 KB) _ZL27opendyslexic_10_boldBitmaps 0000a0dd ( 40.22 KB) _ZL13FilesPageHtml 0000949d ( 37.15 KB) _ZL30opendyslexic_10_regularBitmaps 00008415 ( 33.02 KB) _ZL32opendyslexic_8_bolditalicBitmaps 00008240 ( 32.56 KB) _ZL15ru_ru_trie_data 00007587 ( 29.38 KB) _ZL28opendyslexic_8_italicBitmaps 00006f4d ( 27.83 KB) _ZL26opendyslexic_8_boldBitmaps 00006943 ( 26.32 KB) _ZL15en_us_trie_data 00006196 ( 24.40 KB) _ZL29opendyslexic_8_regularBitmaps 00004990 ( 18.39 KB) _ZL21ubuntu_12_boldBitmaps 000042ce ( 16.70 KB) _ZL24ubuntu_12_regularBitmaps 000036d0 ( 13.70 KB) _ZL25notosans_18_regularGlyphs 000036d0 ( 13.70 KB) _ZL25notosans_16_regularGlyphs 000036d0 ( 13.70 KB) _ZL25notosans_14_regularGlyphs 000036d0 ( 13.70 KB) _ZL25notosans_12_regularGlyphs 000036d0 ( 13.70 KB) _ZL24notosans_8_regularGlyphs 000036d0 ( 13.70 KB) _ZL22notosans_18_boldGlyphs 000036d0 ( 13.70 KB) _ZL22notosans_16_boldGlyphs 000036d0 ( 13.70 KB) _ZL22notosans_14_boldGlyphs 000036d0 ( 13.70 KB) _ZL22notosans_12_boldGlyphs 000036c0 ( 13.69 KB) _ZL28notosans_18_bolditalicGlyphs 000036c0 ( 13.69 KB) _ZL28notosans_16_bolditalicGlyphs 000036c0 ( 13.69 KB) _ZL28notosans_14_bolditalicGlyphs 000036c0 ( 13.69 KB) _ZL28notosans_12_bolditalicGlyphs 000036c0 ( 13.69 KB) _ZL24notosans_18_italicGlyphs 000036c0 ( 13.69 KB) _ZL24notosans_16_italicGlyphs 000036c0 ( 13.69 KB) _ZL24notosans_14_italicGlyphs 000036c0 ( 13.69 KB) _ZL24notosans_12_italicGlyphs 00003627 ( 13.54 KB) _ZL21ubuntu_10_boldBitmaps 00003551 ( 13.33 KB) _ZL12es_trie_data 000030c4 ( 12.19 KB) _ZL24ubuntu_10_regularBitmaps 00002eb0 ( 11.67 KB) _ZL28bookerly_18_bolditalicGlyphs 00002eb0 ( 11.67 KB) _ZL28bookerly_16_bolditalicGlyphs 00002eb0 ( 11.67 KB) _ZL28bookerly_14_bolditalicGlyphs 00002eb0 ( 11.67 KB) _ZL28bookerly_12_bolditalicGlyphs 00002eb0 ( 11.67 KB) _ZL25bookerly_18_regularGlyphs 00002eb0 ( 11.67 KB) _ZL25bookerly_16_regularGlyphs 00002eb0 ( 11.67 KB) _ZL25bookerly_14_regularGlyphs 00002eb0 ( 11.67 KB) _ZL25bookerly_12_regularGlyphs 00002eb0 ( 11.67 KB) _ZL24bookerly_18_italicGlyphs 00002eb0 ( 11.67 KB) _ZL24bookerly_16_italicGlyphs 00002eb0 ( 11.67 KB) _ZL24bookerly_14_italicGlyphs 00002eb0 ( 11.67 KB) _ZL24bookerly_12_italicGlyphs 00002eb0 ( 11.67 KB) _ZL22bookerly_18_boldGlyphs 00002eb0 ( 11.67 KB) _ZL22bookerly_16_boldGlyphs 00002eb0 ( 11.67 KB) _ZL22bookerly_14_boldGlyphs 00002eb0 ( 11.67 KB) _ZL22bookerly_12_boldGlyphs 00002d50 ( 11.33 KB) _ZL32opendyslexic_14_bolditalicGlyphs 00002d50 ( 11.33 KB) _ZL32opendyslexic_12_bolditalicGlyphs 00002d50 ( 11.33 KB) _ZL32opendyslexic_10_bolditalicGlyphs 00002d50 ( 11.33 KB) _ZL31opendyslexic_8_bolditalicGlyphs 00002d50 ( 11.33 KB) _ZL29opendyslexic_14_regularGlyphs 00002d50 ( 11.33 KB) _ZL29opendyslexic_12_regularGlyphs 00002d50 ( 11.33 KB) _ZL29opendyslexic_10_regularGlyphs 00002d50 ( 11.33 KB) _ZL28opendyslexic_8_regularGlyphs 00002d50 ( 11.33 KB) _ZL28opendyslexic_14_italicGlyphs 00002d50 ( 11.33 KB) _ZL28opendyslexic_12_italicGlyphs 00002d50 ( 11.33 KB) _ZL28opendyslexic_10_italicGlyphs 00002d50 ( 11.33 KB) _ZL27opendyslexic_8_italicGlyphs 00002d50 ( 11.33 KB) _ZL26opendyslexic_14_boldGlyphs 00002d50 ( 11.33 KB) _ZL26opendyslexic_12_boldGlyphs 00002d50 ( 11.33 KB) _ZL26opendyslexic_10_boldGlyphs 00002d50 ( 11.33 KB) _ZL25opendyslexic_8_boldGlyphs 00002bca ( 10.95 KB) _ZL25notosans_8_regularBitmaps 0000294c ( 10.32 KB) _ZL16SettingsPageHtml 000024f0 ( 9.23 KB) _ZL23ubuntu_12_regularGlyphs 000024f0 ( 9.23 KB) _ZL23ubuntu_10_regularGlyphs 000024f0 ( 9.23 KB) _ZL20ubuntu_12_boldGlyphs 000024f0 ( 9.23 KB) _ZL20ubuntu_10_boldGlyphs 00001b4c ( 6.82 KB) _ZL12fr_trie_data 000012e8 ( 4.73 KB) ciphersuite_definitions 00000c8d ( 3.14 KB) _ZL12HomePageHtml 00000708 ( 1.76 KB) _ZL7Logo120 00000708 ( 1.76 KB) _ZL7Logo120 00000688 ( 1.63 KB) esp_err_msg_table 00000613 ( 1.52 KB) _ZL12it_trie_data 00000500 ( 1.25 KB) namingBitmap 00000450 ( 1.08 KB) _ZN4mime9mimeTableE 00000404 ( 1.00 KB) _ZNSt8__detail12__prime_listE 00000340 ( 0.81 KB) ciphersuite_preference 00000300 ( 0.75 KB) _ZL31bookerly_18_bolditalicIntervals 00000300 ( 0.75 KB) _ZL31bookerly_16_bolditalicIntervals 00000300 ( 0.75 KB) _ZL31bookerly_14_bolditalicIntervals 00000300 ( 0.75 KB) _ZL31bookerly_12_bolditalicIntervals 00000300 ( 0.75 KB) _ZL28bookerly_18_regularIntervals 00000300 ( 0.75 KB) _ZL28bookerly_16_regularIntervals 00000300 ( 0.75 KB) _ZL28bookerly_14_regularIntervals 00000300 ( 0.75 KB) _ZL28bookerly_12_regularIntervals 00000300 ( 0.75 KB) _ZL27bookerly_18_italicIntervals 00000300 ( 0.75 KB) _ZL27bookerly_16_italicIntervals 00000300 ( 0.75 KB) _ZL27bookerly_14_italicIntervals 00000300 ( 0.75 KB) _ZL27bookerly_12_italicIntervals 00000300 ( 0.75 KB) _ZL25bookerly_18_boldIntervals 00000300 ( 0.75 KB) _ZL25bookerly_16_boldIntervals 00000300 ( 0.75 KB) _ZL25bookerly_14_boldIntervals 00000300 ( 0.75 KB) _ZL25bookerly_12_boldIntervals 000002a0 ( 0.66 KB) small_prime 000002a0 ( 0.66 KB) _ZL35opendyslexic_14_bolditalicIntervals 000002a0 ( 0.66 KB) _ZL35opendyslexic_12_bolditalicIntervals 000002a0 ( 0.66 KB) _ZL35opendyslexic_10_bolditalicIntervals 000002a0 ( 0.66 KB) _ZL34opendyslexic_8_bolditalicIntervals 000002a0 ( 0.66 KB) _ZL32opendyslexic_14_regularIntervals 000002a0 ( 0.66 KB) _ZL32opendyslexic_12_regularIntervals 000002a0 ( 0.66 KB) _ZL32opendyslexic_10_regularIntervals 000002a0 ( 0.66 KB) _ZL31opendyslexic_8_regularIntervals 000002a0 ( 0.66 KB) _ZL31opendyslexic_14_italicIntervals 000002a0 ( 0.66 KB) _ZL31opendyslexic_12_italicIntervals 000002a0 ( 0.66 KB) _ZL31opendyslexic_10_italicIntervals 000002a0 ( 0.66 KB) _ZL30opendyslexic_8_italicIntervals 000002a0 ( 0.66 KB) _ZL29opendyslexic_14_boldIntervals 000002a0 ( 0.66 KB) _ZL29opendyslexic_12_boldIntervals 000002a0 ( 0.66 KB) _ZL29opendyslexic_10_boldIntervals 000002a0 ( 0.66 KB) _ZL28opendyslexic_8_boldIntervals 00000280 ( 0.62 KB) K 000001c8 ( 0.45 KB) _ZL26ubuntu_12_regularIntervals 000001c8 ( 0.45 KB) _ZL26ubuntu_10_regularIntervals 000001c8 ( 0.45 KB) _ZL23ubuntu_12_boldIntervals 000001c8 ( 0.45 KB) _ZL23ubuntu_10_boldIntervals 0000016c ( 0.36 KB) utf8_encoding_ns 0000016c ( 0.36 KB) utf8_encoding 0000016c ( 0.36 KB) little2_encoding_ns 0000016c ( 0.36 KB) little2_encoding 0000016c ( 0.36 KB) latin1_encoding_ns 0000016c ( 0.36 KB) latin1_encoding 0000016c ( 0.36 KB) internal_utf8_encoding_ns 0000016c ( 0.36 KB) internal_utf8_encoding 0000016c ( 0.36 KB) big2_encoding_ns 0000016c ( 0.36 KB) big2_encoding 0000016c ( 0.36 KB) ascii_encoding_ns 0000016c ( 0.36 KB) ascii_encoding 0000016c ( 0.36 KB) __default_global_locale 00000150 ( 0.33 KB) oid_sig_alg 00000150 ( 0.33 KB) mbedtls_cipher_definitions 00000140 ( 0.31 KB) adc_error_coef_atten 00000140 ( 0.31 KB) NUM_ERROR_CORRECTION_CODEWORDS 0000012c ( 0.29 KB) _ZL11lookupTable 00000101 ( 0.25 KB) _ctype_ 00000100 ( 0.25 KB) unhex 00000100 ( 0.25 KB) tokens 00000100 ( 0.25 KB) nmstrtPages 00000100 ( 0.25 KB) namePages 00000100 ( 0.25 KB) __chclass 00000100 ( 0.25 KB) FSb4 00000100 ( 0.25 KB) FSb3 00000100 ( 0.25 KB) FSb2 00000100 ( 0.25 KB) FSb 000000fc ( 0.25 KB) _C_time_locale 000000f0 ( 0.23 KB) oid_ecp_grp 000000d4 ( 0.21 KB) _ZL8mapTable 000000c8 ( 0.20 KB) __mprec_tens 000000c0 ( 0.19 KB) dh_group5_prime 000000c0 ( 0.19 KB) dh_group5_order 000000b4 ( 0.18 KB) _ZL31notosans_18_bolditalicIntervals 000000b4 ( 0.18 KB) _ZL31notosans_16_bolditalicIntervals 000000b4 ( 0.18 KB) _ZL31notosans_14_bolditalicIntervals 000000b4 ( 0.18 KB) _ZL31notosans_12_bolditalicIntervals 000000b4 ( 0.18 KB) _ZL28notosans_18_regularIntervals ============================================ Top 40 largest symbols in section: .flash.text Total section size: 1431082 bytes (1397.54 KB) ============================================ 000025b8 ( 9.43 KB) http_parser_execute 000023aa ( 8.92 KB) _vfprintf_r 000022ce ( 8.70 KB) _svfprintf_r 0000225a ( 8.59 KB) _svfwprintf_r 00001fdc ( 7.96 KB) __ssvfscanf_r 00001cb0 ( 7.17 KB) _Z15getSettingsListv 00001bbc ( 6.93 KB) mbedtls_ssl_handshake_server_step 00001ac2 ( 6.69 KB) __ssvfiscanf_r 000018fe ( 6.25 KB) mbedtls_ssl_handshake_client_step 000015fe ( 5.50 KB) mdns_parse_packet 00001554 ( 5.33 KB) _vfiprintf_r 0000146e ( 5.11 KB) _svfiprintf_r 0000123a ( 4.56 KB) doProlog 0000101e ( 4.03 KB) tcp_input 0000100e ( 4.01 KB) unsignedCharToPrintable 00000f4e ( 3.83 KB) pjpeg_decode_mcu 00000ef6 ( 3.74 KB) nd6_input 00000d4a ( 3.32 KB) _dtoa_r 00000d44 ( 3.32 KB) little2_contentTok 00000d44 ( 3.32 KB) big2_contentTok 00000d36 ( 3.30 KB) _strtod_l 00000d30 ( 3.30 KB) mbedtls_high_level_strerr 00000cec ( 3.23 KB) ieee80211_sta_new_state 00000ca6 ( 3.16 KB) tcp_receive 00000c82 ( 3.13 KB) mbedtls_internal_sha512_process 00000c14 ( 3.02 KB) _ZN9WebServer10_parseFormER10WiFiClient6Stringm 00000bc0 ( 2.94 KB) qrcode_initBytes 00000b62 ( 2.85 KB) __multf3 00000b1c ( 2.78 KB) normal_contentTok 00000a98 ( 2.65 KB) _ZN16ContentOpfParser12startElementEPvPKcPS2_ 00000a96 ( 2.65 KB) _ZN18JpegToBmpConverter27jpegFileToBmpStreamInternalER6FsFileR5Printiibb 00000a82 ( 2.63 KB) _mdns_service_task 00000a64 ( 2.60 KB) __strftime 00000a64 ( 2.60 KB) _ZNK9BaseTheme19drawRecentBookCoverER11GfxRenderer4RectRKSt6vectorI10RecentBookSaIS4_EEiRbS9_S9_St8functionIFbvEE 00000a60 ( 2.59 KB) __strftime 000009cc ( 2.45 KB) _Z16start_ssl_clientP17sslclient_contextRK9IPAddressmPKciS5_bS5_S5_S5_S5_bPS5_ 000009c4 ( 2.44 KB) doContent 0000099a ( 2.40 KB) wpa_sm_rx_eapol 00000984 ( 2.38 KB) __divtf3 00000974 ( 2.36 KB) _ZNSt6locale5_ImplC2Ej ============================================ Top 10 largest symbols in section: .iram0.text Total section size: 57640 bytes (56.29 KB) ============================================ 00000668 ( 1.60 KB) rmt_driver_isr_default 00000504 ( 1.25 KB) tlsf_realloc 00000458 ( 1.09 KB) tlsf_free 000003e8 ( 0.98 KB) tlsf_malloc 000003d0 ( 0.95 KB) esp_sleep_start 00000340 ( 0.81 KB) rtc_sleep_init 00000218 ( 0.52 KB) spi_flash_mmap_pages 000001fc ( 0.50 KB) esp_flash_erase_region 000001fc ( 0.50 KB) call_start_cpu0 000001de ( 0.47 KB) wdt_hal_init ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **YES** |
||
|
|
6ec5fc5603 |
feat: lower CPU freq on idle, add HalPowerManager (#852)
## Summary Continue my experiment from https://github.com/crosspoint-reader/crosspoint-reader/pull/801 This PR add the ability to lower the CPU frequency on extended idle period (currently set to 3 seconds). By default, the esp32c3 CPU is set to 160MHz, and now on idle, we can reduce it to just 10MHz. Note that while this functionality is already provided by [esp power management](https://docs.espressif.com/projects/esp-idf/en/v4.3/esp32c3/api-reference/system/power_management.html), the current Arduino build lacks of this, and enabling it is just too complicated (not worth the effort compared to this PR) Update: more info in https://github.com/crosspoint-reader/crosspoint-reader/pull/852#issuecomment-3904562827 ## Testing Pre-condition for each test case: the battery is charged to 100%, and is left plugged in after fully charged for an extra 1 hour. The table below shows how much battery is **used** for a given duration: | case / duration | 6 hrs | 12 hrs | | --- | --- | --- | | `delay(10)` | 26% | 48% | | `delay(50)`, PR https://github.com/crosspoint-reader/crosspoint-reader/pull/801 | 20% | Not tested | | `delay(50)` + low CPU freq (This PR) | Not tested | 25% | | `delay(10)` + low CPU freq (1) | Not tested | Not tested | (1) I decided not to test this case because it may not make sense. The problem is that CPU frequency vs power consumption do not follow a linear relationship, see [this](https://www.arrow.com/en/research-and-events/articles/esp32-power-consumption-can-be-reduced-with-sleep-modes) as an example. So, tight loop (10ms) + lower CPU freq significantly impact battery life, because the active CPU time is now much higher compared to the wall time. **So in conclusion, this PR improves ~150% to ~200% battery use time per charge.** The projected battery life is now: ~36-48 hrs of reading time (normal reading, no wifi) --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
3d47c081f2 |
fix: use RAII render lock everywhere (#916)
## Summary Follow-up to https://github.com/crosspoint-reader/crosspoint-reader/pull/774 --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Refactor** * Modernized internal synchronization mechanisms across multiple components to improve code reliability and maintainability. All functionality remains unchanged. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a616f42cb4 |
refactor: move render() to Activity super class, use freeRTOS notification (#774)
## Summary Currently, each activity has to manage their own `displayTaskLoop` which adds redundant boilerplate code. The loop is a wait loop which is also not the best practice, as the `updateRequested` boolean is not protected by a mutex. In this PR: - Move `displayTaskLoop` to the super `Activity` class - Replace `updateRequested` with freeRTOS's [direct to task notification](https://www.freertos.org/Documentation/02-Kernel/02-Kernel-features/03-Direct-to-task-notifications/01-Task-notifications) - For `ActivityWithSubactivity`, whenever a sub-activity is present, the parent's `render()` automatically goes inactive With this change, activities now only need to expose `render()` function, and anywhere in the code base can call `requestUpdate()` to request a new rendering pass. ## Additional Context In theory, this change may also make the battery life a bit better, since one wait loop is removed. Although the equipment in my home lab wasn't been able to verify it (the electric current is too noisy and small). Would appreciate if anyone has any insights on this subject. Update: I managed to hack [a small piece of code](https://github.com/ngxson/crosspoint-reader/tree/xsn/measure_cpu_usage) that allow tracking CPU idle time. The CPU load does decrease a bit (1.47% down to 1.39%), which make sense, because the display task is now sleeping most of the time unless notified. This should translate to a slightly increase in battery life in the long run. ``` PR: [40012] [MEM] Free: 185856 bytes, Total: 231004 bytes, Min Free: 123316 bytes [40012] [IDLE] Idle time: 98.61% (CPU load: 1.39%) [50017] [MEM] Free: 185856 bytes, Total: 231004 bytes, Min Free: 123316 bytes [50017] [IDLE] Idle time: 98.61% (CPU load: 1.39%) [60022] [MEM] Free: 185856 bytes, Total: 231004 bytes, Min Free: 123316 bytes [60022] [IDLE] Idle time: 98.61% (CPU load: 1.39%) master: [20012] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [20012] [IDLE] Idle time: 98.53% (CPU load: 1.47%) [30017] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [30017] [IDLE] Idle time: 98.53% (CPU load: 1.47%) [40022] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [40022] [IDLE] Idle time: 98.53% (CPU load: 1.47%) ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Streamlined rendering architecture by consolidating update mechanisms across all activities, improving efficiency and consistency. * Modernized synchronization patterns for display updates to ensure reliable, conflict-free rendering. * **Bug Fixes** * Enhanced rendering stability through improved locking mechanisms and explicit update requests. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: znelson <znelson@users.noreply.github.com> |
||
|
|
0508bfc1f7 |
perf: apply (micro) optimization on SerializedHyphenationPatterns (#689)
## Summary This PR applies a micro optimization on `SerializedHyphenationPatterns`, which allow reading `rootOffset` directly without having to parse then cache it. It should not affect storage space since no new bytes are added. This also gets rid of the linear cache search whenever `liangBreakIndexes` is called. In theory, the performance should be improved a bit, although it may be too small to be noticeable in practice. ## Testing master branch: ``` english: 99.1023% french: 100% german: 97.7289% russian: 97.2167% spanish: 99.0236% ``` This PR: ``` english: 99.1023% french: 100% german: 97.7289% russian: 97.2167% spanish: 99.0236% ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? PARTIALLY - mostly IDE tab-autocompletions |
||
|
|
5816ab2a47 |
feat: use pre-compressed HTML pages (#861)
## Summary Pre-compress the HTML file to save flash space. I'm using `gzip` because it's supported everywhere (indeed, we are using the same optimization on [llama.cpp server](https://github.com/ggml-org/llama.cpp), our HTML page is huge 😅 ). This free up ~40KB flash space. Some users suggested using `brotli` which is known to further reduce 20% in size, but it doesn't supported by firefox (only supports if served via HTTPS), and some reverse proxy like nginx doesn't support it out of the box (unrelated in this context, but just mention for completeness) ``` PR: RAM: [=== ] 31.0% (used 101700 bytes from 327680 bytes) Flash: [==========] 95.5% (used 6259244 bytes from 6553600 bytes) master: RAM: [=== ] 31.0% (used 101700 bytes from 327680 bytes) Flash: [==========] 96.2% (used 6302416 bytes from 6553600 bytes) ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **PARTIALLY**, only the python part |
||
|
|
0991782fb4 |
feat: more power saving on idle (#801)
## Summary This PR extends the delay in main loop from 10ms to 50ms after the device is idle for a while. This translates to extended battery life in a longer period (see testing section above), while not hurting too much the user experience. With the help from [this patch](https://github.com/ngxson/crosspoint-reader/tree/xsn/measure_cpu_usage), I was able to measure the CPU usage on idle: ``` PR: [20017] [MEM] Free: 150188 bytes, Total: 232092 bytes, Min Free: 150092 bytes [20017] [IDLE] Idle time: 99.62% (CPU load: 0.38%) [30042] [MEM] Free: 150188 bytes, Total: 232092 bytes, Min Free: 150092 bytes [30042] [IDLE] Idle time: 99.63% (CPU load: 0.37%) [40067] [MEM] Free: 150188 bytes, Total: 232092 bytes, Min Free: 150092 bytes [40067] [IDLE] Idle time: 99.62% (CPU load: 0.38%) master: [20012] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [20012] [IDLE] Idle time: 98.53% (CPU load: 1.47%) [30017] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [30017] [IDLE] Idle time: 98.53% (CPU load: 1.47%) [40022] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [40022] [IDLE] Idle time: 98.53% (CPU load: 1.47%) ``` While this is a x3.8 reduce in CPU usage, it doesn't translate to the same amount of battery life extension in real life. The reasons are: 1. The CPU is not shut down completely 2. freeRTOS tick is still running (however, I planned to experiment with tickless functionality) 3. Current leakage to other components, for example: voltage dividers, eink screen, SD card, etc A note on [light-sleep](https://docs.espressif.com/projects/esp-idf/en/stable/esp32c3/api-reference/system/sleep_modes.html) functionality: it is not possible in our use case because: - Light-sleep for 50ms introduce too much overhead on wake up, it has negative effect on battery life - Light-sleep for longer period doesn't work because the ADC GPIO buttons cannot be used as wake up source ## Testing (duration = 6 hrs) To test this, I patched the `CrossPointSettings::getSleepTimeoutMs()` to always returns a timeout of 6 hrs. This allow me to leave the device idle for 6 hrs straight. - On master branch, 6 hrs costs 26% battery life (100% --> 74%), meaning battery life is ~23 hrs - With this PR, 6 hrs costs 20% battery life (100% --> 80%), meaning battery life is ~30 hrs So in theory, this extends the battery by about 7 hrs. Even with some error margin added, I think 3 hrs increase is possible with a normal usage setup (i.e. only read ebooks, no wifi) ## Additional Context Would appreciate if someone can test this with an oscilloscope. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
7f40c3f477 |
feat: add HalStorage (#656)
## Summary Continue my changes to introduce the HAL infrastructure from https://github.com/crosspoint-reader/crosspoint-reader/pull/522 This PR touches quite a lot of files, but most of them are just name changing. It should not have any impacts to the end behavior. ## Additional Context My plan is to firstly add this small shim layer, which sounds useless at first, but then I'll implement an emulated driver which can be helpful for testing and for development. Currently, on my fork, I'm using a FS driver that allow "mounting" a local directory from my computer to the device, much like the `-v` mount option on docker. This allows me to quickly reset `.crosspoint` directory if anything goes wrong. I plan to upstream this feature when this PR get merged. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? NO |
||
|
|
6909f127b4 |
perf: optimize drawPixel() (#748)
## Summary Ref https://github.com/crosspoint-reader/crosspoint-reader/pull/737 This PR further reduce ~25ms from rendering time, testing inside the Setting screen: ``` master: [68440] [GFX] Time = 73 ms from clearScreen to displayBuffer PR: [97806] [GFX] Time = 47 ms from clearScreen to displayBuffer ``` And in extreme case (fill the entire screen with black or gray color): ``` master: [1125] [ ] Test fillRectDither drawn in 327 ms [1347] [ ] Test fillRect drawn in 222 ms PR: [1334] [ ] Test fillRectDither drawn in 225 ms [1455] [ ] Test fillRect drawn in 121 ms ``` Note that https://github.com/crosspoint-reader/crosspoint-reader/pull/737 is NOT applied on top of this PR. But with 2 of them combined, it should reduce from 47ms --> 42ms ## Details This PR based on the fact that function calls are costly if the function is small enough. For example, this simple call: ``` int rotatedX = 0; int rotatedY = 0; rotateCoordinates(x, y, &rotatedX, &rotatedY); ``` Generated assembly code: <img width="771" height="215" alt="image" src="https://github.com/user-attachments/assets/37991659-3304-41c3-a3b2-fb967da53f82" /> This adds ~10 instructions just to prepare the registers prior to the function call, plus some more instructions for the function's epilogue/prologue. Inlining it removing all of these: <img width="1471" height="832" alt="image" src="https://github.com/user-attachments/assets/b67a22ee-93ba-4017-88ed-c973e28ec914" /> Of course, this optimization is not magic. It's only beneficial under 3 conditions: - The function is small, not in size, but in terms of effective instructions. For example, the `rotateCoordinates` is simply a jump table, where each branch is just 3-4 inst - The function has multiple input arguments, which requires some move to put it onto the correct place - The function is called very frequently (i.e. critical path) --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
b45eaf7ded |
feat: optimize fillRectDither (#737)
## Summary
This PR optimizes the `fillRectDither` function, making it as fast as a
normal `fillRect`
Testing code:
```cpp
{
auto start_t = millis();
renderer.fillRectDither(0, 0, renderer.getScreenWidth(), renderer.getScreenHeight(), Color::LightGray);
auto elapsed = millis() - start_t;
Serial.printf("[%lu] [ ] Test fillRectDither drawn in %lu ms\n", millis(), elapsed);
}
{
auto start_t = millis();
renderer.fillRect(0, 0, renderer.getScreenWidth(), renderer.getScreenHeight(), true);
auto elapsed = millis() - start_t;
Serial.printf("[%lu] [ ] Test fillRect drawn in %lu ms\n", millis(), elapsed);
}
```
Before:
```
[1125] [ ] Test fillRectDither drawn in 327 ms
[1347] [ ] Test fillRect drawn in 222 ms
```
After:
```
[1065] [ ] Test fillRectDither drawn in 238 ms
[1287] [ ] Test fillRect drawn in 222 ms
```
## Visual validation
Before:
<img width="415" height="216" alt="Screenshot 2026-02-07 at 01 04 19"
src="https://github.com/user-attachments/assets/5802dbba-187b-4d2b-a359-1318d3932d38"
/>
After:
<img width="420" height="191" alt="Screenshot 2026-02-07 at 01 36 30"
src="https://github.com/user-attachments/assets/3c3c8e14-3f3a-4205-be78-6ed771dcddf4"
/>
## Details
The original version is quite slow because it does quite a lot of
computations. A single pixel needs around 20 instructions just to know
if it's black or white:
<img width="1170" height="693" alt="Screenshot 2026-02-07 at 00 15 54"
src="https://github.com/user-attachments/assets/7c5a55e7-0598-4340-8b7b-17307d7921cb"
/>
With the new, templated and more light-weight approach, each pixel takes
only 3-4 instructions, the modulo operator is translated into bitwise
ops:
<img width="1175" height="682" alt="Screenshot 2026-02-07 at 01 47 51"
src="https://github.com/user-attachments/assets/4ec2cf74-6cc0-4b5b-87d5-831563ef164f"
/>
---
### AI Usage
While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.
Did you use AI tools to help write this code? **NO**
|
||
|
|
a87eacc6ab |
perf: optimize drawPixel() (#748)
## Summary Ref https://github.com/crosspoint-reader/crosspoint-reader/pull/737 This PR further reduce ~25ms from rendering time, testing inside the Setting screen: ``` master: [68440] [GFX] Time = 73 ms from clearScreen to displayBuffer PR: [97806] [GFX] Time = 47 ms from clearScreen to displayBuffer ``` And in extreme case (fill the entire screen with black or gray color): ``` master: [1125] [ ] Test fillRectDither drawn in 327 ms [1347] [ ] Test fillRect drawn in 222 ms PR: [1334] [ ] Test fillRectDither drawn in 225 ms [1455] [ ] Test fillRect drawn in 121 ms ``` Note that https://github.com/crosspoint-reader/crosspoint-reader/pull/737 is NOT applied on top of this PR. But with 2 of them combined, it should reduce from 47ms --> 42ms ## Details This PR based on the fact that function calls are costly if the function is small enough. For example, this simple call: ``` int rotatedX = 0; int rotatedY = 0; rotateCoordinates(x, y, &rotatedX, &rotatedY); ``` Generated assembly code: <img width="771" height="215" alt="image" src="https://github.com/user-attachments/assets/37991659-3304-41c3-a3b2-fb967da53f82" /> This adds ~10 instructions just to prepare the registers prior to the function call, plus some more instructions for the function's epilogue/prologue. Inlining it removing all of these: <img width="1471" height="832" alt="image" src="https://github.com/user-attachments/assets/b67a22ee-93ba-4017-88ed-c973e28ec914" /> Of course, this optimization is not magic. It's only beneficial under 3 conditions: - The function is small, not in size, but in terms of effective instructions. For example, the `rotateCoordinates` is simply a jump table, where each branch is just 3-4 inst - The function has multiple input arguments, which requires some move to put it onto the correct place - The function is called very frequently (i.e. critical path) --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
76908d38e1 |
feat: optimize fillRectDither (#737)
## Summary
This PR optimizes the `fillRectDither` function, making it as fast as a
normal `fillRect`
Testing code:
```cpp
{
auto start_t = millis();
renderer.fillRectDither(0, 0, renderer.getScreenWidth(), renderer.getScreenHeight(), Color::LightGray);
auto elapsed = millis() - start_t;
Serial.printf("[%lu] [ ] Test fillRectDither drawn in %lu ms\n", millis(), elapsed);
}
{
auto start_t = millis();
renderer.fillRect(0, 0, renderer.getScreenWidth(), renderer.getScreenHeight(), true);
auto elapsed = millis() - start_t;
Serial.printf("[%lu] [ ] Test fillRect drawn in %lu ms\n", millis(), elapsed);
}
```
Before:
```
[1125] [ ] Test fillRectDither drawn in 327 ms
[1347] [ ] Test fillRect drawn in 222 ms
```
After:
```
[1065] [ ] Test fillRectDither drawn in 238 ms
[1287] [ ] Test fillRect drawn in 222 ms
```
## Visual validation
Before:
<img width="415" height="216" alt="Screenshot 2026-02-07 at 01 04 19"
src="https://github.com/user-attachments/assets/5802dbba-187b-4d2b-a359-1318d3932d38"
/>
After:
<img width="420" height="191" alt="Screenshot 2026-02-07 at 01 36 30"
src="https://github.com/user-attachments/assets/3c3c8e14-3f3a-4205-be78-6ed771dcddf4"
/>
## Details
The original version is quite slow because it does quite a lot of
computations. A single pixel needs around 20 instructions just to know
if it's black or white:
<img width="1170" height="693" alt="Screenshot 2026-02-07 at 00 15 54"
src="https://github.com/user-attachments/assets/7c5a55e7-0598-4340-8b7b-17307d7921cb"
/>
With the new, templated and more light-weight approach, each pixel takes
only 3-4 instructions, the modulo operator is translated into bitwise
ops:
<img width="1175" height="682" alt="Screenshot 2026-02-07 at 01 47 51"
src="https://github.com/user-attachments/assets/4ec2cf74-6cc0-4b5b-87d5-831563ef164f"
/>
---
### AI Usage
While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.
Did you use AI tools to help write this code? **NO**
|
||
|
|
db659f3ea2 |
fix: move http upload state to heap (#657)
## Summary The main motivation behind this PR was because `uploadBuffer` is statically allocated, but only used when web server is enabled. This results in 4KB of memory sitting idle most of the time. As expected, 4KB of initial RAM is freed with this PR: ``` master: RAM: [=== ] 32.5% (used 106508 bytes from 327680 bytes) PR: RAM: [=== ] 31.2% (used 102276 bytes from 327680 bytes) ``` ## Additional Context This also highlights the importance of only using statically-allocated buffer when absolutely needed (for example, if the component is active most of the time). Otherwise, it makes more sense to tie the buffer's life cycle to its activity. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? NO |
||
|
|
da4d3b5ea5 |
feat: add HalDisplay and HalGPIO (#522)
## Summary Extracted some changes from https://github.com/crosspoint-reader/crosspoint-reader/pull/500 to make reviewing easier This PR adds HAL (Hardware Abstraction Layer) for display and GPIO components, making it easier to write a stub or an emulated implementation of the hardware. SD card HAL will be added via another PR, because it's a bit more tricky. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |