forked from M-Labs/artiq
Rust: implement moninj.
This commit is contained in:
parent
2e4d19a1ce
commit
2fefd0ad4a
@ -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 }
|
||||
|
@ -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();
|
||||
|
124
artiq/runtime.rs/src/moninj.rs
Normal file
124
artiq/runtime.rs/src/moninj.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
65
artiq/runtime.rs/src/moninj_proto.rs
Normal file
65
artiq/runtime.rs/src/moninj_proto.rs
Normal 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(())
|
||||
}
|
||||
}
|
52
artiq/runtime.rs/src/proto.rs
Normal file
52
artiq/runtime.rs/src/proto.rs
Normal 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)
|
||||
}
|
@ -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> {
|
||||
|
@ -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"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user