+141
-92
src/badge_display/mod.rs
+141
-92
src/badge_display/mod.rs
···
27
27
use gpio::Output;
28
28
use heapless::String;
29
29
use tinybmp::Bmp;
30
-
use uc8151::asynch::Uc8151;
31
30
use uc8151::LUT;
32
31
use uc8151::WIDTH;
32
+
use uc8151::{asynch::Uc8151, HEIGHT};
33
33
use {defmt_rtt as _, panic_probe as _};
34
34
35
35
use crate::{env::env_value, helpers::easy_format, Spi0Bus};
36
36
37
37
//Display state
38
+
pub static SCREEN_TO_SHOW: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<Screen>> =
39
+
blocking_mutex::Mutex::new(RefCell::new(Screen::Badge));
40
+
pub static DISPLAY_CHANGED: AtomicBool = AtomicBool::new(false);
38
41
pub static CURRENT_IMAGE: AtomicU8 = AtomicU8::new(0);
39
42
pub static CHANGE_IMAGE: AtomicBool = AtomicBool::new(true);
40
43
pub static WIFI_COUNT: AtomicU32 = AtomicU32::new(0);
···
42
45
blocking_mutex::Mutex::new(RefCell::new(String::<8>::new()));
43
46
pub static TEMP: AtomicU8 = AtomicU8::new(0);
44
47
pub static HUMIDITY: AtomicU8 = AtomicU8::new(0);
48
+
49
+
#[derive(Debug, Clone, Copy, PartialEq, defmt::Format)]
50
+
pub enum Screen {
51
+
Badge,
52
+
WifiList,
53
+
}
45
54
46
55
#[embassy_executor::task]
47
56
pub async fn run_the_display(
···
102
111
//New start every 120 cycles or 60 seconds
103
112
let cycles_to_clear_at: i32 = 120;
104
113
let mut cycles_since_last_clear = 0;
105
-
114
+
let mut current_screen = Screen::Badge;
106
115
loop {
107
116
//Timed based display events
108
-
109
-
//Runs every second;
110
-
if cycles_since_last_clear % 2 == 0 {
111
-
// update_time_values_from_cycles();
117
+
if DISPLAY_CHANGED.load(core::sync::atomic::Ordering::Relaxed) {
118
+
let clear_rectangle = Rectangle::new(Point::new(0, 0), Size::new(WIDTH, HEIGHT));
119
+
clear_rectangle
120
+
.into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
121
+
.draw(&mut display)
122
+
.unwrap();
123
+
let _ = display.update().await;
124
+
DISPLAY_CHANGED.store(false, core::sync::atomic::Ordering::Relaxed);
125
+
first_run = true;
112
126
}
113
127
114
-
//Updates the top bar
115
-
//Runs every 60 cycles/30 seconds and first run
116
-
if cycles_since_last_clear % 60 == 0 || first_run {
117
-
let count = WIFI_COUNT.load(core::sync::atomic::Ordering::Relaxed);
118
-
let temp = TEMP.load(core::sync::atomic::Ordering::Relaxed);
119
-
let humidity = HUMIDITY.load(core::sync::atomic::Ordering::Relaxed);
120
-
let top_text: String<64> = easy_format::<64>(format_args!(
121
-
"{}F {}% Wifi found: {}",
122
-
temp, humidity, count
123
-
));
124
-
let top_bounds = Rectangle::new(Point::new(0, 0), Size::new(WIDTH, 24));
125
-
top_bounds
126
-
.into_styled(
127
-
PrimitiveStyleBuilder::default()
128
-
.stroke_color(BinaryColor::Off)
129
-
.fill_color(BinaryColor::On)
130
-
.stroke_width(1)
131
-
.build(),
132
-
)
133
-
.draw(&mut display)
134
-
.unwrap();
128
+
SCREEN_TO_SHOW.lock(|x| current_screen = *x.borrow());
129
+
info!("Current Screen: {:?}", current_screen);
130
+
if current_screen == Screen::Badge {
131
+
//Updates the top bar
132
+
//Runs every 60 cycles/30 seconds and first run
133
+
if cycles_since_last_clear % 60 == 0 || first_run {
134
+
let count = WIFI_COUNT.load(core::sync::atomic::Ordering::Relaxed);
135
+
let temp = TEMP.load(core::sync::atomic::Ordering::Relaxed);
136
+
let humidity = HUMIDITY.load(core::sync::atomic::Ordering::Relaxed);
137
+
let top_text: String<64> = easy_format::<64>(format_args!(
138
+
"{}F {}% Wifi found: {}",
139
+
temp, humidity, count
140
+
));
141
+
let top_bounds = Rectangle::new(Point::new(0, 0), Size::new(WIDTH, 24));
142
+
top_bounds
143
+
.into_styled(
144
+
PrimitiveStyleBuilder::default()
145
+
.stroke_color(BinaryColor::Off)
146
+
.fill_color(BinaryColor::On)
147
+
.stroke_width(1)
148
+
.build(),
149
+
)
150
+
.draw(&mut display)
151
+
.unwrap();
135
152
136
-
Text::new(top_text.as_str(), Point::new(8, 16), character_style)
137
-
.draw(&mut display)
138
-
.unwrap();
153
+
Text::new(top_text.as_str(), Point::new(8, 16), character_style)
154
+
.draw(&mut display)
155
+
.unwrap();
139
156
140
-
// Draw the text box.
141
-
let result = display.partial_update(top_bounds.try_into().unwrap()).await;
142
-
match result {
143
-
Ok(_) => {}
144
-
Err(_) => {
145
-
info!("Error updating display");
157
+
// Draw the text box.
158
+
let result = display.partial_update(top_bounds.try_into().unwrap()).await;
159
+
match result {
160
+
Ok(_) => {}
161
+
Err(_) => {
162
+
info!("Error updating display");
163
+
}
146
164
}
147
165
}
148
-
}
149
166
150
-
//Runs every 120 cycles/60 seconds and first run
151
-
if cycles_since_last_clear == 0 {
152
-
let mut time_text: String<8> = String::<8>::new();
167
+
//Runs every 120 cycles/60 seconds and first run
168
+
if cycles_since_last_clear == 0 || first_run {
169
+
let mut time_text: String<8> = String::<8>::new();
170
+
171
+
let time_box_rectangle_location = Point::new(0, 96);
172
+
RTC_TIME_STRING.lock(|x| {
173
+
time_text.push_str(x.borrow().as_str()).unwrap();
174
+
});
153
175
154
-
let time_box_rectangle_location = Point::new(0, 96);
155
-
RTC_TIME_STRING.lock(|x| {
156
-
time_text.push_str(x.borrow().as_str()).unwrap();
157
-
});
176
+
//The bounds of the box for time and refresh area
177
+
let time_bounds = Rectangle::new(time_box_rectangle_location, Size::new(88, 24));
178
+
time_bounds
179
+
.into_styled(
180
+
PrimitiveStyleBuilder::default()
181
+
.stroke_color(BinaryColor::Off)
182
+
.fill_color(BinaryColor::On)
183
+
.stroke_width(1)
184
+
.build(),
185
+
)
186
+
.draw(&mut display)
187
+
.unwrap();
158
188
159
-
//The bounds of the box for time and refresh area
160
-
let time_bounds = Rectangle::new(time_box_rectangle_location, Size::new(88, 24));
161
-
time_bounds
162
-
.into_styled(
163
-
PrimitiveStyleBuilder::default()
164
-
.stroke_color(BinaryColor::Off)
165
-
.fill_color(BinaryColor::On)
166
-
.stroke_width(1)
167
-
.build(),
189
+
//Adding a y offset to the box location to fit inside the box
190
+
Text::new(
191
+
time_text.as_str(),
192
+
(
193
+
time_box_rectangle_location.x + 8,
194
+
time_box_rectangle_location.y + 16,
195
+
)
196
+
.into(),
197
+
character_style,
168
198
)
169
199
.draw(&mut display)
170
200
.unwrap();
171
201
172
-
//Adding a y offset to the box location to fit inside the box
173
-
Text::new(
174
-
time_text.as_str(),
175
-
(
176
-
time_box_rectangle_location.x + 8,
177
-
time_box_rectangle_location.y + 16,
178
-
)
179
-
.into(),
180
-
character_style,
181
-
)
182
-
.draw(&mut display)
183
-
.unwrap();
184
-
185
-
let result = display
186
-
.partial_update(time_bounds.try_into().unwrap())
187
-
.await;
188
-
match result {
189
-
Ok(_) => {}
190
-
Err(_) => {
191
-
info!("Error updating display");
202
+
let result = display
203
+
.partial_update(time_bounds.try_into().unwrap())
204
+
.await;
205
+
match result {
206
+
Ok(_) => {}
207
+
Err(_) => {
208
+
info!("Error updating display");
209
+
}
192
210
}
193
211
}
194
-
}
195
212
196
-
//Manually triggered display events
213
+
//Manually triggered display events
197
214
198
-
if CHANGE_IMAGE.load(core::sync::atomic::Ordering::Relaxed) {
199
-
let current_image = get_current_image();
200
-
let tga: Bmp<BinaryColor> = Bmp::from_slice(¤t_image.image()).unwrap();
201
-
let image = Image::new(&tga, current_image.image_location());
202
-
//clear image location by writing a white rectangle over previous image location
203
-
let clear_rectangle = Rectangle::new(
204
-
current_image.previous().image_location(),
205
-
Size::new(157, 101),
206
-
);
207
-
clear_rectangle
208
-
.into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
209
-
.draw(&mut display)
210
-
.unwrap();
215
+
if CHANGE_IMAGE.load(core::sync::atomic::Ordering::Relaxed) || first_run {
216
+
let current_image = get_current_image();
217
+
let tga: Bmp<BinaryColor> = Bmp::from_slice(¤t_image.image()).unwrap();
218
+
let image = Image::new(&tga, current_image.image_location());
219
+
//clear image location by writing a white rectangle over previous image location
220
+
let clear_rectangle = Rectangle::new(
221
+
current_image.previous().image_location(),
222
+
Size::new(157, 101),
223
+
);
224
+
clear_rectangle
225
+
.into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
226
+
.draw(&mut display)
227
+
.unwrap();
211
228
212
-
let _ = image.draw(&mut display);
213
-
//TODO need to look up the reginal area display
214
-
let _ = display.update().await;
215
-
CHANGE_IMAGE.store(false, core::sync::atomic::Ordering::Relaxed);
229
+
let _ = image.draw(&mut display);
230
+
//TODO need to look up the reginal area display
231
+
let _ = display.update().await;
232
+
CHANGE_IMAGE.store(false, core::sync::atomic::Ordering::Relaxed);
233
+
}
234
+
} else {
235
+
if cycles_since_last_clear % 60 == 0 || first_run {
236
+
let top_bounds = Rectangle::new(Point::new(0, 0), Size::new(WIDTH, 24));
237
+
top_bounds
238
+
.into_styled(
239
+
PrimitiveStyleBuilder::default()
240
+
.stroke_color(BinaryColor::Off)
241
+
.fill_color(BinaryColor::On)
242
+
.stroke_width(1)
243
+
.build(),
244
+
)
245
+
.draw(&mut display)
246
+
.unwrap();
247
+
248
+
let top_text: String<64> = easy_format::<64>(format_args!(
249
+
"Wifi found: {}",
250
+
WIFI_COUNT.load(core::sync::atomic::Ordering::Relaxed)
251
+
));
252
+
253
+
Text::new(top_text.as_str(), Point::new(8, 16), character_style)
254
+
.draw(&mut display)
255
+
.unwrap();
256
+
257
+
let result = display.partial_update(top_bounds.try_into().unwrap()).await;
258
+
match result {
259
+
Ok(_) => {}
260
+
Err(_) => {
261
+
info!("Error updating display");
262
+
}
263
+
}
264
+
}
216
265
}
217
266
218
267
cycles_since_last_clear += 1;
+40
-5
src/main.rs
+40
-5
src/main.rs
···
5
5
#![no_std]
6
6
#![no_main]
7
7
use badge_display::display_image::DisplayImage;
8
-
use badge_display::{run_the_display, CHANGE_IMAGE, CURRENT_IMAGE, RTC_TIME_STRING, WIFI_COUNT};
8
+
use badge_display::{
9
+
run_the_display, Screen, CHANGE_IMAGE, CURRENT_IMAGE, DISPLAY_CHANGED, RTC_TIME_STRING,
10
+
SCREEN_TO_SHOW, WIFI_COUNT,
11
+
};
9
12
use core::fmt::Write;
10
13
use core::str::from_utf8;
11
14
use cyw43_driver::setup_cyw43;
···
81
84
let cs = Output::new(cs, Level::High);
82
85
let busy = Input::new(busy, Pull::Up);
83
86
84
-
let _btn_up = Input::new(p.PIN_15, Pull::Down);
85
-
let _btn_down = Input::new(p.PIN_11, Pull::Down);
86
-
let _btn_a = Input::new(p.PIN_12, Pull::Down);
87
+
let btn_up = Input::new(p.PIN_15, Pull::Down);
88
+
let btn_down = Input::new(p.PIN_11, Pull::Down);
89
+
let btn_a = Input::new(p.PIN_12, Pull::Down);
87
90
let btn_b = Input::new(p.PIN_13, Pull::Down);
88
91
let btn_c = Input::new(p.PIN_14, Pull::Down);
89
92
···
281
284
continue;
282
285
}
283
286
287
+
if btn_a.is_high() {
288
+
info!("Button A pressed");
289
+
user_led.toggle();
290
+
Timer::after(Duration::from_millis(500)).await;
291
+
current_cycle += 500;
292
+
continue;
293
+
}
294
+
295
+
if btn_down.is_high() {
296
+
info!("Button Down pressed");
297
+
SCREEN_TO_SHOW.lock(|screen| {
298
+
screen.replace(Screen::WifiList);
299
+
});
300
+
DISPLAY_CHANGED.store(true, core::sync::atomic::Ordering::Relaxed);
301
+
Timer::after(Duration::from_millis(500)).await;
302
+
current_cycle += 500;
303
+
continue;
304
+
}
305
+
306
+
if btn_up.is_high() {
307
+
info!("Button Up pressed");
308
+
SCREEN_TO_SHOW.lock(|screen| {
309
+
screen.replace(Screen::Badge);
310
+
});
311
+
DISPLAY_CHANGED.store(true, core::sync::atomic::Ordering::Relaxed);
312
+
Timer::after(Duration::from_millis(500)).await;
313
+
current_cycle += 500;
314
+
continue;
315
+
}
316
+
284
317
if btn_b.is_high() {
285
318
info!("Button B pressed");
286
-
user_led.toggle();
319
+
save.wifi_counted = 0;
320
+
save.bssid.clear();
321
+
WIFI_COUNT.store(0, core::sync::atomic::Ordering::Relaxed);
287
322
Timer::after(Duration::from_millis(500)).await;
288
323
current_cycle += 500;
289
324
continue;