#![no_std]
#![no_main]
#![allow(clippy::bool_comparison)]
use bsp::ehal;
use bsp::hal;
use feather_m4 as bsp;
#[cfg(not(feature = "use_semihosting"))]
use panic_halt as _;
#[cfg(feature = "use_semihosting")]
use panic_semihosting as _;
use bsp::entry;
use ehal::digital::v2::ToggleableOutputPin;
use hal::clock::GenericClockController;
use hal::nvm::{smart_eeprom, Nvm};
use hal::pac::{interrupt, CorePeripherals, Peripherals};
use hal::usb::UsbBus;
use usb_device::bus::UsbBusAllocator;
use usb_device::prelude::*;
use usbd_serial::{SerialPort, USB_CLASS_CDC};
use cortex_m::asm::delay as cycle_delay;
use cortex_m::peripheral::NVIC;
use core::sync::atomic;
#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let mut core = CorePeripherals::take().unwrap();
let mut clocks = GenericClockController::with_external_32kosc(
peripherals.GCLK,
&mut peripherals.MCLK,
&mut peripherals.OSC32KCTRL,
&mut peripherals.OSCCTRL,
&mut peripherals.NVMCTRL,
);
let pins = bsp::Pins::new(peripherals.PORT);
let mut red_led = pins.d13.into_push_pull_output();
let mut nvm = Nvm::new(peripherals.NVMCTRL);
let bus_allocator = unsafe {
USB_ALLOCATOR = Some(bsp::usb_allocator(
pins.usb_dm,
pins.usb_dp,
peripherals.USB,
&mut clocks,
&mut peripherals.MCLK,
));
USB_ALLOCATOR.as_ref().unwrap()
};
unsafe {
USB_SERIAL = Some(SerialPort::new(bus_allocator));
USB_BUS = Some(
UsbDeviceBuilder::new(bus_allocator, UsbVidPid(0x16c0, 0x27dd))
.manufacturer("Fake company")
.product("Serial port")
.serial_number("TEST")
.device_class(USB_CLASS_CDC)
.build(),
);
}
unsafe {
core.NVIC.set_priority(interrupt::USB_OTHER, 1);
core.NVIC.set_priority(interrupt::USB_TRCPT0, 1);
core.NVIC.set_priority(interrupt::USB_TRCPT1, 1);
NVIC::unmask(interrupt::USB_OTHER);
NVIC::unmask(interrupt::USB_TRCPT0);
NVIC::unmask(interrupt::USB_TRCPT1);
}
while USER_PRESENT.load(atomic::Ordering::Acquire) == false {
cycle_delay(25 * 1024 * 1024);
red_led.toggle().ok();
}
match nvm.smart_eeprom() {
Ok(se) => {
use smart_eeprom::SmartEepromMode::*;
let mut seeprom = match se {
Unlocked(se) => se,
Locked(se) => se.unlock(),
};
let write_buf = [0x01u8, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
serial_writeln!("Write dummy data");
seeprom.set(0x10, &write_buf);
seeprom.set(0x18, &write_buf);
serial_writeln!("Read dummy data");
let mut read_buf = [0u8; 14];
seeprom.get(0x14, &mut read_buf);
read_buf.rotate_left(4);
if read_buf[..8] == write_buf {
serial_writeln!("Smart EEPROM test successful");
} else {
serial_writeln!("Smart EEPROM test failed");
}
}
Err(e) => {
serial_writeln!("Failed to initialize Smart EEPROM: {:?}!", e);
}
}
loop {
cycle_delay(5 * 1024 * 1024);
red_led.toggle().ok();
}
}
static mut USB_ALLOCATOR: Option<UsbBusAllocator<UsbBus>> = None;
static mut USB_BUS: Option<UsbDevice<UsbBus>> = None;
static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
static USER_PRESENT: atomic::AtomicBool = atomic::AtomicBool::new(false);
fn usbserial_get<T, R>(borrower: T) -> R
where
T: Fn(&mut SerialPort<UsbBus>) -> R,
{
usb_free(|_| unsafe {
let usb_serial = USB_SERIAL.as_mut().expect("UsbSerial not initialized");
borrower(usb_serial)
})
}
#[inline]
fn usb_free<F, R>(f: F) -> R
where
F: FnOnce(&cortex_m::interrupt::CriticalSection) -> R,
{
NVIC::mask(interrupt::USB_OTHER);
NVIC::mask(interrupt::USB_TRCPT0);
NVIC::mask(interrupt::USB_TRCPT1);
let r = f(unsafe { &cortex_m::interrupt::CriticalSection::new() });
unsafe {
NVIC::unmask(interrupt::USB_OTHER);
NVIC::unmask(interrupt::USB_TRCPT0);
NVIC::unmask(interrupt::USB_TRCPT1);
};
r
}
#[macro_export]
macro_rules! serial_writeln {
($($tt:tt)+) => {{
use core::fmt::Write;
let mut s: heapless::String<256> = heapless::String::new();
core::write!(&mut s, $($tt)*).unwrap();
usbserial_get(|usbserial| {
usbserial.write(s.as_bytes()).ok();
usbserial.write("\r\n".as_bytes()).ok();
});
}};
}
fn poll_usb() {
unsafe {
if let Some(usb_dev) = USB_BUS.as_mut() {
if let Some(serial) = USB_SERIAL.as_mut() {
usb_dev.poll(&mut [serial]);
let mut buf = [0u8; 64];
if let Ok(count) = serial.read(&mut buf) {
if count > 0 {
USER_PRESENT.store(true, atomic::Ordering::Release);
}
serial.write(&buf[..count]).unwrap();
};
};
}
};
}
#[interrupt]
fn USB_OTHER() {
poll_usb();
}
#[interrupt]
fn USB_TRCPT0() {
poll_usb();
}
#[interrupt]
fn USB_TRCPT1() {
poll_usb();
}