Initial commit

This commit is contained in:
2026-03-20 17:23:49 +01:00
commit 3e016daa9c
15 changed files with 2538 additions and 0 deletions

2
.codespellrc Normal file
View File

@@ -0,0 +1,2 @@
[codespell]
ignore-words-list = ratatui,crate,ser

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

2009
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

18
Cargo.toml Normal file
View File

@@ -0,0 +1,18 @@
[workspace]
members = [
"crates/firmware",
"crates/simulator",
"crates/ui",
]
resolver = "3"
[workspace.package]
edition = "2024"
version = "0.1.0"
[workspace.dependencies]
embedded-graphics = "0.8"
embedded-graphics-simulator = "0.8"
mousefood = "0.4"
ratatui = "0.30"
ui = { path = "crates/ui" }

135
Readme.md Normal file
View File

@@ -0,0 +1,135 @@
# Vaka OS
> **WARNING**
> Vaka OS is an early-stage experimental firmware project.
> It is currently **beta / experimental software** and may be unsafe to run on real hardware.
> Installing experimental firmware can **brick your device**, **break OTA**, or require **SWD recovery**.
> Proceed only if you understand the risks.
Vaka OS is a Rust-first firmware project primarily targeting the **PineTime smartwatch**.
The project focuses on experimenting with a modern Rust embedded stack and a shared UI system that can run both on device and in a desktop simulator.
The primary goals are:
- Full Rust control over the firmware stack
- A simulator-driven development workflow
- A UI architecture reusable between firmware and simulator
- Safe OTA experimentation using a dual-firmware verification model
## Workspace Layout
```
crates/
firmware/
simulator/
ui/
docs/
Readme.md
Cargo.toml
```
### crates
- **firmware** firmware running on the watch
- **simulator** desktop environment for development
- **ui** shared UI code usable by firmware and simulator
See **docs/architecture.md**.
### docs
Supporting documentation.
## Development Modes
Vaka OS supports two workflows.
### Simulator / Development Mode
Used for fast iteration without flashing the device.
Typical loop:
edit code
run simulator
test behavior
repeat
Used for:
- UI layout
- interaction logic
- application experimentation
Simulator success **does not guarantee hardware success**.
### Device Mode (Build and Upload)
Used when testing on the actual PineTime hardware.
Typical loop:
- build firmware
- package OTA update
- upload to watch
- boot firmware
- verify behavior
See **docs/development.md**.
## Dual Firmware Verification Model
PineTime firmware updates typically follow a **dual-slot update model**.
The device contains two firmware areas:
- slot A → currently running firmware
- slot B → new firmware update
Typical OTA update process:
1. New firmware is uploaded to the **inactive slot**
2. Bootloader boots the new firmware **once**
3. Firmware runs in **unconfirmed state**
4. User manually verifies functionality
5. Firmware confirms itself
6. Bootloader marks it as the new permanent firmware
If firmware **fails to confirm**:
reboot → bootloader restores previous firmware
This provides protection against broken updates.
Vaka OS intends to use a workflow compatible with this behavior.
## OTA Safety Rules
Important development rules:
- Never overwrite the bootloader
- Always test new firmware as **unconfirmed**
- Keep a working firmware available
- Do not assume simulator success equals hardware safety
## Documentation
See:
- docs/architecture.md
- docs/development.md
- docs/hardware.md
- docs/roadmap.md
## Project Status
Early project setup and architecture exploration.

View File

@@ -0,0 +1,7 @@
[package]
name = "firmware"
edition.workspace = true
version.workspace = true
[lib]
path = "src/lib.rs"

View File

@@ -0,0 +1,8 @@
#![no_std]
#![doc = "Firmware placeholder crate for PineTime-specific code."]
/// Returns a static marker used while the firmware crate is still a stub.
#[must_use]
pub const fn platform_name() -> &'static str {
"PineTime"
}

View File

@@ -0,0 +1,9 @@
[package]
name = "simulator"
edition.workspace = true
version.workspace = true
[dependencies]
embedded-graphics.workspace = true
embedded-graphics-simulator.workspace = true
ui.workspace = true

View File

@@ -0,0 +1,31 @@
//! Minimal simulator experiment using Ratatui, Mousefood, and embedded-graphics-simulator.
use std::{error::Error, thread, time::Duration};
use embedded_graphics::{pixelcolor::Rgb888, prelude::Size};
use embedded_graphics_simulator::{
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
fn main() -> Result<(), Box<dyn Error>> {
let mut display = SimulatorDisplay::<Rgb888>::new(Size::new(240, 240));
ui::start_ui(&mut display)?;
let output_settings = OutputSettingsBuilder::new().scale(2).build();
let mut window = Window::new("Vaka simulator", &output_settings);
'running: loop {
window.update(&display);
for event in window.events() {
if matches!(event, SimulatorEvent::Quit) {
break 'running;
}
}
thread::sleep(Duration::from_millis(16));
}
Ok(())
}

12
crates/ui/Cargo.toml Normal file
View File

@@ -0,0 +1,12 @@
[package]
name = "ui"
edition.workspace = true
version.workspace = true
[lib]
path = "src/lib.rs"
[dependencies]
mousefood.workspace = true
ratatui.workspace = true
embedded-graphics.workspace = true

35
crates/ui/src/lib.rs Normal file
View File

@@ -0,0 +1,35 @@
#![doc = "Shared UI helpers for firmware and simulator."]
use std::error::Error;
use embedded_graphics::prelude::{Dimensions, DrawTarget};
use mousefood::prelude::*;
use ratatui::{
Terminal,
style::Stylize,
widgets::{Block, Paragraph},
};
/// Returns the first shared text used by the simulator experiment.
#[must_use]
pub const fn hello_world() -> &'static str {
"Hello, world from Ratatui"
}
pub fn start_ui<D>(display: &mut D) -> Result<(), Box<dyn Error>>
where
D: DrawTarget<Color = Rgb888> + Dimensions + 'static,
{
let backend = EmbeddedBackend::new(display, EmbeddedBackendConfig::default());
let mut terminal = Terminal::new(backend)?;
terminal.draw(|frame| {
let widget = Paragraph::new(crate::hello_world().bold().yellow())
.block(Block::bordered().title("Vaka"))
.centered();
frame.render_widget(widget, frame.area());
})?;
Ok(())
}

77
docs/architecture.md Normal file
View File

@@ -0,0 +1,77 @@
# Architecture
## Core Crates
### ui
Shared UI layer used by both firmware and simulator.
Responsibilities:
- application views
- layout logic
- widget composition
- UI state
- event abstraction
The goal is to keep most UI logic portable between simulator and hardware.
### firmware
The firmware crate targets **PineTime hardware**.
Responsibilities:
- hardware initialization
- display driver integration
- BLE stack integration
- input and touch handling
- power management
- system services
### simulator
Desktop environment used for development.
Responsibilities:
- run UI without hardware
- simulate events and inputs
- allow rapid UI iteration
- reduce flashing cycles
## Rendering Model
The expected rendering stack is:
```
ratatui
mousefood
embedded-graphics
display driver
```
Simulator rendering will use a different backend but share the UI layer.
## Simulator Role
The simulator exists to improve development speed.
It should help with:
- UI development
- event testing
- application logic
However:
Simulator correctness does **not guarantee hardware correctness**.
Timing, memory limits, BLE behavior, and display performance must still be tested on the real device.

107
docs/development.md Normal file
View File

@@ -0,0 +1,107 @@
# Development
Two modes exist:
- simulator development
- device firmware development
# Simulator Development Mode
Used for rapid iteration.
Typical loop:
edit code
run simulator
inspect UI behavior
repeat
Use this mode for:
- layout development
- UI interaction
- application logic
Simulator behavior may differ from hardware.
---
# Device Firmware Mode
Used when testing on the PineTime.
Typical loop:
cargo build
generate firmware image
package OTA update
upload to watch
reboot device
verify behavior
Testing on hardware is necessary for:
- BLE
- memory limits
- timing behavior
- display performance
---
# OTA Packaging
The intended artifact chain is:
cargo build
→ firmware ELF
→ binary image
→ OTA zip package
→ upload via companion app
Exact tooling may evolve as the project stabilizes.
---
# OTA Verification
The PineTime bootloader uses a verification model.
Steps:
1. firmware installed to secondary slot
2. bootloader boots new firmware once
3. firmware runs in **unconfirmed state**
4. firmware must confirm itself
5. bootloader marks it permanent
If confirmation does not happen:
reboot → previous firmware restored
---
# Safety Guidelines
Bootloader safety:
- never overwrite bootloader memory
- treat bootloader as protected space
Firmware safety:
- avoid breaking both firmware slots
- always test new firmware as unconfirmed
Development discipline:
- simulator success is not sufficient
- always validate hardware behavior

72
docs/hardware.md Normal file
View File

@@ -0,0 +1,72 @@
# Hardware
Current target: **PineTime smartwatch**.
PineTime is an open hardware smartwatch designed by Pine64.
It is capable of running fully custom firmware.
## Core Specifications
Main hardware components include:
- Nordic **nRF52832** MCU (ARM Cortex-M4F)
- 64 KB RAM
- 512 KB internal flash
- additional **4 MB SPI NOR flash** for assets
- Bluetooth Low Energy support
The CPU runs at **64 MHz** and includes a floating-point unit.
## Display
PineTime includes:
- 1.3 inch IPS display
- resolution **240×240**
- **ST7789 display controller**
- capacitive touchscreen controller
The display is connected through SPI.
## Sensors
The device contains several sensors and peripherals:
- BMA421 accelerometer
- HRS3300 heart rate sensor
- vibration motor
- capacitive touchscreen
These are typically connected over I²C.
## Battery
PineTime uses a small Li-Po battery around **170-180 mAh** capacity.
Battery life depends heavily on firmware design and BLE usage.
## Development Constraints
Important constraints for firmware design:
- very limited RAM (64 KB)
- limited internal flash (512 KB)
- firmware must run entirely from internal flash
- external flash cannot execute code
The external flash is mainly used for:
- fonts
- assets
- large UI resources.
## Future Hardware Support
Vaka OS is designed primarily for PineTime.
Portability may be considered later but is **not a primary goal** during early development.

15
docs/roadmap.md Normal file
View File

@@ -0,0 +1,15 @@
# Roadmap
- [ ] establish workspace structure
- [ ] basic rendering pipeline
- [ ] simulator UI testing
- [ ] display driver integration
- [ ] input and touch handling
- [ ] basic BLE functionality
- [ ] OTA artifact packaging
- [ ] Gadgetbridge compatibility experiments
- [ ] stable OTA workflow
- [ ] firmware verification logic
- [ ] improved simulator fidelity
- [ ] device services architecture