rp2040_combined/
main.rs

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        // NeoPixel LED / WS2812 を PIO で制御する
232        // https://cdn-shop.adafruit.com/datasheets/WS2812.pdf
233        //
234        // RP2040 Datasheet にサンプルコードがあるが、勉強のため見ないで書いた
235        //
236        // WS2812 は1本の線で、データを次のフォーマットでエンコードして送る
237        //      ┌─────┐         ┌
238        //   0: │ T0H │   T0L   │   T0H: 0.35 us, T0L: 0.80 us, +/- 0.15 us
239        //      ┘     └─────────┘
240        //      ┌─────────┐     ┌
241        //   1: │   T1H   │ T1L │   T1H: 0.70 us, T1L: 0.60 us, +/- 0.15 us
242        //      ┘         └─────┘
243        //
244        // PIO の1クロックを約 0.1 us (sys_clk: 125 MHz, divisor: 12 + 128/256) として
245        // T0H: 0.3 us, T0L: 0.7 us, T1H: 0.7 us, T1L: 0.7 us 程度で制御する
246        //
247        // データは G, R, B の順で 8-bit ずつ、MSB-first で送る
248        // シフト方向を左にし、[31:8] にデータを詰めるのを想定
249
250        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",        // (1) L:1
256            "   jmp !x skip side 1 [2]", // (2) L:1, H:2
257            "   nop side 1 [3]",         // (3) H:1, H:2
258            "skip:",                     //
259            "   jmp loop side 0 [5]",    // (4) H:1, L:5
260        );
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        // misc/hsv2rgb.rs で生成
340        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                // 2500 W あたりで最高輝度にする
605                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, // EHD1
825                            0x81, // EHD2
826                            tid_be[0], tid_be[1], // TID
827                            0x05, 0xff, 0x01, // SEOJ
828                            0x02, 0x88, 0x01, // DEOJ
829                            0x62, // ESV (Get)
830                            0x04, // OPC
831                            0x97, // EPC (現在時刻設定)
832                            0x00, // PDC
833                            0x98, // EPC (現在年月日設定)
834                            0x00, // PDC
835                            0xd3, // EPC (電力係数)
836                            0x00, // PDC
837                            0xe7, // EPC (瞬時電力計測値)
838                            0x00, // PDC
839                        ],
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, // EHD1
859                    0x81, // EHD2
860                    tid_be[0], tid_be[1], // TID
861                    0x02, 0x88, 0x01, // DEOJ
862                    0x05, 0xff, 0x01, // SEOJ
863                    0x72, // ESV (Get_Res)
864                    0x04, // OPC
865                ];
866
867                // TODO: スマートメーターは ESV = 0x73 (プロパティ値通知, INT) で次のプロパティを送ってきていそうなので使う
868                // - 定時積算電力量計測値 (正方向計測値) 0xEA
869                // - 定時積算電力量計測値 (逆方向計測値) 0xEB
870                //
871                // INFO  Rx: NotificationUdpReceived { source_address: REDACTED, source_port: 3610, destination_port: 3610, source_pan_id: REDACTED, source_type: 0, encryption: 2, rssi: -69, data: "[16, 129, 0, 1, 2, 136, 1, 5, 255, 1, 115, 2, 234, 11, 7, 232, 9, 1, 10, 30, 0, 0, 0, 28, 210, 235, 11, 7, 232, 9, 1, 10, 30, 0, 0, 0, 0, 21]" }
872
873                '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                            // TODO: ちゃんとデータサイズとかチェックする
889                            status.lock(|status| {
890                                *status = Bp35c0J11Status::Data {
891                                    datetime: (
892                                        u16::from_be_bytes([data[18], data[19]]), // year
893                                        data[20],                                 // month
894                                        data[21],                                 // day
895                                        data[14],                                 // hour
896                                        data[15],                                 // min
897                                    ),
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            // モジュールに power cycle をかけて復帰を試みる
929            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            //                  ┌───── configuration register
959            //                  │         ┌───── Resolution (16-bit)
960            //                  │         │  ┌───── Operation mode (One shot)
961            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            //                     ┌───── temperature value register
967            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                // CGRAM[0]
1025                0b000_00000,
1026                0b000_00100,
1027                0b000_00100,
1028                0b000_00100,
1029                0b000_00100,
1030                0b000_00100,
1031                0b000_00000,
1032                0b000_00000,
1033                // CGRAM[1]
1034                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        // 起動メッセージ
1050        {
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}