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: i32,
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::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_01_00,
342 0x00_00_01_00,
343 0x00_00_02_00,
344 0x00_00_02_00,
345 0x00_00_02_00,
346 0x00_00_03_00,
347 0x00_00_03_00,
348 0x00_00_03_00,
349 0x00_00_04_00,
350 0x00_00_04_00,
351 0x00_00_04_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 match bp35c0_j11_status.lock(|status| *status) {
603 Bp35c0J11Status::Data { instant, .. } if instant.is_negative() => {
605 ctx.local.neopixel.set_rgb(1, 0, 2);
606 }
607 Bp35c0J11Status::Data { instant, .. } => {
609 let i = ((instant as usize * (TABLE.len() - 1)) / 2500).min(TABLE.len() - 1);
610 ctx.local.neopixel.set_raw(TABLE[i]);
611 }
612 _ => {
613 ctx.local.neopixel.set_rgb(0, 0, 0);
614 }
615 }
616 Mono::delay(1.secs()).await;
617 }
618 }
619
620 #[task(
621 priority = 1,
622 shared = [bp35c0_j11_status],
623 local = [bp35c0_j11_resetn, txs0108e_oe, uart1_rx_receiver, uart1_tx]
624 )]
625 async fn task_bp35c0_j11(ctx: task_bp35c0_j11::Context) {
626 use bp35c0_j11::*;
627
628 ctx.local.txs0108e_oe.set_high().unwrap();
629 Mono::delay(500.millis()).await;
630
631 let mut status = ctx.shared.bp35c0_j11_status;
632 let rx = ctx.local.uart1_rx_receiver;
633 let tx = ctx.local.uart1_tx;
634
635 loop {
636 ctx.local.bp35c0_j11_resetn.set_high().unwrap();
637 Mono::delay(500.millis()).await;
638
639 'retry: loop {
640 if let Ok(Response::NotificationPoweredOn) = rx.recv().await {
641 break 'retry;
642 }
643 }
644
645 'retry: loop {
646 tx.send(Command::GetVersionInformation).unwrap();
647
648 while let Ok(resp) = rx.recv().await {
649 if let Response::GetVersionInformation { result, .. } = resp {
650 if result == 0x01 {
651 break 'retry;
652 } else {
653 Mono::delay(1.secs()).await;
654 continue 'retry;
655 }
656 }
657 }
658 }
659
660 'retry: loop {
661 tx.send(Command::SetOperationMode {
662 mode: OperationMode::Dual,
663 han_sleep: false,
664 channel: Channel::Ch4F922p5MHz,
665 tx_power: TxPower::P20mW,
666 })
667 .unwrap();
668
669 while let Ok(resp) = rx.recv().await {
670 if let Response::SetOperationMode { result, .. } = resp {
671 if result == 0x01 {
672 break 'retry;
673 } else {
674 Mono::delay(1.secs()).await;
675 continue 'retry;
676 }
677 }
678 }
679 }
680
681 let channel = 'retry: loop {
682 tx.send(Command::DoActiveScan {
683 duration: ScanDuration::T616p96ms,
684 mask_channels: 0x3fff0,
685 pairing_id: Some(u64::from_be_bytes(ROUTE_B_ID[24..32].try_into().unwrap())),
686 })
687 .unwrap();
688
689 status.lock(|status| *status = Bp35c0J11Status::Scanning);
690
691 let mut scan_result = None;
692 while let Ok(resp) = rx.recv().await {
693 match resp {
694 Response::DoActiveScan { result } => match (result, scan_result.take()) {
695 (0x01, Some(channel)) => break 'retry channel,
696 _ => {
697 Mono::delay(1.secs()).await;
698 continue 'retry;
699 }
700 },
701 Response::NotificationActiveScan { channel, terminal }
702 if !terminal.is_empty() =>
703 {
704 scan_result.replace(channel);
705 }
706 _ => {}
707 }
708 }
709 };
710
711 #[cfg(feature = "defmt")]
712 defmt::info!("channel = {}", channel);
713
714 'retry: loop {
715 tx.send(Command::SetOperationMode {
716 mode: OperationMode::Dual,
717 han_sleep: false,
718 channel,
719 tx_power: TxPower::P20mW,
720 })
721 .unwrap();
722
723 while let Ok(resp) = rx.recv().await {
724 if let Response::SetOperationMode { result, .. } = resp {
725 if result == 0x01 {
726 break 'retry;
727 } else {
728 Mono::delay(1.secs()).await;
729 continue 'retry;
730 }
731 }
732 }
733 }
734
735 'retry: loop {
736 tx.send(Command::SetRouteBPanaAuthenticationInformation {
737 id: ROUTE_B_ID,
738 password: ROUTE_B_PASSWORD,
739 })
740 .unwrap();
741
742 while let Ok(resp) = rx.recv().await {
743 if let Response::SetRouteBPanaAuthenticationInformation { result, .. } = resp {
744 if result == 0x01 {
745 break 'retry;
746 } else {
747 Mono::delay(1.secs()).await;
748 continue 'retry;
749 }
750 }
751 }
752 }
753
754 'retry: loop {
755 tx.send(Command::StartRouteBOperation).unwrap();
756
757 while let Ok(resp) = rx.recv().await {
758 if let Response::StartRouteBOperation { result, .. } = resp {
759 if result == 0x01 {
760 break 'retry;
761 } else {
762 Mono::delay(1.secs()).await;
763 continue 'retry;
764 }
765 }
766 }
767 }
768
769 'retry: loop {
770 tx.send(Command::OpenUdpPort(0x0e1a)).unwrap();
771
772 while let Ok(resp) = rx.recv().await {
773 if let Response::OpenUdpPort { result, .. } = resp {
774 if result == 0x01 {
775 break 'retry;
776 } else {
777 Mono::delay(1.secs()).await;
778 continue 'retry;
779 }
780 }
781 }
782 }
783
784 let mac_address = 'retry: loop {
785 tx.send(Command::StartRouteBPana).unwrap();
786
787 'wait: while let Ok(resp) = rx.recv().await {
788 match resp {
789 Response::StartRouteBPana { result, .. } if result != 0x01 => break 'wait,
790 Response::NotificationPanaAuthentication {
791 result,
792 mac_address,
793 } => {
794 if result == 0x01 {
795 break 'retry mac_address;
796 } else {
797 break 'wait;
798 }
799 }
800 _ => {}
801 }
802 }
803
804 Mono::delay(1.secs()).await;
805 };
806
807 #[cfg(feature = "defmt")]
808 defmt::info!("mac_address = {}", mac_address);
809
810 status.lock(|status| *status = Bp35c0J11Status::Ready);
811
812 let destination_address = 0xfe800000000000000000000000000000_u128
813 | (mac_address ^ 0x02000000_00000000) as u128;
814
815 let mut last_data = Mono::now();
816
817 'outer: for tid in 0.. {
818 if Mono::now() >= last_data + 60.secs() {
819 break 'outer;
820 }
821
822 let tid_be = ((tid & 0xffff) as u16).to_be_bytes();
823
824 'retry: loop {
825 tx.send(Command::TransmitData {
826 destination_address,
827 source_port: 0x0e1a,
828 destination_port: 0x0e1a,
829 data: &[
830 0x10, 0x81, tid_be[0], tid_be[1], 0x05, 0xff, 0x01, 0x02, 0x88, 0x01, 0x62, 0x04, 0x97, 0x00, 0x98, 0x00, 0xd3, 0x00, 0xe7, 0x00, ],
846 })
847 .unwrap();
848
849 while let Ok(resp) = rx.recv().await {
850 if let Response::TransmitData { result, .. } = resp {
851 if result == 0x01 {
852 break 'retry;
853 } else {
854 Mono::delay(1.secs()).await;
855 continue 'outer;
856 }
857 }
858 }
859 }
860
861 let now = Mono::now();
862
863 let data_expected = [
864 0x10, 0x81, tid_be[0], tid_be[1], 0x02, 0x88, 0x01, 0x05, 0xff, 0x01, 0x72, 0x04, ];
872
873 'wait: loop {
880 let resp = futures::select_biased! {
881 r = rx.recv().fuse() => r.ok(),
882 _ = Mono::delay_until(now + 10.secs()).fuse() => None,
883 };
884
885 match resp {
886 Some(Response::NotificationUdpReceived {
887 source_port: 0x0e1a,
888 destination_port: 0x0e1a,
889 source_type: 0x00,
890 data,
891 rssi,
892 ..
893 }) if data.starts_with(&data_expected) && data.len() == 34 => {
894 status.lock(|status| {
896 *status = Bp35c0J11Status::Data {
897 datetime: (
898 u16::from_be_bytes([data[18], data[19]]), data[20], data[21], data[14], data[15], ),
904 instant: i32::from_be_bytes([
905 data[30], data[31], data[32], data[33],
906 ]),
907 rssi,
908 }
909 });
910 last_data = Mono::now();
911 break 'wait;
912 }
913
914 Some(_) => {}
915
916 None => {
917 #[cfg(feature = "defmt")]
918 defmt::warn!("timeout");
919 break 'wait;
920 }
921 }
922 }
923
924 Mono::delay_until(now + 10.secs()).await;
925 }
926
927 #[cfg(feature = "defmt")]
928 defmt::warn!("reset");
929
930 status.lock(|status| {
931 *status = Bp35c0J11Status::Resetting;
932 });
933
934 ctx.local.bp35c0_j11_resetn.set_low().unwrap();
936 Mono::delay(500.millis()).await;
937 }
938 }
939
940 #[task(
941 priority = 1,
942 shared = [temperature_raw],
943 local = [spi0, spi0_csn_adt7310]
944 )]
945 async fn task_adt7310(ctx: task_adt7310::Context) {
946 let spi = ctx.local.spi0;
947 let spi_csn = ctx.local.spi0_csn_adt7310;
948
949 {
950 spi_csn.set_low().unwrap();
951 spi.write(&[0xff_u8; 4]).unwrap();
952 spi_csn.set_high().unwrap();
953 Mono::delay(1.millis()).await;
954 }
955
956 let mut temperature_raw = ctx.shared.temperature_raw;
957
958 loop {
959 let now = Mono::now();
960
961 spi_csn.set_low().unwrap();
962
963 #[allow(clippy::unusual_byte_groupings)]
964 spi.write(&[0b0_0_001_0_00, 0b1_01_0_0_0_00]).unwrap();
968
969 Mono::delay(240.millis()).await;
970
971 #[allow(clippy::unusual_byte_groupings)]
972 let mut buf = [0b0_1_010_0_00, 0, 0];
974
975 spi.transfer(buf.as_mut_slice()).unwrap();
976
977 spi_csn.set_high().unwrap();
978
979 temperature_raw.lock(|temp| *temp = i16::from_be_bytes([buf[1], buf[2]]));
980
981 Mono::delay_until(now + 1.secs()).await;
982 }
983 }
984
985 #[task(
986 priority = 1,
987 shared = [bp35c0_j11_status, temperature_raw],
988 local = [i2c1, lcd_resetn, uart0]
989 )]
990 async fn task_lcd(ctx: task_lcd::Context) {
991 const LCD_ADDRESS: u8 = 0x3e;
992
993 ctx.local.lcd_resetn.set_high().unwrap();
994 Mono::delay(50.millis()).await;
995
996 type Duration = <Mono as TimerQueueBasedMonotonic>::Duration;
997
998 let i2c = ctx.local.i2c1;
999 let lcd = st7032i::St7032i::<_, _, _, Duration>::new(i2c, LCD_ADDRESS);
1000
1001 let (lcd, delay) = lcd.set_instruction_set::<st7032i::Normal>().unwrap();
1002 Mono::delay(delay).await;
1003
1004 let (mut lcd, delay) = lcd.set_instruction_set::<st7032i::Extention>().unwrap();
1005 Mono::delay(delay).await;
1006
1007 let delay = lcd.cmd_internal_osc_frequency().unwrap();
1008 Mono::delay(delay).await;
1009
1010 let delay = lcd.cmd_contrast_set(0b1100).unwrap();
1011 Mono::delay(delay).await;
1012
1013 let delay = lcd.cmd_power_icon_contrast_set(false, true, 0b01).unwrap();
1014 Mono::delay(delay).await;
1015
1016 let delay = lcd.cmd_follower_control(true, 0b100).unwrap();
1017 Mono::delay(delay).await;
1018
1019 let (mut lcd, delay) = lcd.set_instruction_set::<st7032i::Normal>().unwrap();
1020 Mono::delay(delay).await;
1021
1022 let delay = lcd.cmd_display_on_off(true, false, false).unwrap();
1023 Mono::delay(delay).await;
1024
1025 let delay = lcd.cmd_set_cgram_address(0).unwrap();
1026 Mono::delay(delay).await;
1027
1028 let delay = lcd
1029 .cmd_write_bytes([
1030 0b000_00000,
1032 0b000_00100,
1033 0b000_00100,
1034 0b000_00100,
1035 0b000_00100,
1036 0b000_00100,
1037 0b000_00000,
1038 0b000_00000,
1039 0b000_00000,
1041 0b000_00000,
1042 0b000_00000,
1043 0b000_00000,
1044 0b000_00000,
1045 0b000_10001,
1046 0b000_01110,
1047 0b000_00000,
1048 ])
1049 .unwrap();
1050 Mono::delay(delay).await;
1051
1052 let delay = lcd.cmd_clear_display().unwrap();
1053 Mono::delay(delay).await;
1054
1055 {
1057 write!(lcd, " Hello!").unwrap();
1058 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1059
1060 let delay = lcd
1061 .cmd_set_ddram_address(st7032i::DDRAM_ADDRESS_LINE2)
1062 .unwrap();
1063 Mono::delay(delay).await;
1064
1065 let _ = lcd
1066 .cmd_write_chars([
1067 '('.into(),
1068 '*'.into(),
1069 st7032i::Character::Cgram(0),
1070 st7032i::Character::Cgram(1),
1071 st7032i::Character::Cgram(0),
1072 ')'.into(),
1073 'ノ'.into(),
1074 ])
1075 .unwrap();
1076 Mono::delay(3.secs()).await;
1077 }
1078
1079 let mut bp35c0_j11_status = ctx.shared.bp35c0_j11_status;
1080 let mut temperature_raw = ctx.shared.temperature_raw;
1081
1082 #[derive(Clone, Copy)]
1083 enum DisplayItemBp35c0J11 {
1084 Date,
1085 Time,
1086 Rssi,
1087 }
1088
1089 #[derive(Clone, Copy)]
1090 enum DisplayItem {
1091 Bp35c0J11(DisplayItemBp35c0J11),
1092 Temperature,
1093 }
1094
1095 let mut next = DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Date);
1096
1097 loop {
1098 let now = Mono::now();
1099
1100 let delay = lcd.cmd_clear_display().unwrap();
1101 Mono::delay(delay).await;
1102
1103 let status = bp35c0_j11_status.lock(|s| *s);
1104
1105 next = match next {
1106 DisplayItem::Bp35c0J11(i) => match (status, i) {
1107 (Bp35c0J11Status::Resetting, _) => {
1108 write!(lcd, "Reset...").unwrap();
1109 DisplayItem::Temperature
1110 }
1111 (Bp35c0J11Status::Initializing, _) => {
1112 write!(lcd, " Init...").unwrap();
1113 DisplayItem::Temperature
1114 }
1115 (Bp35c0J11Status::Scanning, _) => {
1116 write!(lcd, " Scan...").unwrap();
1117 DisplayItem::Temperature
1118 }
1119 (Bp35c0J11Status::Ready, _) => {
1120 write!(lcd, " Ready!").unwrap();
1121 DisplayItem::Temperature
1122 }
1123 (Bp35c0J11Status::Data { datetime, .. }, DisplayItemBp35c0J11::Date) => {
1124 let (year, month, day, _hour, _min) = datetime;
1125 write!(lcd, "{:02}-{:02}-{:02}", year % 100, month, day).unwrap();
1126 DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Time)
1127 }
1128 (Bp35c0J11Status::Data { datetime, .. }, DisplayItemBp35c0J11::Time) => {
1129 let (_year, _month, _day, hour, min) = datetime;
1130 write!(lcd, " {hour:02}:{min:02}").unwrap();
1131 DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Rssi)
1132 }
1133 (Bp35c0J11Status::Data { rssi, .. }, DisplayItemBp35c0J11::Rssi) => {
1134 write!(lcd, " {rssi:>3} dBm").unwrap();
1135 DisplayItem::Temperature
1136 }
1137 },
1138 DisplayItem::Temperature => {
1139 let temp_raw = temperature_raw.lock(|temp| *temp);
1140 let temp_int = temp_raw / 128;
1141 let temp_frac = 78125_u32 * (temp_raw % 128).unsigned_abs() as u32;
1142 write!(lcd, "{:2}.{:03} C", temp_int, temp_frac / 10000).unwrap();
1143 DisplayItem::Bp35c0J11(DisplayItemBp35c0J11::Date)
1144 }
1145 };
1146
1147 Mono::delay(st7032i::EXECUTION_TIME_SHORT.into()).await;
1148
1149 let delay = lcd
1150 .cmd_set_ddram_address(st7032i::DDRAM_ADDRESS_LINE2)
1151 .unwrap();
1152 Mono::delay(delay).await;
1153
1154 if let Bp35c0J11Status::Data { instant, .. } = status {
1155 write!(lcd, "{instant:>6} W").unwrap();
1156 } else {
1157 write!(lcd, "------ W").unwrap();
1158 }
1159
1160 Mono::delay_until(now + 2.secs().max(st7032i::EXECUTION_TIME_SHORT.into())).await;
1161 }
1162 }
1163
1164 #[task(
1165 priority = 1,
1166 binds = UART1_IRQ,
1167 local = [uart1_rx, uart1_rx_sender, bp35c0_j11_parser]
1168 )]
1169 fn uart1_irq(ctx: uart1_irq::Context) {
1170 let uart = ctx.local.uart1_rx;
1171 let parser = ctx.local.bp35c0_j11_parser;
1172 let sender = ctx.local.uart1_rx_sender;
1173 let mut rx_buf = [0; 32];
1174 if let Ok(len) = uart.read_raw(&mut rx_buf) {
1175 for resp in rx_buf[0..len].iter().flat_map(|&c| parser.parse(c)) {
1176 #[cfg(feature = "defmt")]
1177 defmt::info!("Rx: {:?}", resp);
1178 sender.try_send(resp).unwrap();
1179 }
1180 }
1181 }
1182}