1#![no_std]
2#![no_main]
3
4use rp2040_hal as hal;
5
6#[cfg(not(feature = "defmt"))]
7#[panic_handler]
8fn panic(_: &core::panic::PanicInfo) -> ! {
9 loop {}
10}
11
12#[cfg(feature = "defmt")]
13use {defmt_rtt as _, panic_probe as _};
14
15use embedded_alloc::LlffHeap as Heap;
16
17#[global_allocator]
18static ALLOCATOR: Heap = Heap::empty();
19
20#[link_section = ".boot2"]
21#[no_mangle]
22#[used]
23static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_GD25Q64CS;
24
25#[rtic::app(
26 device = hal::pac,
27 peripherals = true,
28 dispatchers = [I2C0_IRQ]
29)]
30mod app {
31 use crate::hal;
32 use crate::ALLOCATOR;
33
34 use core::fmt::Write;
35 use core::mem::MaybeUninit;
36 use core::ptr::addr_of_mut;
37
38 use hal::{
39 fugit::{ExtU64, RateExtU32},
40 gpio::{FunctionI2c, FunctionPio0, FunctionSio, FunctionSpi, FunctionUart},
41 gpio::{PinState, PullDown, PullUp, SioOutput},
42 i2c::I2C,
43 pio::PIOExt,
44 spi::Spi,
45 uart::{DataBits, StopBits, UartConfig, UartPeripheral},
46 Clock,
47 };
48
49 use embedded_hal::digital::OutputPin;
50 use embedded_hal::spi::MODE_3 as SPI_MODE_3;
51 use embedded_hal_0_2_x::blocking::spi::{Transfer as SpiTransfer, Write as SpiWrite};
52
53 use futures::FutureExt;
54
55 use rtic_monotonics::{rp2040::prelude::*, TimerQueueBasedMonotonic};
56 rp2040_timer_monotonic!(Mono);
57
58 use route_b_secrets::{ROUTE_B_ID, ROUTE_B_PASSWORD};
59
60 const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
61
62 type Uart0TxPin = hal::gpio::Pin<hal::gpio::bank0::Gpio0, FunctionUart, PullDown>;
63 type Uart0RxPin = hal::gpio::Pin<hal::gpio::bank0::Gpio1, FunctionUart, PullDown>;
64 type Uart0Pins = (Uart0TxPin, Uart0RxPin);
65
66 type Uart1TxPin = hal::gpio::Pin<hal::gpio::bank0::Gpio24, FunctionUart, PullDown>;
67 type Uart1RxPin = hal::gpio::Pin<hal::gpio::bank0::Gpio25, FunctionUart, PullDown>;
68 type Uart1Pins = (Uart1TxPin, Uart1RxPin);
69
70 type I2c1SdaPin = hal::gpio::Pin<hal::gpio::bank0::Gpio2, FunctionI2c, PullUp>;
71 type I2c1SclPin = hal::gpio::Pin<hal::gpio::bank0::Gpio3, FunctionI2c, PullUp>;
72 type I2c1Pins = (I2c1SdaPin, I2c1SclPin);
73
74 type Spi0TxPin = hal::gpio::Pin<hal::gpio::bank0::Gpio19, FunctionSpi, PullDown>;
75 type Spi0RxPin = hal::gpio::Pin<hal::gpio::bank0::Gpio20, FunctionSpi, PullDown>;
76 type Spi0SckPin = hal::gpio::Pin<hal::gpio::bank0::Gpio18, FunctionSpi, PullDown>;
77 type Spi0Pins = (Spi0TxPin, Spi0RxPin, Spi0SckPin);
78 type Spi0CsnAdt7310Pin =
79 hal::gpio::Pin<hal::gpio::bank0::Gpio6, FunctionSio<SioOutput>, PullDown>;
80
81 type Bp35c0J11ResetnPin =
82 hal::gpio::Pin<hal::gpio::bank0::Gpio11, FunctionSio<SioOutput>, PullDown>;
83
84 type Txs0108eOePin = hal::gpio::Pin<hal::gpio::bank0::Gpio10, FunctionSio<SioOutput>, PullDown>;
85
86 type LcdResetnPin = hal::gpio::Pin<hal::gpio::bank0::Gpio7, FunctionSio<SioOutput>, PullDown>;
87
88 type LedPin = hal::gpio::Pin<hal::gpio::bank0::Gpio13, FunctionSio<SioOutput>, PullDown>;
89
90 const UART1_RX_QUEUE_DEPTH: usize = 4;
91 type Uart1RxQueue = rtic_sync::channel::Channel<bp35c0_j11::Response, UART1_RX_QUEUE_DEPTH>;
92 type Uart1RxSender<'a> =
93 rtic_sync::channel::Sender<'a, bp35c0_j11::Response, UART1_RX_QUEUE_DEPTH>;
94 type Uart1RxReceiver<'a> =
95 rtic_sync::channel::Receiver<'a, bp35c0_j11::Response, UART1_RX_QUEUE_DEPTH>;
96
97 struct Bp35c0J11Writer<W: embedded_io::Write>(W);
98
99 impl<W: embedded_io::Write> Bp35c0J11Writer<W> {
100 fn send(&mut self, cmd: bp35c0_j11::Command) -> Result<(), W::Error> {
101 #[cfg(feature = "defmt")]
102 defmt::info!("Tx: {:?}", cmd);
103
104 let mut buf = [0; 128];
105 let len = bp35c0_j11::serialize_to_bytes(&cmd, &mut buf).unwrap();
106 self.0.write_all(&buf[..len])
107 }
108 }
109
110 struct NeoPixel<S: hal::pio::ValidStateMachine>(hal::pio::Tx<S>);
111
112 impl<S: hal::pio::ValidStateMachine> NeoPixel<S> {
113 fn set_rgb(&mut self, r: u8, g: u8, b: u8) -> bool {
114 self.0.write(u32::from_be_bytes([g, r, b, 0]))
115 }
116
117 fn set_raw(&mut self, grbx: u32) -> bool {
118 self.0.write(grbx)
119 }
120 }
121
122 #[derive(Clone, Copy)]
123 pub enum Bp35c0J11Status {
124 Initializing,
125 Scanning,
126 Ready,
127 Data {
128 datetime: (u16, u8, u8, u8, u8),
129 instant: u32,
130 rssi: i8,
131 },
132 Resetting,
133 }
134
135 #[shared]
136 struct Shared {
137 bp35c0_j11_status: Bp35c0J11Status,
138 temperature_raw: i16,
139 }
140
141 #[local]
142 struct Local {
143 uart0: UartPeripheral<hal::uart::Enabled, hal::pac::UART0, Uart0Pins>,
144 uart1_rx: hal::uart::Reader<hal::pac::UART1, Uart1Pins>,
145 uart1_rx_receiver: Uart1RxReceiver<'static>,
146 uart1_rx_sender: Uart1RxSender<'static>,
147 uart1_tx: Bp35c0J11Writer<hal::uart::Writer<hal::pac::UART1, Uart1Pins>>,
148 i2c1: I2C<hal::pac::I2C1, I2c1Pins>,
149 spi0: Spi<hal::spi::Enabled, hal::pac::SPI0, Spi0Pins>,
150 spi0_csn_adt7310: Spi0CsnAdt7310Pin,
151 bp35c0_j11_resetn: Bp35c0J11ResetnPin,
152 txs0108e_oe: Txs0108eOePin,
153 lcd_resetn: LcdResetnPin,
154 led: LedPin,
155 neopixel: NeoPixel<(hal::pac::PIO0, hal::pio::SM0)>,
156 bp35c0_j11_parser: bp35c0_j11::Parser,
157 }
158
159 #[init(
160 local = [
161 uart1_rx_queue: Uart1RxQueue = Uart1RxQueue::new(),
162 ]
163 )]
164 fn init(ctx: init::Context) -> (Shared, Local) {
165 {
166 const HEAP_SIZE: usize = 8 * 1024;
167 static mut HEAP: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
168 unsafe { ALLOCATOR.init(addr_of_mut!(HEAP) as usize, HEAP_SIZE) }
169 }
170
171 let mut resets = ctx.device.RESETS;
172 let mut watchdog = hal::watchdog::Watchdog::new(ctx.device.WATCHDOG);
173
174 let clocks = hal::clocks::init_clocks_and_plls(
175 XOSC_CRYSTAL_FREQ,
176 ctx.device.XOSC,
177 ctx.device.CLOCKS,
178 ctx.device.PLL_SYS,
179 ctx.device.PLL_USB,
180 &mut resets,
181 &mut watchdog,
182 )
183 .unwrap();
184
185 let sio = hal::Sio::new(ctx.device.SIO);
186 let pins = hal::gpio::Pins::new(
187 ctx.device.IO_BANK0,
188 ctx.device.PADS_BANK0,
189 sio.gpio_bank0,
190 &mut resets,
191 );
192
193 let pins_uart = (pins.gpio0.into_function(), pins.gpio1.into_function());
194 let uart0 = UartPeripheral::new(ctx.device.UART0, pins_uart, &mut resets)
195 .enable(
196 UartConfig::new(115_200.Hz(), DataBits::Eight, None, StopBits::One),
197 clocks.peripheral_clock.freq(),
198 )
199 .unwrap();
200
201 let pins_uart = (pins.gpio24.into_function(), pins.gpio25.into_function());
202 let mut uart1 = UartPeripheral::new(ctx.device.UART1, pins_uart, &mut resets)
203 .enable(
204 UartConfig::new(115_200.Hz(), DataBits::Eight, None, StopBits::One),
205 clocks.peripheral_clock.freq(),
206 )
207 .unwrap();
208 uart1.enable_rx_interrupt();
209
210 let i2c1 = I2C::i2c1(
211 ctx.device.I2C1,
212 pins.gpio2.reconfigure(),
213 pins.gpio3.reconfigure(),
214 400.kHz(),
215 &mut resets,
216 &clocks.system_clock,
217 );
218
219 let pins_spi = (
220 pins.gpio19.into_function(),
221 pins.gpio20.into_function(),
222 pins.gpio18.into_function(),
223 );
224 let spi0 = Spi::<_, _, _, 8>::new(ctx.device.SPI0, pins_spi).init(
225 &mut resets,
226 clocks.peripheral_clock.freq(),
227 5.MHz(),
228 SPI_MODE_3,
229 );
230
231 let neopixel: hal::gpio::Pin<_, FunctionPio0, _> = pins.gpio16.into_function();
251 let neopixel_pin_id = neopixel.id().num;
252 let program = pio_proc::pio_asm!(
253 ".side_set 1",
254 "loop:",
255 " out x, 1 side 0", " jmp !x skip side 1 [2]", " nop side 1 [3]", "skip:", " jmp loop side 0 [5]", );
261 let (mut pio, sm0, _, _, _) = ctx.device.PIO0.split(&mut resets);
262 let installed = pio.install(&program.program).unwrap();
263 let (mut sm, _, tx) = hal::pio::PIOBuilder::from_installed_program(installed)
264 .clock_divisor_fixed_point(12, 128)
265 .autopull(true)
266 .pull_threshold(24)
267 .out_shift_direction(hal::pio::ShiftDirection::Left)
268 .side_set_pin_base(neopixel_pin_id)
269 .build(sm0);
270 sm.set_pindirs([(neopixel_pin_id, hal::pio::PinDir::Output)]);
271 sm.start();
272
273 let spi0_csn_adt7310 = pins.gpio6.into_push_pull_output_in_state(PinState::High);
274 let bp35c0_j11_resetn = pins.gpio11.into_push_pull_output_in_state(PinState::Low);
275 let txs0108e_oe = pins.gpio10.into_push_pull_output_in_state(PinState::Low);
276 let lcd_resetn = pins.gpio7.into_push_pull_output_in_state(PinState::Low);
277 let led = pins.gpio13.into_push_pull_output_in_state(PinState::Low);
278
279 let (uart1_rx, uart1_tx) = uart1.split();
280 let (uart1_rx_sender, uart1_rx_receiver) = ctx.local.uart1_rx_queue.split();
281
282 Mono::start(ctx.device.TIMER, &resets);
283
284 task_adt7310::spawn().unwrap();
285 task_bp35c0_j11::spawn().unwrap();
286 task_lcd::spawn().unwrap();
287 task_led_blink::spawn().unwrap();
288 task_neopixel::spawn().unwrap();
289
290 (
291 Shared {
292 bp35c0_j11_status: Bp35c0J11Status::Initializing,
293 temperature_raw: 0,
294 },
295 Local {
296 uart0,
297 uart1_rx,
298 uart1_rx_receiver,
299 uart1_rx_sender,
300 uart1_tx: Bp35c0J11Writer(uart1_tx),
301 i2c1,
302 spi0,
303 spi0_csn_adt7310,
304 bp35c0_j11_resetn,
305 txs0108e_oe,
306 lcd_resetn,
307 led,
308 neopixel: NeoPixel(tx),
309 bp35c0_j11_parser: bp35c0_j11::Parser::default(),
310 },
311 )
312 }
313
314 #[task(priority = 1, local = [led])]
315 async fn task_led_blink(ctx: task_led_blink::Context) {
316 loop {
317 let now = Mono::now();
318
319 ctx.local.led.set_high().unwrap();
320 Mono::delay(100.millis()).await;
321 ctx.local.led.set_low().unwrap();
322
323 Mono::delay(200.millis()).await;
324
325 ctx.local.led.set_high().unwrap();
326 Mono::delay(100.millis()).await;
327 ctx.local.led.set_low().unwrap();
328
329 Mono::delay_until(now + 1_500.millis()).await;
330 }
331 }
332
333 #[task(
334 priority = 1,
335 shared = [bp35c0_j11_status],
336 local = [neopixel]
337 )]
338 async fn task_neopixel(ctx: task_neopixel::Context) {
339 static TABLE: [u32; 256] = [
341 0x00_00_05_00,
342 0x00_00_05_00,
343 0x00_00_05_00,
344 0x00_00_05_00,
345 0x00_00_05_00,
346 0x00_00_05_00,
347 0x00_00_05_00,
348 0x00_00_05_00,
349 0x00_00_05_00,
350 0x00_00_05_00,
351 0x00_00_05_00,
352 0x00_00_05_00,
353 0x00_00_05_00,
354 0x01_00_05_00,
355 0x01_00_05_00,
356 0x01_00_05_00,
357 0x01_00_05_00,
358 0x01_00_05_00,
359 0x01_00_05_00,
360 0x01_00_05_00,
361 0x01_00_05_00,
362 0x01_00_05_00,
363 0x01_00_05_00,
364 0x01_00_05_00,
365 0x01_00_05_00,
366 0x02_00_05_00,
367 0x02_00_05_00,
368 0x02_00_05_00,
369 0x02_00_05_00,
370 0x02_00_05_00,
371 0x02_00_05_00,
372 0x02_00_05_00,
373 0x02_00_05_00,
374 0x02_00_05_00,
375 0x02_00_05_00,
376 0x02_00_05_00,
377 0x02_00_05_00,
378 0x02_00_05_00,
379 0x03_00_05_00,
380 0x03_00_05_00,
381 0x03_00_05_00,
382 0x03_00_05_00,
383 0x03_00_05_00,
384 0x03_00_05_00,
385 0x03_00_05_00,
386 0x03_00_05_00,
387 0x03_00_05_00,
388 0x03_00_05_00,
389 0x03_00_05_00,
390 0x03_00_05_00,
391 0x04_00_05_00,
392 0x04_00_05_00,
393 0x04_00_05_00,
394 0x04_00_05_00,
395 0x04_00_05_00,
396 0x04_00_05_00,
397 0x04_00_05_00,
398 0x04_00_05_00,
399 0x04_00_05_00,
400 0x04_00_05_00,
401 0x04_00_05_00,
402 0x04_00_05_00,
403 0x04_00_05_00,
404 0x05_00_05_00,
405 0x05_00_05_00,
406 0x05_00_05_00,
407 0x05_00_04_00,
408 0x05_00_04_00,
409 0x05_00_04_00,
410 0x05_00_04_00,
411 0x05_00_04_00,
412 0x05_00_04_00,
413 0x05_00_04_00,
414 0x05_00_04_00,
415 0x05_00_04_00,
416 0x05_00_04_00,
417 0x05_00_04_00,
418 0x05_00_04_00,
419 0x05_00_03_00,
420 0x05_00_03_00,
421 0x05_00_03_00,
422 0x05_00_03_00,
423 0x05_00_03_00,
424 0x05_00_03_00,
425 0x05_00_03_00,
426 0x05_00_03_00,
427 0x05_00_03_00,
428 0x05_00_03_00,
429 0x05_00_03_00,
430 0x05_00_03_00,
431 0x05_00_03_00,
432 0x05_00_02_00,
433 0x05_00_02_00,
434 0x05_00_02_00,
435 0x05_00_02_00,
436 0x05_00_02_00,
437 0x05_00_02_00,
438 0x05_00_02_00,
439 0x05_00_02_00,
440 0x05_00_02_00,
441 0x05_00_02_00,
442 0x05_00_02_00,
443 0x05_00_02_00,
444 0x05_00_01_00,
445 0x05_00_01_00,
446 0x05_00_01_00,
447 0x05_00_01_00,
448 0x05_00_01_00,
449 0x05_00_01_00,
450 0x05_00_01_00,
451 0x05_00_01_00,
452 0x05_00_01_00,
453 0x05_00_01_00,
454 0x05_00_01_00,
455 0x05_00_01_00,
456 0x05_00_01_00,
457 0x05_00_00_00,
458 0x05_00_00_00,
459 0x05_00_00_00,
460 0x05_00_00_00,
461 0x05_00_00_00,
462 0x05_00_00_00,
463 0x05_00_00_00,
464 0x05_00_00_00,
465 0x05_00_00_00,
466 0x05_00_00_00,
467 0x05_00_00_00,
468 0x05_00_00_00,
469 0x05_00_00_00,
470 0x05_00_00_00,
471 0x05_00_00_00,
472 0x05_00_00_00,
473 0x05_00_00_00,
474 0x05_00_00_00,
475 0x05_00_00_00,
476 0x05_00_00_00,
477 0x05_00_00_00,
478 0x05_00_00_00,
479 0x05_00_00_00,
480 0x05_00_00_00,
481 0x05_01_00_00,
482 0x05_01_00_00,
483 0x05_01_00_00,
484 0x05_01_00_00,
485 0x05_01_00_00,
486 0x05_01_00_00,
487 0x05_01_00_00,
488 0x05_01_00_00,
489 0x05_01_00_00,
490 0x05_01_00_00,
491 0x05_01_00_00,
492 0x05_01_00_00,
493 0x05_01_00_00,
494 0x05_02_00_00,
495 0x05_02_00_00,
496 0x05_02_00_00,
497 0x05_02_00_00,
498 0x05_02_00_00,
499 0x05_02_00_00,
500 0x05_02_00_00,
501 0x05_02_00_00,
502 0x05_02_00_00,
503 0x05_02_00_00,
504 0x05_02_00_00,
505 0x05_02_00_00,
506 0x05_03_00_00,
507 0x05_03_00_00,
508 0x05_03_00_00,
509 0x05_03_00_00,
510 0x05_03_00_00,
511 0x05_03_00_00,
512 0x05_03_00_00,
513 0x05_03_00_00,
514 0x05_03_00_00,
515 0x05_03_00_00,
516 0x05_03_00_00,
517 0x05_03_00_00,
518 0x05_04_00_00,
519 0x05_04_00_00,
520 0x05_04_00_00,
521 0x05_04_00_00,
522 0x05_04_00_00,
523 0x05_04_00_00,
524 0x05_04_00_00,
525 0x05_04_00_00,
526 0x05_04_00_00,
527 0x05_04_00_00,
528 0x05_05_00_00,
529 0x05_05_00_00,
530 0x05_05_00_00,
531 0x05_05_00_00,
532 0x05_05_00_00,
533 0x05_05_00_00,
534 0x05_05_00_00,
535 0x05_05_00_00,
536 0x05_05_00_00,
537 0x05_05_00_00,
538 0x05_05_00_00,
539 0x05_06_00_00,
540 0x05_06_00_00,
541 0x05_06_00_00,
542 0x05_06_00_00,
543 0x05_06_00_00,
544 0x05_06_00_00,
545 0x05_06_00_00,
546 0x05_06_00_00,
547 0x05_07_00_00,
548 0x05_07_00_00,
549 0x05_07_00_00,
550 0x05_07_00_00,
551 0x05_07_00_00,
552 0x05_08_00_00,
553 0x05_08_00_00,
554 0x05_09_00_00,
555 0x06_09_00_00,
556 0x06_09_00_00,
557 0x06_0a_00_00,
558 0x06_0b_00_00,
559 0x06_0b_00_00,
560 0x07_0c_00_00,
561 0x07_0d_00_00,
562 0x07_0e_00_00,
563 0x08_0f_00_00,
564 0x08_10_00_00,
565 0x08_12_00_00,
566 0x09_13_00_00,
567 0x09_15_00_00,
568 0x0a_17_00_00,
569 0x0b_1a_00_00,
570 0x0b_1c_00_00,
571 0x0c_20_00_00,
572 0x0d_23_00_00,
573 0x0e_27_00_00,
574 0x0f_2c_00_00,
575 0x10_32_00_00,
576 0x11_38_00_00,
577 0x13_3f_00_00,
578 0x14_48_00_00,
579 0x15_52_00_00,
580 0x17_5e_00_00,
581 0x19_6b_00_00,
582 0x1b_7b_00_00,
583 0x1d_8e_00_00,
584 0x1e_a4_00_00,
585 0x20_be_00_00,
586 0x22_dc_00_00,
587 0x23_ff_00_00,
588 0x20_ff_00_00,
589 0x1c_ff_00_00,
590 0x18_ff_00_00,
591 0x13_ff_00_00,
592 0x10_ff_00_00,
593 0x0c_ff_00_00,
594 0x08_ff_00_00,
595 0x03_ff_00_00,
596 0x00_ff_00_00,
597 ];
598
599 let mut bp35c0_j11_status = ctx.shared.bp35c0_j11_status;
600
601 loop {
602 if let Bp35c0J11Status::Data { instant, .. } = bp35c0_j11_status.lock(|status| *status)
603 {
604 let i = ((instant as usize * (TABLE.len() - 1)) / 2500).min(TABLE.len() - 1);
606 ctx.local.neopixel.set_raw(TABLE[i]);
607 } else {
608 ctx.local.neopixel.set_rgb(0, 0, 0);
609 }
610 Mono::delay(1.secs()).await;
611 }
612 }
613
614 #[task(
615 priority = 1,
616 shared = [bp35c0_j11_status],
617 local = [bp35c0_j11_resetn, txs0108e_oe, uart1_rx_receiver, uart1_tx]
618 )]
619 async fn task_bp35c0_j11(ctx: task_bp35c0_j11::Context) {
620 use bp35c0_j11::*;
621
622 ctx.local.txs0108e_oe.set_high().unwrap();
623 Mono::delay(500.millis()).await;
624
625 let mut status = ctx.shared.bp35c0_j11_status;
626 let rx = ctx.local.uart1_rx_receiver;
627 let tx = ctx.local.uart1_tx;
628
629 loop {
630 ctx.local.bp35c0_j11_resetn.set_high().unwrap();
631 Mono::delay(500.millis()).await;
632
633 'retry: loop {
634 if let Ok(Response::NotificationPoweredOn) = rx.recv().await {
635 break 'retry;
636 }
637 }
638
639 'retry: loop {
640 tx.send(Command::GetVersionInformation).unwrap();
641
642 while let Ok(resp) = rx.recv().await {
643 if let Response::GetVersionInformation { result, .. } = resp {
644 if result == 0x01 {
645 break 'retry;
646 } else {
647 Mono::delay(1.secs()).await;
648 continue 'retry;
649 }
650 }
651 }
652 }
653
654 'retry: loop {
655 tx.send(Command::SetOperationMode {
656 mode: OperationMode::Dual,
657 han_sleep: false,
658 channel: Channel::Ch4F922p5MHz,
659 tx_power: TxPower::P20mW,
660 })
661 .unwrap();
662
663 while let Ok(resp) = rx.recv().await {
664 if let Response::SetOperationMode { result, .. } = resp {
665 if result == 0x01 {
666 break 'retry;
667 } else {
668 Mono::delay(1.secs()).await;
669 continue 'retry;
670 }
671 }
672 }
673 }
674
675 let channel = 'retry: loop {
676 tx.send(Command::DoActiveScan {
677 duration: ScanDuration::T616p96ms,
678 mask_channels: 0x3fff0,
679 pairing_id: Some(u64::from_be_bytes(ROUTE_B_ID[24..32].try_into().unwrap())),
680 })
681 .unwrap();
682
683 status.lock(|status| *status = Bp35c0J11Status::Scanning);
684
685 let mut scan_result = None;
686 while let Ok(resp) = rx.recv().await {
687 match resp {
688 Response::DoActiveScan { result } => match (result, scan_result.take()) {
689 (0x01, Some(channel)) => break 'retry channel,
690 _ => {
691 Mono::delay(1.secs()).await;
692 continue 'retry;
693 }
694 },
695 Response::NotificationActiveScan { channel, terminal } => {
696 if !terminal.is_empty() {
697 scan_result.replace(channel);
698 }
699 }
700 _ => {}
701 }
702 }
703 };
704
705 #[cfg(feature = "defmt")]
706 defmt::info!("channel = {}", channel);
707
708 'retry: loop {
709 tx.send(Command::SetOperationMode {
710 mode: OperationMode::Dual,
711 han_sleep: false,
712 channel,
713 tx_power: TxPower::P20mW,
714 })
715 .unwrap();
716
717 while let Ok(resp) = rx.recv().await {
718 if let Response::SetOperationMode { result, .. } = resp {
719 if result == 0x01 {
720 break 'retry;
721 } else {
722 Mono::delay(1.secs()).await;
723 continue 'retry;
724 }
725 }
726 }
727 }
728
729 'retry: loop {
730 tx.send(Command::SetRouteBPanaAuthenticationInformation {
731 id: ROUTE_B_ID,
732 password: ROUTE_B_PASSWORD,
733 })
734 .unwrap();
735
736 while let Ok(resp) = rx.recv().await {
737 if let Response::SetRouteBPanaAuthenticationInformation { result, .. } = resp {
738 if result == 0x01 {
739 break 'retry;
740 } else {
741 Mono::delay(1.secs()).await;
742 continue 'retry;
743 }
744 }
745 }
746 }
747
748 'retry: loop {
749 tx.send(Command::StartRouteBOperation).unwrap();
750
751 while let Ok(resp) = rx.recv().await {
752 if let Response::StartRouteBOperation { result, .. } = resp {
753 if result == 0x01 {
754 break 'retry;
755 } else {
756 Mono::delay(1.secs()).await;
757 continue 'retry;
758 }
759 }
760 }
761 }
762
763 'retry: loop {
764 tx.send(Command::OpenUdpPort(0x0e1a)).unwrap();
765
766 while let Ok(resp) = rx.recv().await {
767 if let Response::OpenUdpPort { result, .. } = resp {
768 if result == 0x01 {
769 break 'retry;
770 } else {
771 Mono::delay(1.secs()).await;
772 continue 'retry;
773 }
774 }
775 }
776 }
777
778 let mac_address = 'retry: loop {
779 tx.send(Command::StartRouteBPana).unwrap();
780
781 'wait: while let Ok(resp) = rx.recv().await {
782 match resp {
783 Response::StartRouteBPana { result, .. } if result != 0x01 => break 'wait,
784 Response::NotificationPanaAuthentication {
785 result,
786 mac_address,
787 } => {
788 if result == 0x01 {
789 break 'retry mac_address;
790 } else {
791 break 'wait;
792 }
793 }
794 _ => {}
795 }
796 }
797
798 Mono::delay(1.secs()).await;
799 };
800
801 #[cfg(feature = "defmt")]
802 defmt::info!("mac_address = {}", mac_address);
803
804 status.lock(|status| *status = Bp35c0J11Status::Ready);
805
806 let destination_address = 0xfe800000000000000000000000000000_u128
807 | (mac_address ^ 0x02000000_00000000) as u128;
808
809 let mut last_data = Mono::now();
810
811 'outer: for tid in 0.. {
812 if Mono::now() >= last_data + 60.secs() {
813 break 'outer;
814 }
815
816 let tid_be = ((tid & 0xffff) as u16).to_be_bytes();
817
818 'retry: loop {
819 tx.send(Command::TransmitData {
820 destination_address,
821 source_port: 0x0e1a,
822 destination_port: 0x0e1a,
823 data: &[
824 0x10, 0x81, tid_be[0], tid_be[1], 0x05, 0xff, 0x01, 0x02, 0x88, 0x01, 0x62, 0x04, 0x97, 0x00, 0x98, 0x00, 0xd3, 0x00, 0xe7, 0x00, ],
840 })
841 .unwrap();
842
843 while let Ok(resp) = rx.recv().await {
844 if let Response::TransmitData { result, .. } = resp {
845 if result == 0x01 {
846 break 'retry;
847 } else {
848 Mono::delay(1.secs()).await;
849 continue 'outer;
850 }
851 }
852 }
853 }
854
855 let now = Mono::now();
856
857 let data_expected = [
858 0x10, 0x81, tid_be[0], tid_be[1], 0x02, 0x88, 0x01, 0x05, 0xff, 0x01, 0x72, 0x04, ];
866
867 'wait: loop {
874 let resp = futures::select_biased! {
875 r = rx.recv().fuse() => r.ok(),
876 _ = Mono::delay_until(now + 10.secs()).fuse() => None,
877 };
878
879 match resp {
880 Some(Response::NotificationUdpReceived {
881 source_port: 0x0e1a,
882 destination_port: 0x0e1a,
883 source_type: 0x00,
884 data,
885 rssi,
886 ..
887 }) if data.starts_with(&data_expected) && data.len() == 34 => {
888 status.lock(|status| {
890 *status = Bp35c0J11Status::Data {
891 datetime: (
892 u16::from_be_bytes([data[18], data[19]]), data[20], data[21], data[14], data[15], ),
898 instant: u32::from_be_bytes([
899 data[30], data[31], data[32], data[33],
900 ]),
901 rssi,
902 }
903 });
904 last_data = Mono::now();
905 break 'wait;
906 }
907
908 Some(_) => {}
909
910 None => {
911 #[cfg(feature = "defmt")]
912 defmt::warn!("timeout");
913 break 'wait;
914 }
915 }
916 }
917
918 Mono::delay_until(now + 10.secs()).await;
919 }
920
921 #[cfg(feature = "defmt")]
922 defmt::warn!("reset");
923
924 status.lock(|status| {
925 *status = Bp35c0J11Status::Resetting;
926 });
927
928 ctx.local.bp35c0_j11_resetn.set_low().unwrap();
930 Mono::delay(500.millis()).await;
931 }
932 }
933
934 #[task(
935 priority = 1,
936 shared = [temperature_raw],
937 local = [spi0, spi0_csn_adt7310]
938 )]
939 async fn task_adt7310(ctx: task_adt7310::Context) {
940 let spi = ctx.local.spi0;
941 let spi_csn = ctx.local.spi0_csn_adt7310;
942
943 {
944 spi_csn.set_low().unwrap();
945 spi.write(&[0xff_u8; 4]).unwrap();
946 spi_csn.set_high().unwrap();
947 Mono::delay(1.millis()).await;
948 }
949
950 let mut temperature_raw = ctx.shared.temperature_raw;
951
952 loop {
953 let now = Mono::now();
954
955 spi_csn.set_low().unwrap();
956
957 #[allow(clippy::unusual_byte_groupings)]
958 spi.write(&[0b0_0_001_0_00, 0b1_01_0_0_0_00]).unwrap();
962
963 Mono::delay(240.millis()).await;
964
965 #[allow(clippy::unusual_byte_groupings)]
966 let mut buf = [0b0_1_010_0_00, 0, 0];
968
969 spi.transfer(buf.as_mut_slice()).unwrap();
970
971 spi_csn.set_high().unwrap();
972
973 temperature_raw.lock(|temp| *temp = i16::from_be_bytes([buf[1], buf[2]]));
974
975 Mono::delay_until(now + 1.secs()).await;
976 }
977 }
978
979 #[task(
980 priority = 1,
981 shared = [bp35c0_j11_status, temperature_raw],
982 local = [i2c1, lcd_resetn, uart0]
983 )]
984 async fn task_lcd(ctx: task_lcd::Context) {
985 const LCD_ADDRESS: u8 = 0x3e;
986
987 ctx.local.lcd_resetn.set_high().unwrap();
988 Mono::delay(50.millis()).await;
989
990 type Duration = <Mono as TimerQueueBasedMonotonic>::Duration;
991
992 let i2c = ctx.local.i2c1;
993 let lcd = st7032i::St7032i::<_, _, _, Duration>::new(i2c, LCD_ADDRESS);
994
995 let (lcd, delay) = lcd.set_instruction_set::<st7032i::Normal>().unwrap();
996 Mono::delay(delay).await;
997
998 let (mut lcd, delay) = lcd.set_instruction_set::<st7032i::Extention>().unwrap();
999 Mono::delay(delay).await;
1000
1001 let delay = lcd.cmd_internal_osc_frequency().unwrap();
1002 Mono::delay(delay).await;
1003
1004 let delay = lcd.cmd_contrast_set(0b1100).unwrap();
1005 Mono::delay(delay).await;
1006
1007 let delay = lcd.cmd_power_icon_contrast_set(false, true, 0b01).unwrap();
1008 Mono::delay(delay).await;
1009
1010 let delay = lcd.cmd_follower_control(true, 0b100).unwrap();
1011 Mono::delay(delay).await;
1012
1013 let (mut lcd, delay) = lcd.set_instruction_set::<st7032i::Normal>().unwrap();
1014 Mono::delay(delay).await;
1015
1016 let delay = lcd.cmd_display_on_off(true, false, false).unwrap();
1017 Mono::delay(delay).await;
1018
1019 let delay = lcd.cmd_set_cgram_address(0).unwrap();
1020 Mono::delay(delay).await;
1021
1022 let delay = lcd
1023 .cmd_write_bytes([
1024 0b000_00000,
1026 0b000_00100,
1027 0b000_00100,
1028 0b000_00100,
1029 0b000_00100,
1030 0b000_00100,
1031 0b000_00000,
1032 0b000_00000,
1033 0b000_00000,
1035 0b000_00000,
1036 0b000_00000,
1037 0b000_00000,
1038 0b000_00000,
1039 0b000_10001,
1040 0b000_01110,
1041 0b000_00000,
1042 ])
1043 .unwrap();
1044 Mono::delay(delay).await;
1045
1046 let delay = lcd.cmd_clear_display().unwrap();
1047 Mono::delay(delay).await;
1048
1049 {
1051 write!(lcd, " Hello!").unwrap();
1052 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1053
1054 let delay = lcd
1055 .cmd_set_ddram_address(st7032i::DDRAM_ADDRESS_LINE2)
1056 .unwrap();
1057 Mono::delay(delay).await;
1058
1059 let _ = lcd
1060 .cmd_write_chars([
1061 '('.into(),
1062 '*'.into(),
1063 st7032i::Character::Cgram(0),
1064 st7032i::Character::Cgram(1),
1065 st7032i::Character::Cgram(0),
1066 ')'.into(),
1067 'ノ'.into(),
1068 ])
1069 .unwrap();
1070 Mono::delay(3.secs()).await;
1071 }
1072
1073 let mut bp35c0_j11_status = ctx.shared.bp35c0_j11_status;
1074 let mut temperature_raw = ctx.shared.temperature_raw;
1075
1076 #[derive(Clone, Copy)]
1077 enum DisplayItemBp35c0J11 {
1078 Datetime,
1079 Instant,
1080 Rssi,
1081 }
1082
1083 #[derive(Clone, Copy)]
1084 enum DisplayItem {
1085 Bp35c0J11(DisplayItemBp35c0J11),
1086 Temperature,
1087 }
1088
1089 let mut next = DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Datetime);
1090
1091 loop {
1092 let delay = lcd.cmd_clear_display().unwrap();
1093 Mono::delay(delay).await;
1094
1095 let now = Mono::now();
1096
1097 let linebreak = |lcd: &mut st7032i::St7032i<_, _, _, Duration>| {
1098 let delay = lcd
1099 .cmd_set_ddram_address(st7032i::DDRAM_ADDRESS_LINE2)
1100 .unwrap();
1101 Mono::delay(delay)
1102 };
1103
1104 next = match next {
1105 DisplayItem::Bp35c0J11(i) => match (bp35c0_j11_status.lock(|s| *s), i) {
1106 (Bp35c0J11Status::Resetting, _) => {
1107 write!(lcd, "BP35C0:").unwrap();
1108 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1109
1110 linebreak(&mut lcd).await;
1111
1112 write!(lcd, "Reset...").unwrap();
1113 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1114
1115 DisplayItem::Temperature
1116 }
1117
1118 (Bp35c0J11Status::Initializing, _) => {
1119 write!(lcd, "BP35C0:").unwrap();
1120 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1121
1122 linebreak(&mut lcd).await;
1123
1124 write!(lcd, " Init...").unwrap();
1125 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1126
1127 DisplayItem::Temperature
1128 }
1129
1130 (Bp35c0J11Status::Scanning, _) => {
1131 write!(lcd, "BP35C0:").unwrap();
1132 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1133
1134 linebreak(&mut lcd).await;
1135
1136 write!(lcd, " Scan...").unwrap();
1137 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1138
1139 DisplayItem::Temperature
1140 }
1141
1142 (Bp35c0J11Status::Ready, _) => {
1143 write!(lcd, "BP35C0:").unwrap();
1144 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1145
1146 linebreak(&mut lcd).await;
1147
1148 write!(lcd, " Ready!").unwrap();
1149 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1150
1151 DisplayItem::Temperature
1152 }
1153
1154 (Bp35c0J11Status::Data { datetime, .. }, DisplayItemBp35c0J11::Datetime) => {
1155 let (year, month, day, hour, min) = datetime;
1156
1157 write!(lcd, "{:02}-{:02}-{:02}", year % 100, month, day).unwrap();
1158 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1159
1160 linebreak(&mut lcd).await;
1161
1162 write!(lcd, " {hour:02}:{min:02}").unwrap();
1163 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1164
1165 DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Instant)
1166 }
1167
1168 (Bp35c0J11Status::Data { instant, .. }, DisplayItemBp35c0J11::Instant) => {
1169 write!(lcd, "Instant:").unwrap();
1170 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1171
1172 linebreak(&mut lcd).await;
1173
1174 write!(lcd, "{instant:>6} W").unwrap();
1175 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1176
1177 DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Rssi)
1178 }
1179
1180 (Bp35c0J11Status::Data { rssi, .. }, DisplayItemBp35c0J11::Rssi) => {
1181 write!(lcd, "RSSI:").unwrap();
1182 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1183
1184 linebreak(&mut lcd).await;
1185
1186 write!(lcd, " {rssi:>3} dBm").unwrap();
1187 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1188
1189 DisplayItem::Temperature
1190 }
1191 },
1192
1193 DisplayItem::Temperature => {
1194 let temp_raw = temperature_raw.lock(|temp| *temp);
1195 let temp_int = temp_raw / 128;
1196 let temp_frac = 78125_u32 * (temp_raw % 128).unsigned_abs() as u32;
1197
1198 write!(lcd, "Temp:").unwrap();
1199 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1200
1201 linebreak(&mut lcd).await;
1202
1203 write!(lcd, "{:3}.{:04}", temp_int, temp_frac / 1000).unwrap();
1204 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1205
1206 DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Datetime)
1207 }
1208 };
1209
1210 Mono::delay_until(now + 3.secs()).await;
1211 }
1212 }
1213
1214 #[task(
1215 priority = 1,
1216 binds = UART1_IRQ,
1217 local = [uart1_rx, uart1_rx_sender, bp35c0_j11_parser]
1218 )]
1219 fn uart1_irq(ctx: uart1_irq::Context) {
1220 let uart = ctx.local.uart1_rx;
1221 let parser = ctx.local.bp35c0_j11_parser;
1222 let sender = ctx.local.uart1_rx_sender;
1223 let mut rx_buf = [0; 32];
1224 if let Ok(len) = uart.read_raw(&mut rx_buf) {
1225 for resp in rx_buf[0..len].iter().flat_map(|&c| parser.parse(c)) {
1226 #[cfg(feature = "defmt")]
1227 defmt::info!("Rx: {:?}", resp);
1228 sender.try_send(resp).unwrap();
1229 }
1230 }
1231 }
1232}