//! Simple CAN-bus send example, it is inspired to the example provided by stm32f4xx-hal
//! Requires a transceiver connected to PB8, 9 (CAN1)

#![no_std]
#![no_main]

use core::panic::PanicInfo;

use bxcan::{Frame, StandardId, filter::Mask32};
use cortex_m::delay::Delay;
use cortex_m_rt::entry; // The runtime
use defmt_rtt as _;
use hal::{
    self,
    can::Can,
    clocks::{self, ApbPrescaler, Clocks, InputSrc, PllSrc, Pllp},
    gpio::{OutputType, Pin, PinMode, Port},
    pac,
};
use nb::block;

// This marks the entrypoint of our application. The cortex_m_rt creates some
// startup code before this, but we don't need to worry about this
#[entry]
fn main() -> ! {
    // Get handles to the hardware objects. These functions can only be called
    // once, so that the borrowchecker can ensure you don't reconfigure
    // something by accident.
    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();
    let mut rcc = dp.RCC;

    // this line is required if you want to take advantage of ST-Link
    hal::debug_workaround();

    // Configure the clocks accordingly with your hardware [its docs](https://docs.rs/stm32-hal2/0.2.0/stm32_hal2/clocks/index.html).
    // In this configuration we have an external crystal of 8MHz.
    // CAN-bus peripheral is on APB1 bus, it is important to make it work properly and set the right bit timing!
    let clock_cfg = Clocks {
        input_src: InputSrc::Pll(PllSrc::Hse(8_000_000)),
        pllm: 8,
        plln: 180,
        pllp: Pllp::Div2,
        apb1_prescaler: ApbPrescaler::Div2,
        ..Default::default()
    };

    // Write the clock configuration to the MCU.
    clock_cfg.setup().unwrap();

    let mut can = {
        let mut _rx = Pin::new(Port::B, 8, PinMode::Alt(9));
        let mut _tx = Pin::new(Port::B, 9, PinMode::Alt(9));

        _rx.output_type(OutputType::PushPull);
        _tx.output_type(OutputType::PushPull);

        let can = Can::new(dp.CAN1, &mut rcc);

        bxcan::Can::builder(can)
            // APB1 (PCLK1): 45MHz, Bit rate: 1000kBit/s, Sample Point 86.7%
            // Value was calculated with http://www.bittiming.can-wiki.info/
            .set_bit_timing(0x001b0002)
            .enable()
    };

    defmt::info!("CAN enabled!");

    let mut test: [u8; 8] = [0; 8];
    let mut count: u8 = 0;
    let id: u16 = 0x500;

    test[1] = 1;
    test[2] = 2;
    test[3] = 3;
    test[4] = 4;
    test[5] = 5;
    test[6] = 6;
    test[7] = 7;
    let test_frame = Frame::new_data(StandardId::new(id).unwrap(), test);

    loop {
        test[0] = count;
        let test_frame = Frame::new_data(StandardId::new(id).unwrap(), test);
        block!(can.transmit(&test_frame)).unwrap();
        if count < 255 {
            count += 1;
        } else {
            count = 0;
        }
    }
}

// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    cortex_m::asm::udf()
}
