Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wip: Bincode #16

Merged
merged 22 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
396 changes: 245 additions & 151 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion models/src/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Card {
}

/// count of cards, witch are avaibale for the player
#[derive(Clone, Debug, Decode, Default, Encode)]
#[derive(Clone, Debug, Decode, Default, Encode, PartialEq)]
pub struct AvailableCards {
pub left: u8,
pub right: u8
Expand Down
48 changes: 44 additions & 4 deletions models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,50 @@ use bincode::{Decode, Encode};
mod cards;
pub use cards::*;

#[derive(Debug, Clone, Decode, Encode)]
pub enum MessageToPc {}
//todo:
// new structure
// event + game + keep alive message

#[derive(Debug, Clone, Decode, Encode)]
pub enum MessageToPyBadge {
#[derive(Debug, Clone, Decode, Encode, PartialEq)]
pub enum Key {
A,
B,
Up,
Down,
Left,
Right
}

#[derive(Debug, Clone, Decode, Encode, PartialEq)]
pub enum ToPcProtocol {
ConnectionResponse
}

#[derive(Debug, Clone, Decode, Encode, PartialEq)]
pub enum ToPcGameEvent {
KeyPressed(Key)
}

#[derive(Debug, Clone, Decode, Encode, PartialEq)]
pub enum MessageToPc {
Protocol(ToPcProtocol),
GameEvent(ToPcGameEvent),
///pybadge is still connected and work
KeepAlive
}

#[derive(Debug, Clone, Decode, Encode, PartialEq)]
pub enum ToPybadgeProtocol {
ConnectionRequest
}

#[derive(Debug, Clone, Decode, Encode, PartialEq)]
pub enum ToPypadeGameEvent {
NewLevel(AvailableCards)
}

#[derive(Debug, Clone, Decode, Encode, PartialEq)]
pub enum MessageToPyBadge {
Protocol(ToPybadgeProtocol),
GameEvent(ToPypadeGameEvent)
}
4 changes: 4 additions & 0 deletions pc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ sdl2_static_link = ["tetra/sdl2_static_link"]
sdl2_bundled = ["tetra/sdl2_bundled"]

[dependencies]
anyhow = "1.0.71"
bincode = { version = "2.0.0-rc.3", features = ["derive"] }
log = "0.4.17"
m3-macro = { version = "0.1.0", path = "../macro" }
m3-map = { version = "0.1.0", path = "../map" }
m3-models = { version = "0.1.0", path = "../models" }
my-env-logger-style = "0.1.0"
num_enum = "0.6.1"
once_cell = { version = "1.17.1", features = ["parking_lot"] }
serialport = "4.2.0"
tetra = "0.8.0"
vek = { version = "0.15.10", default-features = false }

Expand Down
17 changes: 12 additions & 5 deletions pc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use tetra::{
Context, ContextBuilder, State
};
type Vec2 = vek::vec::repr_c::vec2::Vec2<f32>;
use log::info;
use log::{debug, info};
use m3_macro::include_map;
use m3_map::Map;
use once_cell::sync::Lazy;
Expand All @@ -14,7 +14,10 @@ use tetra::{
};

mod tiles;
use tiles::Textures;
use tiles::{MapBaseTile, Textures};
use usb::Players;

mod usb;

const CARGO_PKG_NAME: &str = env!("CARGO_PKG_NAME");
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
Expand All @@ -32,7 +35,8 @@ struct GameState {
textures: Textures,
grass_postion: Vec2,
grass_rotation: f32,
level: Option<Map>
level: Option<Map>,
players: Players
}

impl GameState {
Expand All @@ -42,7 +46,8 @@ impl GameState {
textures,
grass_postion: Vec2::default(),
grass_rotation: 0.0,
level: Some(LEVELS.first().unwrap().to_owned())
level: Some(LEVELS.first().unwrap().to_owned()),
players: usb::Players::init()
})
}
}
Expand Down Expand Up @@ -82,6 +87,7 @@ impl State for GameState {
//update the current state.
//is called 60 time pro seconds (alsong framerated does not drop)
fn update(&mut self, ctx: &mut Context) -> tetra::Result<()> {
let player_events = self.players.get_events();
//use delta time, to avoid that the logic is effected by frame drops
let time = get_delta_time(ctx); //use time
self.grass_postion.x += 0.1 * time.as_millis() as f32;
Expand All @@ -92,7 +98,8 @@ impl State for GameState {

fn main() -> tetra::Result {
my_env_logger_style::just_log();
info!("{:?}", LEVELS[0]);
info!("{CARGO_PKG_NAME} v{CARGO_PKG_VERSION}");
debug!("{:?}", LEVELS[0]);
ContextBuilder::new(format!("{CARGO_PKG_NAME} v{CARGO_PKG_VERSION}"), 1280, 720)
.quit_on_escape(true)
.multisampling(8) //anti-aliasing
Expand Down
199 changes: 199 additions & 0 deletions pc/src/usb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
use anyhow::Context;
use bincode::error::DecodeError;
use log::{debug, info, trace};
use m3_models::{MessageToPc, MessageToPyBadge, ToPcGameEvent, ToPybadgeProtocol};
use serialport::{available_ports, ClearBuffer, SerialPort, SerialPortInfo};
use std::{
io,
sync::mpsc::{Receiver, Sender, TryRecvError},
thread,
time::Duration
};

struct Player {
receiver: Receiver<MessageToPc>,
sender: Sender<MessageToPyBadge>,
port_name: String
}

#[derive(Default)]
pub(crate) struct Players {
players: [Option<Player>; 4],
///uart devices, wich where not classificated as pybadge yets
possible_players: Vec<Player>
}

impl Players {
pub(crate) fn init() -> Players {
let players = Players::default();
let mut ports = available_ports().unwrap();
debug!("avaibale ports: {ports:?}");
ports.retain(|port| {
!players
.players
.iter()
.flatten()
.any(|player| player.port_name == port.port_name)
});
let mut possible_players: Vec<Player> = Vec::new();
for port in ports {
let (sender_to_pc, receiver_to_pc) = std::sync::mpsc::channel();
let (sender_to_pybadge, receiver_to_pydage) = std::sync::mpsc::channel();
let possible_player = Player {
receiver: receiver_to_pc,
sender: sender_to_pybadge,
port_name: port.port_name.clone()
};
possible_players.push(possible_player);
thread::Builder::new()
.name(port.port_name.clone())
.spawn(move || {
let sender_to_pc: Sender<MessageToPc> = sender_to_pc;
let receiver_to_pydage: Receiver<MessageToPyBadge> =
receiver_to_pydage;
let mut pybadge = Pybadge::init(port).unwrap();
//clean connection
pybadge.port.clear(ClearBuffer::All).unwrap();
pybadge.write(&MessageToPyBadge::Protocol(
ToPybadgeProtocol::ConnectionRequest
));
loop {
match receiver_to_pydage.try_recv() {
Err(err) => match err {
TryRecvError::Empty => {},
TryRecvError::Disconnected => {
panic!("channel disconnected")
} /* or should I just break and close the thread? */
},
Ok(message) => pybadge.write(&message)
}
if let Some(message) = pybadge.try_next_event() {
if message != MessageToPc::KeepAlive {
sender_to_pc.send(message).unwrap();
}
}
}
})
.unwrap();
}
Players {
players: [None, None, None, None],
possible_players
}
}

///get aviable player events.
///Element i of return value repsent player i.
///ELement is None if no pybade is connected for player i.
pub fn get_events(&mut self) -> [Option<Vec<ToPcGameEvent>>; 4] {
if self.players.iter().any(|f| f.is_none()) {
//check if some of the serial ports a pybadge and it as player
let mut i: usize = 0;
let mut found_player = false;
for possible_player in self.possible_players.iter() {
if MessageToPc::Protocol(m3_models::ToPcProtocol::ConnectionResponse)
== match possible_player.receiver.try_recv() {
Ok(value) => value,
Err(err) => match err {
TryRecvError::Empty => continue,
TryRecvError::Disconnected => panic!("channel disconnected")
}
} {
found_player = true;
break;
}
i += 1;
}
if found_player {
let new_player = self.possible_players.remove(i);
info!("player join from port {}", new_player.port_name);
*self.players.iter_mut().find(|f| f.is_none()).unwrap() =
Some(new_player);
}
}
let mut events = [None, None, None, None];
for (i, player) in self.players.iter().enumerate() {
if let Some(player) = player {
let mut events_of_player = Vec::new();
match player.receiver.try_recv() {
Ok(event) => match event {
MessageToPc::GameEvent(event) => events_of_player.push(event),
MessageToPc::Protocol(_protocol) => todo!(),
MessageToPc::KeepAlive => {}
},
Err(err) => match err {
TryRecvError::Empty => continue,
TryRecvError::Disconnected => panic!("channel disconnected")
}
}
events[i] = Some(events_of_player);
}
}
events
}
}

pub(crate) struct Pybadge {
port: Box<dyn SerialPort>,
port_name: String,
buf: Vec<u8>
}

impl Pybadge {
fn init(port: SerialPortInfo) -> anyhow::Result<Self> {
let port_name = port.port_name.clone();
let port = serialport::new(port.port_name, 960)
.timeout(Duration::from_secs(1))
.open()
.with_context(|| "Failed to open port")?;
Ok(Pybadge {
port,
port_name,
buf: Vec::new()
})
}

fn try_next_event(&mut self) -> Option<MessageToPc> {
match bincode::decode_from_slice(&self.buf, bincode::config::standard()) {
Ok((event, len)) => {
self.buf.drain(..len);
if event == MessageToPc::KeepAlive {
//do not spam debug log full
trace!("recieve message form {:?} {event:?}", self.port_name);
} else {
debug!("recieve message form {:?} {event:?}", self.port_name);
};
return Some(event);
},
Err(err) => {
match err {
//we need to wait for more data first
DecodeError::UnexpectedEnd { .. } => {},
_ => panic!("Could not decode message\n {}", err)
}
}
};
let mut buffer = [0_u8; 16];
let len = match self.port.read(&mut buffer) {
Ok(value) => value,
Err(err) => match err.kind() {
io::ErrorKind::TimedOut => 0,
_ => panic!("{err}")
}
};
if len != 0 {
let mut new_data: Vec<u8> =
buffer[..len].iter().map(|f| f.to_owned()).collect();
trace!("recieve data form {:?} {new_data:?}", self.port_name);
self.buf.append(&mut new_data);
}
None
}

fn write(&mut self, message: &MessageToPyBadge) {
debug!("send message to {:?} {:?}", &self.port_name, &message);
let data = bincode::encode_to_vec(message, bincode::config::standard()).unwrap();
trace!("send data to {:?} {:?}", &self.port_name, data);
self.port.write_all(&data).unwrap();
}
}
7 changes: 1 addition & 6 deletions pybadge/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,4 @@ rustflags = [
"-C", "link-arg=--nmagic",

"-C", "link-arg=-Tlink.x",
]

[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
]
12 changes: 11 additions & 1 deletion pybadge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,14 @@ edition = "2021"
publish = false

[dependencies]
pybadge-high = { git = "https://github.com/LuckyTurtleDev/pybadge-high.git", branch = "main", default-features = false }
bincode = { version = "2.0.0-rc.3", default-features = false, features = ["derive"] }
embedded-graphics = "0.7.1"
heapless = "0.7.16"
m3-models = { version = "0.1.0", path = "../models" }
pybadge-high = { version = "0.1.3", features = ["usb", "time", "bluescreen", "bluescreen-message-nightly"] }


[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
Loading