stm32_rust_template/apps/
blink.rs1use crate::apps::App;
2use crate::arch::cortex_m4::systick::get_ticks;
3use crate::driver::gpio::stm32f407::{GpioDriver, pins};
4use crate::driver::gpio::{Direction, Gpio};
5
6const BOUNCE: [u8; 6] = [0b0001, 0b0010, 0b0100, 0b1000, 0b0100, 0b0010];
7const IN_OUT: [u8; 6] = [0b1001, 0b0110, 0b1111, 0b0110, 0b1001, 0b0000];
8const TWINKLE: [u8; 8] = [
9 0b0001, 0b1000, 0b0010, 0b0100, 0b1000, 0b0001, 0b0100, 0b0010,
10];
11const CHASE: [u8; 4] = [0b0001, 0b0010, 0b0100, 0b1000];
12const FAST_MS: u32 = 120;
13const MED_MS: u32 = 220;
14const SLOW_MS: u32 = 320;
15const SMOKE_DELAY_MS: u32 = 700;
16const SMOKE_OFF_DELAY_MS: u32 = 200;
17
18#[derive(Clone, Copy)]
19enum State {
20 Smoke(u8),
21 SmokeDelay(u8),
22 SmokeOffDelay,
23 Bounce(u8, u8),
24 BounceDelay(u8, u8),
25 InOut(u8, u8),
26 InOutDelay(u8, u8),
27 AllOn,
28 AllOnDelay,
29 AllOff,
30 AllOffDelay,
31 Twinkle(u8, u8),
32 TwinkleDelay(u8, u8),
33 Chase(u8),
34 ChaseDelay(u8),
35}
36
37pub struct BlinkApp {
38 gpio_driver: Option<GpioDriver<'static>>,
39 initialized: bool,
40 state: State,
41 last_tick: u32,
42}
43
44impl BlinkApp {
45 pub fn new() -> Self {
46 Self {
47 gpio_driver: None,
48 initialized: false,
49 state: State::Smoke(0),
50 last_tick: 0,
51 }
52 }
53
54 pub fn init(&mut self) -> Result<(), i32> {
55 if self.initialized {
56 return Ok(());
57 }
58 let mut gpio = GpioDriver::new_gpiod();
59
60 for &p in &[pins::PD12, pins::PD13, pins::PD14, pins::PD15] {
62 gpio.set_direction(p, Direction::Output)?;
63 gpio.set_output(p, false);
64 }
65
66 self.gpio_driver = Some(gpio);
67 self.initialized = true;
68 Ok(())
69 }
70
71 #[inline(always)]
72 fn delay(mut cycles: u32) {
73 while cycles > 0 {
74 cortex_m::asm::nop();
75 cycles -= 1;
76 }
77 }
78
79 fn write_mask_4(gpio: &mut GpioDriver, mask4: u8) {
82 const ACTIVE_LOW: bool = false; let pins = [pins::PD12, pins::PD13, pins::PD14, pins::PD15];
86 for (i, &p) in pins.iter().enumerate() {
88 let want_on = ((mask4 >> i) & 1) != 0;
89 let level = if ACTIVE_LOW { !want_on } else { want_on };
90 gpio.set_output(p, level);
91 }
92 }
93
94 pub fn tick(&mut self) {
95 if !self.initialized {
96 return;
97 }
98 if let Some(ref mut gpio) = self.gpio_driver {
99 match self.state {
100 State::Smoke(step) => {
101 if step < 4 {
102 for j in 0..4 {
103 Self::write_mask_4(gpio, if j == step { 1 << j } else { 0 });
104 }
105 self.last_tick = get_ticks();
106 self.state = State::SmokeDelay(step);
107 } else {
108 Self::write_mask_4(gpio, 0);
109 self.last_tick = get_ticks();
110 self.state = State::SmokeOffDelay;
111 }
112 }
113 State::SmokeDelay(step) => {
114 if get_ticks().wrapping_sub(self.last_tick) >= SMOKE_DELAY_MS {
115 self.state = State::Smoke(step + 1);
116 }
117 }
118 State::SmokeOffDelay => {
119 if get_ticks().wrapping_sub(self.last_tick) >= SMOKE_OFF_DELAY_MS {
120 self.state = State::Bounce(0, 0);
121 }
122 }
123 State::Bounce(count, step) => {
124 let m = BOUNCE[step as usize];
125 Self::write_mask_4(gpio, m);
126 self.last_tick = get_ticks();
127 self.state = State::BounceDelay(count, step);
128 }
129 State::BounceDelay(count, step) => {
130 if get_ticks().wrapping_sub(self.last_tick) >= MED_MS {
131 let next_step = step + 1;
132 if next_step >= BOUNCE.len() as u8 {
133 let next_count = count + 1;
134 if next_count >= 4 {
135 self.state = State::InOut(0, 0);
136 } else {
137 self.state = State::Bounce(next_count, 0);
138 }
139 } else {
140 self.state = State::Bounce(count, next_step);
141 }
142 }
143 }
144 State::InOut(count, step) => {
145 let m = IN_OUT[step as usize];
146 Self::write_mask_4(gpio, m);
147 self.last_tick = get_ticks();
148 self.state = State::InOutDelay(count, step);
149 }
150 State::InOutDelay(count, step) => {
151 if get_ticks().wrapping_sub(self.last_tick) >= FAST_MS {
152 let next_step = step + 1;
153 if next_step >= IN_OUT.len() as u8 {
154 let next_count = count + 1;
155 if next_count >= 6 {
156 self.state = State::AllOn;
157 } else {
158 self.state = State::InOut(next_count, 0);
159 }
160 } else {
161 self.state = State::InOut(count, next_step);
162 }
163 }
164 }
165 State::AllOn => {
166 Self::write_mask_4(gpio, 0b1111);
167 self.last_tick = get_ticks();
168 self.state = State::AllOnDelay;
169 }
170 State::AllOnDelay => {
171 if get_ticks().wrapping_sub(self.last_tick) >= SLOW_MS {
172 self.state = State::AllOff;
173 }
174 }
175 State::AllOff => {
176 Self::write_mask_4(gpio, 0b0000);
177 self.last_tick = get_ticks();
178 self.state = State::AllOffDelay;
179 }
180 State::AllOffDelay => {
181 if get_ticks().wrapping_sub(self.last_tick) >= MED_MS {
182 self.state = State::Twinkle(0, 0);
183 }
184 }
185 State::Twinkle(count, step) => {
186 let m = TWINKLE[step as usize];
187 Self::write_mask_4(gpio, m);
188 self.last_tick = get_ticks();
189 self.state = State::TwinkleDelay(count, step);
190 }
191 State::TwinkleDelay(count, step) => {
192 if get_ticks().wrapping_sub(self.last_tick) >= FAST_MS {
193 let next_step = step + 1;
194 if next_step >= TWINKLE.len() as u8 {
195 let next_count = count + 1;
196 if next_count >= 6 {
197 self.state = State::Chase(0);
198 } else {
199 self.state = State::Twinkle(next_count, 0);
200 }
201 } else {
202 self.state = State::Twinkle(count, next_step);
203 }
204 }
205 }
206 State::Chase(step) => {
207 let m = CHASE[step as usize];
208 Self::write_mask_4(gpio, m);
209 self.last_tick = get_ticks();
210 self.state = State::ChaseDelay(step);
211 }
212 State::ChaseDelay(step) => {
213 if get_ticks().wrapping_sub(self.last_tick) >= FAST_MS {
214 let next_step = step + 1;
215 if next_step >= CHASE.len() as u8 {
216 self.state = State::Bounce(0, 0);
217 } else {
218 self.state = State::Chase(next_step);
219 }
220 }
221 }
222 }
223 }
224 }
225}
226
227impl App for BlinkApp {
228 fn init(&mut self) -> Result<(), i32> {
229 self.init()
230 }
231 fn loop_step(&mut self) {
232 self.tick();
233 }
234}
235
236pub fn create_simple_blink_app() -> BlinkApp {
237 BlinkApp::new()
238}