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