mousefood

repository·main·Indexed 23 days ago

https://github.com/ratatui/mousefood

A no-std embedded-graphics backend for Ratatui, enabling terminal user interfaces to run on microcontrollers and e-ink displays. Version 0.5.2 supports various hardware including ESP32-C6, RP2040, and STM32, providing an EmbeddedBackend to bridge Ratatui with embedded-graphics drivers. It includes features for custom color themes, font configuration for bold and italic text, and cursor style management.

Tokens
7.6K
Snippets
16
Records
50
Agent score
77%

What's inside mousefood

  1. Configure EPD (e-ink) Support with Flush Callbacks

    main

    When using EPD (e-ink) drivers like weact-studio-epd, epd-waveshare, or lilygo-epd47, the drivers typically maintain their own internal buffers. To avoid the memory overhead of the Mousefood framebuffer, you should disable default features and use the flush_callback in EmbeddedBackendConfig. This allows you to pass the Mousefood buffer directly to the driver's update method.

    To minimize memory usage, use: mousefood = { version = "*", default-features = false, features = ["<driver-feature>"] }.

    // Example pattern for Waveshare EPD
    use mousefood::prelude::*;
    use epd_waveshare::{epd2in9_v2::*, prelude::*};
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        // ... driver initialization ...
        let mut epd = Epd2in9::new(&mut spi_device, busy, dc, rst, &mut delay, None)?;
        let mut display = Display2in9::default();
    
        let config = EmbeddedBackendConfig {
            flush_callback: Box::new(move |d| {
                epd.update_and_display_frame(&mut spi_device, d.buffer(), &mut delay)
                    .expect("epd update failed");
            }),
            ..Default::default()
        };
    
        let backend = EmbeddedBackend::new(&mut display, config);
        let _terminal = Terminal::new(backend)?;
        Ok(())
    }
  2. Hardware and Implementation Notes for RP2040 Ratatui Demo

    main

    The RP2040 Ratatui E-Paper demo includes several specific implementation details for the hardware constraints of the RP2040-Zero:

    • Memory: A 100 KB heap is allocated from the RP2040's RAM for Ratatui widget building and rendering.
    • Color Conversion: A custom adapter is used to convert standard Ratatui colors into the black-and-white pixels required by the e-paper screen.
    • Atomics: Because the RP2040-Zero lacks hardware atomics required by ratatui, portable-atomic is used to emulate them in software.
    • Build Requirements: The project must be built from its own directory to correctly apply the build-std and build-std-features flags defined in its local .cargo/config.toml.
    • Power Management: The CPU and screen are put to sleep between frame updates to conserve power and prevent e-ink ghosting.
  3. Quickstart: Set up an EmbeddedBackend for Ratatui

    main

    To use Mousefood with Ratatui, initialize your display driver, wrap it in an EmbeddedBackend using EmbeddedBackendConfig, and then pass that backend to a ratatui::Terminal.

    Note: In the example below, MockDisplay is used for demonstration; replace it with your actual hardware display driver (e.g., ILI9341, SSD1306).

    use mousefood::embedded_graphics::{mock_display::MockDisplay, pixelcolor::Rgb888};
    use mousefood::prelude::*;
    use ratatui::widgets::{Block, Paragraph};
    use ratatui::{Frame, Terminal};
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        // replace this with your display driver
        // e.g. ILI9341, ST7735, SSD1306, etc.
        let mut display = MockDisplay::<Rgb888>::new();
    
        let backend = EmbeddedBackend::new(&mut display, EmbeddedBackendConfig::default());
        let mut terminal = Terminal::new(backend)?;
    
        terminal.draw(draw)?;
        Ok(())
    }
    
    fn draw(frame: &mut Frame) {
        let block = Block::bordered().title("Mousefood");
        let paragraph = Paragraph::new("Hello from Mousefood!").block(block);
        frame.render_widget(paragraph, frame.area());
    }
  4. Adapt the ESP32 demo for different screens or boards

    main

    If you are porting the ESP32 std demo to a different hardware setup, you must adjust the following parameters in the source code:

    • Display Driver and Geometry: The demo is hardcoded for the ST7789 driver with a screen size of 135x240 and a hardware offset of 52, 40. Update these to match your specific panel.
    • Battery Voltage Measurement: The T-Display uses a voltage divider that halves the battery voltage before it reaches the ADC on GPIO 34. The code compensates for this by multiplying the ADC reading by 2. If using a custom circuit, ensure your voltage divider setup is accounted for in your logic to avoid damaging the ESP32 or getting incorrect readings.
  5. Hardware and Software Requirements for ESP32-C6 EPD Demo

    main

    To ensure compatibility and avoid known issues, follow these requirements:

    • Display Driver: Uses the weact-studio-epd crate with the blocking driver.
    • HAL Version: Use esp-hal v1.1.0 to avoid issue ratatui/mousefood#175.
    • Scaffolding: The project is generated with esp-generate 1.3.0 to maintain compatible ESP crate versions.
    • Flashing Tool: probe-rs.
    • Logging: defmt over RTT.
  6. Build and flash the RP2040 Ratatui E-Paper Demo

    main

    To run the Ratatui and mousefood demo on an RP2040-Zero with a Waveshare 1.54" E-Paper display, follow these steps:

    1. One-Time Setup

    Install the elf2uf2-rs tool and create a mount point:

    cargo install elf2uf2-rs
    sudo mkdir -p /mnt/rp2

    2. Enter BOOT Mode

    Put the RP2040-Zero into bootloader mode using the physical buttons:

    1. Press and hold the BOOT button.
    2. While holding BOOT, press and release the RESET button.
    3. Hold BOOT for one more second, then release it. The board should appear as a USB mass storage device named RPI-RP2.

    3. Build the Firmware

    Compile the project in release mode:

    cargo build --release

    The binary is located at: ../../target/thumbv6m-none-eabi/release/rp2040-1in54-epd-example

    4. Convert to UF2 Format

    Convert the ELF binary to the UF2 format required by the RP2040 bootloader:

    elf2uf2-rs convert ../../target/thumbv6m-none-eabi/release/rp2040-1in54-epd-example flash.uf2

    5. Flash the Firmware

    Mount the device (ensure you use the correct device path, e.g., /dev/sda1) with the sync option to prevent corruption, copy the file, and unmount:

    # Mount with synchronous writes
    sudo mount -t vfat -o sync /dev/sda1 /mnt/rp2
    
    # Copy the UF2 file (the board flashes automatically upon detection)
    sudo cp flash.uf2 /mnt/rp2/
    
    # Safely unmount
    sudo umount /mnt/rp2
    cargo build --release
    elf2uf2-rs convert ../../target/thumbv6m-none-eabi/release/rp2040-1in54-epd-example flash.uf2
    sudo mount -t vfat -o sync /dev/sda1 /mnt/rp2
    sudo cp flash.uf2 /mnt/rp2/
    sudo umount /mnt/rp2
  7. Run the Lilygo T5 e-paper demo

    main

    This example demonstrates how to use mousefood on the Lilygo T5 e-paper within a no_std environment. The hardware configuration is integrated into the PCB, so no external wiring is required.

    To address screen refresh issues caused by the driver's drawing mode (which may result in suboptimal character superposition), you must implement the following two steps in your implementation:

    1. Update the flush_callback to include a screen clear.
    2. Call terminal.clear() to force a full redraw from mousefood.
  8. Optimize performance and binary size for embedded devices

    main

    When working with embedded devices, be aware of the following:

    • Flash Memory: Most embedded devices have very limited flash memory.
    • Frame Rate vs. Binary Size: To achieve high frame rates when using the fonts feature, it is recommended to use opt-level = 3. Note that this may increase the resulting binary size.
  9. Run a Ratatui application on STM32 with SSD1306 OLED

    main

    This demo project shows how to run a ratatui application on an STM32 microcontroller using an SSD1306 OLED display via the I2C protocol.

    Key implementation details:

    • Display Mode: Uses the ssd1306 crate in buffered graphics mode, where the framebuffer is stored in RAM and flushed to the display after each frame.
    • Memory Management: Because ratatui requires dynamic allocation, the project configures a 30 KB heap using embedded-alloc.
  10. Run mousefood apps in the simulator

    main

    The simulator package allows you to run mousefood applications on your computer using the embedded-graphics-simulator crate. This is useful for testing hardware-agnostic code without needing physical microcontrollers or EPD displays.

    Requirements

    You must have SDL2 installed on your system.

    If you are using nix, you can prepare your environment by running:

    nix-shell -p SDL2
    cargo run -p simulator
  11. Configure monochrome mode for grayscale displays

    main

    If you are using displays that utilize embedded-graphics pixel colors like Gray2, Gray4, or Gray8, you should enable the monochrome feature. This converts Ratatui colors to grayscale, making them compatible with monochrome hardware.

    mousefood = { version = "*", features = ["monochrome"] }