840 lines
27 KiB
Markdown
840 lines
27 KiB
Markdown
---
|
|
sub_title: "Real Time Systems 10"
|
|
class_code: "ELERTS10"
|
|
toc: true
|
|
auther:
|
|
- name: "Finley van Reenen (0964590)"
|
|
email: "mail@lailatheelf.nl"
|
|
name_short: "E.L.F. van Reenen"
|
|
---
|
|
|
|
# Rust Verslag
|
|
|
|
## Opdracht 8.2
|
|
|
|
> Maak een toestandsmachine volgens de State Pattern methode zoals beschreven in
|
|
> het boek. Er zijn drie toestanden: rood, groen en oranje. Tussen de toestanden
|
|
> wordt geschakeld op basis van tijd: respectievelijk $4s$, $3s$ en $1s$.
|
|
|
|
De State Pattern-methode in Rust maakt gebruik van structs en traits. Om dit
|
|
mogelijk te maken moet er een struct zijn die de leds kan aansturen. Hiervoor
|
|
is het de `struct Pin` van de stm32f4xx-hal nodig in de struct. Om mijn
|
|
implementatie makkelijker onderhoudbaar te maken, worden de `struct Pin`'s
|
|
doorgegeven aan de `struct StateMachine`. Hiervoor is een trait nodig die
|
|
functies voor het aanpassen van de led-status beschrijft. De `toggle`-functie
|
|
die gebruikt wordt in het voorbeeld is niet geïmplementeerd via een trait.
|
|
Deze kan dus niet gebruikt worden zonder de hal aan te passen. In de
|
|
documentatie van de `struct Pin` implementeert die de `trait OutputPin` van de
|
|
embedded_hal crate^[https://docs.rs/stm32f4xx-hal/0.22.0/stm32f4xx_hal/gpio/struct.Pin.html#impl-OutputPin-for-Pin%3CP,+N,+Output%3CMODE%3E%3E-1]. Dus deze crate is toegevoegd aan het project, zodat hier gebruik van gemaakt kan worden.
|
|
|
|
Om te testen of dit werkt is er een struct aangemaakt met een simple toggle
|
|
functie en de embeded_hal geïmporteerd. Dit is gedaan met de volgende code:
|
|
|
|
```rust
|
|
use embedded_hal::digital::{ErrorType as DigitalErrorType, OutputPin, PinState};
|
|
|
|
struct Leds<'a, Red: OutputPin, Green: OutputPin, Orange: OutputPin> {
|
|
red: &'a mut Red,
|
|
red_state: PinState,
|
|
green: &'a mut Green,
|
|
green_state: PinState,
|
|
orange: &'a mut Orange,
|
|
orange_state: PinState,
|
|
}
|
|
impl<'a, Red: OutputPin, Green: OutputPin, Orange: OutputPin> Leds<'a, Red, Green, Orange> {
|
|
pub fn new(red: &'a mut Red, green: &'a mut Green, orange: &'a mut Orange) -> Self {
|
|
let _ = red.set_low();
|
|
let _ = green.set_low();
|
|
let _ = orange.set_low();
|
|
Self {
|
|
red,
|
|
red_state: PinState::Low,
|
|
green,
|
|
green_state: PinState::Low,
|
|
orange,
|
|
orange_state: PinState::Low,
|
|
}
|
|
}
|
|
|
|
pub fn red_toggle(&mut self) -> Result<(), <Red as DigitalErrorType>::Error> {
|
|
if self.red_state == PinState::Low {
|
|
self.red_state = PinState::High;
|
|
} else {
|
|
self.red_state = PinState::Low;
|
|
}
|
|
self.red.set_state(self.red_state)
|
|
}
|
|
}
|
|
```
|
|
|
|
Daarnaast is ook de `fn main()` aangepast naar het volgende:
|
|
|
|
```rust
|
|
#[entry]
|
|
fn main() -> ! {
|
|
if let (Some(dp), Some(cp)) = (
|
|
pac::Peripherals::take(),
|
|
cortex_m::peripheral::Peripherals::take(),
|
|
) {
|
|
//GPIOD ophalen
|
|
let gpiod = dp.GPIOD.split();
|
|
// create structs for pins
|
|
let mut green = gpiod.pd12.into_push_pull_output();
|
|
let mut red = gpiod.pd14.into_push_pull_output();
|
|
let mut orange = gpiod.pd13.into_push_pull_output();
|
|
// create leds struct
|
|
let mut leds = Leds::new(&mut red, &mut green, &mut orange);
|
|
|
|
//Klok instellen
|
|
let rcc = dp.RCC.constrain();
|
|
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze();
|
|
|
|
// Create a delay abstraction based on SysTick
|
|
let mut delay = cp.SYST.delay(&clocks);
|
|
let mut status:bool = false;
|
|
loop {
|
|
// On for 1s, off for 1s.
|
|
let _ = leds.red_toggle();
|
|
status ^= true;
|
|
delay.delay_ms(1000_u32);
|
|
|
|
//dit verschijnt in een van de open terminals in vscode
|
|
hprintln!("Led {:?}", status.then(|| "aan!").unwrap_or("uit!"));
|
|
}
|
|
}
|
|
|
|
loop {}
|
|
}
|
|
```
|
|
|
|
### Statemachine
|
|
|
|
De statemachine is geïmplementeerd in zijn eigen struct. In het Rust boek wordt
|
|
er is gebruikgemaakt van `Box` van de std library, maar deze zit niet in de core
|
|
library. Ik heb dit vervangen door een enum. Het nadeel is dat functies niet meer
|
|
dynamisch aangeroepen kunnen worden. Om hier toch makkelijk mee om te gaan, is de volgende functie aangemaakt die het juiste object van de enum pakt en diens functie aanroept.
|
|
|
|
De statemachine struct is als volgt geïmplementeerd in het bestand `state_machine.rs`.
|
|
|
|
```rust
|
|
use embedded_hal::digital::{OutputPin, PinState};
|
|
|
|
use crate::leds::{Leds, Toggle};
|
|
|
|
enum States {
|
|
Red(StateRed),
|
|
Orange(StateOrange),
|
|
Green(StateGreen),
|
|
}
|
|
|
|
trait State<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> Self;
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> States;
|
|
}
|
|
|
|
pub struct StateMachine<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> {
|
|
state: States,
|
|
leds: &'a mut Leds<'a, RP, RT, GP, GT, OP, OT>,
|
|
}
|
|
impl<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> StateMachine<'a, RP, RT, GP, GT, OP, OT>
|
|
{
|
|
pub fn new(leds: &'a mut Leds<'a, RP, RT, GP, GT, OP, OT>) -> Self {
|
|
Self {
|
|
state: States::Red(StateRed::new(leds)),
|
|
leds,
|
|
}
|
|
}
|
|
pub fn second_passed(&mut self) {
|
|
self.state = match &self.state {
|
|
States::Red(state) => state.second_passed(self.leds),
|
|
States::Orange(state) => state.second_passed(self.leds),
|
|
States::Green(state) => state.second_passed(self.leds),
|
|
}
|
|
}
|
|
}
|
|
|
|
// ...
|
|
```
|
|
|
|
### Leds en Toggle
|
|
|
|
Als te zien is in de statemachine code is er gebruikgemaakt van een struct `Leds` die andere generics gebruikt als eerder. Dit is een geüpdatete variant hiervan. De vorige versie had 1 trait met herhalende functie voor elke led. Deze functies zijn nu gedefinieerd in de `trait Toggle`. De toggle functie waar het concept is getest, is eigenlijk niet nodig voor deze opdracht, maar ik vond het een leuke uitdaging om dit erin te houden, aangezien Rust beveiligingen heeft die ervoor zorgen dat een pin niet gebruikt kan worden zonder toegang tot een specifiek object. Dit zorgt ervoor dat het object kan bijhouden wat de laatste status van de pin is en dus de toggle altijd werkt zonder de status van de pin uit te lezen.
|
|
|
|
De toggle functie is geïmplementeerd in `leds.rs`
|
|
|
|
```rust
|
|
use embedded_hal::digital::{OutputPin, PinState};
|
|
|
|
pub trait Toggle<T: OutputPin> {
|
|
fn toggle(&mut self) -> Result<(), T::Error>;
|
|
fn set(&mut self, state: PinState) -> Result<(), T::Error>;
|
|
fn get(&self) -> PinState;
|
|
|
|
fn high(&mut self) -> Result<(), T::Error> {
|
|
self.set(PinState::High)
|
|
}
|
|
fn low(&mut self) -> Result<(), T::Error> {
|
|
self.set(PinState::Low)
|
|
}
|
|
}
|
|
|
|
pub struct ToggleLed<'a, T: OutputPin> {
|
|
pin: &'a mut T,
|
|
state: PinState
|
|
}
|
|
impl<'a, T: OutputPin> ToggleLed<'a, T> {
|
|
pub fn new(pin: &'a mut T) -> Result<Self, T::Error> {
|
|
match pin.set_low() {
|
|
Ok(_) => Ok(Self { pin, state: PinState::Low }),
|
|
Err(e) => Err(e)
|
|
}
|
|
}
|
|
}
|
|
impl<'a, T: OutputPin> Toggle<T> for ToggleLed<'a, T> {
|
|
fn toggle(&mut self) -> Result<(), T::Error> {
|
|
if self.state == PinState::High {
|
|
self.state = PinState::Low;
|
|
} else {
|
|
self.state = PinState::Low;
|
|
}
|
|
self.pin.set_state(self.state)
|
|
}
|
|
fn set(&mut self, state: PinState) -> Result<(), T::Error> {
|
|
if state != self.state {
|
|
self.state = state;
|
|
self.pin.set_state(self.state)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
fn get(&self) -> PinState {
|
|
self.state
|
|
}
|
|
}
|
|
|
|
// ...
|
|
```
|
|
|
|
De `struct Leds` was wat lastiger wegens een bug in Rust^[[github.com/rust-lang/rust/issues/60214](https://github.com/rust-lang/rust/issues/60214)]. De `struct Leds` gebruikt een generic voor de `trait Toggl<T>`. Maar deze trait heeft ook een generic. Deze kan alleen ingevuld worden door met een struct, dus `T: Toggle<DigitalPin>` heeft een error. Een oplossing hiervoor is een extra generic (`P: OutputPin, T: Toggle<P>`), echter de generic `P` wordt verder nergens gebruikt. De compiler detecteert het gebruik niet in `Toggle<P>`. En geeft een error hiervoor. Een workaround voor dit is door een extra element toe te voegen aan de struct met type `PhantomData<P>`.
|
|
|
|
Met deze workaround toegepast is de `struct Leds` als volgt geïmplementeerd in `leds.rs`
|
|
|
|
```rust
|
|
// ...
|
|
|
|
pub struct Leds<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> {
|
|
pub red: &'a mut RT,
|
|
pub green: &'a mut GT,
|
|
pub orange: &'a mut OT,
|
|
|
|
// phantom data to convince rustc the generics RP, GP and OP are used.
|
|
_r: PhantomData<RP>,
|
|
_g: PhantomData<GP>,
|
|
_b: PhantomData<OP>,
|
|
}
|
|
impl<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> Leds<'a, RP, RT, GP, GT, OP, OT> {
|
|
pub fn new(red: &'a mut RT, green: &'a mut GT, orange: &'a mut OT) -> Self {
|
|
Self {
|
|
red,
|
|
green,
|
|
orange,
|
|
|
|
_r: PhantomData,
|
|
_g: PhantomData,
|
|
_b: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn set_all(&mut self, red: PinState, green: PinState, orange: PinState) {
|
|
let _ = self.red.set(red);
|
|
let _ = self.orange.set(orange);
|
|
let _ = self.green.set(green);
|
|
}
|
|
}
|
|
```
|
|
|
|
### states
|
|
|
|
De states zijn geïmplementeerd in `state_machine.rs`
|
|
|
|
```rust
|
|
// ...
|
|
|
|
// ####################################################
|
|
// ## RED #############################################
|
|
// ####################################################
|
|
|
|
struct StateRed {
|
|
time_passed: u32
|
|
}
|
|
impl<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> State<RP, RT, GP, GT, OP, OT> for StateRed {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> Self {
|
|
leds.set_all(PinState::High, PinState::Low, PinState::Low);
|
|
Self {
|
|
time_passed: 0
|
|
}
|
|
}
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> States {
|
|
if self.time_passed + 1 >= 4 {
|
|
States::Green(StateGreen::new(leds))
|
|
} else {
|
|
States::Red(Self {
|
|
time_passed: self.time_passed + 1
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// ####################################################
|
|
// ## GREEN ###########################################
|
|
// ####################################################
|
|
|
|
struct StateGreen {
|
|
time_passed: u32
|
|
}
|
|
impl<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> State<RP, RT, GP, GT, OP, OT> for StateGreen {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> Self {
|
|
leds.set_all(PinState::Low, PinState::High, PinState::Low);
|
|
Self {
|
|
time_passed: 0
|
|
}
|
|
}
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> States {
|
|
if self.time_passed + 1 >= 3 {
|
|
States::Orange(StateOrange::new(leds))
|
|
} else {
|
|
States::Green(Self {
|
|
time_passed: self.time_passed + 1
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// ####################################################
|
|
// ## ORANGE ############################################
|
|
// ####################################################
|
|
|
|
struct StateOrange {}
|
|
impl<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>
|
|
> State<RP, RT, GP, GT, OP, OT> for StateOrange {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> Self {
|
|
leds.set_all(PinState::Low, PinState::Low, PinState::High);
|
|
Self {}
|
|
}
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT>) -> States {
|
|
States::Red(StateRed::new(leds))
|
|
}
|
|
}
|
|
|
|
```
|
|
|
|
### main.rs
|
|
|
|
```rust
|
|
#![deny(unsafe_code)]
|
|
#![allow(clippy::empty_loop)]
|
|
#![no_main]
|
|
#![no_std]
|
|
|
|
// Halt on panic
|
|
use panic_halt as _; // panic handler
|
|
|
|
use cortex_m_rt::entry;
|
|
use stm32f4xx_hal::{self as hal};
|
|
|
|
use crate::hal::{pac, prelude::*};
|
|
|
|
mod leds;
|
|
use crate::leds::{Leds, ToggleLed};
|
|
mod state_machine;
|
|
use crate::state_machine::StateMachine;
|
|
|
|
#[entry]
|
|
fn main() -> ! {
|
|
if let (Some(dp), Some(cp)) = (
|
|
pac::Peripherals::take(),
|
|
cortex_m::peripheral::Peripherals::take(),
|
|
) {
|
|
//GPIOD ophalen
|
|
let gpiod = dp.GPIOD.split();
|
|
//led pinnen uphalen
|
|
let mut green_pin = &mut gpiod.pd12.into_push_pull_output();
|
|
let mut red_pin = &mut gpiod.pd14.into_push_pull_output();
|
|
let mut orange_pin = &mut gpiod.pd15.into_push_pull_output();
|
|
let mut green = ToggleLed::new(&mut green_pin).expect("faild to set green led");
|
|
let mut red = ToggleLed::new(&mut red_pin).expect("faild to set red led");
|
|
let mut orange = ToggleLed::new(&mut orange_pin).expect("faild to set orange led");
|
|
let mut leds = Leds::new(&mut red, &mut green, &mut orange);
|
|
//leds struct en state machine maken
|
|
let mut state_machine = StateMachine::new(&mut leds);
|
|
|
|
//Klok instellen
|
|
let rcc = dp.RCC.constrain();
|
|
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze();
|
|
|
|
// Create a delay abstraction based on SysTick
|
|
let mut delay = cp.SYST.delay(&clocks);
|
|
loop {
|
|
let _ = state_machine.second_passed();
|
|
delay.delay_ms(1000_u32);
|
|
}
|
|
}
|
|
|
|
loop {}
|
|
}
|
|
```
|
|
|
|
## opdracht 8.3
|
|
|
|
> Voeg nu een toestand toe waarbij de blauwe “User” knop aangeeft dat de brug open wilt gaan. Vanuit de rode toestand moet dan naar een andere toestand (brug-open?) worden gesprongen. Wanneer de knop wordt losgelaten springt brug-open naar de rode toestand. In de brug-open-toestand moet de rode led knipperen. Dit knipperen moet elke met een periodetijd van $2s$ ($2s$ aan, $1s$ uit).
|
|
|
|
Om deze aanpassing te doen, moeten de volgende onderdelen aangepast worden:
|
|
|
|
- blue led initialiseren en toevoegen aan `struct Leds` en alle plekken waar deze gebruikt wordt
|
|
- knop initialiseren
|
|
- functies toevoegen voor de knop `trait State` en alle implementaties ervan
|
|
- de state `BridgeOpen` toevoegen aan:
|
|
- `enum States`
|
|
- de tussenfuncties in `struct StateMachine`
|
|
- nieuwe `struct StateBridgeOpen`
|
|
- uitlezen van de knop en aanroepen van de nieuwe functies in `trait State`
|
|
- de `struct StateRed` aanpassen voor de nieuwe logica
|
|
- logica toevoegen aan `struct StateBridgeOpen`
|
|
|
|
### resultaat
|
|
|
|
Ook beschikbaar op [git.gay/LailaTheElf/rts10_reports/src/branch/main/report-3/rts10_rust](https://git.gay/LailaTheElf/RTS10_reports/src/branch/main/report-3/rts10_rust).
|
|
|
|
#### leds.rs
|
|
|
|
```rust
|
|
use core::marker::PhantomData;
|
|
|
|
use embedded_hal::digital::{OutputPin, PinState};
|
|
|
|
pub trait Toggle<T: OutputPin> {
|
|
fn toggle(&mut self) -> Result<(), T::Error>;
|
|
fn set(&mut self, state: PinState) -> Result<(), T::Error>;
|
|
fn get(&self) -> PinState;
|
|
|
|
fn high(&mut self) -> Result<(), T::Error> {
|
|
self.set(PinState::High)
|
|
}
|
|
fn low(&mut self) -> Result<(), T::Error> {
|
|
self.set(PinState::Low)
|
|
}
|
|
}
|
|
|
|
pub struct ToggleLed<'a, T: OutputPin> {
|
|
pin: &'a mut T,
|
|
state: PinState
|
|
}
|
|
impl<'a, T: OutputPin> ToggleLed<'a, T> {
|
|
pub fn new(pin: &'a mut T) -> Result<Self, T::Error> {
|
|
match pin.set_low() {
|
|
Ok(_) => Ok(Self { pin, state: PinState::Low }),
|
|
Err(e) => Err(e)
|
|
}
|
|
}
|
|
}
|
|
impl<'a, T: OutputPin> Toggle<T> for ToggleLed<'a, T> {
|
|
fn toggle(&mut self) -> Result<(), T::Error> {
|
|
if self.state == PinState::High {
|
|
self.state = PinState::Low;
|
|
} else {
|
|
self.state = PinState::Low;
|
|
}
|
|
self.pin.set_state(self.state)
|
|
}
|
|
fn set(&mut self, state: PinState) -> Result<(), T::Error> {
|
|
if state != self.state {
|
|
self.state = state;
|
|
self.pin.set_state(self.state)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
fn get(&self) -> PinState {
|
|
self.state
|
|
}
|
|
}
|
|
|
|
pub struct Leds<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> {
|
|
pub red: &'a mut RT,
|
|
pub green: &'a mut GT,
|
|
pub orange: &'a mut OT,
|
|
pub blue: &'a mut BT,
|
|
|
|
// phantom data to convince rustc the generics RP, GP, OP and BP are used.
|
|
_r: PhantomData<RP>,
|
|
_g: PhantomData<GP>,
|
|
_o: PhantomData<OP>,
|
|
_b: PhantomData<BP>,
|
|
}
|
|
impl<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> Leds<'a, RP, RT, GP, GT, OP, OT, BP, BT> {
|
|
pub fn new(red: &'a mut RT, green: &'a mut GT, orange: &'a mut OT, blue: &'a mut BT) -> Self {
|
|
Self {
|
|
red,
|
|
green,
|
|
orange,
|
|
blue,
|
|
|
|
_r: PhantomData,
|
|
_g: PhantomData,
|
|
_o: PhantomData,
|
|
_b: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn set_all(&mut self, red: PinState, green: PinState, orange: PinState, blue: PinState) {
|
|
let _ = self.red.set(red);
|
|
let _ = self.orange.set(orange);
|
|
let _ = self.green.set(green);
|
|
let _ = self.blue.set(blue);
|
|
}
|
|
}
|
|
```
|
|
|
|
#### state_machine.rs
|
|
|
|
```rust
|
|
use embedded_hal::digital::{OutputPin, PinState};
|
|
|
|
use crate::leds::{Leds, Toggle};
|
|
|
|
enum States {
|
|
Red(StateRed),
|
|
Orange(StateOrange),
|
|
Green(StateGreen),
|
|
BridgeOpen(StateBridgeOpen)
|
|
}
|
|
|
|
trait State<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> Self;
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States;
|
|
fn button_press(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States;
|
|
fn button_release(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States;
|
|
}
|
|
|
|
pub struct StateMachine<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> {
|
|
state: States,
|
|
leds: &'a mut Leds<'a, RP, RT, GP, GT, OP, OT, BP, BT>
|
|
}
|
|
impl<'a,
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> StateMachine<'a, RP, RT, GP, GT, OP, OT, BP, BT>
|
|
{
|
|
pub fn new(leds: &'a mut Leds<'a, RP, RT, GP, GT, OP, OT, BP, BT>) -> Self {
|
|
Self {
|
|
state: States::Red(StateRed::new(leds)),
|
|
leds
|
|
}
|
|
}
|
|
pub fn second_passed(&mut self) {
|
|
self.state = match &self.state {
|
|
States::Red(state) => state.second_passed(self.leds),
|
|
States::Orange(state) => state.second_passed(self.leds),
|
|
States::Green(state) => state.second_passed(self.leds),
|
|
States::BridgeOpen(state) => state.second_passed(self.leds),
|
|
}
|
|
}
|
|
pub fn button_press(&mut self) {
|
|
self.state = match &self.state {
|
|
States::Red(state) => state.button_press(self.leds),
|
|
States::Orange(state) => state.button_press(self.leds),
|
|
States::Green(state) => state.button_press(self.leds),
|
|
States::BridgeOpen(state) => state.button_press(self.leds),
|
|
}
|
|
}
|
|
pub fn button_release(&mut self) {
|
|
self.state = match &self.state {
|
|
States::Red(state) => state.button_release(self.leds),
|
|
States::Orange(state) => state.button_release(self.leds),
|
|
States::Green(state) => state.button_release(self.leds),
|
|
States::BridgeOpen(state) => state.button_release(self.leds),
|
|
}
|
|
}
|
|
}
|
|
|
|
// ####################################################
|
|
// ## RED #############################################
|
|
// ####################################################
|
|
|
|
struct StateRed {
|
|
time_passed: u32
|
|
}
|
|
impl<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> State<RP, RT, GP, GT, OP, OT, BP, BT> for StateRed {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> Self {
|
|
leds.set_all(PinState::High, PinState::Low, PinState::Low, PinState::Low);
|
|
Self {
|
|
time_passed: 0
|
|
}
|
|
}
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
if self.time_passed + 1 >= 4 {
|
|
States::Green(StateGreen::new(leds))
|
|
} else {
|
|
States::Red(Self {
|
|
time_passed: self.time_passed + 1
|
|
})
|
|
}
|
|
}
|
|
|
|
fn button_press(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::BridgeOpen(StateBridgeOpen::new(leds))
|
|
}
|
|
fn button_release(&self, _leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::Red(Self {
|
|
time_passed: self.time_passed
|
|
})
|
|
}
|
|
}
|
|
|
|
// ####################################################
|
|
// ## GREEN ###########################################
|
|
// ####################################################
|
|
|
|
struct StateGreen {
|
|
time_passed: u32
|
|
}
|
|
impl<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> State<RP, RT, GP, GT, OP, OT, BP, BT> for StateGreen {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> Self {
|
|
leds.set_all(PinState::Low, PinState::High, PinState::Low, PinState::Low);
|
|
Self {
|
|
time_passed: 0
|
|
}
|
|
}
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
if self.time_passed + 1 >= 3 {
|
|
States::Orange(StateOrange::new(leds))
|
|
} else {
|
|
States::Green(Self {
|
|
time_passed: self.time_passed + 1
|
|
})
|
|
}
|
|
}
|
|
|
|
fn button_press(&self, _leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::Green(Self {
|
|
time_passed: self.time_passed
|
|
})
|
|
}
|
|
fn button_release(&self, _leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::Green(Self {
|
|
time_passed: self.time_passed
|
|
})
|
|
}
|
|
}
|
|
|
|
// ####################################################
|
|
// ## ORANGE ############################################
|
|
// ####################################################
|
|
|
|
struct StateOrange {}
|
|
impl<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> State<RP, RT, GP, GT, OP, OT, BP, BT> for StateOrange {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> Self {
|
|
leds.set_all(PinState::Low, PinState::Low, PinState::High, PinState::Low);
|
|
Self {}
|
|
}
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::Red(StateRed::new(leds))
|
|
}
|
|
|
|
fn button_press(&self, _leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::Orange(Self {})
|
|
}
|
|
fn button_release(&self, _leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::Orange(Self {})
|
|
}
|
|
}
|
|
|
|
// ####################################################
|
|
// ## BRIDGE_OPEN #####################################
|
|
// ####################################################
|
|
|
|
struct StateBridgeOpen {
|
|
time_passed: u32
|
|
}
|
|
impl<
|
|
RP: OutputPin, RT: Toggle<RP>,
|
|
GP: OutputPin, GT: Toggle<GP>,
|
|
OP: OutputPin, OT: Toggle<OP>,
|
|
BP: OutputPin, BT: Toggle<BP>
|
|
> State<RP, RT, GP, GT, OP, OT, BP, BT> for StateBridgeOpen {
|
|
fn new(leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> Self {
|
|
leds.set_all(PinState::Low, PinState::Low, PinState::Low, PinState::High);
|
|
Self {
|
|
time_passed: 0
|
|
}
|
|
}
|
|
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
if self.time_passed + 1 == 2 {
|
|
let _ = leds.blue.low();
|
|
States::BridgeOpen(Self {
|
|
time_passed: self.time_passed + 1
|
|
})
|
|
} else if self.time_passed + 1 >= 3 {
|
|
let _ = leds.blue.high();
|
|
States::BridgeOpen(Self {
|
|
time_passed: 0
|
|
})
|
|
} else {
|
|
States::BridgeOpen(Self {
|
|
time_passed: self.time_passed + 1
|
|
})
|
|
}
|
|
}
|
|
|
|
fn button_press(&self, _leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::BridgeOpen(Self {
|
|
time_passed: self.time_passed
|
|
})
|
|
}
|
|
fn button_release(&self, leds: &mut Leds<RP, RT, GP, GT, OP, OT, BP, BT>) -> States {
|
|
States::Red(StateRed::new(leds))
|
|
}
|
|
}
|
|
```
|
|
|
|
#### main.rs
|
|
|
|
```rust
|
|
#![deny(unsafe_code)]
|
|
#![allow(clippy::empty_loop)]
|
|
#![no_main]
|
|
#![no_std]
|
|
|
|
use embedded_hal::digital::PinState;
|
|
// Halt on panic
|
|
use panic_halt as _; // panic handler
|
|
|
|
use cortex_m_rt::entry;
|
|
use stm32f4xx_hal::{self as hal};
|
|
|
|
use crate::hal::{pac, prelude::*};
|
|
|
|
mod leds;
|
|
use crate::leds::{Leds, ToggleLed};
|
|
mod state_machine;
|
|
use crate::state_machine::StateMachine;
|
|
|
|
#[entry]
|
|
fn main() -> ! {
|
|
if let (Some(dp), Some(cp)) = (
|
|
pac::Peripherals::take(),
|
|
cortex_m::peripheral::Peripherals::take(),
|
|
) {
|
|
//GPIOD ophalen
|
|
let gpiod = dp.GPIOD.split();
|
|
//led pinnen uphalen
|
|
let mut green_pin = &mut gpiod.pd12.into_push_pull_output();
|
|
let mut red_pin = &mut gpiod.pd14.into_push_pull_output();
|
|
let mut orange_pin = &mut gpiod.pd13.into_push_pull_output();
|
|
let mut blue_pin = &mut gpiod.pd15.into_push_pull_output();
|
|
let mut green = ToggleLed::new(&mut green_pin).expect("faild to set green led");
|
|
let mut red = ToggleLed::new(&mut red_pin).expect("faild to set red led");
|
|
let mut orange = ToggleLed::new(&mut orange_pin).expect("faild to set orange led");
|
|
let mut blue = ToggleLed::new(&mut blue_pin).expect("faild to set blue led");
|
|
let mut leds = Leds::new(&mut red, &mut green, &mut orange, &mut blue);
|
|
//user knop
|
|
let gpioa = dp.GPIOA.split();
|
|
let button = &mut gpioa.pa0.into_floating_input();
|
|
//leds struct en state machine maken
|
|
let mut state_machine = StateMachine::new(&mut leds);
|
|
|
|
//Klok instellen
|
|
let rcc = dp.RCC.constrain();
|
|
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze();
|
|
|
|
// Create a delay abstraction based on SysTick
|
|
let mut delay = cp.SYST.delay(&clocks);
|
|
let mut button_high = button.is_high();
|
|
loop {
|
|
let _ = state_machine.second_passed();
|
|
for _ in 0..99 {
|
|
if button_high != button.is_high() {
|
|
button_high = button.is_high();
|
|
if button_high {
|
|
state_machine.button_press();
|
|
} else {
|
|
state_machine.button_release();
|
|
}
|
|
}
|
|
delay.delay_ms(10_u32);
|
|
}
|
|
}
|
|
}
|
|
|
|
loop {}
|
|
}
|
|
```
|