#![feature(alloc_error_handler, never_type)]
#![no_std]
#![no_main]
extern crate alloc;
#[cfg(feature = "semihosting")]
extern crate panic_semihosting;
#[panic_handler]
#[cfg(all(not(feature = "itm"), not(feature = "semihosting")))]
fn panic_bootloader(_: &core::panic::PanicInfo) -> ! {
unsafe { crate::reboot::reboot_bootloader(core::mem::transmute(())) }
}
#[cfg(feature = "itm")]
extern crate panic_itm;
#[cfg(all(feature = "itm", feature = "semihosting"))]
compile_error!("can't enable itm and semihosting simultaneously");
#[macro_use]
mod allocator;
#[macro_use]
mod matrix;
mod executor;
mod layout;
mod mutex;
mod reboot;
mod usb;
mod wake_flag;
use crate::{
executor::Executor,
matrix::{
Scanner,
StatefulScanner,
},
mutex::IFree,
usb::UsbSink,
wake_flag::*,
};
use cortex_m_rt as rt;
use embedded_hal::prelude::*;
use keebrs::{
core::Core,
led::NoLeds,
matrix::{
Matrix,
Pull,
Read,
},
net::chain::ChainNet,
translate::Translator,
usb::{
hid::HidClass,
keyboard::Keyboard,
},
};
use log::{
error,
info,
};
use rtic::app;
use stm32_usbd::UsbBus;
use stm32f1xx_futures::{
self,
hal::{
self,
serial::{
Config as SerialConfig,
Serial,
},
time::KiloHertz,
timer::Timer,
usb::Peripheral as UsbPeripheral,
},
prelude::*,
serial,
stm32::{
self,
TIM1,
},
timer,
};
use usb_device::{
bus::UsbBusAllocator,
device::UsbDeviceBuilder,
prelude::*,
};
type UsbBusType = UsbBus<UsbPeripheral>;
set_allocator!();
const SCANS_PER_SEC: usize = 2_000;
const DEBOUNCE_MS: usize = 5;
const SCAN_KHZ: usize = SCANS_PER_SEC / 1_000;
const DEBOUNCE_CYCLES: usize = SCAN_KHZ * DEBOUNCE_MS;
const VID: u16 = 0x1209;
const PID: u16 = 0x9200;
const USART_BAUD: u32 = 115_200;
#[app(device = stm32f1xx_futures::stm32, peripherals = true)]
const APP: () = {
struct Resources {
KB_CLASS: HidClass<'static, UsbBusType, Keyboard<NoLeds>>,
USB_DEVICE: UsbDevice<'static, UsbBusType>,
MATRIX: Scanner,
SCAN_REACTOR: timer::Reactor<TIM1>,
LEFT_REACTOR: serial::Reactor<stm32::USART1, [u8; 32]>,
RIGHT_REACTOR: serial::Reactor<stm32::USART3, [u8; 32]>,
#[init(WakeFlag::new())]
USB_FLAG: WakeFlag,
}
#[init]
fn init(mut ctx: init::Context) -> init::LateResources {
static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None;
init_allocator();
#[cfg(feature = "semihosting")]
cortex_m_logger::SemihostingLogger::init();
#[cfg(feature = "itm")]
cortex_m_logger::ITMLogger::init();
#[cfg(any(feature = "itm", feature = "semihosting"))]
log::set_max_level(log::LevelFilter::max());
let mut flash = ctx.device.FLASH.constrain();
let mut rcc = ctx.device.RCC.constrain();
let clocks = rcc
.cfgr
.use_hse(8.mhz())
.sysclk(72.mhz())
.pclk1(36.mhz())
.pclk2(72.mhz())
.freeze(&mut flash.acr);
let mut afio = ctx.device.AFIO.constrain(&mut rcc.apb2);
let mut gpioa = ctx.device.GPIOA.split(&mut rcc.apb2);
let mut gpiob = ctx.device.GPIOB.split(&mut rcc.apb2);
let mut gpioc = ctx.device.GPIOC.split(&mut rcc.apb2);
let mut matrix = build_scanner!(afio, gpioa, gpiob, gpioc);
let bkp = rcc
.bkp
.constrain(ctx.device.BKP, &mut rcc.apb1, &mut ctx.device.PWR);
check_bootloader_key(bkp, &mut matrix);
let tim1 =
Timer::tim1(ctx.device.TIM1, &clocks, &mut rcc.apb2).start_count_down(KiloHertz(2));
let scan_reactor = timer::Reactor::new(tim1);
let bus = UsbBusType::new(UsbPeripheral {
usb: ctx.device.USB,
pin_dm: gpioa.pa11.into_floating_input(&mut gpioa.crh),
pin_dp: gpioa.pa12.into_floating_input(&mut gpioa.crh),
});
let reporter = keebrs::usb::report::Reporter::new();
*USB_BUS = Some(bus);
let kb_class = HidClass::new(
Keyboard::new(NoLeds::new(), reporter),
USB_BUS.as_ref().unwrap(),
);
let mut usb_device = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(VID, PID))
.manufacturer("JRC")
.product("Polymer")
.serial_number(env!("GIT_VERSION"))
.build();
let _ = usb_device.force_reset();
let left_usart = Serial::usart1(
ctx.device.USART1,
(
gpiob.pb6.into_alternate_push_pull(&mut gpiob.crl),
gpiob.pb7,
),
&mut afio.mapr,
SerialConfig::default()
.baudrate(USART_BAUD.bps())
.parity_even(),
clocks,
&mut rcc.apb2,
);
let left_reactor = serial::Reactor::new(left_usart.split());
let right_usart = Serial::usart3(
ctx.device.USART3,
(
gpiob.pb10.into_alternate_push_pull(&mut gpiob.crh),
gpiob.pb11,
),
&mut afio.mapr,
SerialConfig::default()
.baudrate(USART_BAUD.bps())
.parity_even(),
clocks,
&mut rcc.apb1,
);
let right_reactor = serial::Reactor::new(right_usart.split());
init::LateResources {
MATRIX: matrix,
SCAN_REACTOR: scan_reactor,
LEFT_REACTOR: left_reactor,
RIGHT_REACTOR: right_reactor,
USB_DEVICE: usb_device,
KB_CLASS: kb_class,
}
}
#[idle(resources = [MATRIX, SCAN_REACTOR, LEFT_REACTOR, RIGHT_REACTOR, KB_CLASS, USB_FLAG])]
fn idle(mut ctx: idle::Context) -> ! {
info!("Init finished");
let mut scan_timer = ctx.resources.SCAN_REACTOR.take();
scan_timer.start(KiloHertz(2));
let left = ctx.resources.LEFT_REACTOR.take();
let right = ctx.resources.RIGHT_REACTOR.take();
let net = ChainNet::new(left, right);
let scanner =
StatefulScanner::with_groups(ctx.resources.MATRIX, DEBOUNCE_CYCLES, 5, || {
cortex_m::asm::delay(5 * 72)
});
let mut executor = Executor::new();
let mut spawner = executor.local_spawner();
let inner_usb_sink = UsbSink(ctx.resources.KB_CLASS);
let usb_flag = &mut ctx.resources.USB_FLAG;
let usb_sink = alloc::boxed::Box::pin(async move {
usb_flag.wait().await;
inner_usb_sink
});
let core = async move {
let (task, net) = keebrs::net::background::<IFree, _, _, _>(net);
spawner
.spawn(task)
.expect("failed to spawn background net task");
let mut core = Core::new(
"ortho5x7",
Translator::new(layout::LAYOUT, 2 * 1000),
net,
usb_sink,
scan_timer,
scanner,
);
core.run().await;
error!("uh oh, shouldn't get here");
};
executor.spawn(core);
info!("starting executor");
loop {
executor.run();
}
}
#[task(binds = USB_HP_CAN_TX, resources = [USB_DEVICE, KB_CLASS, USB_FLAG])]
fn USB_HP_CAN_TX(ctx: USB_HP_CAN_TX::Context) {
let dev = &mut *ctx.resources.USB_DEVICE;
let class = &mut *ctx.resources.KB_CLASS;
if dev.poll(&mut [class]) {
ctx.resources.USB_FLAG.wake();
}
}
#[task(binds = USB_LP_CAN_RX0, resources = [USB_DEVICE, KB_CLASS, USB_FLAG])]
fn USB_LP_CAN_RX0(ctx: USB_LP_CAN_RX0::Context) {
let dev = &mut *ctx.resources.USB_DEVICE;
let class = &mut *ctx.resources.KB_CLASS;
if dev.poll(&mut [class]) {
ctx.resources.USB_FLAG.wake();
}
}
#[task(binds = USART1, resources = [LEFT_REACTOR])]
fn USART1(ctx: USART1::Context) {
ctx.resources.LEFT_REACTOR.turn()
}
#[task(binds = USART3, resources = [RIGHT_REACTOR])]
fn USART3(ctx: USART3::Context) {
ctx.resources.RIGHT_REACTOR.turn()
}
#[task(binds = TIM1_UP, resources = [SCAN_REACTOR])]
fn TIM1_UP(ctx: TIM1_UP::Context) {
ctx.resources.SCAN_REACTOR.turn()
}
};
fn check_bootloader_key<M: Pull + Read>(bkp: hal::backup_domain::BackupDomain, matrix: &mut M) {
matrix.pull(0);
cortex_m::asm::delay(5 * 72);
let reboot = matrix.read(0);
matrix.release(0);
if reboot {
reboot::reboot_bootloader(bkp);
}
}