Rust: implement moninj.

This commit is contained in:
whitequark 2016-10-04 12:38:52 +00:00
parent 2e4d19a1ce
commit 2fefd0ad4a
7 changed files with 308 additions and 57 deletions

View File

@ -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<T, F>(err: lwip_sys::err, f: F) -> Result<T>
#[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 }

View File

@ -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();

View File

@ -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)
}
}
}

View File

@ -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<TtlMode> {
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<Request> {
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(())
}
}

View File

@ -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<u8> {
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<u16> {
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<u32> {
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<u64> {
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)
}

View File

@ -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<u8>) -> Result<SocketAddr> {
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<usize> {

View File

@ -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<u8> {
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<u32> {
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<u64> {
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<Vec<u8>> {
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"))
})
}
}