diff --git a/Cargo.lock b/Cargo.lock index 5374048e..09c6d6e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,11 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + [[package]] name = "bit_field" version = "0.10.0" @@ -90,12 +96,50 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6" +[[package]] +name = "num-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + [[package]] name = "pin-utils" version = "0.1.0-alpha.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" +[[package]] +name = "proc-macro2" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + [[package]] name = "r0" version = "1.0.0" @@ -109,6 +153,8 @@ dependencies = [ "libasync", "libboard_zynq", "libsupport_zynq", + "num-derive", + "num-traits", ] [[package]] @@ -122,6 +168,23 @@ dependencies = [ "managed", ] +[[package]] +name = "syn" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + [[package]] name = "vcell" version = "0.1.2" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 68c44ec1..4c310452 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -13,3 +13,8 @@ default = ["target_zc706"] libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libsupport_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libasync = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } +num-derive = "0.3" + +[dependencies.num-traits] +version = "0.2" +default-features = false diff --git a/runtime/src/network.rs b/runtime/src/network.rs index 2bde3d2d..ab81dc4a 100644 --- a/runtime/src/network.rs +++ b/runtime/src/network.rs @@ -1,6 +1,9 @@ use core::{mem::transmute, task::Poll}; +use core::fmt; + +use num_derive::{FromPrimitive, ToPrimitive}; +use num_traits::{FromPrimitive, ToPrimitive}; -use alloc::{borrow::ToOwned, format}; use libboard_zynq::{ println, self as zynq, @@ -16,36 +19,101 @@ use libsupport_zynq::alloc::{vec, vec::Vec}; use libasync::smoltcp::{Sockets, TcpStream}; -async fn handle_connection(stream: TcpStream) -> smoltcp::Result<()> { - stream.send("Enter your name: ".bytes()).await?; - let name = stream.recv(|buf| { +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + NetworkError(smoltcp::Error), + UnexpectedPattern, + UnrecognizedPacket, + +} + +pub type Result = core::result::Result; + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Error::NetworkError(error) => write!(f, "network error: {}", error), + &Error::UnexpectedPattern => write!(f, "unexpected pattern"), + &Error::UnrecognizedPacket => write!(f, "unrecognized packet"), + } + } +} + +impl From for Error { + fn from(error: smoltcp::Error) -> Self { + Error::NetworkError(error) + } +} + + +async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<()> { + stream.recv(|buf| { for (i, b) in buf.iter().enumerate() { - if *b == '\n' as u8 { - return match core::str::from_utf8(&buf[0..i]) { - Ok(name) => - Poll::Ready((i + 1, Some(name.to_owned()))), - Err(_) => - Poll::Ready((i + 1, None)) - }; + if *b == pattern[i] { + if i + 1 == pattern.len() { + return Poll::Ready((i + 1, Ok(()))); + } + } else { + return Poll::Ready((i + 1, Err(Error::UnexpectedPattern))); } } - if buf.len() > 100 { - // Too much input, consume all - Poll::Ready((buf.len(), None)) + Poll::Pending + }).await? +} + +async fn read_u8(stream: &TcpStream) -> Result { + Ok(stream.recv(|buf| { + if buf.len() >= 1 { + Poll::Ready((1, buf[0])) } else { Poll::Pending } - }).await?; - match name { - Some(name) => - stream.send(format!("Hello {}!\n", name).bytes()).await?, - None => - stream.send("I had trouble reading your name.\n".bytes()).await?, - } - stream.flush().await; + }).await?) +} + +#[derive(FromPrimitive, ToPrimitive)] +enum Request { + SystemInfo = 3, + LoadKernel = 5, + RunKernel = 6, + RPCReply = 7, + RPCException = 8, +} + +#[derive(FromPrimitive, ToPrimitive)] +enum Reply { + SystemInfo = 2, + LoadCompleted = 5, + LoadFailed = 6, + KernelFinished = 7, + KernelStartupFailed = 8, + KernelException = 9, + RPCRequest = 10, + WatchdogExpired = 14, + ClockFailure = 15, +} + +async fn send_header(stream: &TcpStream, reply: Reply) -> Result<()> { + stream.send([0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()].iter().copied()).await?; Ok(()) } +async fn handle_connection(stream: TcpStream) -> Result<()> { + expect(&stream, b"ARTIQ coredev\n").await?; + loop { + expect(&stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await?; + let request: Request = FromPrimitive::from_u8(read_u8(&stream).await?) + .ok_or(Error::UnrecognizedPacket)?; + match request { + Request::SystemInfo => { + send_header(&stream, Reply::SystemInfo).await?; + stream.send("ARZQ".bytes()).await?; + }, + _ => return Err(Error::UnrecognizedPacket) + } + } +} + const HWADDR: [u8; 6] = [0, 0x23, 0xab, 0xad, 0x1d, 0xea]; const IPADDR: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 52])); @@ -89,7 +157,7 @@ pub fn network_main() { TcpStream::listen(1381, 2048, 2048, 8, |stream| async { let _ = handle_connection(stream) .await - .map_err(|e| println!("Connection: {:?}", e)); + .map_err(|e| println!("Connection: {}", e)); }); let mut time = 0u32;