use alloc::string::String;
use core::fmt::Debug;
use log::info;
use futures::{
future::{
select,
Either,
},
prelude::*,
};
use crate::{
key::ModuleKey,
locator::Locator,
net::{
self,
*,
},
serial::Msg,
stateful::{
ScanStateful,
ScanStatefulExt,
},
translate::{
Translate,
Translated,
Translator,
},
};
enum UsbOut<U, O> {
Invalid,
Disconnected(U),
Connected(O),
}
impl<U, O> UsbOut<U, O> {
fn fut(&mut self) -> U {
match core::mem::replace(self, UsbOut::Invalid) {
Self::Disconnected(u) => u,
_ => panic!("Expected disconnected usb output"),
}
}
fn sink(&mut self) -> O {
match core::mem::replace(self, UsbOut::Invalid) {
Self::Connected(o) => o,
_ => panic!("Expected connected usb output"),
}
}
}
pub struct Core<N, U, T, S, O> {
my_type: String,
translator: Translator,
locator: Locator,
net: N,
usb: UsbOut<U, O>,
timer: T,
scanner: S,
}
impl<N, U, T, S, O> Core<N, U, T, S, O>
where
T: Stream + Unpin,
S: ScanStateful + Unpin,
{
pub fn new(
my_type: &str,
translator: Translator,
net: N,
usb_sink: U,
timer: T,
scanner: S,
) -> Core<N, U, T, S, O>
where
U: Future<Output = O>,
{
let locator = Locator::new(translator.layout.modules.iter().map(|b| b.ty));
Core {
my_type: my_type.into(),
translator,
locator,
timer,
usb: UsbOut::Disconnected(usb_sink),
scanner,
net,
}
}
pub async fn run(&mut self)
where
U: Future<Output = O> + Unpin,
O: Sink<Translated> + Unpin,
N: Net<Msg> + Unpin,
<N as Sink<net::Msg<Msg>>>::Error: Debug,
{
let usb = self.usb.fut();
match select(usb, self.net.try_next().map_ok(|o| o.map(|m| m.unpack()))).await {
Either::Left((sink, _)) => {
self.usb = UsbOut::Connected(sink);
for _ in 0..5 {
self.timer.next().await;
}
self.run_primary().await
}
Either::Right((Ok(Some((_, Msg::Init))), _)) => self.run_secondary().await,
_ => panic!("Unexpected message while waiting for init"),
}
}
pub async fn run_secondary(&mut self)
where
N: NetSend<Msg> + NetRecv<Msg> + Unpin,
{
info!("Running secondary as {}", self.my_type);
let _ = self
.net
.send_to(0, Msg::ModuleType(self.my_type.clone()))
.await;
loop {
let incoming = self.net.try_next().map_ok(|o| o.map(|m| m.unpack()));
let timer = self.timer.next();
match select(incoming, timer).await {
Either::Right(_) => {
let key = self.scanner.change().await;
if let Some(key) = key {
let _ = self.net.send_to(0, Msg::KeyEvent(key)).await;
} else {
continue;
}
}
Either::Left((Ok(Some((_, Msg::Init))), _)) => {
let _ = self
.net
.send_to(0, Msg::ModuleType(self.my_type.clone()))
.await;
}
_ => continue,
};
}
}
pub async fn run_primary(&mut self)
where
O: Sink<Translated> + Unpin,
N: Net<Msg> + Unpin,
<N as Sink<net::Msg<Msg>>>::Error: Debug,
{
let mut sink = self.usb.sink();
self.locator.add_module(0, self.my_type.clone());
let _ = self
.net
.broadcast(Msg::Init)
.await
.expect("failed to init other modules");
loop {
let key = match select(
self.net.try_next().map_ok(|o| o.map(|m| m.unpack())),
self.timer.next(),
)
.await
{
Either::Left((Ok(Some((from, Msg::KeyEvent(key)))), _)) => {
let module = if let Some(newpos) = self.locator.remap(from) {
newpos
} else {
continue;
};
Some(ModuleKey {
module: module,
key,
})
}
Either::Left((Ok(Some((from, Msg::ModuleType(module_type)))), _)) => {
self.locator.add_module(from, module_type);
continue;
}
Either::Right((_, _)) => {
let key = self.scanner.change().await;
let module = if let Some(newpos) = self.locator.remap(0) {
newpos
} else {
continue;
};
key.map(|key| ModuleKey { module, key })
}
_ => continue,
};
if let Some(translated) = self.translator.translate(key) {
match translated {
Translated::Broadcast(msg) => {
let _ = self.net.broadcast(msg).await;
}
Translated::Send(to, msg) => {
let _ = self.net.send_to(to, msg).await;
}
default => {
let _ = sink.send(default).await;
}
}
}
}
}
}