//! Firmware for the HackAmp.
#![no_main]
#![no_std]

//use cortex_m::interrupt;
use panic_semihosting as _;
//use stm32f4xx_hal::dma::StreamsTuple;
use stm32f4xx_hal::prelude::*;

//use audio_buffer::AudioBuffer;
use halext::i2s::I2SClocks;
use pins::Pins;

// Remove "pub" to check whether there is any dead code.
pub mod audio_buffer;
pub mod halext;
//pub mod mixer;
pub mod pins;

#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
const APP: () = {
    struct Resources {}

    #[init]
    fn init(ctx: init::Context) {
        // Initialize clocks.
        let rcc = ctx.device.RCC.constrain();
        let _clocks = rcc
            .cfgr
            .use_hse(8.mhz())
            .sysclk(48.mhz())
            .pclk1(24.mhz())
            .require_pll48clk()
            .freeze();
        let i2sclocks = unsafe { I2SClocks::init() };

        // Configure the GPIOs.
        let _pins = Pins::configure(
            ctx.device.GPIOA,
            ctx.device.GPIOB,
            ctx.device.GPIOC,
            ctx.device.GPIOD,
            ctx.device.GPIOE,
            ctx.device.GPIOF,
            ctx.device.GPIOG,
            ctx.device.DMA1,
            ctx.device.SPI2,
            ctx.device.I2S2EXT,
            i2sclocks,
        );

        /*// The components of the firmware are connected via audio buffers.
        static AMP_I2S_IN_BUFFER: AudioBuffer = AudioBuffer::new();
        static AMP_I2S_OUT_BUFFER: AudioBuffer = AudioBuffer::new();
        //static BT_I2S_IN_BUFFER: AudioBuffer = AudioBuffer::new();
        static BT_I2S_OUT_BUFFER: AudioBuffer = AudioBuffer::new();
        /*static USB1_IN_BUFFER: AudioBuffer = AudioBuffer::new();
        static USB1_OUT_BUFFER: AudioBuffer = AudioBuffer::new();
        static USB2_IN_BUFFER: AudioBuffer = AudioBuffer::new();
        static USB2_OUT_BUFFER: AudioBuffer = AudioBuffer::new();*/

        // We initialize the output audio buffers with some data. As the I2S input buffers are
        // filled at the same rate as the I2S output buffers, this initial state ensures that the
        // output buffers never run empty (note that the USB audio interfaces perform their own
        // adaptive synchronization).
        interrupt::free(|cs| {
            for buffer in [&AMP_I2S_OUT_BUFFER, &BT_I2S_OUT_BUFFER].iter() {
                // We initialize two packets so that the I2S interface can immediately initialize
                // both DMA buffers (double buffering).
                for _ in 0..2 {
                    let mut packet = buffer.borrow_write(cs).unwrap();
                    let data = packet.as_mut();
                    for i in 0..data.len() {
                        data[i] = 0x8000000; // "0"
                    }
                    buffer.write_finished(packet, cs);
                }
            }
        });

        i2s.start();

        // TODO: Resources.*/
    }

    /*#[idle(resources = [])]
    fn idle(_ctx: idle::Context) -> ! {
        loop {
            // TODO
        }
    }*/
};
