diff --git a/artiq/runtime.rs/liblwip/lib.rs b/artiq/runtime.rs/liblwip/lib.rs index 4a6e1b3c1..81c874bc6 100644 --- a/artiq/runtime.rs/liblwip/lib.rs +++ b/artiq/runtime.rs/liblwip/lib.rs @@ -9,6 +9,7 @@ extern crate std_artiq as std; use core::marker::PhantomData; use core::cell::RefCell; +use core::fmt; use alloc::boxed::Box; use collections::LinkedList; use libc::c_void; @@ -102,19 +103,54 @@ fn result_from(err: lwip_sys::err, f: F) -> Result #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum IpAddr { - Ip4([u8; 4]), - Ip6([u16; 8]), - IpAny + V4([u8; 4]), + V6([u16; 8]), + Any } -pub const IP4_ANY: IpAddr = IpAddr::Ip4([0, 0, 0, 0]); -pub const IP6_ANY: IpAddr = IpAddr::Ip6([0, 0, 0, 0, 0, 0, 0, 0]); -pub const IP_ANY: IpAddr = IpAddr::IpAny; +pub const IP4_ANY: IpAddr = IpAddr::V4([0, 0, 0, 0]); +pub const IP6_ANY: IpAddr = IpAddr::V6([0, 0, 0, 0, 0, 0, 0, 0]); +pub const IP_ANY: IpAddr = IpAddr::Any; + +impl fmt::Display for IpAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + IpAddr::V4(ref octets) => + write!(f, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]), + + IpAddr::V6(ref segments) => { + #[derive(Clone, Copy, PartialEq, Eq)] + enum State { Head, Skip, Tail }; + + let mut state = State::Head; + for (idx, &segment) in segments.iter().enumerate() { + match state { + State::Head | State::Skip if segment == 0 => + state = State::Skip, + State::Skip if segment != 0 => { + state = State::Tail; + try!(write!(f, ":{:x}", segment)) + } + _ => try!(write!(f, "{:x}", segment)) + } + + if state != State::Skip && idx != 15 { + try!(write!(f, ":")) + } + } + Ok(()) + }, + + IpAddr::Any => + write!(f, "*") + } + } +} impl IpAddr { fn into_raw(self) -> lwip_sys::ip_addr { match self { - IpAddr::Ip4(ref octets) => + IpAddr::V4(octets) => lwip_sys::ip_addr { data: [(octets[0] as u32) << 24 | (octets[1] as u32) << 16 | @@ -123,7 +159,7 @@ impl IpAddr { 0, 0, 0], type_: lwip_sys::IPADDR_TYPE_V4 }, - IpAddr::Ip6(ref segments) => + IpAddr::V6(segments) => lwip_sys::ip_addr { data: [(segments[0] as u32) << 16 | (segments[1] as u32), (segments[2] as u32) << 16 | (segments[3] as u32), @@ -131,7 +167,7 @@ impl IpAddr { (segments[6] as u32) << 16 | (segments[7] as u32)], type_: lwip_sys::IPADDR_TYPE_V6 }, - IpAddr::IpAny => + IpAddr::Any => lwip_sys::ip_addr { data: [0; 4], type_: lwip_sys::IPADDR_TYPE_ANY @@ -142,17 +178,17 @@ impl IpAddr { unsafe fn from_raw(raw: *mut lwip_sys::ip_addr) -> IpAddr { match *raw { lwip_sys::ip_addr { type_: lwip_sys::IPADDR_TYPE_V4, data } => - IpAddr::Ip4([(data[0] >> 24) as u8, + IpAddr::V4([(data[0] >> 24) as u8, (data[0] >> 16) as u8, (data[0] >> 8) as u8, (data[0] >> 0) as u8]), lwip_sys::ip_addr { type_: lwip_sys::IPADDR_TYPE_V6, data } => - IpAddr::Ip6([(data[0] >> 16) as u16, data[0] as u16, + IpAddr::V6([(data[0] >> 16) as u16, data[0] as u16, (data[1] >> 16) as u16, data[1] as u16, (data[2] >> 16) as u16, data[2] as u16, (data[3] >> 16) as u16, data[3] as u16]), lwip_sys::ip_addr { type_: lwip_sys::IPADDR_TYPE_ANY, .. } => - IpAddr::IpAny + IpAddr::Any } } } @@ -163,6 +199,12 @@ pub struct SocketAddr { pub port: u16 } +impl fmt::Display for SocketAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}:{}", self.ip, self.port) + } +} + impl SocketAddr { pub fn new(ip: IpAddr, port: u16) -> SocketAddr { SocketAddr { ip: ip, port: port } diff --git a/artiq/runtime.rs/src/lib.rs b/artiq/runtime.rs/src/lib.rs index 5d73b8a17..0e1860f48 100644 --- a/artiq/runtime.rs/src/lib.rs +++ b/artiq/runtime.rs/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(libc, const_fn, try_borrow)] +#![feature(libc, const_fn, try_borrow, stmt_expr_attributes)] #[macro_use] extern crate std_artiq as std; @@ -24,11 +24,14 @@ mod sched; mod logger; mod cache; +mod proto; mod kernel_proto; mod session_proto; +mod moninj_proto; mod kernel; mod session; +mod moninj; extern { fn network_init(); @@ -52,6 +55,7 @@ pub unsafe extern fn rust_main() { let mut scheduler = sched::Scheduler::new(); scheduler.spawner().spawn(8192, session::thread); + scheduler.spawner().spawn(4096, moninj::thread); loop { scheduler.run(); diff --git a/artiq/runtime.rs/src/moninj.rs b/artiq/runtime.rs/src/moninj.rs new file mode 100644 index 000000000..13c8ef4cd --- /dev/null +++ b/artiq/runtime.rs/src/moninj.rs @@ -0,0 +1,124 @@ +use std::vec::Vec; +use std::io; +use board::csr; +use sched::{Waiter, Spawner}; +use sched::{UdpSocket, SocketAddr, IP_ANY}; +use moninj_proto::*; + +const MONINJ_TTL_OVERRIDE_ENABLE: u8 = 0; +const MONINJ_TTL_OVERRIDE_O: u8 = 1; +const MONINJ_TTL_OVERRIDE_OE: u8 = 2; + +fn worker(socket: &mut UdpSocket) -> io::Result<()> { + let mut buf = Vec::new(); + loop { + let addr = try!(socket.recv_from(&mut buf)); + let request = try!(Request::read_from(&mut io::Cursor::new(&buf))); + trace!("{} -> {:?}", addr, request); + + match request { + Request::Monitor => { + let mut dds_ftws = [0; (csr::CONFIG_RTIO_DDS_COUNT as usize * + csr::CONFIG_DDS_CHANNELS_PER_BUS as usize)]; + let mut reply = Reply::default(); + + for i in 0..csr::CONFIG_RTIO_REGULAR_TTL_COUNT as u8 { + unsafe { + csr::rtio_moninj::mon_chan_sel_write(i); + csr::rtio_moninj::mon_probe_sel_write(0); + csr::rtio_moninj::mon_value_update_write(1); + if csr::rtio_moninj::mon_value_read() != 0 { + reply.ttl_levels |= 1 << i; + } + csr::rtio_moninj::mon_probe_sel_write(1); + csr::rtio_moninj::mon_value_update_write(1); + if csr::rtio_moninj::mon_value_read() != 0 { + reply.ttl_oes |= 1 << i; + } + csr::rtio_moninj::inj_chan_sel_write(i); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE); + if csr::rtio_moninj::inj_value_read() != 0 { + reply.ttl_overrides |= 1 << i; + } + } + } + + reply.dds_rtio_first_channel = csr::CONFIG_RTIO_FIRST_DDS_CHANNEL as u16; + reply.dds_channels_per_bus = csr::CONFIG_DDS_CHANNELS_PER_BUS as u16; + + for j in 0..csr::CONFIG_RTIO_DDS_COUNT { + unsafe { + csr::rtio_moninj::mon_chan_sel_write( + (csr::CONFIG_RTIO_FIRST_DDS_CHANNEL + j) as u8); + for i in 0..csr::CONFIG_DDS_CHANNELS_PER_BUS { + csr::rtio_moninj::mon_probe_sel_write(i as u8); + csr::rtio_moninj::mon_value_update_write(1); + dds_ftws[(csr::CONFIG_DDS_CHANNELS_PER_BUS * j + i) as usize] = + csr::rtio_moninj::mon_value_read(); + } + } + } + reply.dds_ftws = &dds_ftws; + + trace!("{} <- {:?}", addr, reply); + buf.clear(); + try!(reply.write_to(&mut buf)); + try!(socket.send_to(&buf, addr)); + }, + + Request::TtlSet { channel, mode: TtlMode::Experiment } => { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE); + csr::rtio_moninj::inj_value_write(0); + } + }, + + Request::TtlSet { channel, mode: TtlMode::High } => { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_O); + csr::rtio_moninj::inj_value_write(1); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_OE); + csr::rtio_moninj::inj_value_write(1); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE); + csr::rtio_moninj::inj_value_write(1); + } + }, + + Request::TtlSet { channel, mode: TtlMode::Low } => { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_O); + csr::rtio_moninj::inj_value_write(0); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_OE); + csr::rtio_moninj::inj_value_write(1); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE); + csr::rtio_moninj::inj_value_write(1); + } + }, + + Request::TtlSet { channel, mode: TtlMode::Input } => { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_OE); + csr::rtio_moninj::inj_value_write(0); + csr::rtio_moninj::inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE); + csr::rtio_moninj::inj_value_write(1); + } + } + } + } +} + +pub fn thread(waiter: Waiter, _spawner: Spawner) { + let mut socket = UdpSocket::new(waiter).expect("cannot create socket"); + socket.bind(SocketAddr::new(IP_ANY, 3250)).expect("cannot bind socket"); + + loop { + match worker(&mut socket) { + Ok(()) => unreachable!(), + Err(err) => error!("moninj aborted: {}", err) + } + } +} diff --git a/artiq/runtime.rs/src/moninj_proto.rs b/artiq/runtime.rs/src/moninj_proto.rs new file mode 100644 index 000000000..2dd613a6e --- /dev/null +++ b/artiq/runtime.rs/src/moninj_proto.rs @@ -0,0 +1,65 @@ +use std::io::{self, Read, Write}; +use proto::*; + +#[derive(Debug)] +pub enum TtlMode { + Experiment, + High, + Low, + Input +} + +impl TtlMode { + pub fn read_from(reader: &mut Read) -> io::Result { + Ok(match try!(read_u8(reader)) { + 0 => TtlMode::Experiment, + 1 => TtlMode::High, + 2 => TtlMode::Low, + 3 => TtlMode::Input, + _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown TTL mode")) + }) + } +} + +#[derive(Debug)] +pub enum Request { + Monitor, + TtlSet { channel: u8, mode: TtlMode } +} + +impl Request { + pub fn read_from(reader: &mut Read) -> io::Result { + Ok(match try!(read_u8(reader)) { + 1 => Request::Monitor, + 2 => Request::TtlSet { + channel: try!(read_u8(reader)), + mode: try!(TtlMode::read_from(reader)) + }, + _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type")) + }) + } +} + +#[derive(Debug, Default)] +pub struct Reply<'a> { + pub ttl_levels: u64, + pub ttl_oes: u64, + pub ttl_overrides: u64, + pub dds_rtio_first_channel: u16, + pub dds_channels_per_bus: u16, + pub dds_ftws: &'a [u32] +} + +impl<'a> Reply<'a> { + pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { + try!(write_u64(writer, self.ttl_levels)); + try!(write_u64(writer, self.ttl_oes)); + try!(write_u64(writer, self.ttl_overrides)); + try!(write_u16(writer, self.dds_rtio_first_channel)); + try!(write_u16(writer, self.dds_channels_per_bus)); + for dds_ftw in self.dds_ftws { + try!(write_u32(writer, *dds_ftw)); + } + Ok(()) + } +} diff --git a/artiq/runtime.rs/src/proto.rs b/artiq/runtime.rs/src/proto.rs new file mode 100644 index 000000000..acb22998b --- /dev/null +++ b/artiq/runtime.rs/src/proto.rs @@ -0,0 +1,52 @@ +#![allow(dead_code)] + +use std::io::{self, Read, Write}; +use byteorder::{ByteOrder, NetworkEndian}; + +// FIXME: replace these with byteorder core io traits once those are in +pub fn read_u8(reader: &mut Read) -> io::Result { + let mut bytes = [0; 1]; + try!(reader.read_exact(&mut bytes)); + Ok(bytes[0]) +} + +pub fn write_u8(writer: &mut Write, value: u8) -> io::Result<()> { + let bytes = [value; 1]; + writer.write_all(&bytes) +} + +pub fn read_u16(reader: &mut Read) -> io::Result { + let mut bytes = [0; 2]; + try!(reader.read_exact(&mut bytes)); + Ok(NetworkEndian::read_u16(&bytes)) +} + +pub fn write_u16(writer: &mut Write, value: u16) -> io::Result<()> { + let mut bytes = [0; 2]; + NetworkEndian::write_u16(&mut bytes, value); + writer.write_all(&bytes) +} + +pub fn read_u32(reader: &mut Read) -> io::Result { + let mut bytes = [0; 4]; + try!(reader.read_exact(&mut bytes)); + Ok(NetworkEndian::read_u32(&bytes)) +} + +pub fn write_u32(writer: &mut Write, value: u32) -> io::Result<()> { + let mut bytes = [0; 4]; + NetworkEndian::write_u32(&mut bytes, value); + writer.write_all(&bytes) +} + +pub fn read_u64(reader: &mut Read) -> io::Result { + let mut bytes = [0; 8]; + try!(reader.read_exact(&mut bytes)); + Ok(NetworkEndian::read_u64(&bytes)) +} + +pub fn write_u64(writer: &mut Write, value: u64) -> io::Result<()> { + let mut bytes = [0; 8]; + NetworkEndian::write_u64(&mut bytes, value); + writer.write_all(&bytes) +} diff --git a/artiq/runtime.rs/src/sched.rs b/artiq/runtime.rs/src/sched.rs index 4737ee0c6..ef4c8876f 100644 --- a/artiq/runtime.rs/src/sched.rs +++ b/artiq/runtime.rs/src/sched.rs @@ -328,12 +328,12 @@ impl<'a> UdpSocket<'a> { Ok(buf.len()) } - pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> { + pub fn recv_from(&self, buf: &mut Vec) -> Result { try!(self.waiter.udp_readable(&self.lower)); let (pbuf, addr) = self.lower.try_recv().unwrap(); - let len = ::std::cmp::min(buf.len(), pbuf.len()); - (&mut buf[..len]).copy_from_slice(&pbuf.as_slice()[..len]); - Ok((len, addr)) + buf.clear(); + buf.extend_from_slice(&pbuf.as_slice()); + Ok(addr) } pub fn send(&self, buf: &[u8]) -> Result { diff --git a/artiq/runtime.rs/src/session_proto.rs b/artiq/runtime.rs/src/session_proto.rs index b3b90d8b5..d2118f911 100644 --- a/artiq/runtime.rs/src/session_proto.rs +++ b/artiq/runtime.rs/src/session_proto.rs @@ -1,42 +1,6 @@ use std::prelude::v1::*; use std::io::{self, Read, Write}; -use byteorder::{ByteOrder, NetworkEndian}; - -// FIXME: replace these with byteorder core io traits once those are in -fn read_u8(reader: &mut Read) -> io::Result { - let mut bytes = [0; 1]; - try!(reader.read_exact(&mut bytes)); - Ok(bytes[0]) -} - -fn write_u8(writer: &mut Write, value: u8) -> io::Result<()> { - let bytes = [value; 1]; - writer.write_all(&bytes) -} - -fn read_u32(reader: &mut Read) -> io::Result { - let mut bytes = [0; 4]; - try!(reader.read_exact(&mut bytes)); - Ok(NetworkEndian::read_u32(&bytes)) -} - -fn write_u32(writer: &mut Write, value: u32) -> io::Result<()> { - let mut bytes = [0; 4]; - NetworkEndian::write_u32(&mut bytes, value); - writer.write_all(&bytes) -} - -fn read_u64(reader: &mut Read) -> io::Result { - let mut bytes = [0; 4]; - try!(reader.read_exact(&mut bytes)); - Ok(NetworkEndian::read_u64(&bytes)) -} - -fn write_u64(writer: &mut Write, value: u64) -> io::Result<()> { - let mut bytes = [0; 4]; - NetworkEndian::write_u64(&mut bytes, value); - writer.write_all(&bytes) -} +use proto::*; fn read_bytes(reader: &mut Read) -> io::Result> { let length = try!(read_u32(reader)); @@ -140,9 +104,9 @@ impl Request { try!(read_sync(reader)); let length = try!(read_u32(reader)) as usize; - let type_ = try!(read_u8(reader)); + let ty = try!(read_u8(reader)); - Ok(match type_ { + Ok(match ty { 1 => Request::Log, 2 => Request::LogClear, 3 => Request::Ident, @@ -168,7 +132,7 @@ impl Request { 12 => Request::FlashRemove { key: try!(read_string(reader)) }, - _ => unreachable!() + _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type")) }) } }