221 lines
6.9 KiB
Markdown
221 lines
6.9 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 gebuik van structs en traits. Om dit
|
|
mognelijk te maken moet er een struct zijn die de leds kan aansturen. Hiervoor
|
|
is het de Pin struct van de stm32f4xx-hal nodig in in struct. Om mijn
|
|
implementatie makkelijker onderhoudbaar te maken worden de Pin structs
|
|
doorgegeven aan de state machine struct. Hiervoor is een triad nodig die
|
|
functions voor het aanpassen van de led status beschijft. De `toggle` functie
|
|
die gebruikt wordt in het voorbeeld is niet geimplementeerd via een trait.
|
|
Deze kan dus niet gebruikt worden zonder de hal aan te passen. In de
|
|
documentatie van de pin struct implementeerd die de OutputPin trait 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 toegevoed aan het project zodat hier
|
|
gebruik van gemaakt kan worden.
|
|
|
|
Om te testen of dit werkt is er een stuct aangemaakt met een simple toggle
|
|
functie en de embeded_hal geimporteerd. Dit is gedaan met de volgende code:
|
|
|
|
```rust
|
|
use embedded_hal::digital::{ErrorType as DigitalErrorType, OutputPin, PinState};
|
|
|
|
struct Leds<'a, Red: OutputPin, Green: OutputPin, Blue: OutputPin> {
|
|
red: &'a mut Red,
|
|
red_state: PinState,
|
|
green: &'a mut Green,
|
|
green_state: PinState,
|
|
blue: &'a mut Blue,
|
|
blue_state: PinState,
|
|
}
|
|
impl<'a, Red: OutputPin, Green: OutputPin, Blue: OutputPin> Leds<'a, Red, Green, Blue> {
|
|
pub fn new(red: &'a mut Red, green: &'a mut Green, blue: &'a mut Blue) -> Self {
|
|
let _ = red.set_low();
|
|
let _ = green.set_low();
|
|
let _ = blue.set_low();
|
|
Self {
|
|
red,
|
|
red_state: PinState::Low,
|
|
green,
|
|
green_state: PinState::Low,
|
|
blue,
|
|
blue_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 main functie 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 blue = gpiod.pd15.into_push_pull_output();
|
|
// create leds struct
|
|
let mut leds = Leds::new(&mut red, &mut green, &mut blue);
|
|
|
|
//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 {}
|
|
}
|
|
```
|
|
|
|
### state machine
|
|
|
|
De statemachine is geimplementeerd in zijn eigen struct
|
|
|
|
- Box is not available without malloc. switch to an enum
|
|
|
|
|
|
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.
|
|
|
|
## code
|
|
|
|
```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 as hal;
|
|
|
|
use crate::hal::{pac, prelude::*};
|
|
use cortex_m_semihosting::hprintln;
|
|
|
|
enum MainStates {
|
|
Rood,
|
|
Groen,
|
|
Orange,
|
|
BrugOpen_on,
|
|
BrugOpen_off
|
|
}
|
|
|
|
#[entry]
|
|
fn main() -> ! {
|
|
if let (Some(dp), Some(cp)) = (
|
|
pac::Peripherals::take(),
|
|
cortex_m::peripheral::Peripherals::take(),
|
|
) {
|
|
//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();
|
|
|
|
//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 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
loop {}
|
|
}
|
|
```
|
|
|
|
|
|
|
|
|