forked from M-Labs/artiq
firmware: integrate smoltcp instead of lwip.
This commit is contained in:
parent
0253e0a89d
commit
527b1e986c
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -1,4 +0,0 @@
|
||||
[submodule "artiq/runtime/lwip"]
|
||||
path = artiq/runtime/lwip
|
||||
url = https://github.com/m-labs/lwip
|
||||
ignore = untracked
|
35
artiq/firmware/Cargo.lock
generated
35
artiq/firmware/Cargo.lock
generated
@ -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"
|
||||
|
@ -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 }
|
||||
|
@ -1,8 +0,0 @@
|
||||
[package]
|
||||
authors = ["M-Labs"]
|
||||
name = "lwip-sys"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "lwip_sys"
|
||||
path = "lib.rs"
|
@ -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);
|
||||
}
|
@ -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 = []
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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"]
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
77
artiq/firmware/runtime/ethmac.rs
Normal file
77
artiq/firmware/runtime/ethmac.rs
Normal 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) }
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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)
|
@ -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__ */
|
@ -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__ */
|
@ -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 */
|
@ -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__ */
|
@ -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
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user