Initial commit
This commit is contained in:
2
.codespellrc
Normal file
2
.codespellrc
Normal file
@@ -0,0 +1,2 @@
|
||||
[codespell]
|
||||
ignore-words-list = ratatui,crate,ser
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
2009
Cargo.lock
generated
Normal file
2009
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
Normal file
18
Cargo.toml
Normal 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
135
Readme.md
Normal 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.
|
||||
|
||||
7
crates/firmware/Cargo.toml
Normal file
7
crates/firmware/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "firmware"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
8
crates/firmware/src/lib.rs
Normal file
8
crates/firmware/src/lib.rs
Normal 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"
|
||||
}
|
||||
9
crates/simulator/Cargo.toml
Normal file
9
crates/simulator/Cargo.toml
Normal 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
|
||||
31
crates/simulator/src/main.rs
Normal file
31
crates/simulator/src/main.rs
Normal 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
12
crates/ui/Cargo.toml
Normal 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
35
crates/ui/src/lib.rs
Normal 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
77
docs/architecture.md
Normal 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
107
docs/development.md
Normal 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
72
docs/hardware.md
Normal 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
15
docs/roadmap.md
Normal 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
|
||||
|
||||
Reference in New Issue
Block a user