write report for 8.2
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embedded_hal::digital::{OutputPin, PinState};
|
||||
|
||||
pub trait Toggle<T: OutputPin> {
|
||||
@@ -57,9 +59,9 @@ pub struct Leds<'a,
|
||||
pub blue: &'a mut BT,
|
||||
|
||||
// phantom data to convince rustc the generics RP, GP and BP are used.
|
||||
_r: Option<RP>,
|
||||
_g: Option<GP>,
|
||||
_b: Option<BP>,
|
||||
_r: PhantomData<RP>,
|
||||
_g: PhantomData<GP>,
|
||||
_b: PhantomData<BP>,
|
||||
}
|
||||
impl<'a,
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
@@ -72,9 +74,9 @@ impl<'a,
|
||||
green,
|
||||
blue,
|
||||
|
||||
_r: None,
|
||||
_g: None,
|
||||
_b: None,
|
||||
_r: PhantomData,
|
||||
_g: PhantomData,
|
||||
_b: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ fn main() -> ! {
|
||||
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 {
|
||||
|
||||
@@ -110,18 +110,257 @@ fn main() -> ! {
|
||||
|
||||
### state machine
|
||||
|
||||
De statemachine is geimplementeerd in zijn eigen struct
|
||||
De state machine is geïmplementeerd in zijn eigen struct. In the rust boek wordt
|
||||
er gebruikt gemaakt van `Box` van de std library, maar deze zit niet in de core
|
||||
library. Ik heb dit vervangen met 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.
|
||||
|
||||
- Box is not available without malloc. switch to an enum
|
||||
De state machine struct is als volgt geïmplementeerd in het bestand `state_machine.rs`.
|
||||
|
||||
```rust
|
||||
use embedded_hal::digital::{OutputPin, PinState};
|
||||
|
||||
Ik heb niet genoeg tijd gehad om dat dit vak te werken, dus mijn code werkt niet
|
||||
zoals dat het moet, het werkt wel. Ik heb veel geëxperimenteerd met Rustlings,
|
||||
ik hierdoor nog enthousiaster geworden om Rust beter te leren. Het is echt een
|
||||
andere denkwijze als C/C++. Rust laat je echt goed denken hoe de code moet
|
||||
werkten en maakt het erg moeilijk om onzichtbare bugs te maken.
|
||||
use crate::leds::{Leds, Toggle};
|
||||
|
||||
## code
|
||||
enum States {
|
||||
Red(StateRed),
|
||||
Blue(StateBlue),
|
||||
Green(StateGreen),
|
||||
}
|
||||
|
||||
trait State<
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
GP: OutputPin, GT: Toggle<GP>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> {
|
||||
fn new(leds: &mut Leds<RP, RT, GP, GT, BP, BT>) -> Self;
|
||||
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, BP, BT>) -> States;
|
||||
}
|
||||
|
||||
pub struct StateMachine<'a,
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
GP: OutputPin, GT: Toggle<GP>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> {
|
||||
state: States,
|
||||
leds: &'a mut Leds<'a, RP, RT, GP, GT, BP, BT>,
|
||||
}
|
||||
impl<'a,
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
GP: OutputPin, GT: Toggle<GP>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> StateMachine<'a, RP, RT, GP, GT, BP, BT>
|
||||
{
|
||||
pub fn new(leds: &'a mut Leds<'a, RP, RT, GP, GT, 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::Blue(state) => state.second_passed(self.leds),
|
||||
States::Green(state) => state.second_passed(self.leds),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
```
|
||||
|
||||
### Leds en Toggle
|
||||
|
||||
Als te zien is in de state machine code is er gebruikgemaakt van een struct `Leds` die andere generics gebruikt als eerder. Dit is een geupdaten variant hiervan. De vorige versie had 1 trait met herhalende function voor elke led. Deze functies zijn nu elke 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 er in te houden, gezien Rust beveiligingen heeft die ervoor zorgt dat een pin niet gebruikt kan worden zonder toegang tot een specifiek object. Dit zorgt er voor dat dat 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 implemented 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 Leds struct 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 met type `PhantomData<P>`.
|
||||
|
||||
Met deze workaround toegepast de `struct Leds` is als volgt geïmplementeerd in `leds.rs`
|
||||
|
||||
```rust
|
||||
// ...
|
||||
|
||||
pub struct Leds<'a,
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
GP: OutputPin, GT: Toggle<GP>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> {
|
||||
pub red: &'a mut RT,
|
||||
pub green: &'a mut GT,
|
||||
pub blue: &'a mut BT,
|
||||
|
||||
// phantom data to convince rustc the generics RP, GP and BP are used.
|
||||
_r: PhantomData<RP>,
|
||||
_g: PhantomData<GP>,
|
||||
_b: PhantomData<BP>,
|
||||
}
|
||||
impl<'a,
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
GP: OutputPin, GT: Toggle<GP>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> Leds<'a, RP, RT, GP, GT, BP, BT> {
|
||||
pub fn new(red: &'a mut RT, green: &'a mut GT, blue: &'a mut BT) -> Self {
|
||||
Self {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
|
||||
_r: PhantomData,
|
||||
_g: PhantomData,
|
||||
_b: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_all(&mut self, red: PinState, green: PinState, blue: PinState) {
|
||||
let _ = self.red.set(red);
|
||||
let _ = self.blue.set(blue);
|
||||
let _ = self.green.set(green);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### states
|
||||
|
||||
De states zijn geimplementeerd in `state_machine.rs`
|
||||
|
||||
```rust
|
||||
// ...
|
||||
|
||||
// ####################################################
|
||||
// ## RED #############################################
|
||||
// ####################################################
|
||||
|
||||
struct StateRed {
|
||||
time_passed: u32
|
||||
}
|
||||
impl<
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
GP: OutputPin, GT: Toggle<GP>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> State<RP, RT, GP, GT, BP, BT> for StateRed {
|
||||
fn new(leds: &mut Leds<RP, RT, GP, GT, BP, BT>) -> 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, BP, BT>) -> 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>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> State<RP, RT, GP, GT, BP, BT> for StateGreen {
|
||||
fn new(leds: &mut Leds<RP, RT, GP, GT, BP, BT>) -> 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, BP, BT>) -> States {
|
||||
if self.time_passed + 1 >= 3 {
|
||||
States::Blue(StateBlue::new(leds))
|
||||
} else {
|
||||
States::Green(Self {
|
||||
time_passed: self.time_passed + 1
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// ## BLUE ############################################
|
||||
// ####################################################
|
||||
|
||||
struct StateBlue {}
|
||||
impl<
|
||||
RP: OutputPin, RT: Toggle<RP>,
|
||||
GP: OutputPin, GT: Toggle<GP>,
|
||||
BP: OutputPin, BT: Toggle<BP>
|
||||
> State<RP, RT, GP, GT, BP, BT> for StateBlue {
|
||||
fn new(leds: &mut Leds<RP, RT, GP, GT, BP, BT>) -> Self {
|
||||
leds.set_all(PinState::Low, PinState::Low, PinState::High);
|
||||
Self {}
|
||||
}
|
||||
fn second_passed(&self, leds: &mut Leds<RP, RT, GP, GT, BP, BT>) -> States {
|
||||
States::Red(StateRed::new(leds))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### main.rs
|
||||
|
||||
```rust
|
||||
#![deny(unsafe_code)]
|
||||
@@ -133,18 +372,14 @@ werkten en maakt het erg moeilijk om onzichtbare bugs te maken.
|
||||
use panic_halt as _; // panic handler
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use stm32f4xx_hal as hal;
|
||||
use stm32f4xx_hal::{self as hal};
|
||||
|
||||
use crate::hal::{pac, prelude::*};
|
||||
use cortex_m_semihosting::hprintln;
|
||||
|
||||
enum MainStates {
|
||||
Rood,
|
||||
Groen,
|
||||
Orange,
|
||||
BrugOpen_on,
|
||||
BrugOpen_off
|
||||
}
|
||||
mod leds;
|
||||
use crate::leds::{Leds, ToggleLed};
|
||||
mod state_machine;
|
||||
use crate::state_machine::StateMachine;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
@@ -154,9 +389,16 @@ fn main() -> ! {
|
||||
) {
|
||||
//GPIOD ophalen
|
||||
let gpiod = dp.GPIOD.split();
|
||||
let mut led_rood = gpiod.pd14.into_push_pull_output();
|
||||
let mut led_groen = gpiod.pd12.into_push_pull_output();
|
||||
let mut led_orange = gpiod.pd13.into_push_pull_output();
|
||||
//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 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 blue = ToggleLed::new(&mut blue_pin).expect("faild to set blue led");
|
||||
let mut leds = Leds::new(&mut red, &mut green, &mut blue);
|
||||
//leds struct en state machine maken
|
||||
let mut state_machine = StateMachine::new(&mut leds);
|
||||
|
||||
//Klok instellen
|
||||
let rcc = dp.RCC.constrain();
|
||||
@@ -164,57 +406,12 @@ fn main() -> ! {
|
||||
|
||||
// Create a delay abstraction based on SysTick
|
||||
let mut delay = cp.SYST.delay(&clocks);
|
||||
let mut main_state : MainStates = MainStates::Rood;
|
||||
loop {
|
||||
match main_state {
|
||||
MainStates::Rood => {
|
||||
hprintln!("Rood");
|
||||
led_rood.set_high();
|
||||
led_groen.set_low();
|
||||
led_orange.set_low();
|
||||
delay.delay(4.secs());
|
||||
main_state = MainStates::Groen;
|
||||
},
|
||||
MainStates::Groen => {
|
||||
hprintln!("Groen");
|
||||
led_rood.set_low();
|
||||
led_groen.set_high();
|
||||
led_orange.set_low();
|
||||
delay.delay(3.secs());
|
||||
main_state = MainStates::Orange;
|
||||
},
|
||||
MainStates::Orange => {
|
||||
hprintln!("Orange");
|
||||
led_rood.set_low();
|
||||
led_groen.set_low();
|
||||
led_orange.set_high();
|
||||
delay.delay(1.secs());
|
||||
main_state = MainStates::BrugOpen_on;
|
||||
},
|
||||
MainStates::BrugOpen_on => {
|
||||
hprintln!("Brug open - on");
|
||||
led_rood.set_high();
|
||||
led_groen.set_low();
|
||||
led_orange.set_low();
|
||||
delay.delay(2.secs());
|
||||
main_state = MainStates::BrugOpen_off;
|
||||
},
|
||||
MainStates::BrugOpen_off => {
|
||||
hprintln!("Brug open - off");
|
||||
led_rood.set_low();
|
||||
led_groen.set_low();
|
||||
led_orange.set_low();
|
||||
delay.delay(1.secs());
|
||||
main_state = MainStates::BrugOpen_on;
|
||||
}
|
||||
}
|
||||
let _ = state_machine.second_passed();
|
||||
delay.delay_ms(1000_u32);
|
||||
}
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2
wiki
2
wiki
Submodule wiki updated: 3ff030559f...eb1f285229
Reference in New Issue
Block a user