Skip to content

Commit b8b96c5

Browse files
committed
Introduce "app-core" crate
1 parent 778382e commit b8b96c5

18 files changed

+192
-87
lines changed

escale_fw_rs/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22
members = [
33
"app",
4+
"lib/app-core",
45
"lib/stuff"
56
]
67

escale_fw_rs/README.md

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
11
# eScale firmware in Rust
22

3+
## Project structure
4+
5+
- [app](./app/)
6+
- The main crate
7+
- [lib/](./lib/)
8+
- [app-core](./lib/app-core/)
9+
- Application logic, hardware independent
10+
- [stuff](./lib/stuff/)
11+
- Auxiliary code, potentially reusable outside the app
12+
- Yes, the name can be improved
13+
314
## UI structure
415

516
- Dashboard (weigh & time)
617
- Taring
7-
- Calibrating
18+
- Calibration
19+
- (Maybe) Diagnostic info
820

921
## General architecture and execution model
1022

1123
- Run _tasks_ in the order defined by a scheduler
1224
- A task may need to initialize, can be ran, can terminate when done, can schedule other tasks
1325
- Services
1426
- A task as a service can be discovered, can provide service-specific interface
27+
1528
OR
1629
- A task can register (as) a service
1730
- A service can be resolved by other tasks
1831
(i.e. the service registry is separate from the task registry)
32+
1933
OR
2034
- A message queue accessible to tasks instead?
2135
- (Weird, but) a service can be published via a message in the queue that is
2236
- never removed (a "pinned" message)
37+
2338
OR
2439
- regularly re-posted
2540

@@ -39,6 +54,7 @@
3954

4055
- Display API
4156
- A display interface is injected into a task as a dependency
57+
4258
OR
4359
- A display interface is published as a "pinned" message in the message queue
4460
- The display service doesn't have to be a task

escale_fw_rs/app/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ rp-pico = "0.4.1"
2727
ssd1306 = "0.7.0"
2828
nau7802 = { git = "https://github.com/werediver/nau7802-rs.git", branch = "next" }
2929

30+
app-core = { path = "../lib/app-core" }
3031
stuff = { path = "../lib/stuff" }

escale_fw_rs/app/src/common.rs

-2
This file was deleted.

escale_fw_rs/app/src/dashboard.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use core::cell::RefCell;
2-
31
use alloc::{format, rc::Rc, string::String};
4-
use stuff::mq::MessageProcessingStatus;
2+
use core::cell::RefCell;
53

6-
use crate::{
7-
common::{Duration, Instant},
8-
input_scanner::InputEvent,
4+
use app_core::{
5+
common::{AppContext, AppMessage, Duration, InputEvent, Instant},
6+
terminal::Terminal,
7+
};
8+
use stuff::{
9+
mq::MessageProcessingStatus,
910
run_loop::{Task, TaskStatus},
10-
AppContext, AppMessage, Terminal,
1111
};
1212

1313
pub struct Dashboard {

escale_fw_rs/app/src/main.rs

+20-53
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
#![feature(alloc_error_handler)]
44
#![feature(trait_alias)]
55

6-
mod common;
76
mod dashboard;
8-
mod input_scanner;
9-
mod run_loop;
7+
mod ssd1306_terminal;
108
mod uptime;
119
mod uptime_delay;
1210

@@ -16,15 +14,9 @@ use alloc::rc::Rc;
1614
use alloc_cortex_m::CortexMHeap;
1715
use core::{alloc::Layout, cell::RefCell};
1816
use cortex_m_rt::entry;
19-
use dashboard::Dashboard;
2017
use embedded_hal::digital::v2::InputPin;
2118
use embedded_time::rate::Extensions;
2219
use panic_probe as _;
23-
use stuff::{
24-
mq::{MessageProcessingStatus, MessageQueue},
25-
scale::Scale,
26-
};
27-
use uptime::Uptime;
2820

2921
use rp_pico as bsp;
3022

@@ -38,12 +30,23 @@ use bsp::hal::{
3830

3931
use nau7802::{Gain, Ldo, Nau7802, SamplesPerSecond};
4032
use ssd1306::{
41-
mode::{TerminalDisplaySize, TerminalMode},
42-
prelude::{WriteOnlyDataCommand, *},
43-
I2CDisplayInterface, Ssd1306,
33+
mode::DisplayConfig, rotation::DisplayRotation, size::DisplaySize128x64, I2CDisplayInterface,
34+
Ssd1306,
4435
};
4536

46-
use crate::{input_scanner::*, run_loop::*};
37+
use app_core::{
38+
common::{AppContext, AppMessage},
39+
input_scanner::InputScanner,
40+
scale::Scale,
41+
terminal::Terminal,
42+
};
43+
use dashboard::Dashboard;
44+
use ssd1306_terminal::Ssd1306Terminal;
45+
use stuff::{
46+
mq::MessageProcessingStatus,
47+
run_loop::{Schedule, Task},
48+
};
49+
use uptime::Uptime;
4750

4851
#[alloc_error_handler]
4952
fn oom(_: Layout) -> ! {
@@ -103,12 +106,12 @@ fn _main() -> ! {
103106
);
104107

105108
let interface = I2CDisplayInterface::new(i2c);
106-
let shared_terminal = Rc::new(RefCell::new(
107-
Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0).into_terminal_mode(),
108-
));
109+
let mut ssd1306 =
110+
Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0).into_terminal_mode();
111+
ssd1306.init().unwrap();
112+
let shared_terminal = Rc::new(RefCell::new(Ssd1306Terminal::new(ssd1306)));
109113
{
110114
let mut terminal = shared_terminal.borrow_mut();
111-
terminal.init().unwrap();
112115
terminal.clear().unwrap();
113116
}
114117

@@ -170,23 +173,6 @@ fn _main() -> ! {
170173
}
171174
}
172175

173-
#[derive(Default)]
174-
struct AppContext {
175-
mq: MessageQueue<AppMessage>,
176-
state: AppState,
177-
}
178-
179-
enum AppMessage {
180-
InputEvent(InputEvent),
181-
Tare,
182-
Calibrate,
183-
}
184-
185-
#[derive(Default)]
186-
struct AppState {
187-
weight: f32,
188-
}
189-
190176
enum AppTask {
191177
InputScanner(InputScanner),
192178
Dashboard(Dashboard),
@@ -200,22 +186,3 @@ impl<'a> AsMut<dyn Task<AppContext> + 'a> for AppTask {
200186
}
201187
}
202188
}
203-
204-
pub trait Terminal: core::fmt::Write {
205-
fn clear(&mut self) -> core::fmt::Result;
206-
fn set_position(&mut self, column: u8, row: u8) -> core::fmt::Result;
207-
}
208-
209-
impl<DI, SIZE> Terminal for Ssd1306<DI, SIZE, TerminalMode>
210-
where
211-
DI: WriteOnlyDataCommand,
212-
SIZE: TerminalDisplaySize,
213-
{
214-
fn clear(&mut self) -> core::fmt::Result {
215-
self.clear().map_err(|_| core::fmt::Error)
216-
}
217-
218-
fn set_position(&mut self, column: u8, row: u8) -> core::fmt::Result {
219-
self.set_position(column, row).map_err(|_| core::fmt::Error)
220-
}
221-
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use ssd1306::{
2+
mode::{TerminalDisplaySize, TerminalMode},
3+
prelude::WriteOnlyDataCommand,
4+
Ssd1306,
5+
};
6+
7+
use app_core::terminal::Terminal;
8+
9+
pub struct Ssd1306Terminal<DI, SIZE>
10+
where
11+
DI: WriteOnlyDataCommand,
12+
SIZE: TerminalDisplaySize,
13+
{
14+
ssd1306: Ssd1306<DI, SIZE, TerminalMode>,
15+
}
16+
17+
impl<DI, SIZE> Ssd1306Terminal<DI, SIZE>
18+
where
19+
DI: WriteOnlyDataCommand,
20+
SIZE: TerminalDisplaySize,
21+
{
22+
pub fn new(ssd1306: Ssd1306<DI, SIZE, TerminalMode>) -> Self {
23+
Self { ssd1306 }
24+
}
25+
}
26+
27+
impl<DI, SIZE> core::fmt::Write for Ssd1306Terminal<DI, SIZE>
28+
where
29+
DI: WriteOnlyDataCommand,
30+
SIZE: TerminalDisplaySize,
31+
{
32+
fn write_str(&mut self, s: &str) -> core::fmt::Result {
33+
self.ssd1306.write_str(s)
34+
}
35+
}
36+
37+
impl<DI, SIZE> Terminal for Ssd1306Terminal<DI, SIZE>
38+
where
39+
DI: WriteOnlyDataCommand,
40+
SIZE: TerminalDisplaySize,
41+
{
42+
fn clear(&mut self) -> core::fmt::Result {
43+
self.ssd1306.clear().map_err(|_| core::fmt::Error)
44+
}
45+
46+
fn set_position(&mut self, column: u8, row: u8) -> core::fmt::Result {
47+
self.ssd1306
48+
.set_position(column, row)
49+
.map_err(|_| core::fmt::Error)
50+
}
51+
}

escale_fw_rs/app/src/uptime.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::common::Instant;
21
use cortex_m::peripheral::{syst::SystClkSource, SYST};
32
use cortex_m_rt::exception;
43

4+
use app_core::common::Instant;
5+
56
pub struct Uptime {
67
_syst: SYST,
78
}

escale_fw_rs/lib/app-core/Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "app-core"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
stuff = { path = "../stuff" }
8+
num-traits = { version = "0.2.15", default-features = false }
9+
fugit = "0.3.6"
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use stuff::mq::MessageQueue;
2+
3+
pub type Instant = fugit::Instant<u64, 1, 1_000_000>;
4+
pub type Duration = fugit::Duration<u64, 1, 1_000_000>;
5+
6+
#[derive(Default)]
7+
pub struct AppContext {
8+
pub mq: MessageQueue<AppMessage>,
9+
pub state: AppState,
10+
}
11+
12+
pub enum AppMessage {
13+
InputEvent(InputEvent),
14+
Tare,
15+
Calibrate,
16+
}
17+
18+
pub enum InputEvent {
19+
ButtonADown,
20+
ButtonBDown,
21+
}
22+
23+
#[derive(Default)]
24+
pub struct AppState {
25+
pub weight: f32,
26+
}

escale_fw_rs/app/src/input_scanner.rs escale_fw_rs/lib/app-core/src/input_scanner.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
use crate::{run_loop::*, AppContext, AppMessage};
2-
31
use alloc::boxed::Box;
42

5-
pub enum InputEvent {
6-
ButtonADown,
7-
ButtonBDown,
8-
}
3+
use stuff::run_loop::{Task, TaskStatus};
4+
5+
use crate::common::{AppContext, AppMessage, InputEvent};
96

107
pub struct InputScanner {
118
button_a: Button,

escale_fw_rs/lib/app-core/src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![cfg_attr(not(test), no_std)]
2+
#![allow(incomplete_features)]
3+
#![feature(generic_const_exprs)]
4+
5+
extern crate alloc;
6+
7+
pub mod common;
8+
pub mod input_scanner;
9+
pub mod scale;
10+
pub mod terminal;

escale_fw_rs/lib/stuff/src/scale.rs escale_fw_rs/lib/app-core/src/scale.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
use num_traits::{float::FloatCore, PrimInt};
2+
use stuff::{ring::Ring, signal::mean};
23

3-
use crate::{ring::Ring, signal::mean};
4-
5-
pub struct Scale<T: PrimInt, U: FloatCore, const N: usize> {
4+
pub struct Scale<T: PrimInt, U: FloatCore, const N: usize>
5+
where
6+
// Require N ≥ 1
7+
[(); N - 1]:,
8+
{
69
ring: Ring<T, N>,
710
tare: U,
811
unit: U,
912
}
1013

11-
impl<T: PrimInt + Default, U: FloatCore, const N: usize> Default for Scale<T, U, N> {
14+
impl<T: PrimInt + Default, U: FloatCore, const N: usize> Default for Scale<T, U, N>
15+
where
16+
[(); N - 1]:,
17+
{
1218
fn default() -> Self {
1319
Self {
1420
ring: Default::default(),
@@ -18,7 +24,10 @@ impl<T: PrimInt + Default, U: FloatCore, const N: usize> Default for Scale<T, U,
1824
}
1925
}
2026

21-
impl<T: PrimInt, U: FloatCore, const N: usize> Scale<T, U, N> {
27+
impl<T: PrimInt, U: FloatCore, const N: usize> Scale<T, U, N>
28+
where
29+
[(); N - 1]:,
30+
{
2231
pub fn push(&mut self, value: T) {
2332
self.ring.push(value);
2433
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub trait Terminal: core::fmt::Write {
2+
fn clear(&mut self) -> core::fmt::Result;
3+
fn set_position(&mut self, column: u8, row: u8) -> core::fmt::Result;
4+
}

escale_fw_rs/lib/stuff/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#![cfg_attr(not(test), no_std)]
2+
#![allow(incomplete_features)]
3+
#![feature(generic_const_exprs)]
4+
5+
extern crate alloc;
26

37
pub mod mq;
48
pub mod ring;
5-
pub mod scale;
9+
pub mod run_loop;
610
pub mod signal;

escale_fw_rs/lib/stuff/src/mq.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
extern crate alloc;
2-
31
use alloc::vec::Vec;
42

53
pub struct MessageQueue<M> {

0 commit comments

Comments
 (0)