Skip to content

Commit 5544210

Browse files
authored
Merge pull request #579 from tock/embedded-graphics
Support Embedded Graphics using the `screen` system call
2 parents 2e8c823 + 14d74a8 commit 5544210

File tree

18 files changed

+433
-1
lines changed

18 files changed

+433
-1
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,4 @@ jobs:
4646
echo 'rustflags = ["-D", "warnings"]' >> .cargo/config.toml
4747
make -j2 setup
4848
make -j2 test
49+
make demos

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/nightly/target
33
/target
44
/demos/*/target
5+
/demos/*/*/target

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ members = [
8989
"apis/storage/key_value",
9090
"demos/st7789",
9191
"demos/st7789-slint",
92+
"libraries/embedded_graphics_libtock",
9293
"panic_handlers/debug_panic",
9394
"panic_handlers/small_panic",
9495
"platform",

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ examples: toolchain
113113
# Used when we need to build a crate for the host OS, as libtock_runtime only
114114
# supports running on Tock.
115115
EXCLUDE_RUNTIME := --exclude libtock --exclude libtock_runtime \
116-
--exclude libtock_debug_panic --exclude libtock_small_panic
116+
--exclude libtock_debug_panic --exclude libtock_small_panic --exclude embedded_graphics_libtock
117117

118118
# Arguments to pass to cargo to exclude demo crates.
119119
EXCLUDE_RUNTIME := $(EXCLUDE_RUNTIME) --exclude st7789 --exclude st7789-slint
@@ -242,6 +242,11 @@ $(eval $(call platform_build,msp432,thumbv7em-none-eabi))
242242
$(eval $(call platform_build,clue_nrf52840,thumbv7em-none-eabi))
243243
$(eval $(call platform_flash,clue_nrf52840,thumbv7em-none-eabi))
244244

245+
.PHONY: demos
246+
demos:
247+
$(MAKE) -C demos/embedded_graphics/spin
248+
$(MAKE) -C demos/embedded_graphics/buttons
249+
245250
# clean cannot safely be invoked concurrently with other actions, so we don't
246251
# need to depend on toolchain. We also manually remove the nightly toolchain's
247252
# target directory, in case the user doesn't want to install the nightly
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "buttons"
3+
version = "0.1.0"
4+
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
5+
license = "Apache-2.0 OR MIT"
6+
edition = "2021"
7+
repository = "https://www.github.com/tock/libtock-rs"
8+
rust-version = "1.87"
9+
description = "libtock-rs button app with embedded graphics"
10+
11+
[dependencies]
12+
embedded-graphics = "0.8.1"
13+
libm = "0.2.15"
14+
15+
libtock = { path = "../../../", version = "0.1.0" }
16+
libtock_platform = { path = "../../../platform" }
17+
embedded_graphics_libtock = { path = "../../../libraries/embedded_graphics_libtock", version = "0.1.0" }
18+
19+
[build-dependencies]
20+
libtock_build_scripts = { path = "../../../build_scripts" }
21+
22+
[workspace]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Makefile for the demo app.
2+
3+
# Crate name of the demo app
4+
DEMO := buttons
5+
6+
all: tab
7+
8+
include ../../../Targets.mk
9+
10+
$(ELF_TARGETS):
11+
LIBTOCK_LINKER_FLASH=$(F) LIBTOCK_LINKER_RAM=$(R) cargo build --target=$(T) --release
12+
@mkdir -p target/$(A).$(F).$(R)/
13+
@cp target/$(T)/release/$(DEMO) target/$(A).$(F).$(R)/
14+
$(eval ELF_LIST += target/$(A).$(F).$(R)/$(DEMO),$(A).$(F).$(R))
15+
16+
# This target (`make tab`) is not parallel-safe
17+
.PHONY: tab
18+
tab: $(ELF_TARGETS)
19+
@mkdir -p target/tab
20+
elf2tab --kernel-major 2 --kernel-minor 1 -n $(DEMO) -o target/tab/$(DEMO).tab --stack 1024 --minimum-footer-size 256 $(ELF_LIST)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Buttons Demo Using Embedded Graphics
2+
====================================
3+
4+
Draws buttons as circles on the screen. When a button is pressed the
5+
corresponding circle is filled in.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
libtock_build_scripts::auto_layout();
3+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#![no_main]
2+
#![no_std]
3+
use core::cell::Cell;
4+
use core::fmt::Write;
5+
use libtock::buttons::{ButtonListener, ButtonState, Buttons};
6+
use libtock::console::Console;
7+
use libtock::runtime::{set_main, stack_size, TockSyscalls};
8+
use libtock_platform::share;
9+
use libtock_platform::ErrorCode;
10+
use libtock_platform::Syscalls;
11+
12+
use embedded_graphics_libtock::tock_screen::TockMonochrome8BitPage128x64Screen;
13+
14+
use embedded_graphics::pixelcolor::BinaryColor;
15+
use embedded_graphics::prelude::Point;
16+
use embedded_graphics::prelude::Primitive;
17+
use embedded_graphics::primitives::{Circle, PrimitiveStyle};
18+
use embedded_graphics::Drawable;
19+
20+
set_main! {main}
21+
stack_size! {4000}
22+
23+
fn run() -> Result<(), ErrorCode> {
24+
let mut screen = TockMonochrome8BitPage128x64Screen::new();
25+
26+
let width = screen.get_width();
27+
let height = screen.get_height();
28+
29+
let button_count = Buttons::count()?;
30+
writeln!(Console::writer(), "[BUTTONS] Count: {}", button_count).unwrap();
31+
32+
// Calculate where the buttons should be drawn.
33+
let button_padding_px = (button_count - 1) * 2;
34+
let max_x = (width - button_padding_px) / button_count;
35+
let max_y = height - 2;
36+
let diameter = core::cmp::min(max_x, max_y);
37+
let buttons_width = (diameter * button_count) + button_padding_px;
38+
let padding_left_px = (width - buttons_width) / 2;
39+
let y = (height / 2) - (diameter / 2);
40+
41+
// Draw the initial button outlines.
42+
for i in 0..button_count {
43+
let x = padding_left_px + ((diameter + 2) * i);
44+
45+
let _ = Circle::new(Point::new(x as i32, y as i32), diameter)
46+
.into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
47+
.draw(&mut screen);
48+
}
49+
let _ = screen.flush();
50+
51+
// Now wait for button presses. Record what happened in the upcall.
52+
let buttons: [Cell<ButtonState>; 10] = [const { Cell::new(ButtonState::Released) }; 10];
53+
let changed: Cell<bool> = Cell::new(false);
54+
55+
let listener = ButtonListener(|button, state| {
56+
// If the button state changed, record it.
57+
if buttons[button as usize].get() != state {
58+
buttons[button as usize].set(state);
59+
changed.set(true);
60+
}
61+
});
62+
share::scope(|subscribe| {
63+
// Subscribe to the button callback.
64+
Buttons::register_listener(&listener, subscribe).unwrap();
65+
66+
// Enable interrupts for each button press.
67+
for i in 0..button_count {
68+
Buttons::enable_interrupts(i).unwrap();
69+
}
70+
71+
// Wait for buttons to be pressed.
72+
loop {
73+
TockSyscalls::yield_wait();
74+
75+
// If a button state changed, re-draw the buttons.
76+
if changed.get() {
77+
changed.set(false);
78+
79+
let mut screen = TockMonochrome8BitPage128x64Screen::new();
80+
81+
// Draw Circles
82+
for i in 0..button_count {
83+
let x = padding_left_px + ((diameter + 2) * i);
84+
85+
// Draw outer circle
86+
let _ = Circle::new(Point::new(x as i32, y as i32), diameter)
87+
.into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
88+
.draw(&mut screen);
89+
90+
match buttons[i as usize].get() {
91+
ButtonState::Pressed => {
92+
let _ =
93+
Circle::new(Point::new(x as i32 + 1, y as i32 + 1), diameter - 2)
94+
.into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
95+
.draw(&mut screen);
96+
}
97+
ButtonState::Released => {
98+
let _ =
99+
Circle::new(Point::new(x as i32 + 1, y as i32 + 1), diameter - 2)
100+
.into_styled(PrimitiveStyle::with_fill(BinaryColor::Off))
101+
.draw(&mut screen);
102+
}
103+
}
104+
}
105+
let _ = screen.flush();
106+
}
107+
}
108+
});
109+
110+
Ok(())
111+
}
112+
113+
fn main() {
114+
match run() {
115+
Ok(()) => {}
116+
Err(_e) => {
117+
writeln!(Console::writer(), "[BUTTONS] Err could not run app").unwrap();
118+
}
119+
}
120+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "spin"
3+
version = "0.1.0"
4+
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
5+
license = "Apache-2.0 OR MIT"
6+
edition = "2021"
7+
repository = "https://www.github.com/tock/libtock-rs"
8+
rust-version = "1.87"
9+
description = "libtock-rs spin app with embedded graphics"
10+
11+
[dependencies]
12+
embedded-graphics = "0.8.1"
13+
libm = "0.2.15"
14+
15+
libtock = { path = "../../../", version = "0.1.0" }
16+
embedded_graphics_libtock = { path = "../../../libraries/embedded_graphics_libtock", version = "0.1.0" }
17+
18+
[build-dependencies]
19+
libtock_build_scripts = { path = "../../../build_scripts" }
20+
21+
[workspace]

0 commit comments

Comments
 (0)