Skip to content

Commit 6e0a294

Browse files
committed
feat: add etc config to control GPIO pin layout
1 parent 7c26d38 commit 6e0a294

File tree

8 files changed

+129
-22
lines changed

8 files changed

+129
-22
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,16 @@ strip = "debuginfo"
3535

3636
[package.metadata.deb]
3737
depends = "libnfc6, adduser, bloop-box-data, systemd"
38-
conf-files = ["/usr/local/etc/rpi0wcar.json", "/etc/systemd/system/rpi0wcar.service"]
38+
conf-files = ["/etc/bloop-box.conf"]
3939
maintainer-scripts = "debian/"
4040
systemd-units = { enable = true }
4141
extended-description = """\
4242
Bloop Box client for sending bloops to a server.\
4343
"""
4444
section = "games"
4545
priority = "optional"
46+
assets = [
47+
["target/arm-unknown-linux-gnueabihf/release/bloop-box", "usr/bin/", "755"],
48+
["README.md", "usr/share/doc/bloop-box/", "644"],
49+
["etc/bloop-box.conf", "etc/", "644"]
50+
]

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ chown bloop-box:nogroup /var/lib/bloop-box
6262

6363
On a development system, you might want to give the bloop-box user a login shell and a home directory.
6464

65+
#### Hardware config
66+
67+
In order to configure the Bloop Box for your specific hardware, you need to copy the `etc/bloop-box.conf` file to via
68+
SSH to `/etc/bloop-box`. If you are using our open hardware motherboard, you can leave all values in it as is, otherwise
69+
you need to adjust it to match your hardware.
70+
6571
#### Systemd
6672

6773
To have the bloop box automatically start when the system boots, create a systemd file in

etc/bloop-box.conf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Bloop Box Cinfiguration
2+
#
3+
# The configuration file is a TOML file. It consists of a sequence of key-value pairs, each on its own line. Strings are
4+
# to be enclosed in double quotes. Lists of values can be given by enclosing a comma-separated sequence of these values
5+
# in square brackets.
6+
#
7+
# See https://github.com/toml-lang/toml for detailed information on the format.
8+
#
9+
# This file contains all configuration settings with explanations and their default values.
10+
11+
# GPIO pins
12+
#
13+
# Pins for connected devices. All pins are addressed via their BCM number.
14+
[gpio]
15+
# Volume control
16+
#volume-down-button = 24
17+
#volume-up-button = 23
18+
19+
# Status RGB LED
20+
#red-led = 16
21+
#green-led = 20
22+
#blue-led = 26

semantic-release-build.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,26 @@ cargo install cross cargo-deb
66
sed -i '/\[package\]/,/^version = "[^"]*"$/ s/^version = "[^"]*"$/version = "'"$VERSION"'"/' Cargo.toml
77
cross build --target arm-unknown-linux-gnueabihf --release
88
cargo-deb -v --no-build --target arm-unknown-linux-gnueabihf --no-strip
9+
10+
# This is workaround for https://github.com/kornelski/cargo-deb/issues/47
11+
# Patch the generated DEB to have ./ paths compatible with `unattended-upgrade`:
12+
pushd target/arm-unknown-linux-gnueabihf/debian || exit 1
13+
DEB_FILE_NAME=$(ls -1 *.deb | head -n 1)
14+
DATA_ARCHIVE=$(ar t "${DEB_FILE_NAME}"| grep -E '^data\.tar')
15+
ar x "${DEB_FILE_NAME}" "${DATA_ARCHIVE}"
16+
tar tf "${DATA_ARCHIVE}"
17+
18+
if [[ "${DATA_ARCHIVE}" == *.xz ]]; then
19+
# Install XZ support that will be needed by TAR
20+
apt-get -y install -y xz-utils
21+
EXTRA_TAR_ARGS=J
22+
fi
23+
24+
mkdir tar-hack
25+
tar -C tar-hack -xf "${DATA_ARCHIVE}"
26+
pushd tar-hack || exit 1
27+
tar c${EXTRA_TAR_ARGS}f "../${DATA_ARCHIVE}" ./*
28+
popd || exit 1
29+
tar tf "${DATA_ARCHIVE}"
30+
ar r "${DEB_FILE_NAME}" "${DATA_ARCHIVE}"
31+
popd || exit 1

src/etc_config.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use anyhow::Result;
2+
use serde::Deserialize;
3+
use tokio::fs::File;
4+
use tokio::io::AsyncReadExt;
5+
6+
fn default_volume_down_button() -> u8 {
7+
24
8+
}
9+
fn default_volume_up_button() -> u8 {
10+
23
11+
}
12+
fn default_red_led() -> u8 {
13+
16
14+
}
15+
fn default_green_led() -> u8 {
16+
20
17+
}
18+
fn default_blue_led() -> u8 {
19+
26
20+
}
21+
22+
#[derive(Debug, Clone, Deserialize)]
23+
pub struct GpioConfig {
24+
#[serde(default = "default_volume_down_button")]
25+
pub volume_down_button: u8,
26+
#[serde(default = "default_volume_up_button")]
27+
pub volume_up_button: u8,
28+
#[serde(default = "default_red_led")]
29+
pub red_led: u8,
30+
#[serde(default = "default_green_led")]
31+
pub green_led: u8,
32+
#[serde(default = "default_blue_led")]
33+
pub blue_led: u8,
34+
}
35+
36+
#[derive(Clone, Deserialize)]
37+
pub struct EtcConfig {
38+
pub gpio: GpioConfig,
39+
}
40+
41+
pub async fn load_etc_config() -> Result<EtcConfig> {
42+
let mut file = File::open("/etc/bloop-box.conf").await?;
43+
let mut toml_config = String::new();
44+
file.read_to_string(&mut toml_config).await?;
45+
let config: EtcConfig = toml::from_str(&toml_config)?;
46+
Ok(config)
47+
}

src/main.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ extern crate core;
22

33
use std::path::Path;
44

5+
use crate::etc_config::load_etc_config;
56
use anyhow::Result;
67
use env_logger::{Builder, Env};
78
use tokio::fs;
@@ -16,6 +17,7 @@ use crate::subsystems::led::Led;
1617
use crate::subsystems::networker::Networker;
1718
use crate::subsystems::volume_control::VolumeControl;
1819

20+
mod etc_config;
1921
mod nfc;
2022
mod subsystems;
2123
mod wifi;
@@ -24,6 +26,7 @@ mod wifi;
2426
async fn main() -> Result<()> {
2527
Builder::from_env(Env::default().default_filter_or("debug")).init();
2628

29+
let etc_config = load_etc_config().await?;
2730
let share_dir = Path::new("/usr/share/bloop-box");
2831
let data_dir = Path::new("/var/lib/bloop-box");
2932
let cache_dir = Path::new(&data_dir).join("cache");
@@ -39,7 +42,7 @@ async fn main() -> Result<()> {
3942
let (networker_status_tx, networker_status_rx) = mpsc::channel(8);
4043

4144
Toplevel::new()
42-
.start("Led", Led::new(led_rx).into_subsystem())
45+
.start("Led", Led::new(etc_config.clone(), led_rx).into_subsystem())
4346
.start(
4447
"ConfigManager",
4548
ConfigManager::new(data_dir, config_rx).into_subsystem(),
@@ -56,7 +59,7 @@ async fn main() -> Result<()> {
5659
)
5760
.start(
5861
"VolumeControl",
59-
VolumeControl::new(audio_player_tx.clone()).into_subsystem(),
62+
VolumeControl::new(etc_config, audio_player_tx.clone()).into_subsystem(),
6063
)
6164
.start(
6265
"Networker",

src/subsystems/led.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::etc_config::EtcConfig;
12
use anyhow::{Error, Result};
23
use log::info;
34
use rppal::gpio::{Gpio, Level, OutputPin};
@@ -21,12 +22,13 @@ pub enum LedState {
2122
}
2223

2324
pub struct Led {
25+
etc_config: EtcConfig,
2426
rx: mpsc::Receiver<LedState>,
2527
}
2628

2729
impl Led {
28-
pub fn new(rx: mpsc::Receiver<LedState>) -> Self {
29-
Self { rx }
30+
pub fn new(etc_config: EtcConfig, rx: mpsc::Receiver<LedState>) -> Self {
31+
Self { etc_config, rx }
3032
}
3133

3234
async fn process(
@@ -89,7 +91,7 @@ impl IntoSubsystem<Error> for Led {
8991

9092
subsys.start(
9193
"InternalLed",
92-
InternalLed::new(internal_rx).into_subsystem(),
94+
InternalLed::new(self.etc_config.clone(), internal_rx).into_subsystem(),
9395
);
9496

9597
tokio::select! {
@@ -104,6 +106,7 @@ impl IntoSubsystem<Error> for Led {
104106
}
105107

106108
struct InternalLed {
109+
etc_config: EtcConfig,
107110
rx: mpsc::Receiver<InternalLedState>,
108111
}
109112

@@ -113,13 +116,9 @@ enum InternalLedState {
113116
Off,
114117
}
115118

116-
const GPIO_RED: u8 = 16;
117-
const GPIO_GREEN: u8 = 20;
118-
const GPIO_BLUE: u8 = 26;
119-
120119
impl InternalLed {
121-
pub fn new(rx: mpsc::Receiver<InternalLedState>) -> Self {
122-
Self { rx }
120+
pub fn new(etc_config: EtcConfig, rx: mpsc::Receiver<InternalLedState>) -> Self {
121+
Self { etc_config, rx }
123122
}
124123

125124
async fn process(
@@ -151,9 +150,9 @@ impl InternalLed {
151150
impl IntoSubsystem<Error> for InternalLed {
152151
async fn run(mut self, subsys: SubsystemHandle) -> Result<()> {
153152
let gpio = Gpio::new()?;
154-
let mut red_pin = gpio.get(GPIO_RED)?.into_output_low();
155-
let mut green_pin = gpio.get(GPIO_GREEN)?.into_output_low();
156-
let mut blue_pin = gpio.get(GPIO_BLUE)?.into_output_low();
153+
let mut red_pin = gpio.get(self.etc_config.gpio.red_led)?.into_output_low();
154+
let mut green_pin = gpio.get(self.etc_config.gpio.green_led)?.into_output_low();
155+
let mut blue_pin = gpio.get(self.etc_config.gpio.blue_led)?.into_output_low();
157156

158157
tokio::select! {
159158
_ = subsys.on_shutdown_requested() => {

src/subsystems/volume_control.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::etc_config::EtcConfig;
12
use anyhow::{Error, Result};
23
use log::info;
34
use rppal::gpio::Gpio;
@@ -9,15 +10,16 @@ use crate::subsystems::audio_player::PlayerCommand;
910
use crate::subsystems::button::Button;
1011

1112
pub struct VolumeControl {
13+
etc_config: EtcConfig,
1214
audio_player: mpsc::Sender<PlayerCommand>,
1315
}
1416

15-
const GPIO_VOLUME_DOWN: u8 = 23;
16-
const GPIO_VOLUME_UP: u8 = 24;
17-
1817
impl VolumeControl {
19-
pub fn new(audio_player: mpsc::Sender<PlayerCommand>) -> Self {
20-
Self { audio_player }
18+
pub fn new(etc_config: EtcConfig, audio_player: mpsc::Sender<PlayerCommand>) -> Self {
19+
Self {
20+
etc_config,
21+
audio_player,
22+
}
2123
}
2224

2325
async fn process(&mut self, mut button_rx: mpsc::Receiver<f32>) -> Result<()> {
@@ -46,8 +48,8 @@ impl IntoSubsystem<Error> for VolumeControl {
4648
async fn run(mut self, subsys: SubsystemHandle) -> Result<()> {
4749
let gpio = Gpio::new()?;
4850
let (button_tx, button_rx) = mpsc::channel::<f32>(1);
49-
let volume_down_pin = gpio.get(GPIO_VOLUME_DOWN)?;
50-
let volume_up_pin = gpio.get(GPIO_VOLUME_UP)?;
51+
let volume_down_pin = gpio.get(self.etc_config.gpio.volume_down_button)?;
52+
let volume_up_pin = gpio.get(self.etc_config.gpio.volume_up_button)?;
5153

5254
subsys.start(
5355
"VolumeDownButton",

0 commit comments

Comments
 (0)