Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b590c6c7d865
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2fefd0ad4af3
Choose a head ref
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on Oct 4, 2016

  1. Copy the full SHA
    2e4d19a View commit details
  2. Rust: implement moninj.

    whitequark committed Oct 4, 2016
    Copy the full SHA
    2fefd0a View commit details
66 changes: 54 additions & 12 deletions artiq/runtime.rs/liblwip/lib.rs
Original file line number Diff line number Diff line change
@@ -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,15 +159,15 @@ 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),
(segments[4] as u32) << 16 | (segments[5] as u32),
(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 }
6 changes: 5 additions & 1 deletion artiq/runtime.rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 124 additions & 0 deletions artiq/runtime.rs/src/moninj.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 65 additions & 0 deletions artiq/runtime.rs/src/moninj_proto.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 52 additions & 0 deletions artiq/runtime.rs/src/proto.rs
Original file line number Diff line number Diff line change
@@ -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)
}
Loading