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: 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        // 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::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_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                // マイナス電力 (売電時) はひかえめな紫🟪
604                Bp35c0J11Status::Data { instant, .. } if instant.is_negative() => {
605                    ctx.local.neopixel.set_rgb(1, 0, 2);
606                }
607                // 2500 W あたりで最高輝度にする
608                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, // EHD1
831                            0x81, // EHD2
832                            tid_be[0], tid_be[1], // TID
833                            0x05, 0xff, 0x01, // SEOJ
834                            0x02, 0x88, 0x01, // DEOJ
835                            0x62, // ESV (Get)
836                            0x04, // OPC
837                            0x97, // EPC (現在時刻設定)
838                            0x00, // PDC
839                            0x98, // EPC (現在年月日設定)
840                            0x00, // PDC
841                            0xd3, // EPC (電力係数)
842                            0x00, // PDC
843                            0xe7, // EPC (瞬時電力計測値)
844                            0x00, // PDC
845                        ],
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, // EHD1
865                    0x81, // EHD2
866                    tid_be[0], tid_be[1], // TID
867                    0x02, 0x88, 0x01, // DEOJ
868                    0x05, 0xff, 0x01, // SEOJ
869                    0x72, // ESV (Get_Res)
870                    0x04, // OPC
871                ];
872
873                // TODO: スマートメーターは ESV = 0x73 (プロパティ値通知, INT) で次のプロパティを送ってきていそうなので使う
874                // - 定時積算電力量計測値 (正方向計測値) 0xEA
875                // - 定時積算電力量計測値 (逆方向計測値) 0xEB
876                //
877                // 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]" }
878
879                '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                            // TODO: ちゃんとデータサイズとかチェックする
895                            status.lock(|status| {
896                                *status = Bp35c0J11Status::Data {
897                                    datetime: (
898                                        u16::from_be_bytes([data[18], data[19]]), // year
899                                        data[20],                                 // month
900                                        data[21],                                 // day
901                                        data[14],                                 // hour
902                                        data[15],                                 // min
903                                    ),
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            // モジュールに power cycle をかけて復帰を試みる
935            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            //                  ┌───── configuration register
965            //                  │         ┌───── Resolution (16-bit)
966            //                  │         │  ┌───── Operation mode (One shot)
967            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            //                     ┌───── temperature value register
973            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                // CGRAM[0]
1031                0b000_00000,
1032                0b000_00100,
1033                0b000_00100,
1034                0b000_00100,
1035                0b000_00100,
1036                0b000_00100,
1037                0b000_00000,
1038                0b000_00000,
1039                // CGRAM[1]
1040                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        // 起動メッセージ
1056        {
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}