#![no_main]
#![no_std]

use embedded_hal::blocking::spi::Write;
use embedded_hal::digital::v2::OutputPin;
use fugit::RateExtU32;
use panic_halt as _;
use rp_pico::entry;
use rp_pico::hal::gpio::{FunctionSio, PinId, PullType, SioOutput};
use rp_pico::{
    hal,
    hal::prelude::*,
    hal::{
        clocks::{init_clocks_and_plls, Clock},
        gpio::Pin,
        pac,
        spi::Spi,
        watchdog::Watchdog,
    },
};

fn send_byte<I, J, P>(
    data: &mut Pin<I, FunctionSio<SioOutput>, P>,
    clock: &mut Pin<J, FunctionSio<SioOutput>, P>,
    delay: &mut cortex_m::delay::Delay,
    byte: u8,
) where
    I: PinId,
    J: PinId,
    P: PullType,
{
    (0..8).for_each(|bit| {
        if byte & (1 << (8 - bit)) > 0 {
            data.set_high();
        } else {
            data.set_low();
        }
        clock.set_high();
        delay.delay_us(100);
        clock.set_low();
        delay.delay_us(100);
    });
    clock.set_low();
}

fn send_start<I, J, P>(
    data: &mut Pin<I, FunctionSio<SioOutput>, P>,
    clock: &mut Pin<J, FunctionSio<SioOutput>, P>,
    delay: &mut cortex_m::delay::Delay,
) where
    I: PinId,
    J: PinId,
    P: PullType,
{
    send_byte(data, clock, delay, 0);
    send_byte(data, clock, delay, 0);
    send_byte(data, clock, delay, 0);
    send_byte(data, clock, delay, 0);
}

fn send_term<I, J, P>(
    data: &mut Pin<I, FunctionSio<SioOutput>, P>,
    clock: &mut Pin<J, FunctionSio<SioOutput>, P>,
    delay: &mut cortex_m::delay::Delay,
) where
    I: PinId,
    J: PinId,
    P: PullType,
{
    send_byte(data, clock, delay, 0xff);
    send_byte(data, clock, delay, 0xff);
    send_byte(data, clock, delay, 0xff);
    send_byte(data, clock, delay, 0xff);
}

fn send<I, J, P>(
    data: &mut Pin<I, FunctionSio<SioOutput>, P>,
    clock: &mut Pin<J, FunctionSio<SioOutput>, P>,
    delay: &mut cortex_m::delay::Delay,
    values: &[u8],
) where
    I: PinId,
    J: PinId,
    P: PullType,
{
    send_start(data, clock, delay);
    for val in values {
        send_byte(data, clock, delay, *val);
    }
    send_term(data, clock, delay);
    clock.set_low();
}

#[entry]
fn main() -> ! {
    let mut pac = pac::Peripherals::take().unwrap();
    let core = pac::CorePeripherals::take().unwrap();
    let sio = hal::Sio::new(pac.SIO);
    let mut watchdog = Watchdog::new(pac.WATCHDOG);

    let pins = rp_pico::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );

    let external_xtal_freq_hz = 12_000_000u32;
    let clocks = init_clocks_and_plls(
        external_xtal_freq_hz,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());

    /*
    let mut spi_clk = pins.gpio10.into_function();
    let mut spi_sdo = pins.gpio11.into_function();
    let spi = Spi::<_, _, _, 8>::new(pac.SPI1, (spi_sdo, spi_clk));
    let mut spi = spi.init(
        &mut pac.RESETS,
        clocks.peripheral_clock.freq(),
        1.MHz(),
        embedded_hal::spi::MODE_1,
    );
    */

    let mut led_pin = pins.led.into_push_pull_output();
    let mut blue_pin = pins.gpio3.into_push_pull_output();
    led_pin.set_high().unwrap();
    delay.delay_ms(500);
    led_pin.set_low().unwrap();

    let mut spi_clk = pins.gpio10.into_push_pull_output();
    let mut spi_sdo = pins.gpio11.into_push_pull_output();
    spi_clk.set_low();
    spi_sdo.set_low();

    let bits_1 = &[
            0, 0, 0, 0,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xff, 0xff, 0xff, 0xff,
    ];
    let bits_2 = &[
            0, 0, 0, 0,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xff, 0xff, 0xff, 0xff,
    ];
    let bits_3 = &[
            0, 0, 0, 0,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xe1, 0x00, 0x00, 0x80,
            0xe1, 0x80, 0x00, 0x00,
            0xe1, 0x00, 0x80, 0x00,
            0xff, 0xff, 0xff, 0xff,
    ];

    let a = 15 / 2;

    loop {
        send(
            &mut spi_sdo,
            &mut spi_clk,
            &mut delay,
            bits_1,
        );
        spi_clk.set_low();
        spi_sdo.set_low();
        delay.delay_ms(500);

        send(
            &mut spi_sdo,
            &mut spi_clk,
            &mut delay,
            bits_2,
        );
        spi_clk.set_low();
        spi_sdo.set_low();
        delay.delay_ms(500);

        send(
            &mut spi_sdo,
            &mut spi_clk,
            &mut delay,
            bits_3,
        );
        spi_clk.set_low();
        spi_sdo.set_low();
        delay.delay_ms(500);

        /*
        spi.write(bits_1);
        delay.delay_ms(500);
        spi.write(bits_2);
        delay.delay_ms(500);
        spi.write(bits_3);
        delay.delay_ms(500);
        */

        /*
        led_pin.set_high().unwrap();
        blue_pin.set_low().unwrap();
        delay.delay_ms(500);
        led_pin.set_low().unwrap();
        blue_pin.set_high().unwrap();
        delay.delay_ms(500);
        */
    }
}
