Skip to content

Commit

Permalink
Merge pull request #34 from andrewdavidmackenzie/option_list
Browse files Browse the repository at this point in the history
Implementing selection widget per pin
  • Loading branch information
andrewdavidmackenzie authored May 21, 2024
2 parents bab576f + e9e27b9 commit 275fd4b
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 30 deletions.
44 changes: 25 additions & 19 deletions src/gpio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
mod pin_descriptions;

use pin_descriptions::*;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io;
use std::io::{BufReader, Write};
use serde::{Deserialize, Serialize};
use pin_descriptions::*;

// All the possible functions a pin can be given
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
Expand All @@ -30,7 +30,7 @@ pub enum PinFunction {
PCM_CLK,
SPIO_CE0_N,
SPIO_CE1_N,
ID_SC
ID_SC,
}

// [board_pin_number] refer to the pins by the number of the pin printed on the board
Expand All @@ -42,14 +42,21 @@ pub struct PinDescription {
pub board_pin_number: u8,
bcm_pin_number: Option<u8>,
pub name: &'static str,
options: &'static[PinFunction], // The set of functions the pin can have, chosen by user config
pub options: &'static [PinFunction], // The set of functions the pin can have, chosen by user config
}
impl std::fmt::Display for PinFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

// Model the 40 pin GPIO connections - including Ground, 3.3V and 5V outputs
pub const GPIO_DESCRIPTION : [PinDescription; 40] = [PIN_1, PIN_2, PIN_3, PIN_4, PIN_5, PIN_6, PIN_7, PIN_8, PIN_9, PIN_10,
PIN_11, PIN_12, PIN_13, PIN_14, PIN_15, PIN_16, PIN_17, PIN_18, PIN_19, PIN_20,
PIN_21, PIN_22, PIN_23, PIN_24, PIN_25, PIN_26, PIN_27, PIN_28, PIN_29, PIN_30,
PIN_31, PIN_32, PIN_33, PIN_34, PIN_35, PIN_36, PIN_37, PIN_38, PIN_39, PIN_40];
pub const GPIO_DESCRIPTION: [PinDescription; 40] = [
PIN_1, PIN_2, PIN_3, PIN_4, PIN_5, PIN_6, PIN_7, PIN_8, PIN_9, PIN_10, PIN_11, PIN_12, PIN_13,
PIN_14, PIN_15, PIN_16, PIN_17, PIN_18, PIN_19, PIN_20, PIN_21, PIN_22, PIN_23, PIN_24, PIN_25,
PIN_26, PIN_27, PIN_28, PIN_29, PIN_30, PIN_31, PIN_32, PIN_33, PIN_34, PIN_35, PIN_36, PIN_37,
PIN_38, PIN_39, PIN_40,
];

// A vector of tuples of (board_pin_number, PinFunction)
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
Expand All @@ -60,8 +67,8 @@ pub struct GPIOConfig {
impl GPIOConfig {
#[cfg(feature = "gui")]
#[allow(dead_code)] // "pi" build enables piglet which doesn't use this :-( TODO
// TODO take AsPath/AsRef etc
pub fn load(filename: &str) -> io::Result<GPIOConfig> {
// TODO take AsPath/AsRef etc
pub fn load(filename: &str) -> io::Result<GPIOConfig> {
let file = File::open(filename)?;
let reader = BufReader::new(file);
let config = serde_json::from_reader(reader)?;
Expand All @@ -85,17 +92,17 @@ pub type PinLevel = bool;
#[derive(Debug)]
#[allow(dead_code)]
pub struct GPIOState {
pub pin_state: [Option<PinLevel>; 40] // TODO make private later
pub pin_state: [Option<PinLevel>; 40], // TODO make private later
}

#[cfg(test)]
mod test {
use crate::gpio::{GPIOConfig, PinFunction};
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use tempfile::tempdir;
use crate::gpio::{GPIOConfig, PinFunction};

#[test]
fn create_a_config() {
Expand All @@ -109,7 +116,8 @@ mod test {
let output_dir = tempdir().expect("Could not create a tempdir").into_path();
let test_file = output_dir.join("test.piggui");
let mut file = File::create(&test_file).expect("Could not create test file");
file.write_all(pin_config.as_bytes()).expect("Could not write to test file");
file.write_all(pin_config.as_bytes())
.expect("Could not write to test file");
let config = GPIOConfig::load(test_file.to_str().unwrap()).unwrap();
assert_eq!(config.configured_pins.len(), 1);
assert_eq!(config.configured_pins[0].0, 1);
Expand All @@ -118,8 +126,7 @@ mod test {

#[test]
fn load_test_file() {
let root = std::env::var("CARGO_MANIFEST_DIR")
.expect("Could not get manifest dir");
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Could not get manifest dir");
let mut path = PathBuf::from(root);
path = path.join("tests/one_pin_config.piggui");
let config = GPIOConfig::load(path.to_str().unwrap()).unwrap();
Expand All @@ -131,7 +138,7 @@ mod test {
#[test]
fn save_one_pin_config() {
let config = GPIOConfig {
configured_pins: vec!((1, PinFunction::Input))
configured_pins: vec![(1, PinFunction::Input)],
};

let output_dir = tempdir().expect("Could not create a tempdir").into_path();
Expand All @@ -140,8 +147,7 @@ mod test {
config.save(test_file.to_str().unwrap()).unwrap();

let pin_config = r#"{"configured_pins":[[1,"Input"]]}"#;
let contents = fs::read_to_string(test_file)
.expect("Could not read test file");
let contents = fs::read_to_string(test_file).expect("Could not read test file");
assert_eq!(contents, pin_config);
}
}
}
70 changes: 59 additions & 11 deletions src/piggui.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
use std::env;

use iced::widget::{button, container, pick_list, Column, Row, Text};
use iced::{alignment, window, Alignment, Color, Element, Length, Sandbox, Settings, Theme};

// Using Custom Widgets
use custom_widgets::{circle::circle, line::line};

// This binary will only be built with the "iced" feature enabled, by use of "required-features"
// in Cargo.toml so no need for the feature to be used here for conditional compiling
use crate::gpio::{GPIOConfig, PinDescription, PinFunction, GPIO_DESCRIPTION};

mod gpio;
mod hw;
mod custom_widgets {
pub mod circle;
pub mod line;
}

use std::env;
// This binary will only be built with the "iced" feature enabled, by use of "required-features"
// in Cargo.toml so no need for the feature to be used here for conditional compiling
use crate::gpio::{GPIOConfig, PinDescription, GPIO_DESCRIPTION};
// Using Custom Widgets
use custom_widgets::{circle::circle, line::line};
use iced::widget::{button, container, Column, Row, Text};
use iced::{alignment, window, Alignment, Color, Element, Length, Sandbox, Settings, Theme};

// Use Hardware via trait
//use hw::Hardware;

Expand All @@ -40,13 +43,15 @@ struct Gpio {
config_file: Option<String>, // filename where to load and save config file to/from
gpio_description: [PinDescription; 40],
gpio_config: GPIOConfig,
pub pin_function_selected: Vec<Option<PinFunction>>,
clicked: bool,
}

#[derive(Debug, Clone, Copy)]

enum Message {
Activate,
PinFunctionSelected(usize, PinFunction),
}

impl Sandbox for Gpio {
Expand Down Expand Up @@ -78,10 +83,14 @@ impl Sandbox for Gpio {
}
};

let num_pins = GPIO_DESCRIPTION.len();
let pin_function_selected = vec![None; num_pins];

Self {
config_file,
gpio_description: GPIO_DESCRIPTION,
gpio_config,
pin_function_selected,
clicked: false,
}
}
Expand All @@ -93,11 +102,14 @@ impl Sandbox for Gpio {
fn update(&mut self, message: Message) {
match message {
Message::Activate => self.clicked = true,
Message::PinFunctionSelected(pin_index, pin_function) => {
self.pin_function_selected[pin_index] = Some(pin_function);
}
}
}

fn view(&self) -> iced::Element<Self::Message> {
container(pin_view(&self.gpio_description, &self.gpio_config))
container(pin_view(&self.gpio_description, &self.gpio_config, self))
.height(Length::Fill)
.width(Length::Fill)
.align_x(alignment::Horizontal::Center)
Expand All @@ -117,10 +129,27 @@ impl Sandbox for Gpio {
fn pin_view(
pin_descriptions: &[PinDescription; 40],
_pin_config: &GPIOConfig,
gpio: &Gpio,
) -> Element<'static, Message> {
let mut column = Column::new().width(Length::Shrink).height(Length::Shrink);

for pair in pin_descriptions.chunks(2) {
for (idx, pair) in pin_descriptions.chunks(2).enumerate() {
let mut pin_option_left = Column::new()
.width(Length::Fixed(100f32))
.align_items(Alignment::Center);

if pair[0].options.len() > 1 {
let mut pin_options_row_left = Row::new().align_items(Alignment::Center);

pin_options_row_left = pin_options_row_left.push(pick_list(
pair[0].options,
gpio.pin_function_selected[idx * 2],
move |pin_function| Message::PinFunctionSelected(idx * 2, pin_function),
));

pin_option_left = pin_option_left.push(pin_options_row_left);
}

let mut pin_name_left = Column::new()
.width(Length::Fixed(55f32))
.align_items(Alignment::Center);
Expand Down Expand Up @@ -373,13 +402,32 @@ fn pin_view(
right_pin = right_pin.push(right_pin_row);
}
}

let mut pin_option_right = Column::new()
.width(Length::Fixed(100f32))
.align_items(Alignment::Center);

if pair[1].options.len() > 1 {
let mut pin_options_row_right = Row::new().align_items(Alignment::Center);

pin_options_row_right = pin_options_row_right.push(pick_list(
pair[1].options,
gpio.pin_function_selected[idx * 2 + 1],
move |pin_function| Message::PinFunctionSelected(idx * 2 + 1, pin_function),
));

pin_option_right = pin_option_right.push(pin_options_row_right);
}

let row = Row::new()
.push(pin_option_left)
.push(pin_name_left)
.push(pin_arrow_left)
.push(left_pin)
.push(right_pin)
.push(pin_arrow_right)
.push(pin_name_right)
.push(pin_option_right)
.spacing(10)
.align_items(Alignment::Center);

Expand Down

0 comments on commit 275fd4b

Please sign in to comment.