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.

more pumpkins

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

This is a binary file and will not be displayed.

+27 -13
src/apps/pumpkin.rs
··· 1 - use embedded_graphics_core::prelude; 2 - use esp_println::{print, println}; 1 + use crate::{ 2 + apps::{AppId, Transition}, 3 + fonts::{self, UiFonts}, 4 + ui::BitmapLabel, 5 + }; 6 + use embedded_graphics::{Drawable, image::Image, pixelcolor::BinaryColor, prelude::Point}; 7 + use esp_println::println; 3 8 use pulp_kernel::{ 9 + board::action::{Action, ActionEvent}, 4 10 kernel::{ 5 11 App, 6 12 config::{SystemSettings, WifiConfig}, ··· 9 15 Alignment, CONTENT_TOP, FULL_CONTENT_W, LARGE_MARGIN, Region, SCREEN_H, SCREEN_W, TITLE_Y, 10 16 }, 11 17 }; 18 + use tinybmp::Bmp; 12 19 13 - use crate::{ 14 - apps::{AppId, Transition}, 15 - fonts::{self, UiFonts}, 16 - ui::BitmapLabel, 17 - }; 20 + static PUMPKIN_HEAD: &[u8; 59374] = include_bytes!("../../assets/pumpkin.bmp"); 18 21 19 22 impl Default for PumpkinApp { 20 23 fn default() -> Self { ··· 59 62 event: pulp_kernel::board::action::ActionEvent, 60 63 ctx: &mut pulp_kernel::kernel::AppContext, 61 64 ) -> pulp_kernel::kernel::Transition<AppId> { 62 - println!("There was some kind of event"); 63 - Transition::None 65 + match event { 66 + ActionEvent::Press(Action::Back) => { 67 + println!("Popping"); 68 + pulp_kernel::kernel::Transition::Home 69 + } 70 + _ => Transition::None, 71 + } 64 72 } 65 73 66 74 fn draw(&self, strip: &mut pulp_kernel::board::StripBuffer) { ··· 70 78 FULL_CONTENT_W, 71 79 self.ui_fonts.heading.line_height, 72 80 ); 73 - BitmapLabel::new(title_region, "Pumpkin", self.ui_fonts.heading) 74 - .alignment(Alignment::CenterLeft) 75 - .draw(strip) 76 - .unwrap(); 81 + let bmp: Bmp<BinaryColor> = Bmp::from_slice(PUMPKIN_HEAD).unwrap(); 82 + Image::new(&bmp, Point::new(50, 50)).draw(strip).unwrap(); 83 + BitmapLabel::new( 84 + title_region, 85 + "Looks like no_std is back on the menu", 86 + self.ui_fonts.heading, 87 + ) 88 + .alignment(Alignment::CenterLeft) 89 + .draw(strip) 90 + .unwrap(); 77 91 } 78 92 }