firmware: integrate smoltcp instead of lwip.

pull/668/head
whitequark 2017-01-16 14:15:24 +00:00
parent 0253e0a89d
commit 527b1e986c
26 changed files with 639 additions and 2008 deletions

4
.gitmodules vendored
View File

@ -1,4 +0,0 @@
[submodule "artiq/runtime/lwip"]
path = artiq/runtime/lwip
url = https://github.com/m-labs/lwip
ignore = untracked

View File

@ -19,7 +19,7 @@ dependencies = [
[[package]]
name = "byteorder"
version = "0.5.3"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -45,7 +45,7 @@ version = "0.0.0"
dependencies = [
"alloc_none 0.0.0",
"board 0.0.0",
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"std_artiq 0.0.0",
]
@ -65,16 +65,9 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lwip"
version = "0.0.0"
dependencies = [
"lwip-sys 0.0.0",
"std_artiq 0.0.0",
]
[[package]]
name = "lwip-sys"
version = "0.0.0"
name = "managed"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "runtime"
@ -82,11 +75,11 @@ version = "0.0.0"
dependencies = [
"alloc_artiq 0.0.0",
"board 0.0.0",
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fringe 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lwip 0.0.0",
"smoltcp 0.1.0 (git+https://github.com/m-labs/smoltcp?rev=d57b42c)",
"std_artiq 0.0.0",
"walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -103,6 +96,16 @@ dependencies = [
"walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "smoltcp"
version = "0.1.0"
source = "git+https://github.com/m-labs/smoltcp?rev=d57b42c#d57b42ca93677e392990df3517c7548853da5192"
dependencies = [
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"managed 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "walkdir"
version = "1.0.3"
@ -123,12 +126,14 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
"checksum fringe 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "987689dcfad85eee8d76b477865641ec483e63fb86d52966bfc350c4a647d78a"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493"
"checksum managed 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5981b4c6de5ce272aaf2caaa56adb8f6fd24a73206b38302db572ab9374aab10"
"checksum smoltcp 0.1.0 (git+https://github.com/m-labs/smoltcp?rev=d57b42c)" = "<none>"
"checksum walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd7c16466ecc507c7cb5988db03e6eab4aaeab89a5c37a29251fcfd3ac9b7afe"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View File

@ -13,4 +13,4 @@ crate-type = ["staticlib"]
alloc_none = { path = "../liballoc_none" }
std_artiq = { path = "../libstd_artiq" }
board = { path = "../libboard" }
byteorder = { version = "0.5", default-features = false }
byteorder = { version = "1.0", default-features = false }

View File

@ -1,8 +0,0 @@
[package]
authors = ["M-Labs"]
name = "lwip-sys"
version = "0.0.0"
[lib]
name = "lwip_sys"
path = "lib.rs"

View File

@ -1,166 +0,0 @@
#![no_std]
#![feature(libc)]
#![allow(non_camel_case_types)]
extern crate libc;
pub use err::*;
pub use pbuf_layer::*;
pub use pbuf_type::*;
pub use ip_addr_type::*;
use libc::{c_void, c_int};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i8)]
pub enum err {
ERR_OK = 0,
ERR_MEM = -1,
ERR_BUF = -2,
ERR_TIMEOUT = -3,
ERR_RTE = -4,
ERR_INPROGRESS = -5,
ERR_VAL = -6,
ERR_WOULDBLOCK = -7,
ERR_USE = -8,
ERR_ALREADY = -9,
ERR_ISCONN = -10,
ERR_CONN = -11,
ERR_IF = -12,
ERR_ABRT = -13,
ERR_RST = -14,
ERR_CLSD = -15,
ERR_ARG = -16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum pbuf_layer {
PBUF_TRANSPORT,
PBUF_IP,
PBUF_LINK,
PBUF_RAW_TX,
PBUF_RAW
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum pbuf_type {
PBUF_RAM,
PBUF_ROM,
PBUF_REF,
PBUF_POOL,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ip_addr_type {
IPADDR_TYPE_V4 = 0,
IPADDR_TYPE_V6 = 6,
IPADDR_TYPE_ANY = 46,
}
#[repr(C)]
pub struct pbuf {
pub next: *mut pbuf,
pub payload: *mut c_void,
pub tot_len: u16,
pub len: u16,
pub type_: pbuf_type,
pub flags: u8,
pub ref_: u16
}
#[derive(Clone)]
#[repr(C)]
pub struct ip4_addr {
pub addr: u32
}
#[derive(Clone)]
#[repr(C)]
pub struct ip6_addr {
pub addr: [u32; 4]
}
#[derive(Clone)]
#[repr(C)]
pub struct ip_addr {
pub data: [u32; 4],
pub type_: ip_addr_type
}
#[repr(C)]
pub struct tcp_pcb {
__opaque: c_void
}
#[repr(C)]
pub struct udp_pcb {
__opaque: c_void
}
pub const TCP_WRITE_FLAG_COPY: u8 = 0x01;
pub const TCP_WRITE_FLAG_MORE: u8 = 0x02;
pub const SOF_REUSEADDR: u8 = 0x04;
pub const SOF_KEEPALIVE: u8 = 0x08;
pub const SOF_BROADCAST: u8 = 0x20;
extern {
pub fn pbuf_alloc(l: pbuf_layer, length: u16, type_: pbuf_type) -> *mut pbuf;
pub fn pbuf_realloc(p: *mut pbuf, length: u16);
pub fn pbuf_ref(p: *mut pbuf);
pub fn pbuf_free(p: *mut pbuf);
pub fn pbuf_cat(head: *mut pbuf, tail: *mut pbuf);
pub fn pbuf_chain(head: *mut pbuf, tail: *mut pbuf);
pub fn pbuf_dechain(p: *mut pbuf) -> *mut pbuf;
pub fn pbuf_copy(p_to: *mut pbuf, p_from: *mut pbuf) -> err;
pub fn pbuf_copy_partial(p: *mut pbuf, dataptr: *mut c_void, len: u16, offset: u16) -> u16;
pub fn pbuf_take(p: *mut pbuf, dataptr: *const c_void, len: u16) -> err;
pub fn pbuf_take_at(p: *mut pbuf, dataptr: *const c_void, len: u16, offset: u16) -> err;
pub fn pbuf_skip(in_: *mut pbuf, in_offset: u16, out_offset: *mut u16) -> *mut pbuf;
pub fn tcp_new() -> *mut tcp_pcb;
pub fn tcp_arg(pcb: *mut tcp_pcb, arg: *mut c_void);
pub fn tcp_bind(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn tcp_listen_with_backlog(pcb: *mut tcp_pcb, backlog: u8) -> *mut tcp_pcb;
pub fn tcp_accept(pcb: *mut tcp_pcb,
accept: Option<extern fn(arg: *mut c_void, newpcb: *mut tcp_pcb,
err: err) -> err>);
pub fn tcp_connect(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16,
connected: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, err: err)) -> err;
pub fn tcp_write(pcb: *mut tcp_pcb, dataptr: *const c_void, len: u16, apiflags: u8) -> err;
pub fn tcp_sent(pcb: *mut tcp_pcb,
sent: Option<extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, len: u16) -> err>);
pub fn tcp_recv(pcb: *mut tcp_pcb,
recv: Option<extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, p: *mut pbuf,
err: err) -> err>);
pub fn tcp_recved(pcb: *mut tcp_pcb, len: u16);
pub fn tcp_poll(pcb: *mut tcp_pcb,
poll: Option<extern fn(arg: *mut c_void, tcb: *mut tcp_pcb)>,
interval: u8);
pub fn tcp_shutdown(pcb: *mut tcp_pcb, shut_rx: c_int, shut_tx: c_int) -> err;
pub fn tcp_close(pcb: *mut tcp_pcb) -> err;
pub fn tcp_abort(pcb: *mut tcp_pcb);
pub fn tcp_err(pcb: *mut tcp_pcb,
err: Option<extern fn(arg: *mut c_void, err: err)>);
// nonstandard
pub fn tcp_sndbuf_(pcb: *mut tcp_pcb) -> u16;
pub fn tcp_so_options_(pcb: *mut tcp_pcb) -> *mut u8;
pub fn tcp_nagle_disable_(pcb: *mut tcp_pcb);
pub fn udp_new() -> *mut udp_pcb;
pub fn udp_new_ip_type(type_: ip_addr_type) -> *mut udp_pcb;
pub fn udp_remove(pcb: *mut udp_pcb);
pub fn udp_bind(pcb: *mut udp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn udp_connect(pcb: *mut udp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn udp_disconnect(pcb: *mut udp_pcb) -> err;
pub fn udp_send(pcb: *mut udp_pcb, p: *mut pbuf) -> err;
pub fn udp_sendto(pcb: *mut udp_pcb, p: *mut pbuf, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn udp_recv(pcb: *mut udp_pcb,
recv: Option<extern fn(arg: *mut c_void, upcb: *mut udp_pcb, p: *mut pbuf,
addr: *mut ip_addr, port: u16)>,
recv_arg: *mut c_void);
}

View File

@ -1,16 +0,0 @@
[package]
authors = ["M-Labs"]
name = "lwip"
version = "0.0.0"
[lib]
name = "lwip"
path = "lib.rs"
[dependencies]
lwip-sys = { path = "../liblwip-sys" }
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
[features]
default = ["preemption"]
preemption = []

View File

@ -1,645 +0,0 @@
#![feature(alloc, collections, libc)]
#![no_std]
extern crate alloc;
extern crate collections;
extern crate libc;
extern crate lwip_sys;
extern crate std_artiq as std;
use core::marker::PhantomData;
use core::ptr;
use core::cell::RefCell;
use core::fmt;
use alloc::boxed::Box;
use collections::LinkedList;
use libc::c_void;
use std::error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
OutOfMemory,
Buffer,
Timeout,
Routing,
InProgress,
IllegalValue,
WouldBlock,
AddressInUse,
AlreadyConnecting,
AlreadyConnected,
NotConnected,
Interface,
ConnectionAborted,
ConnectionReset,
ConnectionClosed,
IllegalArgument,
// Not used by lwip; added for building blocking interfaces.
Interrupted
}
impl Error {
fn as_str(&self) -> &str {
match *self {
Error::OutOfMemory => "out of memory error",
Error::Buffer => "buffer error",
Error::Timeout => "timeout",
Error::Routing => "routing error",
Error::InProgress => "operation in progress",
Error::IllegalValue => "illegal value",
Error::WouldBlock => "operation would block",
Error::AddressInUse => "address in use",
Error::AlreadyConnecting => "already connecting",
Error::AlreadyConnected => "already connected",
Error::NotConnected => "not connected",
Error::Interface => "low-level netif error",
Error::ConnectionAborted => "connection aborted",
Error::ConnectionReset => "connection reset",
Error::ConnectionClosed => "connection closed",
Error::IllegalArgument => "illegal argument",
Error::Interrupted => "interrupted"
}
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl error::Error for Error {
fn description(&self) -> &str {
self.as_str()
}
}
impl From<Error> for std::io::Error {
fn from(lower: Error) -> std::io::Error {
use std::io;
match lower {
Error::Interrupted => io::Error::new(io::ErrorKind::Interrupted, "interrupted"),
err => io::Error::new(io::ErrorKind::Other, err)
}
}
}
pub type Result<T> = core::result::Result<T, Error>;
fn result_from<T, F>(err: lwip_sys::err, f: F) -> Result<T>
where F: FnOnce() -> T {
match err {
lwip_sys::ERR_OK => Ok(f()),
lwip_sys::ERR_MEM => Err(Error::OutOfMemory),
lwip_sys::ERR_BUF => Err(Error::Buffer),
lwip_sys::ERR_TIMEOUT => Err(Error::Timeout),
lwip_sys::ERR_RTE => Err(Error::Routing),
lwip_sys::ERR_INPROGRESS => Err(Error::InProgress),
lwip_sys::ERR_VAL => Err(Error::IllegalValue),
lwip_sys::ERR_WOULDBLOCK => Err(Error::WouldBlock),
lwip_sys::ERR_USE => Err(Error::AddressInUse),
lwip_sys::ERR_ALREADY => Err(Error::AlreadyConnecting),
lwip_sys::ERR_ISCONN => Err(Error::AlreadyConnected),
lwip_sys::ERR_CONN => Err(Error::NotConnected),
lwip_sys::ERR_IF => Err(Error::Interface),
lwip_sys::ERR_ABRT => Err(Error::ConnectionAborted),
lwip_sys::ERR_RST => Err(Error::ConnectionReset),
lwip_sys::ERR_CLSD => Err(Error::ConnectionClosed),
lwip_sys::ERR_ARG => Err(Error::IllegalArgument),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum IpAddr {
V4([u8; 4]),
V6([u16; 8]),
Any
}
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::V4(octets) =>
lwip_sys::ip_addr {
data: [(octets[0] as u32) << 24 |
(octets[1] as u32) << 16 |
(octets[2] as u32) << 8 |
(octets[3] as u32) << 0,
0, 0, 0],
type_: lwip_sys::IPADDR_TYPE_V4
},
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::Any =>
lwip_sys::ip_addr {
data: [0; 4],
type_: lwip_sys::IPADDR_TYPE_ANY
}
}
}
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::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::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::Any
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SocketAddr {
pub ip: IpAddr,
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 }
}
}
#[derive(Debug)]
pub struct Pbuf<'payload> {
raw: *mut lwip_sys::pbuf,
phantom: PhantomData<&'payload [u8]>
}
#[cfg(not(feature = "preemption"))]
unsafe impl<'payload> Send for Pbuf<'payload> {}
impl<'payload> Pbuf<'payload> {
unsafe fn from_raw(raw: *mut lwip_sys::pbuf) -> Pbuf<'payload> {
Pbuf { raw: raw, phantom: PhantomData }
}
fn as_raw(&self) -> *mut lwip_sys::pbuf {
self.raw
}
#[allow(dead_code)]
fn into_raw(self) -> *mut lwip_sys::pbuf {
let raw = self.raw;
core::mem::forget(self);
raw
}
fn from_slice_with_type<'a>(slice: &'a [u8], type_: lwip_sys::pbuf_type) -> Pbuf<'a> {
assert!(slice.len() <= core::u16::MAX as usize);
unsafe {
let raw = lwip_sys::pbuf_alloc(lwip_sys::PBUF_RAW, slice.len() as u16, type_);
(*raw).payload = slice.as_ptr() as *mut u8 as *mut c_void;
Pbuf { raw: raw, phantom: PhantomData }
}
}
pub fn from_slice(slice: &'payload [u8]) -> Pbuf<'payload> {
Self::from_slice_with_type(slice, lwip_sys::PBUF_REF)
}
pub fn from_static_slice(slice: &'static [u8]) -> Pbuf<'static> {
// Avoids a copy.
Self::from_slice_with_type(slice, lwip_sys::PBUF_ROM)
}
pub fn len(&self) -> usize {
unsafe { (*self.raw).len as usize }
}
pub fn as_slice(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts((*self.raw).payload as *const u8,
(*self.raw).len as usize)
}
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe {
core::slice::from_raw_parts_mut((*self.raw).payload as *mut u8,
(*self.raw).len as usize)
}
}
pub fn concat(&mut self, tail: Pbuf<'payload>) {
unsafe { lwip_sys::pbuf_cat(self.raw, tail.raw) }
}
pub fn chain(&mut self, tail: &mut Pbuf<'payload>) {
unsafe { lwip_sys::pbuf_chain(self.raw, tail.raw) }
}
}
impl<'a> Drop for Pbuf<'a> {
fn drop(&mut self) {
unsafe { lwip_sys::pbuf_free(self.raw) }
}
}
#[derive(Debug)]
pub struct UdpSocketState {
recv_buffer: LinkedList<(Pbuf<'static>, SocketAddr)>
}
impl UdpSocketState {
pub fn readable(&self) -> bool {
!self.recv_buffer.is_empty()
}
}
#[derive(Debug)]
pub struct UdpSocket {
raw: *mut lwip_sys::udp_pcb,
state: Box<RefCell<UdpSocketState>>
}
#[cfg(not(feature = "preemption"))]
unsafe impl Send for UdpSocket {}
impl UdpSocket {
pub fn new() -> Result<UdpSocket> {
extern fn recv(arg: *mut c_void, _pcb: *mut lwip_sys::udp_pcb,
pbuf: *mut lwip_sys::pbuf,
addr: *mut lwip_sys::ip_addr, port: u16) {
unsafe {
let state = arg as *mut RefCell<UdpSocketState>;
let socket_addr = SocketAddr { ip: IpAddr::from_raw(addr), port: port };
(*state).borrow_mut().recv_buffer.push_back((Pbuf::from_raw(pbuf), socket_addr));
}
}
unsafe {
let raw = lwip_sys::udp_new();
if raw.is_null() { return Err(Error::OutOfMemory) }
let mut state = Box::new(RefCell::new(UdpSocketState {
recv_buffer: LinkedList::new()
}));
let arg = &mut *state as *mut RefCell<UdpSocketState> as *mut _;
lwip_sys::udp_recv(raw, Some(recv), arg);
Ok(UdpSocket { raw: raw, state: state })
}
}
pub fn state(&self) -> &RefCell<UdpSocketState> {
&*self.state
}
pub fn bind(&self, addr: SocketAddr) -> Result<()> {
result_from(unsafe {
lwip_sys::udp_bind(self.raw, &mut addr.ip.into_raw(), addr.port)
}, || ())
}
pub fn connect(&self, addr: SocketAddr) -> Result<()> {
result_from(unsafe {
lwip_sys::udp_connect(self.raw, &mut addr.ip.into_raw(), addr.port)
}, || ())
}
pub fn disconnect(&self) -> Result<()> {
result_from(unsafe {
lwip_sys::udp_disconnect(self.raw)
}, || ())
}
pub fn send<'a>(&'a self, pbuf: Pbuf<'a>) -> Result<()> {
result_from(unsafe {
lwip_sys::udp_send(self.raw, pbuf.as_raw())
}, || ())
}
pub fn send_to<'a>(&'a self, pbuf: Pbuf<'a>, addr: SocketAddr) -> Result<()> {
result_from(unsafe {
lwip_sys::udp_sendto(self.raw, pbuf.as_raw(),
&mut addr.ip.into_raw(), addr.port)
}, || ())
}
pub fn try_recv(&self) -> Option<(Pbuf<'static>, SocketAddr)> {
self.state.borrow_mut().recv_buffer.pop_front()
}
}
impl Drop for UdpSocket {
fn drop(&mut self) {
unsafe { lwip_sys::udp_remove(self.raw) }
}
}
#[derive(Debug)]
pub struct TcpListenerState {
backlog: LinkedList<TcpStream>
}
impl TcpListenerState {
pub fn acceptable(&self) -> bool {
!self.backlog.is_empty()
}
}
#[derive(Debug)]
pub struct TcpListener {
raw: *mut lwip_sys::tcp_pcb,
state: Box<RefCell<TcpListenerState>>
}
#[cfg(not(feature = "preemption"))]
unsafe impl Send for TcpListener {}
impl TcpListener {
pub fn bind(addr: SocketAddr) -> Result<TcpListener> {
extern fn accept(arg: *mut c_void, newpcb: *mut lwip_sys::tcp_pcb,
err: lwip_sys::err) -> lwip_sys::err {
if err != lwip_sys::ERR_OK { return err }
unsafe {
let state = arg as *mut RefCell<TcpListenerState>;
(*state).borrow_mut().backlog.push_back(TcpStream::from_raw(newpcb));
}
lwip_sys::ERR_OK
}
unsafe {
let raw = lwip_sys::tcp_new();
if raw.is_null() { return Err(Error::OutOfMemory) }
try!(result_from(lwip_sys::tcp_bind(raw, &mut addr.ip.into_raw(), addr.port),
|| ()));
let raw2 = lwip_sys::tcp_listen_with_backlog(raw, 0xff);
if raw2.is_null() {
lwip_sys::tcp_abort(raw);
return Err(Error::OutOfMemory)
}
let mut state = Box::new(RefCell::new(TcpListenerState {
backlog: LinkedList::new()
}));
let arg = &mut *state as *mut RefCell<TcpListenerState> as *mut _;
lwip_sys::tcp_arg(raw2, arg);
lwip_sys::tcp_accept(raw2, Some(accept));
Ok(TcpListener { raw: raw2, state: state })
}
}
pub fn state(&self) -> &RefCell<TcpListenerState> {
&*self.state
}
pub fn try_accept(&self) -> Option<TcpStream> {
self.state.borrow_mut().backlog.pop_front()
}
pub fn keepalive(&self) -> bool {
unsafe { *lwip_sys::tcp_so_options_(self.raw) & lwip_sys::SOF_KEEPALIVE != 0 }
}
pub fn set_keepalive(&self, keepalive: bool) {
if keepalive {
unsafe { *lwip_sys::tcp_so_options_(self.raw) |= lwip_sys::SOF_KEEPALIVE }
} else {
unsafe { *lwip_sys::tcp_so_options_(self.raw) &= !lwip_sys::SOF_KEEPALIVE }
}
}
}
impl Drop for TcpListener {
fn drop(&mut self) {
unsafe {
// tcp_close never fails on listening sockets
let _ = lwip_sys::tcp_close(self.raw);
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Shutdown {
Read,
Write,
Both,
}
#[derive(Debug)]
pub struct TcpStreamState {
recv_buffer: LinkedList<Result<Pbuf<'static>>>,
send_avail: usize,
total_sent: usize
}
impl TcpStreamState {
pub fn readable(&self) -> bool {
!self.recv_buffer.is_empty()
}
pub fn writeable(&self) -> bool {
!(self.send_avail == 0)
}
}
#[derive(Debug)]
pub struct TcpStream {
raw: *mut lwip_sys::tcp_pcb,
state: Box<RefCell<TcpStreamState>>
}
#[cfg(not(feature = "preemption"))]
unsafe impl Send for TcpStream {}
impl TcpStream {
fn from_raw(raw: *mut lwip_sys::tcp_pcb) -> TcpStream {
extern fn recv(arg: *mut c_void, _raw: *mut lwip_sys::tcp_pcb,
pbuf: *mut lwip_sys::pbuf, err: lwip_sys::err) -> lwip_sys::err {
if err != lwip_sys::ERR_OK { return err }
unsafe {
let state = arg as *mut RefCell<TcpStreamState>;
if pbuf.is_null() {
(*state).borrow_mut().recv_buffer.push_back(Err(Error::ConnectionClosed))
} else {
(*state).borrow_mut().recv_buffer.push_back(Ok(Pbuf::from_raw(pbuf)))
}
}
lwip_sys::ERR_OK
}
extern fn sent(arg: *mut c_void, raw: *mut lwip_sys::tcp_pcb,
len: u16) -> lwip_sys::err {
unsafe {
let state = arg as *mut RefCell<TcpStreamState>;
let mut state = (*state).borrow_mut();
state.send_avail = lwip_sys::tcp_sndbuf_(raw) as usize;
state.total_sent = state.total_sent.wrapping_add(len as usize);
}
lwip_sys::ERR_OK
}
extern fn err(arg: *mut c_void, err: lwip_sys::err) {
unsafe {
let state = arg as *mut RefCell<TcpStreamState>;
(*state).borrow_mut().recv_buffer.push_back(result_from(err, || unreachable!()))
}
}
unsafe {
let mut state = Box::new(RefCell::new(TcpStreamState {
recv_buffer: LinkedList::new(),
send_avail: lwip_sys::tcp_sndbuf_(raw) as usize,
total_sent: 0
}));
let arg = &mut *state as *mut RefCell<TcpStreamState> as *mut _;
lwip_sys::tcp_arg(raw, arg);
lwip_sys::tcp_recv(raw, Some(recv));
lwip_sys::tcp_sent(raw, Some(sent));
lwip_sys::tcp_err(raw, Some(err));
lwip_sys::tcp_nagle_disable_(raw);
TcpStream { raw: raw, state: state }
}
}
pub fn state(&self) -> &RefCell<TcpStreamState> {
&*self.state
}
unsafe fn write_common(&self, data: &[u8], copy: bool) -> Result<usize> {
let sndbuf = lwip_sys::tcp_sndbuf_(self.raw) as usize;
let len = if data.len() < sndbuf { data.len() } else { sndbuf };
let result = result_from({
lwip_sys::tcp_write(self.raw, data as *const [u8] as *const _, len as u16,
lwip_sys::TCP_WRITE_FLAG_MORE |
if copy { lwip_sys::TCP_WRITE_FLAG_COPY } else { 0 })
}, || len);
self.state.borrow_mut().send_avail = lwip_sys::tcp_sndbuf_(self.raw) as usize;
result
}
pub fn write(&self, data: &[u8]) -> Result<usize> {
unsafe { self.write_common(data, true) }
}
pub fn write_in_place<F>(&self, data: &[u8], mut relinquish: F) -> Result<usize>
where F: FnMut() -> Result<()> {
let cursor = self.state.borrow().total_sent;
let written = try!(unsafe { self.write_common(data, false) });
loop {
let cursor_now = self.state.borrow().total_sent;
if cursor_now >= cursor.wrapping_add(written) {
return Ok(written)
} else {
try!(relinquish())
}
}
}
pub fn flush(&self) -> Result<()> {
result_from(unsafe {
lwip_sys::tcp_write(self.raw, ptr::null(), 0, 0)
}, || ())
}
pub fn try_read(&self) -> Result<Option<Pbuf<'static>>> {
let mut state = self.state.borrow_mut();
match state.recv_buffer.front() {
None => return Ok(None),
Some(&Err(err)) => return Err(err),
Some(_) => ()
}
match state.recv_buffer.pop_front() {
Some(Ok(pbuf)) => {
unsafe { lwip_sys::tcp_recved(self.raw, pbuf.len() as u16) }
return Ok(Some(pbuf))
},
_ => unreachable!()
}
}
pub fn shutdown(&self, how: Shutdown) -> Result<()> {
let (shut_rx, shut_tx) = match how {
Shutdown::Read => (1, 0),
Shutdown::Write => (0, 1),
Shutdown::Both => (1, 1)
};
result_from(unsafe {
lwip_sys::tcp_shutdown(self.raw, shut_rx, shut_tx)
}, || ())
}
pub fn close(self) -> Result<()> {
let result = result_from(unsafe {
lwip_sys::tcp_close(self.raw)
}, || ());
core::mem::forget(self); // closing twice is illegal
result
}
}
impl Drop for TcpStream {
fn drop(&mut self) {
unsafe {
// lwip *will* try to call back after tcp_close
lwip_sys::tcp_recv(self.raw, None);
lwip_sys::tcp_sent(self.raw, None);
lwip_sys::tcp_err(self.raw, None);
// tcp_close can fail here, but in drop() we don't care
let _ = lwip_sys::tcp_close(self.raw);
}
}
}

View File

@ -15,9 +15,14 @@ path = "lib.rs"
[dependencies]
alloc_artiq = { path = "../liballoc_artiq" }
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
lwip = { path = "../liblwip", default-features = false }
board = { path = "../libboard" }
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
log = { version = "0.3", default-features = false }
log = { version = "0.3", default-features = false, features = [] }
log_buffer = { version = "1.0" }
byteorder = { version = "0.5", default-features = false }
byteorder = { version = "1.0", default-features = false }
[dependencies.smoltcp]
git = "https://github.com/m-labs/smoltcp"
rev = "d57b42c"
default-features = false
features = ["use_alloc", "use_collections", "use_log"]#, "verbose"]

View File

@ -1,7 +1,6 @@
use std::io::{self, Write};
use board::{self, csr};
use sched::{Waiter, Spawner};
use sched::{TcpListener, TcpStream, SocketAddr, IP_ANY};
use sched::{Io, TcpSocket};
use analyzer_proto::*;
const BUFFER_SIZE: usize = 512 * 1024;
@ -41,7 +40,7 @@ fn disarm() {
}
}
fn worker(mut stream: TcpStream) -> io::Result<()> {
fn worker(socket: &mut TcpSocket) -> io::Result<()> {
let data = unsafe { &BUFFER.data[..] };
let overflow_occurred = unsafe { csr::rtio_analyzer::message_encoder_overflow_read() != 0 };
let total_byte_count = unsafe { csr::rtio_analyzer::dma_byte_count_read() };
@ -57,36 +56,35 @@ fn worker(mut stream: TcpStream) -> io::Result<()> {
};
trace!("{:?}", header);
try!(header.write_to(&mut stream));
try!(header.write_to(socket));
if wraparound {
try!(stream.write(&data[pointer..]));
try!(stream.write(&data[..pointer]));
try!(socket.write_all(&data[pointer..]));
try!(socket.write_all(&data[..pointer]));
} else {
try!(stream.write(&data[..pointer]));
try!(socket.write_all(&data[..pointer]));
}
Ok(())
}
pub fn thread(waiter: Waiter, _spawner: Spawner) {
pub fn thread(io: Io) {
// verify that the hack above works
assert!(::core::mem::align_of::<Buffer>() == 64);
let addr = SocketAddr::new(IP_ANY, 1382);
let listener = TcpListener::bind(waiter, addr).expect("cannot bind socket");
listener.set_keepalive(true);
let mut socket = TcpSocket::with_buffer_size(&io, 65535);
loop {
arm();
let (stream, addr) = listener.accept().expect("cannot accept client");
info!("connection from {}", addr);
socket.listen(1382).expect("analyzer: cannot listen");
socket.accept().expect("analyzer: cannot accept");
info!("connection from {}", socket.remote_endpoint());
disarm();
match worker(stream) {
match worker(&mut socket) {
Ok(()) => (),
Err(err) => error!("analyzer aborted: {}", err)
}
socket.close().expect("analyzer: cannot close");
}
}

View File

@ -0,0 +1,77 @@
use core::slice;
use board::{csr, mem};
use smoltcp::Error;
use smoltcp::phy::Device;
const RX0_BASE: usize = mem::ETHMAC_BASE + 0x0000;
const RX1_BASE: usize = mem::ETHMAC_BASE + 0x0800;
const TX0_BASE: usize = mem::ETHMAC_BASE + 0x1000;
const TX1_BASE: usize = mem::ETHMAC_BASE + 0x1800;
const RX_BUFFERS: [*mut u8; 2] = [RX0_BASE as *mut u8, RX1_BASE as *mut u8];
const TX_BUFFERS: [*mut u8; 2] = [TX0_BASE as *mut u8, TX1_BASE as *mut u8];
pub struct EthernetDevice;
impl Device for EthernetDevice {
type RxBuffer = RxBuffer;
type TxBuffer = TxBuffer;
fn mtu(&self) -> usize { 1500 }
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
unsafe {
if csr::ethmac::sram_writer_ev_pending_read() != 0 {
let slot = csr::ethmac::sram_writer_slot_read();
let length = csr::ethmac::sram_writer_length_read();
Ok(RxBuffer(slice::from_raw_parts(RX_BUFFERS[slot as usize],
length as usize)))
} else {
Err(Error::Exhausted)
}
}
}
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
unsafe {
if csr::ethmac::sram_reader_ready_read() != 0 {
let slot = csr::ethmac::sram_reader_slot_read();
let slot = (slot + 1) % (TX_BUFFERS.len() as u8);
csr::ethmac::sram_reader_slot_write(slot);
csr::ethmac::sram_reader_length_write(length as u16);
Ok(TxBuffer(slice::from_raw_parts_mut(TX_BUFFERS[slot as usize],
length as usize)))
} else {
Err(Error::Exhausted)
}
}
}
}
pub struct RxBuffer(&'static [u8]);
impl AsRef<[u8]> for RxBuffer {
fn as_ref(&self) -> &[u8] { self.0 }
}
impl Drop for RxBuffer {
fn drop(&mut self) {
unsafe { csr::ethmac::sram_writer_ev_pending_write(1) }
}
}
pub struct TxBuffer(&'static mut [u8]);
impl AsRef<[u8]> for TxBuffer {
fn as_ref(&self) -> &[u8] { self.0 }
}
impl AsMut<[u8]> for TxBuffer {
fn as_mut(&mut self) -> &mut [u8] { self.0 }
}
impl Drop for TxBuffer {
fn drop(&mut self) {
unsafe { csr::ethmac::sram_reader_start_write(1) }
}
}

View File

@ -10,11 +10,11 @@ extern crate log;
extern crate log_buffer;
extern crate byteorder;
extern crate fringe;
extern crate lwip;
extern crate smoltcp;
extern crate board;
use core::fmt::Write;
use logger::BufferLogger;
use std::boxed::Box;
extern {
fn putchar(c: libc::c_int) -> libc::c_int;
@ -57,7 +57,17 @@ pub extern fn panic_fmt(args: self::core::fmt::Arguments, file: &'static str, li
}
}
macro_rules! borrow_mut {
($x:expr) => ({
match $x.try_borrow_mut() {
Ok(x) => x,
Err(_) => panic!("cannot borrow mutably at {}:{}", file!(), line!())
}
})
}
mod config;
mod ethmac;
mod rtio_mgt;
mod mailbox;
mod rpc_queue;
@ -83,12 +93,102 @@ mod moninj;
#[cfg(has_rtio_analyzer)]
mod analyzer;
extern {
fn network_init();
fn lwip_service();
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
fn startup() {
board::uart::set_speed(921600);
board::clock::init();
info!("booting ARTIQ");
info!("software version {}", GIT_COMMIT);
info!("gateware version {}", board::ident(&mut [0; 64]));
let t = board::clock::get_ms();
info!("press 'e' to erase startup and idle kernels...");
while board::clock::get_ms() < t + 1000 {
if unsafe { readchar_nonblock() != 0 && readchar() == b'e' as libc::c_char } {
config::remove("startup_kernel");
config::remove("idle_kernel");
info!("startup and idle kernels erased");
break
}
}
info!("continuing boot");
#[cfg(has_i2c)]
board::i2c::init();
#[cfg(has_ad9516)]
board::ad9516::init().expect("cannot initialize ad9516");
#[cfg(has_converter_spi)]
board::ad9154::init().expect("cannot initialize ad9154");
fn _net_trace_writer<U>(printer: smoltcp::wire::PrettyPrinter<U>)
where U: smoltcp::wire::pretty_print::PrettyPrint {
print!("\x1b[37m{}\x1b[0m", printer)
}
let net_device = ethmac::EthernetDevice;
// let net_device = smoltcp::phy::Tracer::<_, smoltcp::wire::EthernetFrame<&[u8]>>
// ::new(net_device, _net_trace_writer);
let arp_cache = smoltcp::iface::SliceArpCache::new([Default::default(); 8]);
let hardware_addr = smoltcp::wire::EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
let protocol_addrs = [smoltcp::wire::IpAddress::v4(192, 168, 1, 50)];
let mut interface = smoltcp::iface::EthernetInterface::new(
Box::new(net_device), Box::new(arp_cache) as Box<smoltcp::iface::ArpCache>,
hardware_addr, protocol_addrs);
let mut scheduler = sched::Scheduler::new();
let io = scheduler.io();
rtio_mgt::startup(&io);
io.spawn(16384, session::thread);
#[cfg(has_rtio_moninj)]
io.spawn(4096, moninj::thread);
#[cfg(has_rtio_analyzer)]
io.spawn(4096, analyzer::thread);
loop {
scheduler.run();
match interface.poll(&mut *borrow_mut!(scheduler.sockets()),
board::clock::get_ms()) {
Ok(()) => (),
Err(smoltcp::Error::Exhausted) => (),
Err(smoltcp::Error::Unrecognized) => (),
Err(e) => warn!("network error: {}", e)
}
}
}
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
use board::{irq, csr};
extern {
fn uart_init();
fn uart_isr();
fn alloc_give(ptr: *mut u8, length: usize);
static mut _fheap: u8;
static mut _eheap: u8;
}
#[no_mangle]
pub unsafe extern fn main() -> i32 {
irq::set_mask(0);
irq::set_ie(true);
uart_init();
alloc_give(&mut _fheap as *mut u8,
&_eheap as *const u8 as usize - &_fheap as *const u8 as usize);
static mut LOG_BUFFER: [u8; 65536] = [0; 65536];
logger::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup);
0
}
#[no_mangle]
pub unsafe extern fn isr() {
let irqs = irq::pending() & irq::get_mask();
if irqs & (1 << csr::UART_INTERRUPT) != 0 {
uart_isr()
}
}
// Allow linking with crates that are built as -Cpanic=unwind even if we use -Cpanic=abort.
// This is never called.
@ -97,70 +197,3 @@ include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
pub extern "C" fn _Unwind_Resume() -> ! {
loop {}
}
#[no_mangle]
pub unsafe extern fn rust_main() {
static mut LOG_BUFFER: [u8; 65536] = [0; 65536];
BufferLogger::new(&mut LOG_BUFFER[..])
.register(move || {
board::uart::set_speed(921600);
board::clock::init();
info!("ARTIQ runtime starting...");
info!("software version {}", GIT_COMMIT);
info!("gateware version {}", board::ident(&mut [0; 64]));
let t = board::clock::get_ms();
info!("press 'e' to erase startup and idle kernels...");
while board::clock::get_ms() < t + 1000 {
if readchar_nonblock() != 0 && readchar() == b'e' as libc::c_char {
config::remove("startup_kernel");
config::remove("idle_kernel");
info!("startup and idle kernels erased");
break
}
}
info!("continuing boot");
#[cfg(has_i2c)]
board::i2c::init();
#[cfg(has_ad9516)]
board::ad9516::init().unwrap();
#[cfg(has_converter_spi)]
board::ad9154::init().unwrap();
network_init();
let mut scheduler = sched::Scheduler::new();
rtio_mgt::startup(scheduler.spawner());
scheduler.spawner().spawn(16384, session::thread);
#[cfg(has_rtio_moninj)]
scheduler.spawner().spawn(4096, moninj::thread);
#[cfg(has_rtio_analyzer)]
scheduler.spawner().spawn(4096, analyzer::thread);
loop {
scheduler.run();
lwip_service();
}
})
}
#[no_mangle]
pub unsafe extern fn isr() {
use board::{irq, csr};
extern { fn uart_isr(); }
let irqs = irq::pending() & irq::get_mask();
if irqs & (1 << csr::UART_INTERRUPT) != 0 {
uart_isr()
}
}
#[no_mangle]
pub fn sys_now() -> u32 {
board::clock::get_ms() as u32
}
#[no_mangle]
pub fn sys_jiffies() -> u32 {
board::clock::get_ms() as u32
}

View File

@ -44,11 +44,11 @@ impl BufferLogger {
}
pub fn clear(&self) {
self.buffer.borrow_mut().clear()
borrow_mut!(self.buffer).clear()
}
pub fn extract<R, F: FnOnce(&str) -> R>(&self, f: F) -> R {
f(self.buffer.borrow_mut().extract())
f(borrow_mut!(self.buffer).extract())
}
pub fn disable_trace_to_uart(&self) {
@ -67,14 +67,24 @@ impl Log for BufferLogger {
fn log(&self, record: &LogRecord) {
if self.enabled(record.metadata()) {
use core::fmt::Write;
writeln!(self.buffer.borrow_mut(),
"[{:12}us] {:>5}({}): {}",
board::clock::get_us(), record.level(), record.target(), record.args()).unwrap();
let force_uart = match self.buffer.try_borrow_mut() {
Ok(mut buffer) => {
use core::fmt::Write;
writeln!(buffer, "[{:12}us] {:>5}({}): {}",
board::clock::get_us(), record.level(),
record.target(), record.args()).unwrap();
false
}
Err(_) => {
// we're trying to log something while sending the log somewhere,
// probably over the network. just let it go to UART.
true
}
};
// Printing to UART is really slow, so avoid doing that when we have an alternative
// route to retrieve the debug messages.
if self.trace_to_uart.get() || record.level() <= LogLevel::Info {
if self.trace_to_uart.get() || record.level() <= LogLevel::Info || force_uart {
println!("[{:12}us] {:>5}({}): {}",
board::clock::get_us(), record.level(), record.target(), record.args());
}

View File

@ -1,8 +1,6 @@
use std::vec::Vec;
use std::io;
use board::csr;
use sched::{Waiter, Spawner};
use sched::{UdpSocket, SocketAddr, IP_ANY};
use sched::{Io, UdpSocket};
use moninj_proto::*;
const MONINJ_TTL_OVERRIDE_ENABLE: u8 = 0;
@ -10,17 +8,17 @@ 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();
let mut buf = vec![0; 512];
loop {
let addr = try!(socket.recv_from(&mut buf));
let request = try!(Request::read_from(&mut io::Cursor::new(&buf)));
let (size, addr) = try!(socket.recv_from(&mut buf));
let request = try!(Request::read_from(&mut io::Cursor::new(&buf[..size])));
trace!("{} -> {:?}", addr, request);
match request {
Request::Monitor => {
#[cfg(has_dds)]
let mut dds_ftws = [0u32; (csr::CONFIG_RTIO_DDS_COUNT as usize *
csr::CONFIG_DDS_CHANNELS_PER_BUS 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 {
@ -115,9 +113,9 @@ fn worker(socket: &mut UdpSocket) -> io::Result<()> {
}
}
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");
pub fn thread(io: Io) {
let mut socket = UdpSocket::with_buffer_size(&io, 1, 512);
socket.bind(3250);
loop {
match worker(&mut socket) {

View File

@ -1,6 +1,6 @@
use config;
use board::csr;
use sched::Spawner;
use sched::Io;
#[cfg(has_rtio_crg)]
pub mod crg {
@ -38,12 +38,11 @@ pub mod crg {
#[cfg(has_drtio)]
mod drtio {
use board::csr;
use sched::{Waiter, Spawner};
use super::*;
pub fn startup(spawner: &Spawner) {
spawner.spawn(4096, link_thread);
spawner.spawn(4096, error_thread);
pub fn startup(io: &Io) {
io.spawn(4096, link_thread);
io.spawn(4096, error_thread);
}
fn link_is_up() -> bool {
@ -92,12 +91,12 @@ mod drtio {
}
}
pub fn link_thread(waiter: Waiter, _spawner: Spawner) {
pub fn link_thread(io: Io) {
loop {
waiter.until(link_is_up).unwrap();
io.until(link_is_up).unwrap();
info!("link RX is up");
waiter.sleep(600).unwrap();
io.sleep(600).unwrap();
info!("wait for remote side done");
init(); // clear all FIFOs first
@ -105,7 +104,7 @@ mod drtio {
sync_tsc();
info!("link initialization completed");
waiter.until(|| !link_is_up()).unwrap();
io.until(|| !link_is_up()).unwrap();
info!("link is down");
}
}
@ -138,22 +137,21 @@ mod drtio {
false
}
pub fn error_thread(waiter: Waiter, _spawner: Spawner) {
pub fn error_thread(io: Io) {
// HACK
waiter.until(poll_errors).unwrap();
io.until(poll_errors).unwrap();
}
}
#[cfg(not(has_drtio))]
mod drtio {
use sched::Spawner;
use super::*;
pub fn startup(_spawner: &Spawner) {}
pub fn startup(_io: &Io) {}
pub fn init() {}
}
pub fn startup(spawner: &Spawner) {
pub fn startup(io: &Io) {
crg::init();
let mut opt = [b'i'];
@ -179,7 +177,7 @@ pub fn startup(spawner: &Spawner) {
warn!("fix clocking and reset the device");
}
drtio::startup(spawner);
drtio::startup(io);
init_core()
}

View File

@ -1,20 +1,28 @@
#![allow(dead_code)]
use std::cell::RefCell;
use std::mem;
use std::cell::{RefCell, RefMut};
use std::vec::Vec;
use std::io::{Read, Write, Result, Error, ErrorKind};
use fringe::OwnedStack;
use fringe::generator::{Generator, Yielder, State as GeneratorState};
use lwip;
use smoltcp::wire::IpEndpoint;
use smoltcp::socket::AsSocket;
use smoltcp::socket::SocketHandle;
type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>;
use board;
use urc::Urc;
#[derive(Debug)]
struct WaitRequest {
timeout: Option<u64>,
event: Option<WaitEvent>
event: Option<*const (Fn() -> bool + 'static)>,
timeout: Option<u64>
}
unsafe impl Send for WaitRequest {}
#[derive(Debug)]
enum WaitResult {
Completed,
@ -24,22 +32,29 @@ enum WaitResult {
#[derive(Debug)]
struct Thread {
generator: Generator<WaitResult, WaitRequest, OwnedStack>,
generator: Generator<WaitResult, WaitRequest, OwnedStack>,
waiting_for: WaitRequest,
interrupted: bool
}
impl Thread {
unsafe fn new<F>(spawner: Spawner, stack_size: usize, f: F) -> ThreadHandle
where F: 'static + FnOnce(Waiter, Spawner) + Send {
unsafe fn new<F>(io: &Io, stack_size: usize, f: F) -> ThreadHandle
where F: 'static + FnOnce(Io) + Send {
let spawned = io.spawned.clone();
let sockets = io.sockets.clone();
let stack = OwnedStack::new(stack_size);
ThreadHandle::new(Thread {
generator: Generator::unsafe_new(stack, |yielder, _| {
f(Waiter(yielder), spawner)
f(Io {
yielder: Some(yielder),
spawned: spawned,
sockets: sockets
})
}),
waiting_for: WaitRequest {
timeout: None,
event: None
event: None,
timeout: None
},
interrupted: false
})
@ -58,7 +73,7 @@ impl Thread {
}
}
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct ThreadHandle(Urc<RefCell<Thread>>);
impl ThreadHandle {
@ -81,52 +96,59 @@ impl ThreadHandle {
}
}
#[derive(Debug)]
pub struct Scheduler {
threads: Vec<ThreadHandle>,
index: usize,
spawner: Spawner
spawned: Urc<RefCell<Vec<ThreadHandle>>>,
sockets: Urc<RefCell<SocketSet>>,
run_idx: usize,
}
impl Scheduler {
pub fn new() -> Scheduler {
Scheduler {
threads: Vec::new(),
index: 0,
spawner: Spawner::new()
spawned: Urc::new(RefCell::new(Vec::new())),
sockets: Urc::new(RefCell::new(SocketSet::new(Vec::new()))),
run_idx: 0,
}
}
pub fn spawner(&self) -> &Spawner {
&self.spawner
pub fn io(&self) -> Io<'static> {
Io {
yielder: None,
spawned: self.spawned.clone(),
sockets: self.sockets.clone()
}
}
pub fn run(&mut self) {
self.threads.append(&mut *self.spawner.queue.borrow_mut());
self.sockets.borrow_mut().prune();
self.threads.append(&mut *borrow_mut!(self.spawned));
if self.threads.len() == 0 { return }
let now = board::clock::get_ms();
let start_index = self.index;
let start_idx = self.run_idx;
loop {
self.index = (self.index + 1) % self.threads.len();
self.run_idx = (self.run_idx + 1) % self.threads.len();
let result = {
let thread = &mut *self.threads[self.index].0.borrow_mut();
let mut thread = borrow_mut!(self.threads[self.run_idx].0);
match thread.waiting_for {
_ if thread.interrupted => {
thread.interrupted = false;
thread.generator.resume(WaitResult::Interrupted)
}
WaitRequest { timeout: Some(instant), .. } if now >= instant =>
WaitRequest { event: Some(_), timeout: Some(instant) } if now >= instant =>
thread.generator.resume(WaitResult::TimedOut),
WaitRequest { event: Some(ref event), .. } if event.completed() =>
WaitRequest { event: None, timeout: Some(instant) } if now >= instant =>
thread.generator.resume(WaitResult::Completed),
WaitRequest { timeout: None, event: None } =>
WaitRequest { event: Some(event), timeout: _ } if unsafe { (*event)() } =>
thread.generator.resume(WaitResult::Completed),
WaitRequest { event: None, timeout: None } =>
thread.generator.resume(WaitResult::Completed),
_ => {
if self.index == start_index {
if self.run_idx == start_idx {
// We've checked every thread and none of them are runnable.
break
} else {
@ -139,12 +161,12 @@ impl Scheduler {
match result {
None => {
// The thread has terminated.
self.threads.remove(self.index);
self.index = 0
self.threads.remove(self.run_idx);
self.run_idx = 0
},
Some(wait_request) => {
// The thread has suspended itself.
let thread = &mut *self.threads[self.index].0.borrow_mut();
let mut thread = borrow_mut!(self.threads[self.run_idx].0);
thread.waiting_for = wait_request
}
}
@ -152,75 +174,38 @@ impl Scheduler {
break
}
}
}
#[derive(Debug, Clone)]
pub struct Spawner {
queue: Urc<RefCell<Vec<ThreadHandle>>>
}
impl Spawner {
fn new() -> Spawner {
Spawner { queue: Urc::new(RefCell::new(Vec::new())) }
pub fn sockets(&self) -> &RefCell<SocketSet> {
&*self.sockets
}
}
#[derive(Clone)]
pub struct Io<'a> {
yielder: Option<&'a Yielder<WaitResult, WaitRequest, OwnedStack>>,
spawned: Urc<RefCell<Vec<ThreadHandle>>>,
sockets: Urc<RefCell<SocketSet>>,
}
impl<'a> Io<'a> {
pub fn spawn<F>(&self, stack_size: usize, f: F) -> ThreadHandle
where F: 'static + FnOnce(Waiter, Spawner) + Send {
let handle = unsafe { Thread::new(self.clone(), stack_size, f) };
self.queue.borrow_mut().push(handle.clone());
where F: 'static + FnOnce(Io) + Send {
let handle = unsafe { Thread::new(self, stack_size, f) };
borrow_mut!(self.spawned).push(handle.clone());
handle
}
}
enum WaitEvent {
Completion(*const (Fn() -> bool + 'static)),
Termination(*const RefCell<Thread>),
UdpReadable(*const RefCell<lwip::UdpSocketState>),
TcpAcceptable(*const RefCell<lwip::TcpListenerState>),
TcpWriteable(*const RefCell<lwip::TcpStreamState>),
TcpReadable(*const RefCell<lwip::TcpStreamState>),
}
impl WaitEvent {
fn completed(&self) -> bool {
match *self {
WaitEvent::Completion(f) =>
unsafe { (*f)() },
WaitEvent::Termination(thread) =>
unsafe { (*thread).borrow().terminated() },
WaitEvent::UdpReadable(state) =>
unsafe { (*state).borrow().readable() },
WaitEvent::TcpAcceptable(state) =>
unsafe { (*state).borrow().acceptable() },
WaitEvent::TcpWriteable(state) =>
unsafe { (*state).borrow().writeable() },
WaitEvent::TcpReadable(state) =>
unsafe { (*state).borrow().readable() },
}
fn yielder(&self) -> &'a Yielder<WaitResult, WaitRequest, OwnedStack> {
self.yielder.expect("cannot suspend the scheduler thread")
}
}
// *const DST doesn't have impl Debug
impl ::core::fmt::Debug for WaitEvent {
fn fmt(&self, f: &mut ::core::fmt::Formatter) ->
::core::result::Result<(), ::core::fmt::Error> {
write!(f, "WaitEvent...")
}
}
unsafe impl Send for WaitEvent {}
#[derive(Debug, Clone, Copy)]
pub struct Waiter<'a>(&'a Yielder<WaitResult, WaitRequest, OwnedStack>);
impl<'a> Waiter<'a> {
pub fn sleep(&self, duration_ms: u64) -> Result<()> {
let request = WaitRequest {
timeout: Some(board::clock::get_ms() + duration_ms),
event: None
};
match self.0.suspend(request) {
match self.yielder().suspend(request) {
WaitResult::TimedOut => Ok(()),
WaitResult::Interrupted => Err(Error::new(ErrorKind::Interrupted, "")),
_ => unreachable!()
@ -228,7 +213,7 @@ impl<'a> Waiter<'a> {
}
fn suspend(&self, request: WaitRequest) -> Result<()> {
match self.0.suspend(request) {
match self.yielder().suspend(request) {
WaitResult::Completed => Ok(()),
WaitResult::TimedOut => Err(Error::new(ErrorKind::TimedOut, "")),
WaitResult::Interrupted => Err(Error::new(ErrorKind::Interrupted, ""))
@ -242,230 +227,251 @@ impl<'a> Waiter<'a> {
})
}
pub fn join(&self, thread: ThreadHandle) -> Result<()> {
self.suspend(WaitRequest {
timeout: None,
event: Some(WaitEvent::Termination(&*thread.0))
})
}
pub fn until<F: Fn() -> bool + 'static>(&self, f: F) -> Result<()> {
self.suspend(WaitRequest {
timeout: None,
event: Some(WaitEvent::Completion(&f as *const _))
event: Some(&f as *const _)
})
}
pub fn udp_readable(&self, socket: &lwip::UdpSocket) -> Result<()> {
self.suspend(WaitRequest {
timeout: None,
event: Some(WaitEvent::UdpReadable(socket.state()))
})
}
pub fn tcp_acceptable(&self, socket: &lwip::TcpListener) -> Result<()> {
self.suspend(WaitRequest {
timeout: None,
event: Some(WaitEvent::TcpAcceptable(socket.state()))
})
}
pub fn tcp_writeable(&self, socket: &lwip::TcpStream) -> Result<()> {
self.suspend(WaitRequest {
timeout: None,
event: Some(WaitEvent::TcpWriteable(socket.state()))
})
}
pub fn tcp_readable(&self, socket: &lwip::TcpStream) -> Result<()> {
self.suspend(WaitRequest {
timeout: None,
event: Some(WaitEvent::TcpReadable(socket.state()))
})
pub fn join(&self, handle: ThreadHandle) -> Result<()> {
self.until(move || handle.terminated())
}
}
// Wrappers around lwip
macro_rules! until {
($socket:expr, $ty:ty, |$var:ident| $cond:expr) => ({
let (sockets, handle) = ($socket.io.sockets.clone(), $socket.handle);
$socket.io.until(move || {
let mut sockets = borrow_mut!(sockets);
let $var = sockets.get_mut(handle).as_socket() as &mut $ty;
$cond
})
})
}
pub use lwip::{IpAddr, IP4_ANY, IP6_ANY, IP_ANY, SocketAddr};
type UdpPacketBuffer = ::smoltcp::socket::UdpPacketBuffer<'static>;
type UdpSocketBuffer = ::smoltcp::socket::UdpSocketBuffer<'static, 'static>;
type UdpSocketLower = ::smoltcp::socket::UdpSocket<'static, 'static>;
#[derive(Debug)]
pub struct UdpSocket<'a> {
waiter: Waiter<'a>,
lower: lwip::UdpSocket
io: &'a Io<'a>,
handle: SocketHandle
}
impl<'a> UdpSocket<'a> {
pub fn new(waiter: Waiter<'a>) -> Result<UdpSocket> {
Ok(UdpSocket {
waiter: waiter,
lower: try!(lwip::UdpSocket::new())
})
pub fn new(io: &'a Io<'a>, rx_buffer: UdpSocketBuffer, tx_buffer: UdpSocketBuffer) ->
UdpSocket<'a> {
let handle = borrow_mut!(io.sockets)
.add(UdpSocketLower::new(rx_buffer, tx_buffer));
UdpSocket {
io: io,
handle: handle
}
}
pub fn into_lower(self) -> lwip::UdpSocket {
self.lower
pub fn with_buffer_size(io: &'a Io<'a>, buffer_depth: usize, buffer_width: usize) ->
UdpSocket<'a> {
let mut rx_buffer = vec![];
let mut tx_buffer = vec![];
for _ in 0..buffer_depth {
rx_buffer.push(UdpPacketBuffer::new(vec![0; buffer_width]));
tx_buffer.push(UdpPacketBuffer::new(vec![0; buffer_width]));
}
Self::new(io,
UdpSocketBuffer::new(rx_buffer),
UdpSocketBuffer::new(tx_buffer))
}
pub fn from_lower(waiter: Waiter<'a>, inner: lwip::UdpSocket) -> UdpSocket {
UdpSocket { waiter: waiter, lower: inner }
fn as_lower<'b>(&'b self) -> RefMut<'b, UdpSocketLower> {
RefMut::map(borrow_mut!(self.io.sockets),
|sockets| sockets.get_mut(self.handle).as_socket())
}
pub fn bind(&self, addr: SocketAddr) -> Result<()> {
Ok(try!(self.lower.bind(addr)))
pub fn bind<T: Into<IpEndpoint>>(&self, endpoint: T) {
self.as_lower().bind(endpoint)
}
pub fn connect(&self, addr: SocketAddr) -> Result<()> {
Ok(try!(self.lower.connect(addr)))
}
pub fn disconnect(&self) -> Result<()> {
Ok(try!(self.lower.disconnect()))
}
pub fn send_to(&self, buf: &[u8], addr: SocketAddr) -> Result<usize> {
try!(self.lower.send_to(lwip::Pbuf::from_slice(buf), addr));
Ok(buf.len())
}
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();
buf.clear();
buf.extend_from_slice(&pbuf.as_slice());
Ok(addr)
}
pub fn send(&self, buf: &[u8]) -> Result<usize> {
try!(self.lower.send(lwip::Pbuf::from_slice(buf)));
Ok(buf.len())
}
pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
try!(self.waiter.udp_readable(&self.lower));
let (pbuf, _addr) = self.lower.try_recv().unwrap();
// lwip checks that addr matches the bind/connect call
let len = ::std::cmp::min(buf.len(), pbuf.len());
(&mut buf[..len]).copy_from_slice(&pbuf.as_slice()[..len]);
Ok(len)
}
pub fn readable(&self) -> bool {
self.lower.state().borrow().readable()
}
}
#[derive(Debug)]
pub struct TcpListener<'a> {
waiter: Waiter<'a>,
lower: lwip::TcpListener
}
impl<'a> TcpListener<'a> {
pub fn bind(waiter: Waiter<'a>, addr: SocketAddr) -> Result<TcpListener> {
Ok(TcpListener {
waiter: waiter,
lower: try!(lwip::TcpListener::bind(addr))
})
}
pub fn into_lower(self) -> lwip::TcpListener {
self.lower
}
pub fn from_lower(waiter: Waiter<'a>, inner: lwip::TcpListener) -> TcpListener {
TcpListener { waiter: waiter, lower: inner }
}
pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> {
try!(self.waiter.tcp_acceptable(&self.lower));
let stream_lower = self.lower.try_accept().unwrap();
let addr = SocketAddr::new(IP_ANY, 0); // FIXME: coax lwip into giving real addr here
Ok((TcpStream {
waiter: self.waiter,
lower: stream_lower,
buffer: None
}, addr))
}
pub fn acceptable(&self) -> bool {
self.lower.state().borrow().acceptable()
}
pub fn keepalive(&self) -> bool {
self.lower.keepalive()
}
pub fn set_keepalive(&self, keepalive: bool) {
self.lower.set_keepalive(keepalive)
}
}
pub use lwip::Shutdown;
pub struct TcpStreamInner(lwip::TcpStream, Option<(lwip::Pbuf<'static>, usize)>);
#[derive(Debug)]
pub struct TcpStream<'a> {
waiter: Waiter<'a>,
lower: lwip::TcpStream,
buffer: Option<(lwip::Pbuf<'static>, usize)>
}
impl<'a> TcpStream<'a> {
pub fn into_lower(self) -> TcpStreamInner {
TcpStreamInner(self.lower, self.buffer)
}
pub fn from_lower(waiter: Waiter<'a>, inner: TcpStreamInner) -> TcpStream {
TcpStream { waiter: waiter, lower: inner.0, buffer: inner.1 }
}
pub fn shutdown(&self, how: Shutdown) -> Result<()> {
Ok(try!(self.lower.shutdown(how)))
}
pub fn readable(&self) -> bool {
self.buffer.is_some() || self.lower.state().borrow().readable()
}
pub fn writeable(&self) -> bool {
self.lower.state().borrow().writeable()
}
}
impl<'a> Read for TcpStream<'a> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.buffer.is_none() {
try!(self.waiter.tcp_readable(&self.lower));
match self.lower.try_read() {
Ok(Some(pbuf)) => self.buffer = Some((pbuf, 0)),
Ok(None) => unreachable!(),
Err(lwip::Error::ConnectionClosed) => return Ok(0),
Err(err) => return Err(Error::from(err))
pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint)> {
try!(until!(self, UdpSocketLower, |s| s.can_recv()));
match self.as_lower().recv_slice(buf) {
Ok(r) => Ok(r),
Err(()) => {
// No data in the buffer--should never happen after the wait above.
unreachable!()
}
}
}
let (pbuf, pos) = self.buffer.take().unwrap();
let remaining = pbuf.len() - pos;
let len = ::std::cmp::min(buf.len(), remaining);
buf[..len].copy_from_slice(&pbuf.as_slice()[pos..pos + len]);
if len < remaining {
self.buffer = Some((pbuf, pos + len))
pub fn send_to(&self, buf: &[u8], addr: IpEndpoint) -> Result<usize> {
try!(until!(self, UdpSocketLower, |s| s.can_send()));
match self.as_lower().send_slice(buf, addr) {
Ok(r) => Ok(r),
Err(()) => {
// No space in the buffer--should never happen after the wait above.
unreachable!()
}
}
Ok(len)
}
}
impl<'a> Write for TcpStream<'a> {
impl<'a> Drop for UdpSocket<'a> {
fn drop(&mut self) {
borrow_mut!(self.io.sockets).release(self.handle)
}
}
type TcpSocketBuffer = ::smoltcp::socket::TcpSocketBuffer<'static>;
type TcpSocketLower = ::smoltcp::socket::TcpSocket<'static>;
pub struct TcpSocketHandle(SocketHandle);
pub struct TcpSocket<'a> {
io: &'a Io<'a>,
handle: SocketHandle
}
impl<'a> TcpSocket<'a> {
pub fn new(io: &'a Io<'a>, rx_buffer: TcpSocketBuffer, tx_buffer: TcpSocketBuffer) ->
TcpSocket<'a> {
let handle = borrow_mut!(io.sockets)
.add(TcpSocketLower::new(rx_buffer, tx_buffer));
TcpSocket {
io: io,
handle: handle
}
}
pub fn with_buffer_size(io: &'a Io<'a>, buffer_size: usize) -> TcpSocket<'a> {
let rx_buffer = vec![0; buffer_size];
let tx_buffer = vec![0; buffer_size];
Self::new(io,
TcpSocketBuffer::new(rx_buffer),
TcpSocketBuffer::new(tx_buffer))
}
pub fn into_handle(self) -> TcpSocketHandle {
let handle = self.handle;
mem::forget(self);
TcpSocketHandle(handle)
}
pub fn from_handle(io: &'a Io<'a>, handle: TcpSocketHandle) -> TcpSocket<'a> {
TcpSocket {
io: io,
handle: handle.0
}
}
fn as_lower<'b>(&'b self) -> RefMut<'b, TcpSocketLower> {
RefMut::map(borrow_mut!(self.io.sockets),
|sockets| sockets.get_mut(self.handle).as_socket())
}
pub fn is_open(&self) -> bool {
self.as_lower().is_open()
}
pub fn is_listening(&self) -> bool {
self.as_lower().is_listening()
}
pub fn is_active(&self) -> bool {
self.as_lower().is_active()
}
pub fn may_send(&self) -> bool {
self.as_lower().may_send()
}
pub fn may_recv(&self) -> bool {
self.as_lower().may_recv()
}
pub fn can_send(&self) -> bool {
self.as_lower().can_send()
}
pub fn can_recv(&self) -> bool {
self.as_lower().can_recv()
}
pub fn local_endpoint(&self) -> IpEndpoint {
self.as_lower().local_endpoint()
}
pub fn remote_endpoint(&self) -> IpEndpoint {
self.as_lower().remote_endpoint()
}
pub fn listen<T: Into<IpEndpoint>>(&self, endpoint: T) -> Result<()> {
self.as_lower().listen(endpoint)
.map_err(|()| Error::new(ErrorKind::Other,
"cannot listen: already connected"))
}
pub fn accept(&self) -> Result<()> {
// We're waiting until at least one half of the connection becomes open.
// This handles the case where a remote socket immediately sends a FIN--
// that still counts as accepting even though nothing may be sent.
until!(self, TcpSocketLower, |s| s.may_send() || s.may_recv())
}
pub fn close(&self) -> Result<()> {
self.as_lower().close();
try!(until!(self, TcpSocketLower, |s| !s.is_open()));
// right now the socket may be in TIME-WAIT state. if we don't give it a chance to send
// a packet, and the user code executes a loop { s.listen(); s.read(); s.close(); }
// then the last ACK will never be sent.
self.io.relinquish()
}
}
impl<'a> Read for TcpSocket<'a> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
// fast path
let result = self.as_lower().recv_slice(buf);
match result {
Ok(0) | Err(()) => {
// slow path
if !self.as_lower().may_recv() { return Ok(0) }
try!(until!(self, TcpSocketLower, |s| s.can_recv()));
Ok(self.as_lower().recv_slice(buf)
.expect("may_recv implies that data was available"))
}
Ok(length) => Ok(length)
}
}
}
impl<'a> Write for TcpSocket<'a> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
try!(self.waiter.tcp_writeable(&self.lower));
Ok(try!(self.lower.write_in_place(buf,
|| self.waiter.relinquish()
.map_err(|_| lwip::Error::Interrupted))))
// fast path
let result = self.as_lower().send_slice(buf);
match result {
Ok(0) | Err(()) => {
// slow path
if !self.as_lower().may_send() { return Ok(0) }
try!(until!(self, TcpSocketLower, |s| s.can_send()));
Ok(self.as_lower().send_slice(buf)
.expect("may_send implies that data was available"))
}
Ok(length) => Ok(length)
}
}
fn flush(&mut self) -> Result<()> {
Ok(try!(self.lower.flush()))
// smoltcp always sends all available data when it's possible; nothing to do
Ok(())
}
}
impl<'a> Drop for TcpSocket<'a> {
fn drop(&mut self) {
if self.is_open() {
// scheduler will remove any closed sockets with zero references.
self.as_lower().close()
}
borrow_mut!(self.io.sockets).release(self.handle)
}
}

View File

@ -1,14 +1,14 @@
use std::prelude::v1::*;
use std::{mem, str};
use std::cell::RefCell;
use std::io::{self, Read, Write, BufWriter};
use std::io::{self, Read, Write};
use std::btree_set::BTreeSet;
use {config, rtio_mgt, mailbox, rpc_queue, kernel};
use logger::BufferLogger;
use cache::Cache;
use urc::Urc;
use sched::{ThreadHandle, Waiter, Spawner};
use sched::{TcpListener, TcpStream, SocketAddr, IP_ANY};
use sched::{ThreadHandle, Io};
use sched::{TcpSocket};
use byteorder::{ByteOrder, NetworkEndian};
use board;
@ -97,7 +97,7 @@ impl<'a> Drop for Session<'a> {
}
}
fn check_magic(stream: &mut TcpStream) -> io::Result<()> {
fn check_magic(stream: &mut TcpSocket) -> io::Result<()> {
const MAGIC: &'static [u8] = b"ARTIQ coredev\n";
let mut magic: [u8; 14] = [0; 14];
@ -109,7 +109,7 @@ fn check_magic(stream: &mut TcpStream) -> io::Result<()> {
}
}
fn host_read(stream: &mut TcpStream) -> io::Result<host::Request> {
fn host_read(stream: &mut TcpSocket) -> io::Result<host::Request> {
let request = try!(host::Request::read_from(stream));
match &request {
&host::Request::LoadKernel(_) => trace!("comm<-host LoadLibrary(...)"),
@ -123,18 +123,18 @@ fn host_write(stream: &mut Write, reply: host::Reply) -> io::Result<()> {
reply.write_to(stream)
}
fn kern_send(waiter: Waiter, request: &kern::Message) -> io::Result<()> {
fn kern_send(io: &Io, request: &kern::Message) -> io::Result<()> {
match request {
&kern::LoadRequest(_) => trace!("comm->kern LoadRequest(...)"),
_ => trace!("comm->kern {:?}", request)
}
unsafe { mailbox::send(request as *const _ as usize) }
waiter.until(mailbox::acknowledged)
io.until(mailbox::acknowledged)
}
fn kern_recv_notrace<R, F>(waiter: Waiter, f: F) -> io::Result<R>
fn kern_recv_notrace<R, F>(io: &Io, f: F) -> io::Result<R>
where F: FnOnce(&kern::Message) -> io::Result<R> {
try!(waiter.until(|| mailbox::receive() != 0));
try!(io.until(|| mailbox::receive() != 0));
if !kernel::validate(mailbox::receive()) {
let message = format!("invalid kernel CPU pointer 0x{:x}", mailbox::receive());
return Err(io::Error::new(io::ErrorKind::InvalidData, message))
@ -152,9 +152,9 @@ fn kern_recv_dotrace(reply: &kern::Message) {
}
#[inline(always)]
fn kern_recv<R, F>(waiter: Waiter, f: F) -> io::Result<R>
fn kern_recv<R, F>(io: &Io, f: F) -> io::Result<R>
where F: FnOnce(&kern::Message) -> io::Result<R> {
kern_recv_notrace(waiter, |reply| {
kern_recv_notrace(io, |reply| {
kern_recv_dotrace(reply);
f(reply)
})
@ -165,15 +165,15 @@ fn kern_acknowledge() -> io::Result<()> {
Ok(())
}
unsafe fn kern_load(waiter: Waiter, session: &mut Session, library: &[u8]) -> io::Result<()> {
unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Result<()> {
if session.running() {
unexpected!("attempted to load a new kernel while a kernel was running")
}
kernel::start();
try!(kern_send(waiter, &kern::LoadRequest(&library)));
kern_recv(waiter, |reply| {
try!(kern_send(io, &kern::LoadRequest(&library)));
kern_recv(io, |reply| {
match reply {
&kern::LoadReply(Ok(())) => {
session.kernel_state = KernelState::Loaded;
@ -197,8 +197,8 @@ fn kern_run(session: &mut Session) -> io::Result<()> {
kern_acknowledge()
}
fn process_host_message(waiter: Waiter,
stream: &mut TcpStream,
fn process_host_message(io: &Io,
stream: &mut TcpSocket,
session: &mut Session) -> io::Result<()> {
match try!(host_read(stream)) {
host::Request::Ident =>
@ -257,7 +257,7 @@ fn process_host_message(waiter: Waiter,
}
host::Request::LoadKernel(kernel) =>
match unsafe { kern_load(waiter, session, &kernel) } {
match unsafe { kern_load(io, session, &kernel) } {
Ok(()) => host_write(stream, host::Reply::LoadCompleted),
Err(_) => {
try!(kern_acknowledge());
@ -276,22 +276,22 @@ fn process_host_message(waiter: Waiter,
unexpected!("unsolicited RPC reply")
}
let slot = try!(kern_recv(waiter, |reply| {
let slot = try!(kern_recv(io, |reply| {
match reply {
&kern::RpcRecvRequest(slot) => Ok(slot),
other => unexpected!("unexpected reply from kernel CPU: {:?}", other)
}
}));
try!(rpc::recv_return(stream, &tag, slot, &|size| {
try!(kern_send(waiter, &kern::RpcRecvReply(Ok(size))));
kern_recv(waiter, |reply| {
try!(kern_send(io, &kern::RpcRecvReply(Ok(size))));
kern_recv(io, |reply| {
match reply {
&kern::RpcRecvRequest(slot) => Ok(slot),
other => unexpected!("unexpected reply from kernel CPU: {:?}", other)
}
})
}));
try!(kern_send(waiter, &kern::RpcRecvReply(Ok(0))));
try!(kern_send(io, &kern::RpcRecvReply(Ok(0))));
session.kernel_state = KernelState::Running;
Ok(())
@ -304,7 +304,7 @@ fn process_host_message(waiter: Waiter,
unexpected!("unsolicited RPC reply")
}
try!(kern_recv(waiter, |reply| {
try!(kern_recv(io, |reply| {
match reply {
&kern::RpcRecvRequest(_) => Ok(()),
other =>
@ -329,7 +329,7 @@ fn process_host_message(waiter: Waiter,
function: into_c_str(&mut session.interner, function),
phantom: ::core::marker::PhantomData
};
try!(kern_send(waiter, &kern::RpcRecvReply(Err(exn))));
try!(kern_send(io, &kern::RpcRecvReply(Err(exn))));
session.kernel_state = KernelState::Running;
Ok(())
@ -337,10 +337,10 @@ fn process_host_message(waiter: Waiter,
}
}
fn process_kern_message(waiter: Waiter,
mut stream: Option<&mut TcpStream>,
fn process_kern_message(io: &Io,
mut stream: Option<&mut TcpSocket>,
session: &mut Session) -> io::Result<bool> {
kern_recv_notrace(waiter, |request| {
kern_recv_notrace(io, |request| {
match (request, session.kernel_state) {
(&kern::LoadReply(_), KernelState::Loaded) |
(&kern::RpcRecvRequest(_), KernelState::RpcWait) => {
@ -371,7 +371,7 @@ fn process_kern_message(waiter: Waiter,
}
&kern::NowInitRequest =>
kern_send(waiter, &kern::NowInitReply(session.congress.now)),
kern_send(io, &kern::NowInitReply(session.congress.now)),
&kern::NowSave(now) => {
session.congress.now = now;
@ -386,7 +386,7 @@ fn process_kern_message(waiter: Waiter,
&kern::DRTIOChannelStateRequest { channel } => {
let (fifo_space, last_timestamp) = rtio_mgt::drtio_dbg::get_channel_state(channel);
kern_send(waiter, &kern::DRTIOChannelStateReply { fifo_space: fifo_space,
kern_send(io, &kern::DRTIOChannelStateReply { fifo_space: fifo_space,
last_timestamp: last_timestamp })
}
&kern::DRTIOResetChannelStateRequest { channel } => {
@ -399,17 +399,17 @@ fn process_kern_message(waiter: Waiter,
}
&kern::DRTIOPacketCountRequest => {
let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts();
kern_send(waiter, &kern::DRTIOPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt })
kern_send(io, &kern::DRTIOPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt })
}
&kern::DRTIOFIFOSpaceReqCountRequest => {
let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count();
kern_send(waiter, &kern::DRTIOFIFOSpaceReqCountReply { cnt: cnt })
kern_send(io, &kern::DRTIOFIFOSpaceReqCountReply { cnt: cnt })
}
&kern::WatchdogSetRequest { ms } => {
let id = try!(session.watchdog_set.set_ms(ms)
.map_err(|()| io_error("out of watchdogs")));
kern_send(waiter, &kern::WatchdogSetReply { id: id })
kern_send(io, &kern::WatchdogSetReply { id: id })
}
&kern::WatchdogClear { id } => {
@ -421,9 +421,8 @@ fn process_kern_message(waiter: Waiter,
match stream {
None => unexpected!("unexpected RPC in flash kernel"),
Some(ref mut stream) => {
let writer = &mut BufWriter::new(stream);
try!(host_write(writer, host::Reply::RpcRequest { async: async }));
try!(rpc::send_args(writer, service, tag, data));
try!(host_write(stream, host::Reply::RpcRequest { async: async }));
try!(rpc::send_args(stream, service, tag, data));
if !async {
session.kernel_state = KernelState::RpcWait
}
@ -434,14 +433,14 @@ fn process_kern_message(waiter: Waiter,
&kern::CacheGetRequest { key } => {
let value = session.congress.cache.get(key);
kern_send(waiter, &kern::CacheGetReply {
kern_send(io, &kern::CacheGetReply {
value: unsafe { mem::transmute::<*const [i32], &'static [i32]>(value) }
})
}
&kern::CachePutRequest { key, value } => {
let succeeded = session.congress.cache.put(key, value).is_ok();
kern_send(waiter, &kern::CachePutReply { succeeded: succeeded })
kern_send(io, &kern::CachePutReply { succeeded: succeeded })
}
#[cfg(has_i2c)]
@ -457,12 +456,12 @@ fn process_kern_message(waiter: Waiter,
#[cfg(has_i2c)]
&kern::I2CWriteRequest { busno, data } => {
let ack = board::i2c::write(busno, data);
kern_send(waiter, &kern::I2CWriteReply { ack: ack })
kern_send(io, &kern::I2CWriteReply { ack: ack })
}
#[cfg(has_i2c)]
&kern::I2CReadRequest { busno, ack } => {
let data = board::i2c::read(busno, ack);
kern_send(waiter, &kern::I2CReadReply { data: data })
kern_send(io, &kern::I2CReadReply { data: data })
}
#[cfg(not(has_i2c))]
@ -475,11 +474,11 @@ fn process_kern_message(waiter: Waiter,
}
#[cfg(not(has_i2c))]
&kern::I2CWriteRequest { .. } => {
kern_send(waiter, &kern::I2CWriteReply { ack: false })
kern_send(io, &kern::I2CWriteReply { ack: false })
}
#[cfg(not(has_i2c))]
&kern::I2CReadRequest { .. } => {
kern_send(waiter, &kern::I2CReadReply { data: 0xff })
kern_send(io, &kern::I2CReadReply { data: 0xff })
}
&kern::RunFinished => {
@ -536,7 +535,7 @@ fn process_kern_message(waiter: Waiter,
})
}
fn process_kern_queued_rpc(stream: &mut TcpStream,
fn process_kern_queued_rpc(stream: &mut TcpSocket,
_session: &mut Session) -> io::Result<()> {
rpc_queue::dequeue(|slice| {
trace!("comm<-kern (async RPC)");
@ -548,8 +547,8 @@ fn process_kern_queued_rpc(stream: &mut TcpStream,
})
}
fn host_kernel_worker(waiter: Waiter,
stream: &mut TcpStream,
fn host_kernel_worker(io: &Io,
stream: &mut TcpSocket,
congress: &mut Congress) -> io::Result<()> {
let mut session = Session::new(congress);
@ -558,12 +557,14 @@ fn host_kernel_worker(waiter: Waiter,
try!(process_kern_queued_rpc(stream, &mut session))
}
if stream.readable() {
try!(process_host_message(waiter, stream, &mut session));
if stream.can_recv() {
try!(process_host_message(io, stream, &mut session))
} else if !stream.may_recv() {
return Ok(())
}
if mailbox::receive() != 0 {
try!(process_kern_message(waiter, Some(stream), &mut session));
try!(process_kern_message(io, Some(stream), &mut session));
}
if session.kernel_state == KernelState::Running {
@ -578,11 +579,11 @@ fn host_kernel_worker(waiter: Waiter,
}
}
try!(waiter.relinquish())
try!(io.relinquish())
}
}
fn flash_kernel_worker(waiter: Waiter,
fn flash_kernel_worker(io: &Io,
congress: &mut Congress,
config_key: &str) -> io::Result<()> {
let mut session = Session::new(congress);
@ -592,7 +593,7 @@ fn flash_kernel_worker(waiter: Waiter,
return Err(io::Error::new(io::ErrorKind::NotFound, "kernel not found"))
}
try!(unsafe { kern_load(waiter, &mut session, &kernel) });
try!(unsafe { kern_load(io, &mut session, &kernel) });
try!(kern_run(&mut session));
loop {
@ -601,7 +602,7 @@ fn flash_kernel_worker(waiter: Waiter,
}
if mailbox::receive() != 0 {
if try!(process_kern_message(waiter, None, &mut session)) {
if try!(process_kern_message(io, None, &mut session)) {
return Ok(())
}
}
@ -614,32 +615,31 @@ fn flash_kernel_worker(waiter: Waiter,
return Err(io_error("RTIO clock failure"))
}
try!(waiter.relinquish())
try!(io.relinquish())
}
}
fn respawn<F>(spawner: Spawner, waiter: Waiter,
handle: &mut Option<ThreadHandle>,
f: F) where F: 'static + FnOnce(Waiter, Spawner) + Send {
fn respawn<F>(io: &Io, handle: &mut Option<ThreadHandle>, f: F)
where F: 'static + FnOnce(Io) + Send {
match handle.take() {
None => (),
Some(handle) => {
if !handle.terminated() {
info!("terminating running kernel");
handle.interrupt();
waiter.join(handle).expect("cannot join interrupt thread")
io.join(handle).expect("cannot join interrupt thread")
}
}
}
*handle = Some(spawner.spawn(16384, f))
*handle = Some(io.spawn(16384, f))
}
pub fn thread(waiter: Waiter, spawner: Spawner) {
pub fn thread(io: Io) {
let congress = Urc::new(RefCell::new(Congress::new()));
info!("running startup kernel");
match flash_kernel_worker(waiter, &mut congress.borrow_mut(), "startup_kernel") {
match flash_kernel_worker(&io, &mut *borrow_mut!(congress), "startup_kernel") {
Ok(()) => info!("startup kernel finished"),
Err(err) => {
if err.kind() == io::ErrorKind::NotFound {
@ -652,27 +652,36 @@ pub fn thread(waiter: Waiter, spawner: Spawner) {
BufferLogger::with_instance(|logger| logger.disable_trace_to_uart());
let addr = SocketAddr::new(IP_ANY, 1381);
let listener = TcpListener::bind(waiter, addr).expect("cannot bind socket");
listener.set_keepalive(true);
const BUFFER_SIZE: usize = 65535;
let mut listener = TcpSocket::with_buffer_size(&io, BUFFER_SIZE);
info!("accepting network sessions");
let mut kernel_thread = None;
loop {
if listener.acceptable() {
let (mut stream, addr) = listener.accept().expect("cannot accept client");
match check_magic(&mut stream) {
Ok(()) => (),
Err(_) => continue
}
info!("new connection from {}", addr);
if !listener.is_open() {
listener.listen(1381).expect("session: cannot listen")
}
if listener.is_active() {
listener.accept().expect("session: cannot accept");
match check_magic(&mut listener) {
Ok(()) => (),
Err(_) => {
warn!("wrong magic from {}", listener.remote_endpoint());
listener.close().expect("session: cannot close");
continue
}
}
info!("new connection from {}", listener.remote_endpoint());
let socket = listener.into_handle();
listener = TcpSocket::with_buffer_size(&io, BUFFER_SIZE);
let stream = stream.into_lower();
let congress = congress.clone();
respawn(spawner.clone(), waiter, &mut kernel_thread, move |waiter, _spawner| {
let mut stream = TcpStream::from_lower(waiter, stream);
let mut congress = congress.borrow_mut();
match host_kernel_worker(waiter, &mut stream, &mut congress) {
respawn(&io, &mut kernel_thread, move |io| {
let mut congress = borrow_mut!(congress);
let mut socket = TcpSocket::from_handle(&io, socket);
match host_kernel_worker(&io, &mut socket, &mut *congress) {
Ok(()) => (),
Err(err) => {
if err.kind() == io::ErrorKind::UnexpectedEof {
@ -682,16 +691,16 @@ pub fn thread(waiter: Waiter, spawner: Spawner) {
}
}
}
})
});
}
if kernel_thread.as_ref().map_or(true, |h| h.terminated()) {
info!("no connection, starting idle kernel");
let congress = congress.clone();
respawn(spawner.clone(), waiter, &mut kernel_thread, move |waiter, _spawner| {
let mut congress = congress.borrow_mut();
match flash_kernel_worker(waiter, &mut congress, "idle_kernel") {
respawn(&io, &mut kernel_thread, move |io| {
let mut congress = borrow_mut!(congress);
match flash_kernel_worker(&io, &mut *congress, "idle_kernel") {
Ok(()) =>
info!("idle kernel finished, standing by"),
Err(err) => {
@ -699,7 +708,7 @@ pub fn thread(waiter: Waiter, spawner: Spawner) {
info!("idle kernel interrupted");
} else if err.kind() == io::ErrorKind::NotFound {
info!("no idle kernel found");
while waiter.relinquish().is_ok() {}
while io.relinquish().is_ok() {}
} else {
error!("idle kernel aborted: {}", err);
}
@ -708,6 +717,6 @@ pub fn thread(waiter: Waiter, spawner: Spawner) {
})
}
let _ = waiter.relinquish();
let _ = io.relinquish();
}
}

View File

@ -46,7 +46,5 @@ class AMPSoC:
def build_artiq_soc(soc, argdict):
builder = Builder(soc, **argdict)
builder.add_extra_software_packages()
builder.add_software_package("liblwip", os.path.join(artiq_dir, "runtime",
"liblwip"))
builder.add_software_package("runtime", os.path.join(artiq_dir, "runtime"))
builder.build()

View File

@ -7,13 +7,9 @@ RUSTOUT := cargo/or1k-unknown-none/debug
RUSTOUT_KSUPPORT := cargo-ksupport/or1k-unknown-none/debug
CFLAGS += \
-I$(LIBALLOC_DIRECTORY) \
-I$(MISOC_DIRECTORY)/software/include/dyld \
-I$(LIBDYLD_DIRECTORY)/include \
-I$(LIBUNWIND_DIRECTORY) \
-I$(LIBUNWIND_DIRECTORY)/../unwinder/include \
-I$(LIBLWIP_DIRECTORY)/../lwip/src/include \
-I$(LIBLWIP_DIRECTORY)
-I$(MISOC_DIRECTORY)/software/include/dyld
CFLAGS += -DNDEBUG
LDFLAGS += --gc-sections \
@ -22,8 +18,7 @@ LDFLAGS += --gc-sections \
-L../libm \
-L../liballoc \
-L../libunwind \
-L../libdyld \
-L../liblwip
-L../libdyld
all: runtime.bin runtime.fbi
@ -34,12 +29,12 @@ $(RUSTOUT)/libruntime.a:
cargo build --target=or1k-unknown-none \
--manifest-path $(realpath $(RUNTIME_DIRECTORY)/../firmware/runtime/Cargo.toml)
runtime.elf: $(RUSTOUT)/libruntime.a flash_storage.o main.o ksupport_data.o
runtime.elf: $(RUSTOUT)/libruntime.a flash_storage.o ksupport_data.o
$(LD) $(LDFLAGS) \
-T $(RUNTIME_DIRECTORY)/runtime.ld \
-o $@ \
$^ \
-lbase-nofloat -lcompiler-rt -lalloc -llwip
-lbase-nofloat -lcompiler-rt -lalloc
@chmod -x $@
.PHONY: $(RUSTOUT_KSUPPORT)/libksupport.a

View File

@ -1,83 +0,0 @@
include ../include/generated/variables.mak
include $(MISOC_DIRECTORY)/software/common.mak
LWIPDIR=$(LIBLWIP_DIRECTORY)/../lwip/src
CFLAGS += $(CPPFLAGS) -I. \
-I$(LWIPDIR)/include \
-I$(LWIPDIR)/include/ipv4
# COREFILES, CORE4FILES: The minimum set of files needed for lwIP.
COREFILES=core/mem.c \
core/memp.c \
core/netif.c \
core/pbuf.c \
core/raw.c \
core/stats.c \
core/sys.c \
core/ip.c \
core/tcp.c \
core/tcp_in.c \
core/tcp_out.c \
core/udp.c \
core/inet_chksum.c \
core/timeouts.c \
core/init.c
CORE4FILES=core/ipv4/etharp.c \
core/ipv4/icmp.c \
core/ipv4/ip4.c \
core/ipv4/ip4_addr.c \
core/ipv4/ip4_frag.c
# NETIFFILES: Files implementing various generic network interface functions.
NETIFFILES=netif/ethernet.c
PPPFILES=netif/ppp/auth.c \
netif/ppp/fsm.c \
netif/ppp/ipcp.c \
netif/ppp/lcp.c \
netif/ppp/magic.c \
netif/ppp/ppp.c \
netif/ppp/pppos.c \
netif/ppp/utils.c \
netif/ppp/vj.c
# LWIPFILES: All the above.
LWIPFILES=$(COREFILES) $(CORE4FILES) $(NETIFFILES) $(PPPFILES)
LWIPOBJS:=$(LWIPFILES:.c=.o) liteethif.o
all: prepare liblwip.a
prepare:
rm -f lwipopts.h
rm -f arch
ln -s $(LIBLWIP_DIRECTORY)/lwipopts.h lwipopts.h
ln -s $(LIBLWIP_DIRECTORY)/arch arch
mkdir -p core/ipv4
mkdir -p netif
mkdir -p netif/ppp
core/%.o: $(LWIPDIR)/core/%.c
$(compile)
core/ipv4/%.o: $(LWIPDIR)/core/ipv4/%.c
$(compile)
netif/%.o: $(LWIPDIR)/netif/%.c
$(compile)
netif/ppp/%.o: $(LWIPDIR)/netif/ppp/%.c
$(compile)
%.o: $(LIBLWIP_DIRECTORY)/%.c
$(compile)
.PHONY: all clean prepare
clean:
rm -f $(LWIPOBJS) liblwip.a
liblwip.a: $(LWIPOBJS)
$(AR) clr liblwip.a $(LWIPOBJS)

View File

@ -1,35 +0,0 @@
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
// LiteETH lwIP port for ARTIQ
// License: BSD
#ifndef __ARCH_CC_H__
#define __ARCH_CC_H__
/* Include some files for defining library routines */
#define BYTE_ORDER BIG_ENDIAN
/* Compiler hints for packing structures */
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
/* prototypes for printf() and abort() */
#include <stdio.h>
#include <stdlib.h>
#include "console.h"
#define pp_printf printf
/* Definitions for ASSERT/DIAG */
#ifdef LWIP_NOASSERT
#define LWIP_PLATFORM_ASSERT(x)
#else
#define LWIP_PLATFORM_ASSERT(x) do {pp_printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__); } while(0)
#endif
#ifdef LWIP_DEBUG
#define LWIP_PLATFORM_DIAG(x) do {pp_printf x;} while(0)
#endif
#endif /* __ARCH_CC_H__ */

View File

@ -1,11 +0,0 @@
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
// LiteETH lwIP port for ARTIQ
// License: BSD
#ifndef __ARCH_PERF_H__
#define __ARCH_PERF_H__
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* __ARCH_PERF_H__ */

View File

@ -1,130 +0,0 @@
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
// LiteETH lwIP port for ARTIQ
// License: BSD
#include <generated/csr.h>
#ifdef CSR_ETHMAC_BASE
#include <lwip/opt.h>
#include <lwip/mem.h>
#include <netif/etharp.h>
#include "liteethif.h"
#include <hw/flags.h>
#include <hw/ethmac_mem.h>
static char *rxbuffer0;
static char *rxbuffer1;
static unsigned int txslot;
static unsigned int txlen;
static char *txbuffer;
static char *txbuffer0;
static char *txbuffer1;
#define IFNAME0 'e'
#define IFNAME1 't'
static err_t liteeth_low_level_output(struct netif *netif, struct pbuf *p)
{
struct pbuf *q;
txlen = 0;
q = p;
while(q) {
memcpy(txbuffer, q->payload, q->len);
txbuffer += q->len;
txlen += q->len;
if(q->tot_len != q->len)
q = q->next;
else
q = NULL;
}
ethmac_sram_reader_slot_write(txslot);
ethmac_sram_reader_length_write(txlen);
while(!ethmac_sram_reader_ready_read());
ethmac_sram_reader_start_write(1);
txslot = (txslot + 1) % 2;
if(txslot)
txbuffer = txbuffer1;
else
txbuffer = txbuffer0;
return ERR_OK;
}
static struct pbuf *liteeth_low_level_input(struct netif *netif)
{
unsigned int rxslot;
unsigned int rxlen;
char *rxbuffer;
struct pbuf *p, *q;
p = NULL;
if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) {
rxslot = ethmac_sram_writer_slot_read();
rxlen = ethmac_sram_writer_length_read();
/* dest MAC + source MAC + 802.1Q + ethertype + payload (MTU) */
if(rxlen <= (netif->mtu + 18)) {
if(rxslot)
rxbuffer = rxbuffer1;
else
rxbuffer = rxbuffer0;
p = pbuf_alloc(PBUF_RAW, rxlen, PBUF_POOL);
q = p;
while(q) {
memcpy(q->payload, rxbuffer, q->len);
rxbuffer += q->len;
if(q->tot_len != q->len)
q = q->next;
else
q = NULL;
}
}
ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
}
return p;
}
void liteeth_input(struct netif *netif)
{
struct pbuf *p;
p = liteeth_low_level_input(netif);
if(p != NULL)
netif->input(p, netif);
}
err_t liteeth_init(struct netif *netif)
{
int i;
netif->hwaddr_len = 6;
for(i=0;i<netif->hwaddr_len;i++)
netif->hwaddr[i] = macadr[i];
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = etharp_output;
netif->linkoutput = liteeth_low_level_output;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER);
ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
rxbuffer0 = (char *)ETHMAC_RX0_BASE;
rxbuffer1 = (char *)ETHMAC_RX1_BASE;
txbuffer0 = (char *)ETHMAC_TX0_BASE;
txbuffer1 = (char *)ETHMAC_TX1_BASE;
txslot = 0;
txbuffer = txbuffer0;
return ERR_OK;
}
#endif /* CSR_ETHMAC_BASE */

View File

@ -1,13 +0,0 @@
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
// LiteETH lwIP port for ARTIQ
// License: BSD
#ifndef __LITEETHIF_H__
#define __LITEETHIF_H__
extern unsigned char macadr[];
void liteeth_input(struct netif *netif);
err_t liteeth_init(struct netif *netif);
#endif /* __LITEETH_IF_H__ */

View File

@ -1,192 +0,0 @@
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
#define NO_SYS 1
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#define LWIP_IPV6 0
#define LWIP_CALLBACK_API 1
#define SYS_LIGHTWEIGHT_PROT 0
/* -------- TCP Timer Intervals ------- */
#define TCP_TMR_INTERVAL 1 /* The TCP timer interval in
milliseconds. */
#define TCP_FAST_INTERVAL 2 /* the fine grained timeout in
milliseconds */
#define TCP_SLOW_INTERVAL 5 /* the coarse grained timeout in
milliseconds */
/* ---------- Memory options ---------- */
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
#define MEM_ALIGNMENT 4
/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#define MEM_SIZE 32 * 1024
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#define MEMP_NUM_PBUF 64
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#define MEMP_NUM_UDP_PCB 2
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#define MEMP_NUM_TCP_PCB 8
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
connections. */
#define MEMP_NUM_TCP_PCB_LISTEN 16
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#define MEMP_NUM_TCP_SEG 255
/* The following four are used only with the sequential API and can be
set to 0 if the application only will use the raw API. */
/* MEMP_NUM_NETBUF: the number of struct netbufs. */
#define MEMP_NUM_NETBUF 0
/* MEMP_NUM_NETCONN: the number of struct netconns. */
#define MEMP_NUM_NETCONN 0
/* MEMP_NUM_TCPIP_MSG: the number of struct tcpip_msg, which is used
for sequential API communication and incoming packets. Used in
src/api/tcpip.c. */
#define MEMP_NUM_TCPIP_MSG_API 0
#define MEMP_NUM_TCPIP_MSG_INPKT 0
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#define MEMP_NUM_SYS_TIMEOUT 5
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE 512
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#define PBUF_POOL_BUFSIZE 1536
/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
link level header. */
#define PBUF_LINK_HLEN 16
/* ---------- TCP options ---------- */
#define LWIP_TCP 1
#define LWIP_TCP_KEEPALIVE 1
#define TCP_KEEPIDLE_DEFAULT 1250
#define TCP_KEEPINTVL_DEFAULT 1000
#define TCP_KEEPCNT_DEFAULT 3
#define TCP_TTL 255
/* Controls if TCP should queue segments that arrive out of
order. Define to 0 if your device is low on memory. */
#define TCP_QUEUE_OOSEQ 1
/* TCP Maximum segment size. */
#define TCP_MSS 1476
/* TCP sender buffer space (bytes). */
#define TCP_SND_BUF 32 * 1024
/* TCP sender buffer space (pbufs). */
#define TCP_SND_QUEUELEN 3 * TCP_SND_BUF/TCP_MSS
/* TCP receive window. */
#define TCP_WND 16 * 1024
/* Maximum number of retransmissions of data segments. */
#define TCP_MAXRTX 12
/* Maximum number of retransmissions of SYN segments. */
#define TCP_SYNMAXRTX 4
/* ---------- ARP options ---------- */
#define ARP_TABLE_SIZE 10
#define ARP_QUEUEING 1
/* ---------- IP options ---------- */
/* Define IP_FORWARD to 1 if you wish to have the ability to forward
IP packets across network interfaces. If you are going to run lwIP
on a device with only one network interface, define this to 0. */
#define IP_FORWARD 0
/* If defined to 1, IP options are allowed (but not parsed). If
defined to 0, all packets with IP options are dropped. */
#define IP_OPTIONS 1
/* ---------- ICMP options ---------- */
#define ICMP_TTL 255
/* ---------- DHCP options ---------- */
/* Define LWIP_DHCP to 1 if you want DHCP configuration of
interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
turning this on does currently not work. */
#define LWIP_DHCP 0
/* 1 if you want to do an ARP check on the offered address
(recommended). */
#define DHCP_DOES_ARP_CHECK 0
/* ---------- UDP options ---------- */
#define LWIP_UDP 1
#define UDP_TTL 255
/* ---------- Statistics options ---------- */
/*#define STATS*/
#ifdef STATS
#define LINK_STATS
#define IP_STATS
#define ICMP_STATS
#define UDP_STATS
#define TCP_STATS
#define MEM_STATS
#define MEMP_STATS
#define PBUF_STATS
#define SYS_STATS
#endif /* STATS */
/* ---------- PPP ---------- */
#define PPP_SUPPORT 1
#define PPPOS_SUPPORT 1
#define PPP_IPV4_SUPPORT 1
#endif /* __LWIPOPTS_H__ */

@ -1 +0,0 @@
Subproject commit 216bf89491815029aa15463a18744afa04df58fe

View File

@ -1,197 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <alloc.h>
#include <irq.h>
#include <uart.h>
#include <console.h>
#include <system.h>
#include <generated/csr.h>
#include <hw/flags.h>
#include <lwip/init.h>
#include <lwip/ip4_addr.h>
#include <lwip/netif.h>
#include <lwip/timeouts.h>
#include <lwip/tcp.h>
#ifdef CSR_ETHMAC_BASE
#include <netif/etharp.h>
#include <liteethif.h>
#else
#include <netif/ppp/ppp.h>
#include <netif/ppp/pppos.h>
#endif
#include "flash_storage.h"
static struct netif netif;
#ifndef CSR_ETHMAC_BASE
static ppp_pcb *ppp;
#endif
void lwip_service(void);
void lwip_service(void)
{
sys_check_timeouts();
#ifdef CSR_ETHMAC_BASE
liteeth_input(&netif);
#else
if(uart_read_nonblock()) {
u8_t c;
c = uart_read();
pppos_input(ppp, &c, 1);
}
#endif
}
#ifdef CSR_ETHMAC_BASE
unsigned char macadr[6];
static int hex2nib(int c)
{
if((c >= '0') && (c <= '9'))
return c - '0';
if((c >= 'a') && (c <= 'f'))
return c - 'a' + 10;
if((c >= 'A') && (c <= 'F'))
return c - 'A' + 10;
return -1;
}
static void init_macadr(void)
{
static const unsigned char default_macadr[6] = {0x10, 0xe2, 0xd5, 0x32, 0x50, 0x00};
#if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE)
char b[32];
char fs_macadr[6];
int i, r, s;
#endif
memcpy(macadr, default_macadr, 6);
#if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE)
r = fs_read("mac", b, sizeof(b) - 1, NULL);
if(r <= 0)
return;
b[r] = 0;
for(i=0;i<6;i++) {
r = hex2nib(b[3*i]);
s = hex2nib(b[3*i + 1]);
if((r < 0) || (s < 0))
return;
fs_macadr[i] = (r << 4) | s;
}
for(i=0;i<5;i++)
if(b[3*i + 2] != ':')
return;
memcpy(macadr, fs_macadr, 6);
#endif
}
static void fsip_or_default(struct ip4_addr *d, char *key, int i1, int i2, int i3, int i4)
{
int r;
#if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE)
char cp[32];
#endif
IP4_ADDR(d, i1, i2, i3, i4);
#if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE)
r = fs_read(key, cp, sizeof(cp) - 1, NULL);
if(r <= 0)
return;
cp[r] = 0;
if(!ip4addr_aton(cp, d))
return;
#endif
}
void network_init(void);
void network_init(void)
{
struct ip4_addr local_ip;
struct ip4_addr netmask;
struct ip4_addr gateway_ip;
init_macadr();
fsip_or_default(&local_ip, "ip", 192, 168, 1, 50);
fsip_or_default(&netmask, "netmask", 255, 255, 255, 0);
fsip_or_default(&gateway_ip, "gateway", 192, 168, 1, 1);
lwip_init();
netif_add(&netif, &local_ip, &netmask, &gateway_ip, 0, liteeth_init, ethernet_input);
netif_set_default(&netif);
netif_set_up(&netif);
netif_set_link_up(&netif);
}
#else /* CSR_ETHMAC_BASE */
static int ppp_connected;
static u32_t ppp_output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
{
for(int i = 0; i < len; i++)
uart_write(data[i]);
return len;
}
static void ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx)
{
if (err_code == PPPERR_NONE) {
ppp_connected = 1;
return;
} else if (err_code == PPPERR_USER) {
return;
} else {
ppp_connect(pcb, 1);
}
}
void network_init(void)
{
lwip_init();
ppp_connected = 0;
ppp = pppos_create(&netif, ppp_output_cb, ppp_status_cb, NULL);
ppp_set_auth(ppp, PPPAUTHTYPE_NONE, "", "");
ppp_set_default(ppp);
ppp_connect(ppp, 0);
while (!ppp_connected)
lwip_service();
}
#endif /* CSR_ETHMAC_BASE */
extern void _fheap, _eheap;
extern void rust_main();
u16_t tcp_sndbuf_(struct tcp_pcb *pcb);
u16_t tcp_sndbuf_(struct tcp_pcb *pcb) {
return tcp_sndbuf(pcb);
}
u8_t* tcp_so_options_(struct tcp_pcb *pcb);
u8_t* tcp_so_options_(struct tcp_pcb *pcb) {
return &pcb->so_options;
}
void tcp_nagle_disable_(struct tcp_pcb *pcb);
void tcp_nagle_disable_(struct tcp_pcb *pcb) {
tcp_nagle_disable(pcb);
}
int main(void)
{
irq_setmask(0);
irq_setie(1);
uart_init();
alloc_give(&_fheap, &_eheap - &_fheap);
rust_main();
return 0;
}