use stm32f0xx_hal as hal;
use hal::prelude::*;
use hal::{delay::Delay, serial::Serial, stm32};
use hal::gpio::{Input, Floating, gpiob};
use embedded_midi::{MidiOut, MidiIn};
use crate::bus::Bus;
use crate::adc::Tlc0832;

pub struct Hardware {
    pub delay: Delay,
    pub button_1_5: gpiob::PB13<Input<Floating>>,
    pub button_6_10: gpiob::PB11<Input<Floating>>,
    pub bus: Bus,
    pub midi_tx: MidiOut<hal::serial::Tx<stm32::USART1>>,
    pub midi_rx: MidiIn<hal::serial::Rx<stm32::USART1>>,
    pub adc: Tlc0832,
}

impl Hardware {
    pub fn init() -> Self {
        let mut dp = stm32::Peripherals::take().unwrap();
        let cp = cortex_m::Peripherals::take().unwrap();

        let mut rcc = dp
            .RCC
            .configure()
            .hsi48()
            .enable_crs(dp.CRS)
            .sysclk(48.mhz())
            .pclk(24.mhz())
            .freeze(&mut dp.FLASH);

        let delay = Delay::new(cp.SYST, &rcc);

        let gpioa = dp.GPIOA.split(&mut rcc);
        let gpiob = dp.GPIOB.split(&mut rcc);

        let button_1_5 = cortex_m::interrupt::free(|cs| gpiob.pb13.into_floating_input(cs));
        let button_6_10 = cortex_m::interrupt::free(|cs| gpiob.pb11.into_floating_input(cs));

        let bus = Bus::new(
            gpioa.pa0, gpiob.pb8, gpiob.pb0, gpiob.pb1, 
            gpiob.pb2, gpiob.pb3, gpiob.pb4, gpiob.pb5, 
            gpiob.pb6, gpiob.pb7
        );

        let serial = cortex_m::interrupt::free(|cs| {
            let tx = gpioa.pa9.into_alternate_af1(cs);
            let rx = gpioa.pa10.into_alternate_af1(cs);
            Serial::usart1(dp.USART1, (tx, rx), 31_250.bps(), &mut rcc)
        });

        let (tx, rx) = serial.split();
        let midi_tx = MidiOut::new(tx);
        let midi_rx = MidiIn::new(rx);

        let adc_sck = cortex_m::interrupt::free(|cs| gpiob.pb10.into_floating_input(cs));
        let adc_miso = cortex_m::interrupt::free(|cs| gpiob.pb14.into_floating_input(cs));
        let adc_mosi = cortex_m::interrupt::free(|cs| gpiob.pb15.into_floating_input(cs));
        let adc_cs = cortex_m::interrupt::free(|cs| gpiob.pb12.into_floating_input(cs));
        
        let adc = Tlc0832::new(dp.SPI2, adc_sck, adc_miso, adc_mosi, adc_cs, &mut rcc);

        Self {
            delay,
            button_1_5,
            button_6_10,
            bus,
            midi_tx,
            midi_rx,
            adc,
        }
    }
}