A fork of pulp-os for the xteink4 adding custom apps
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

readme, who does

+247 -2
-2
.gitignore
··· 9 9 **/*.rs.bk 10 10 *.pdb 11 11 **/.DS_Store 12 - 13 - *.md
+247
README.md
··· 1 + A fork of [pulp-os](https://github.com/hansmrtn/pulp-os). The creator has VERY much so done the hard parts. This is just a fork playing around and adding custom apps to it 2 + 3 + 4 + pulp-os -- e-reader firmware for the XTEink X4 5 + 6 + bare-metal e-reader operating system for the XTEink X4 board 7 + (ESP32-C3 + SSD1677 e-paper). written in Rust. no std, no 8 + framebuffer, no dyn dispatch. async runtime via Embassy on 9 + esp-rtos. 10 + 11 + hardware 12 + mcu ESP32-C3, single-core RISC-V RV32IMC, 160 MHz 13 + ram 400 KB DRAM; ~172 KB heap (108 KB main + 64 KB reclaimed) 14 + display 800x480 SSD1677 mono e-paper, DMA-backed SPI, portrait 15 + storage microSD over shared SPI bus (400 kHz probe, 20 MHz run) 16 + input 2 ADC ladders (GPIO1, GPIO2) + power button (GPIO3 IRQ) 17 + battery li-ion via ADC, 100K/100K divider on GPIO0 18 + 19 + pin map: 20 + GPIO0 battery ADC GPIO6 EPD BUSY 21 + GPIO1 button row 1 ADC GPIO7 SPI MISO 22 + GPIO2 button row 2 ADC GPIO8 SPI SCK 23 + GPIO3 power button GPIO10 SPI MOSI 24 + GPIO4 EPD DC GPIO12 SD CS (raw register GPIO) 25 + GPIO5 EPD RST GPIO21 EPD CS 26 + 27 + EPD and SD share SPI2, arbitrated by CriticalSectionDevice. 28 + 29 + building 30 + requires stable Rust >= 1.88 and the riscv32imc-unknown-none-elf 31 + target. rust-toolchain.toml handles both automatically. 32 + 33 + cargo build --release 34 + espflash flash --monitor --chip esp32c3 target/... 35 + 36 + or: 37 + 38 + cargo run --release 39 + 40 + local path dependencies (sibling dirs): 41 + embedded-sdmmc async FAT filesystem over SD/SPI (local fork) 42 + smol-epub no_std epub/zip/html/image processing 43 + 44 + features 45 + txt reader lazy page-indexed, read-ahead prefetch, 46 + proportional font wrapping 47 + epub reader ZIP/OPF/HTML-strip pipeline, chapter cache on SD, 48 + proportional fonts with bold/italic/heading styles, 49 + inline PNG/JPEG (1-bit Floyd-Steinberg dithered), 50 + TOC browser (NCX or inline), chapter navigation 51 + file browser paginated SD listing, background EPUB title 52 + scanner (resolves titles from OPF metadata) 53 + bookmarks 16-slot LRU in RAM, flushed to SD every 30 s; 54 + home screen bookmarks browser sorted by recency 55 + wifi upload HTTP file upload + mDNS (pulp.local); 56 + drag-and-drop web UI with delete support 57 + fonts regular/bold/italic TTFs rasterised at build time 58 + via fontdue; five sizes, book and UI independently 59 + configurable 60 + display partial DU refresh (~400 ms page turn), periodic 61 + full GC refresh (configurable interval) 62 + quick menu per-app actions + screen refresh + go home, 63 + triggered by power button 64 + settings sleep timeout, ghost clear interval, 65 + book font size, UI font size, wifi credentials 66 + sleep idle timeout + power long-press; EPD deep sleep 67 + (~3 uA) + ESP32-C3 deep sleep (~5 uA); GPIO3 wake 68 + 69 + controls 70 + Prev / Next scroll or turn page 71 + PrevJump / NextJump page skip (files: full page; reader: chapter) 72 + Select open item 73 + Back go back; long-press goes home 74 + Power (short) open quick-action menu 75 + Power (long) deep sleep 76 + 77 + runtime 78 + embassy async executor on esp-rtos. five concurrent tasks: 79 + 80 + main event loop: input dispatch, app work, rendering 81 + input_task 10 ms ADC poll, debounce, battery read (30 s) 82 + housekeeping status bar (5 s), SD check (30 s), bookmark flush (30 s) 83 + idle_timeout configurable idle timer, signals deep sleep 84 + worker_task background CPU-heavy work (HTML strip, image decode) 85 + 86 + CPU sleeps (WFI) whenever all tasks are waiting. 87 + 88 + directory layout 89 + kernel/ pulp-kernel workspace crate (zero app imports) 90 + src/ 91 + lib.rs crate root, re-exports 92 + kernel/ 93 + mod.rs Kernel struct, resource ownership 94 + app.rs App trait, AppLayer trait, AppIdType, 95 + Transition, Redraw, AppContext, Launcher, 96 + QuickAction protocol types 97 + console.rs boot console (FONT_6X13, no fontdue) 98 + scheduler.rs main loop, render pipeline, sleep 99 + handle.rs KernelHandle (app I/O API) 100 + tasks.rs spawned embassy tasks 101 + work_queue.rs background work with generation cancellation 102 + bookmarks.rs LRU bookmark cache 103 + config.rs settings parser/writer 104 + dir_cache.rs sorted directory cache with title resolution 105 + wake.rs uptime helper (embassy monotonic clock) 106 + board/ board support (pin map, SPI wiring, button layout) 107 + mod.rs Board::init, peripheral splitting 108 + action.rs ActionEvent (semantic button actions) 109 + battery.rs voltage-to-percentage mapping 110 + button.rs physical button enum, ButtonMapper 111 + layout.rs button-to-action table 112 + raw_gpio.rs register-level GPIO for SD CS 113 + drivers/ hardware drivers 114 + mod.rs driver re-exports 115 + ssd1677.rs EPD display driver, 3-phase partial refresh 116 + strip.rs 4 KB strip buffer, rotation, glyph blitting 117 + sdcard.rs SD card init and SPI wiring 118 + storage.rs FAT filesystem ops, poll_once, with_fs! macros 119 + input.rs ADC button polling, debounce, repeat 120 + battery.rs ADC battery voltage sampling 121 + ui/ font-independent primitives 122 + mod.rs Region, Alignment, stack measurement 123 + stack_fmt.rs no_alloc formatting (StackFmt) 124 + statusbar.rs status bar rendering 125 + widget.rs widget trait and helpers 126 + 127 + src/ distro / app layer 128 + bin/main.rs entry point, hardware init, boot 129 + lib.rs crate root 130 + ui/ 131 + mod.rs app-side UI helpers 132 + fonts/ 133 + mod.rs font size tiers, FontSet lookups 134 + bitmap.rs build-time bitmap font data 135 + apps/ 136 + mod.rs AppId enum, type aliases binding kernel generics 137 + manager.rs AppLayer impl, with_app! dispatch, lifecycle 138 + home.rs launcher menu + bookmarks browser 139 + files.rs SD file browser + background title scanner 140 + settings.rs settings UI 141 + upload.rs wifi upload server 142 + reader/ 143 + mod.rs state machine, lifecycle, draw, quick actions 144 + paging.rs text wrapping, page navigation, load/prefetch 145 + epub_pipeline.rs ZIP/OPF parsing, chapter caching, background strip 146 + images.rs image detection, decode dispatch, dithering 147 + widgets/ 148 + mod.rs widget re-exports 149 + bitmap_label.rs proportional text label (uses fonts/) 150 + quick_menu.rs power-button overlay menu 151 + button_feedback.rs button press visual feedback 152 + 153 + build.rs fontdue TTF rasterisation at compile time 154 + assets/fonts/ TTF files (regular, bold, italic) 155 + assets/upload.html web UI for wifi upload mode 156 + 157 + design notes 158 + kernel / app split. the kernel crate (kernel/) has zero imports 159 + from apps/ or fonts/. the scheduler is generic over AppLayer; 160 + it never names a concrete app. AppId is defined by the distro, 161 + not the kernel -- the kernel only knows AppIdType::HOME. 162 + 163 + no dyn dispatch. with_app!() macro matches AppId, expands to 164 + concrete calls per app struct. all monomorphised; no vtable, 165 + no Box. 166 + 167 + strip rendering. 12 x 40-row strips (4 KB each) instead of a 168 + 48 KB framebuffer. draw callback fires per strip during SPI 169 + transfer. blit_1bpp_270 fast path walks physical memory linearly 170 + for the portrait rotation. windowed mode for partial refresh. 171 + 172 + 3-phase partial refresh. write BW RAM, kick DU waveform, collect 173 + input during ~400 ms refresh, then sync RED RAM. phase3 skipped 174 + during rapid navigation (RED marked stale; next partial uses 175 + inv_red recovery). full GC promoted after configurable number 176 + of partials to clear ghosting. 177 + 178 + SPI bus sharing. EPD and SD share one SPI2 bus. all SD I/O 179 + completes before any EPD render pass. busy_wait_with_input() 180 + collects only input events, no background work. violating the 181 + ordering panics (RefCell double-borrow), never corrupts. 182 + 183 + poll_once. embedded-sdmmc's async API wraps blocking SPI+DMA 184 + that never pends. poll_once drives every future to completion 185 + in a single poll, avoiding task spawn overhead. 186 + 187 + KernelHandle. apps never touch hardware. KernelHandle borrows 188 + the Kernel for one lifecycle method and exposes file I/O, dir 189 + cache, bookmarks. every async method does sync work then 190 + yield_now() for executor fairness. 191 + 192 + smol-epub sync bridge. smol-epub I/O uses closures, not async. 193 + with_sync_reader() provides a scoped closure that completes 194 + all storage access before returning -- no borrows across await. 195 + 196 + heavy statics. large structs (ReaderApp ~28 KB, DirCache ~10 KB, 197 + StripBuffer ~4 KB) live in ConstStaticCell / StaticCell so the 198 + async future stays ~200 B. 199 + 200 + nav stack. Launcher<Id> holds a 4-deep stack. transitions 201 + (Push/Pop/Replace/Home) drive on_suspend / on_enter / on_resume 202 + lifecycle. Push degrades to Replace when stack is full. 203 + 204 + dirty-region tracking. apps call ctx.mark_dirty(region); regions 205 + are unioned per frame. partial DU or full GC issued accordingly. 206 + 207 + work queue. dedicated embassy task for CPU-heavy work (HTML strip, 208 + image decode). generation-based cancellation: bump a counter and 209 + drain channels; worker checks generation before and after 210 + processing. channel capacity 1 for back-pressure. 211 + 212 + input. ADC ladders at 100 Hz, 4-sample oversampling, 15 ms 213 + debounce, 1 s long-press, 150 ms repeat. ButtonMapper translates 214 + physical buttons to semantic actions. apps never see hardware. 215 + 216 + fonts. build.rs rasterises TTFs via fontdue into 1-bit bitmaps 217 + at five sizes (xsmall through xlarge), three styles (regular, 218 + bold, italic). ASCII direct-indexed, extended unicode binary- 219 + searched. book and UI sizes independently hot-swappable. 220 + 221 + boot console. kernel renders text during hardware init using 222 + built-in FONT_6X13 mono font. works with zero fontdue, zero 223 + TTFs. if the SD card is missing, user still sees boot progress. 224 + 225 + bookmarks. 16-slot LRU, RAM-resident, binary format on SD. 226 + flushed every 30 s if dirty, plus on sleep. lookup by fnv1a 227 + hash + case-insensitive name comparison. 228 + 229 + settings. key=value text in _PULP/SETTINGS.TXT. parsed at boot, 230 + saved on change. font size changes propagate to all apps. 231 + 232 + wifi upload. bypasses normal dispatch. HTTP server on port 80, 233 + mDNS on 5353 (pulp.local). multipart upload with 8.3 filename 234 + sanitisation. radio torn down before returning to app loop. 235 + 236 + memory budget. ~172 KB heap for epub text and image decode 237 + (alloc::vec). everything else is static or stack. ~56 KB stack, 238 + painted 0xDEAD_BEEF at boot, high-water mark logged every 5 s. 239 + 240 + forkable kernel. designed to be extracted as a standalone crate. 241 + a fork defines its own AppId, implements AppLayer, brings its 242 + own fonts and apps, writes a main.rs. the kernel provides 243 + drivers, scheduling, storage, bookmarks, config, and a working 244 + EPD with mono boot console. 245 + 246 + license 247 + MIT