firmware: implement libio and use in in drtioaux.

pull/1017/head
whitequark 2018-05-14 10:02:39 +00:00
parent d543c9aa63
commit 46c8afc56c
8 changed files with 633 additions and 381 deletions

View File

@ -107,10 +107,9 @@ version = "0.0.0"
dependencies = [
"board 0.0.0",
"build_misoc 0.0.0",
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"io 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"std_artiq 0.0.0",
]
[[package]]
@ -125,6 +124,13 @@ dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "io"
version = "0.0.0"
dependencies = [
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"

View File

@ -14,6 +14,5 @@ build_misoc = { path = "../libbuild_misoc" }
[dependencies]
log = { version = "0.4", default-features = false }
crc = { version = "1.7", default-features = false }
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
io = { path = "../libio", features = ["byteorder"] }
board = { path = "../libboard" }
byteorder = { version = "1.0", default-features = false }

View File

@ -0,0 +1,139 @@
use super::*;
use {Error, Result};
use io::Cursor;
use io::proto::ProtoRead;
pub fn reset(linkno: u8) {
let linkno = linkno as usize;
unsafe {
// clear buffer first to limit race window with buffer overflow
// error. We assume the CPU is fast enough so that no two packets
// will be received between the buffer and the error flag are cleared.
(board::csr::DRTIO[linkno].aux_rx_present_write)(1);
(board::csr::DRTIO[linkno].aux_rx_error_write)(1);
}
}
fn has_rx_error(linkno: u8) -> bool {
let linkno = linkno as usize;
unsafe {
let error = (board::csr::DRTIO[linkno].aux_rx_error_read)() != 0;
if error {
(board::csr::DRTIO[linkno].aux_rx_error_write)(1)
}
error
}
}
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, !>
where F: FnOnce(&[u8]) -> Result<T, !>
{
let linkidx = linkno as usize;
unsafe {
if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 {
let ptr = board::mem::DRTIO_AUX[linkidx].base +
board::mem::DRTIO_AUX[linkidx].size / 2;
let len = (board::csr::DRTIO[linkidx].aux_rx_length_read)();
let result = f(slice::from_raw_parts(ptr as *mut u8, len as usize));
(board::csr::DRTIO[linkidx].aux_rx_present_write)(1);
Ok(Some(result?))
} else {
Ok(None)
}
}
}
pub fn recv_link(linkno: u8) -> Result<Option<Packet>, !> {
if has_rx_error(linkno) {
return Err(Error::GatewareError)
}
receive(linkno, |buffer| {
if buffer.len() < 8 {
return Err(Error::Io(IoError::UnexpectedEof))
}
let mut reader = Cursor::new(buffer);
let checksum_at = buffer.len() - 4;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at);
if reader.read_u32()? != checksum {
return Err(Error::CorruptedPacket)
}
reader.set_position(0);
Packet::read_from(&mut reader)
})
}
pub fn recv_timeout_link(linkno: u8, timeout_ms: Option<u64>) -> Result<Packet, !> {
let timeout_ms = timeout_ms.unwrap_or(10);
let limit = board::clock::get_ms() + timeout_ms;
while board::clock::get_ms() < limit {
match recv_link(linkno)? {
None => (),
Some(packet) => return Ok(packet),
}
}
Err(Error::TimedOut)
}
fn transmit<F>(linkno: u8, f: F) -> Result<(), !>
where F: FnOnce(&mut [u8]) -> Result<usize, !>
{
let linkno = linkno as usize;
unsafe {
while (board::csr::DRTIO[linkno].aux_tx_read)() != 0 {}
let ptr = board::mem::DRTIO_AUX[linkno].base;
let len = board::mem::DRTIO_AUX[linkno].size / 2;
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, len))?;
(board::csr::DRTIO[linkno].aux_tx_length_write)(len as u16);
(board::csr::DRTIO[linkno].aux_tx_write)(1);
Ok(())
}
}
pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), !> {
transmit(linkno, |buffer| {
let mut writer = Cursor::new(buffer);
packet.write_to(&mut writer)?;
let padding = 4 - (writer.position() % 4);
if padding != 4 {
for _ in 0..padding {
writer.write_u8(0)?;
}
}
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
writer.write_u32(checksum)?;
Ok(writer.position())
})
}
// TODO: routing
fn get_linkno(nodeno: u8) -> Result<u8, !> {
if nodeno == 0 || nodeno as usize > board::csr::DRTIO.len() {
return Err(Error::NoRoute)
}
Ok(nodeno - 1)
}
pub fn recv(nodeno: u8) -> Result<Option<Packet>, !> {
let linkno = get_linkno(nodeno)?;
recv_link(linkno)
}
pub fn recv_timeout(nodeno: u8, timeout_ms: Option<u64>) -> Result<Packet, !> {
let linkno = get_linkno(nodeno)?;
recv_timeout_link(linkno, timeout_ms)
}
pub fn send(nodeno: u8, packet: &Packet) -> Result<(), !> {
let linkno = get_linkno(nodeno)?;
send_link(linkno, packet)
}

View File

@ -1,17 +1,63 @@
#![no_std]
#![feature(never_type)]
extern crate byteorder;
extern crate crc;
#[macro_use]
extern crate std_artiq as std;
extern crate io;
extern crate board;
mod proto;
use std::io::{self, Read, Write};
#[cfg(has_drtio)]
use core::slice;
use proto::*;
use core::result;
use core::fmt;
use io::{Read, Write, Error as IoError};
use io::proto::{ProtoRead, ProtoWrite};
pub type Result<T, E> = result::Result<T, Error<E>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error<T> {
UnknownPacket(u8),
CorruptedPacket,
TimedOut,
NoRoute,
GatewareError,
Io(IoError<T>),
Other(T)
}
impl<T: fmt::Display> fmt::Display for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::UnknownPacket(ty) =>
write!(f, "unknown packet type {:#02x}", ty),
&Error::CorruptedPacket =>
write!(f, "packet CRC failed"),
&Error::TimedOut =>
write!(f, "timed out waiting for data"),
&Error::NoRoute =>
write!(f, "invalid node number"),
&Error::GatewareError =>
write!(f, "gateware reported error"),
&Error::Io(ref io) =>
write!(f, "I/O error ({})", io),
&Error::Other(ref err) =>
write!(f, "{}", err)
}
}
}
impl<T> From<T> for Error<T> {
fn from(value: T) -> Error<T> {
Error::Other(value)
}
}
impl<T> From<IoError<T>> for Error<T> {
fn from(value: IoError<T>) -> Error<T> {
Error::Io(value)
}
}
#[derive(Debug)]
pub enum Packet {
@ -49,215 +95,220 @@ pub enum Packet {
}
impl Packet {
pub fn read_from(reader: &mut Read) -> io::Result<Packet> {
Ok(match read_u8(reader)? {
pub fn read_from<T: Read>(reader: &mut T) -> Result<Packet, T::ReadError> {
Ok(match reader.read_u8()? {
0x00 => Packet::EchoRequest,
0x01 => Packet::EchoReply,
0x02 => Packet::ResetRequest {
phy: read_bool(reader)?
phy: reader.read_bool()?
},
0x03 => Packet::ResetAck,
0x20 => Packet::RtioErrorRequest,
0x21 => Packet::RtioNoErrorReply,
0x22 => Packet::RtioErrorSequenceErrorReply {
channel: read_u16(reader)?
channel: reader.read_u16()?
},
0x23 => Packet::RtioErrorCollisionReply {
channel: read_u16(reader)?
channel: reader.read_u16()?
},
0x24 => Packet::RtioErrorBusyReply {
channel: read_u16(reader)?
channel: reader.read_u16()?
},
0x40 => Packet::MonitorRequest {
channel: read_u16(reader)?,
probe: read_u8(reader)?
channel: reader.read_u16()?,
probe: reader.read_u8()?
},
0x41 => Packet::MonitorReply {
value: read_u32(reader)?
value: reader.read_u32()?
},
0x50 => Packet::InjectionRequest {
channel: read_u16(reader)?,
overrd: read_u8(reader)?,
value: read_u8(reader)?
channel: reader.read_u16()?,
overrd: reader.read_u8()?,
value: reader.read_u8()?
},
0x51 => Packet::InjectionStatusRequest {
channel: read_u16(reader)?,
overrd: read_u8(reader)?
channel: reader.read_u16()?,
overrd: reader.read_u8()?
},
0x52 => Packet::InjectionStatusReply {
value: read_u8(reader)?
value: reader.read_u8()?
},
0x80 => Packet::I2cStartRequest {
busno: read_u8(reader)?
busno: reader.read_u8()?
},
0x81 => Packet::I2cRestartRequest {
busno: read_u8(reader)?
busno: reader.read_u8()?
},
0x82 => Packet::I2cStopRequest {
busno: read_u8(reader)?
busno: reader.read_u8()?
},
0x83 => Packet::I2cWriteRequest {
busno: read_u8(reader)?,
data: read_u8(reader)?
busno: reader.read_u8()?,
data: reader.read_u8()?
},
0x84 => Packet::I2cWriteReply {
succeeded: read_bool(reader)?,
ack: read_bool(reader)?
succeeded: reader.read_bool()?,
ack: reader.read_bool()?
},
0x85 => Packet::I2cReadRequest {
busno: read_u8(reader)?,
ack: read_bool(reader)?
busno: reader.read_u8()?,
ack: reader.read_bool()?
},
0x86 => Packet::I2cReadReply {
succeeded: read_bool(reader)?,
data: read_u8(reader)?
succeeded: reader.read_bool()?,
data: reader.read_u8()?
},
0x87 => Packet::I2cBasicReply {
succeeded: read_bool(reader)?
succeeded: reader.read_bool()?
},
0x90 => Packet::SpiSetConfigRequest {
busno: read_u8(reader)?,
flags: read_u8(reader)?,
length: read_u8(reader)?,
div: read_u8(reader)?,
cs: read_u8(reader)?
busno: reader.read_u8()?,
flags: reader.read_u8()?,
length: reader.read_u8()?,
div: reader.read_u8()?,
cs: reader.read_u8()?
},
/* 0x91: was Packet::SpiSetXferRequest */
0x92 => Packet::SpiWriteRequest {
busno: read_u8(reader)?,
data: read_u32(reader)?
busno: reader.read_u8()?,
data: reader.read_u32()?
},
0x93 => Packet::SpiReadRequest {
busno: read_u8(reader)?
busno: reader.read_u8()?
},
0x94 => Packet::SpiReadReply {
succeeded: read_bool(reader)?,
data: read_u32(reader)?
succeeded: reader.read_bool()?,
data: reader.read_u32()?
},
0x95 => Packet::SpiBasicReply {
succeeded: read_bool(reader)?
succeeded: reader.read_bool()?
},
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown packet type"))
ty => return Err(Error::UnknownPacket(ty))
})
}
pub fn write_to(&self, writer: &mut Write) -> io::Result<()> {
pub fn write_to<T: Write>(&self, writer: &mut T) -> Result<(), T::WriteError> {
match *self {
Packet::EchoRequest => write_u8(writer, 0x00)?,
Packet::EchoReply => write_u8(writer, 0x01)?,
Packet::EchoRequest =>
writer.write_u8(0x00)?,
Packet::EchoReply =>
writer.write_u8(0x01)?,
Packet::ResetRequest { phy } => {
write_u8(writer, 0x02)?;
write_bool(writer, phy)?;
writer.write_u8(0x02)?;
writer.write_bool(phy)?;
},
Packet::ResetAck => write_u8(writer, 0x03)?,
Packet::ResetAck =>
writer.write_u8(0x03)?,
Packet::RtioErrorRequest => write_u8(writer, 0x20)?,
Packet::RtioNoErrorReply => write_u8(writer, 0x21)?,
Packet::RtioErrorRequest =>
writer.write_u8(0x20)?,
Packet::RtioNoErrorReply =>
writer.write_u8(0x21)?,
Packet::RtioErrorSequenceErrorReply { channel } => {
write_u8(writer, 0x22)?;
write_u16(writer, channel)?;
writer.write_u8(0x22)?;
writer.write_u16(channel)?;
},
Packet::RtioErrorCollisionReply { channel } => {
write_u8(writer, 0x23)?;
write_u16(writer, channel)?;
writer.write_u8(0x23)?;
writer.write_u16(channel)?;
},
Packet::RtioErrorBusyReply { channel } => {
write_u8(writer, 0x24)?;
write_u16(writer, channel)?;
writer.write_u8(0x24)?;
writer.write_u16(channel)?;
},
Packet::MonitorRequest { channel, probe } => {
write_u8(writer, 0x40)?;
write_u16(writer, channel)?;
write_u8(writer, probe)?;
writer.write_u8(0x40)?;
writer.write_u16(channel)?;
writer.write_u8(probe)?;
},
Packet::MonitorReply { value } => {
write_u8(writer, 0x41)?;
write_u32(writer, value)?;
writer.write_u8(0x41)?;
writer.write_u32(value)?;
},
Packet::InjectionRequest { channel, overrd, value } => {
write_u8(writer, 0x50)?;
write_u16(writer, channel)?;
write_u8(writer, overrd)?;
write_u8(writer, value)?;
writer.write_u8(0x50)?;
writer.write_u16(channel)?;
writer.write_u8(overrd)?;
writer.write_u8(value)?;
},
Packet::InjectionStatusRequest { channel, overrd } => {
write_u8(writer, 0x51)?;
write_u16(writer, channel)?;
write_u8(writer, overrd)?;
writer.write_u8(0x51)?;
writer.write_u16(channel)?;
writer.write_u8(overrd)?;
},
Packet::InjectionStatusReply { value } => {
write_u8(writer, 0x52)?;
write_u8(writer, value)?;
writer.write_u8(0x52)?;
writer.write_u8(value)?;
},
Packet::I2cStartRequest { busno } => {
write_u8(writer, 0x80)?;
write_u8(writer, busno)?;
writer.write_u8(0x80)?;
writer.write_u8(busno)?;
},
Packet::I2cRestartRequest { busno } => {
write_u8(writer, 0x81)?;
write_u8(writer, busno)?;
writer.write_u8(0x81)?;
writer.write_u8(busno)?;
},
Packet::I2cStopRequest { busno } => {
write_u8(writer, 0x82)?;
write_u8(writer, busno)?;
writer.write_u8(0x82)?;
writer.write_u8(busno)?;
},
Packet::I2cWriteRequest { busno, data } => {
write_u8(writer, 0x83)?;
write_u8(writer, busno)?;
write_u8(writer, data)?;
writer.write_u8(0x83)?;
writer.write_u8(busno)?;
writer.write_u8(data)?;
},
Packet::I2cWriteReply { succeeded, ack } => {
write_u8(writer, 0x84)?;
write_bool(writer, succeeded)?;
write_bool(writer, ack)?;
writer.write_u8(0x84)?;
writer.write_bool(succeeded)?;
writer.write_bool(ack)?;
},
Packet::I2cReadRequest { busno, ack } => {
write_u8(writer, 0x85)?;
write_u8(writer, busno)?;
write_bool(writer, ack)?;
writer.write_u8(0x85)?;
writer.write_u8(busno)?;
writer.write_bool(ack)?;
},
Packet::I2cReadReply { succeeded, data } => {
write_u8(writer, 0x86)?;
write_bool(writer, succeeded)?;
write_u8(writer, data)?;
writer.write_u8(0x86)?;
writer.write_bool(succeeded)?;
writer.write_u8(data)?;
},
Packet::I2cBasicReply { succeeded } => {
write_u8(writer, 0x87)?;
write_bool(writer, succeeded)?;
writer.write_u8(0x87)?;
writer.write_bool(succeeded)?;
},
Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => {
write_u8(writer, 0x90)?;
write_u8(writer, busno)?;
write_u8(writer, flags)?;
write_u8(writer, length)?;
write_u8(writer, div)?;
write_u8(writer, cs)?;
writer.write_u8(0x90)?;
writer.write_u8(busno)?;
writer.write_u8(flags)?;
writer.write_u8(length)?;
writer.write_u8(div)?;
writer.write_u8(cs)?;
},
Packet::SpiWriteRequest { busno, data } => {
write_u8(writer, 0x92)?;
write_u8(writer, busno)?;
write_u32(writer, data)?;
writer.write_u8(0x92)?;
writer.write_u8(busno)?;
writer.write_u32(data)?;
},
Packet::SpiReadRequest { busno } => {
write_u8(writer, 0x93)?;
write_u8(writer, busno)?;
writer.write_u8(0x93)?;
writer.write_u8(busno)?;
},
Packet::SpiReadReply { succeeded, data } => {
write_u8(writer, 0x94)?;
write_bool(writer, succeeded)?;
write_u32(writer, data)?;
writer.write_u8(0x94)?;
writer.write_bool(succeeded)?;
writer.write_u32(data)?;
},
Packet::SpiBasicReply { succeeded } => {
write_u8(writer, 0x95)?;
write_bool(writer, succeeded)?;
writer.write_u8(0x95)?;
writer.write_bool(succeeded)?;
},
}
Ok(())
@ -265,163 +316,4 @@ impl Packet {
}
#[cfg(has_drtio)]
pub mod hw {
use super::*;
use std::io::Cursor;
pub fn reset(linkno: u8) {
let linkno = linkno as usize;
unsafe {
// clear buffer first to limit race window with buffer overflow
// error. We assume the CPU is fast enough so that no two packets
// will be received between the buffer and the error flag are cleared.
(board::csr::DRTIO[linkno].aux_rx_present_write)(1);
(board::csr::DRTIO[linkno].aux_rx_error_write)(1);
}
}
fn rx_has_error(linkno: u8) -> bool {
let linkno = linkno as usize;
unsafe {
let error = (board::csr::DRTIO[linkno].aux_rx_error_read)() != 0;
if error {
(board::csr::DRTIO[linkno].aux_rx_error_write)(1)
}
error
}
}
struct RxBuffer(u8, &'static [u8]);
impl Drop for RxBuffer {
fn drop(&mut self) {
unsafe {
(board::csr::DRTIO[self.0 as usize].aux_rx_present_write)(1);
}
}
}
fn rx_get_buffer(linkno: u8) -> Option<RxBuffer> {
let linkidx = linkno as usize;
unsafe {
if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 {
let length = (board::csr::DRTIO[linkidx].aux_rx_length_read)();
let base = board::mem::DRTIO_AUX[linkidx].base + board::mem::DRTIO_AUX[linkidx].size/2;
let sl = slice::from_raw_parts(base as *mut u8, length as usize);
Some(RxBuffer(linkno, sl))
} else {
None
}
}
}
pub fn recv_link(linkno: u8) -> io::Result<Option<Packet>> {
if rx_has_error(linkno) {
return Err(io::Error::new(io::ErrorKind::Other, "gateware reported error"))
}
let buffer = rx_get_buffer(linkno);
match buffer {
Some(rxb) => {
let slice = rxb.1;
let mut reader = Cursor::new(slice);
let len = slice.len();
if len < 8 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "packet too short"))
}
let computed_crc = crc::crc32::checksum_ieee(&reader.get_ref()[0..len-4]);
reader.set_position((len-4) as u64);
let crc = read_u32(&mut reader)?;
if crc != computed_crc {
return Err(io::Error::new(io::ErrorKind::InvalidData, "packet CRC failed"))
}
reader.set_position(0);
let packet_r = Packet::read_from(&mut reader);
match packet_r {
Ok(packet) => Ok(Some(packet)),
Err(e) => Err(e)
}
}
None => Ok(None)
}
}
pub fn recv_timeout_link(linkno: u8, timeout_ms: Option<u64>) -> io::Result<Packet> {
let timeout_ms = timeout_ms.unwrap_or(10);
let limit = board::clock::get_ms() + timeout_ms;
while board::clock::get_ms() < limit {
match recv_link(linkno) {
Ok(None) => (),
Ok(Some(packet)) => return Ok(packet),
Err(e) => return Err(e)
}
}
return Err(io::Error::new(io::ErrorKind::TimedOut, "timed out waiting for data"))
}
fn tx_get_buffer(linkno: u8) -> &'static mut [u8] {
let linkno = linkno as usize;
unsafe {
while (board::csr::DRTIO[linkno].aux_tx_read)() != 0 {}
let base = board::mem::DRTIO_AUX[linkno].base;
let size = board::mem::DRTIO_AUX[linkno].size/2;
slice::from_raw_parts_mut(base as *mut u8, size)
}
}
fn tx_ack_buffer(linkno: u8, length: u16) {
let linkno = linkno as usize;
unsafe {
(board::csr::DRTIO[linkno].aux_tx_length_write)(length);
(board::csr::DRTIO[linkno].aux_tx_write)(1)
}
}
pub fn send_link(linkno: u8, packet: &Packet) -> io::Result<()> {
let sl = tx_get_buffer(linkno);
let mut writer = Cursor::new(sl);
packet.write_to(&mut writer)?;
let mut len = writer.position();
let padding = 4 - (len % 4);
if padding != 4 {
for _ in 0..padding {
write_u8(&mut writer, 0)?;
}
len += padding;
}
let crc = crc::crc32::checksum_ieee(&writer.get_ref()[0..len as usize]);
write_u32(&mut writer, crc)?;
len += 4;
tx_ack_buffer(linkno, len as u16);
Ok(())
}
// TODO: routing
fn get_linkno(nodeno: u8) -> io::Result<u8> {
if nodeno == 0 || nodeno as usize > board::csr::DRTIO.len() {
return Err(io::Error::new(io::ErrorKind::NotFound, "invalid node number"))
}
Ok(nodeno - 1)
}
pub fn recv(nodeno: u8) -> io::Result<Option<Packet>> {
let linkno = get_linkno(nodeno)?;
recv_link(linkno)
}
pub fn recv_timeout(nodeno: u8, timeout_ms: Option<u64>) -> io::Result<Packet> {
let linkno = get_linkno(nodeno)?;
recv_timeout_link(linkno, timeout_ms)
}
pub fn send(nodeno: u8, packet: &Packet) -> io::Result<()> {
let linkno = get_linkno(nodeno)?;
send_link(linkno, packet)
}
}
pub mod hw;

View File

@ -1,106 +0,0 @@
#![allow(dead_code)]
use std::io::{self, Read, Write};
use std::vec::Vec;
use std::string::String;
use byteorder::{ByteOrder, NetworkEndian};
// FIXME: replace these with byteorder core io traits once those are in
#[inline(always)]
pub fn read_u8(reader: &mut Read) -> io::Result<u8> {
let mut bytes = [0; 1];
reader.read_exact(&mut bytes)?;
Ok(bytes[0])
}
#[inline(always)]
pub fn write_u8(writer: &mut Write, value: u8) -> io::Result<()> {
let bytes = [value; 1];
writer.write_all(&bytes)
}
#[inline(always)]
pub fn read_bool(reader: &mut Read) -> io::Result<bool> {
if read_u8(reader)? == 0 {
Ok(false)
} else {
Ok(true)
}
}
#[inline(always)]
pub fn write_bool(writer: &mut Write, value: bool) -> io::Result<()> {
if value {
write_u8(writer, 1)
} else {
write_u8(writer, 0)
}
}
#[inline(always)]
pub fn read_u16(reader: &mut Read) -> io::Result<u16> {
let mut bytes = [0; 2];
reader.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u16(&bytes))
}
#[inline(always)]
pub fn write_u16(writer: &mut Write, value: u16) -> io::Result<()> {
let mut bytes = [0; 2];
NetworkEndian::write_u16(&mut bytes, value);
writer.write_all(&bytes)
}
#[inline(always)]
pub fn read_u32(reader: &mut Read) -> io::Result<u32> {
let mut bytes = [0; 4];
reader.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u32(&bytes))
}
#[inline(always)]
pub fn write_u32(writer: &mut Write, value: u32) -> io::Result<()> {
let mut bytes = [0; 4];
NetworkEndian::write_u32(&mut bytes, value);
writer.write_all(&bytes)
}
#[inline(always)]
pub fn read_u64(reader: &mut Read) -> io::Result<u64> {
let mut bytes = [0; 8];
reader.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u64(&bytes))
}
#[inline(always)]
pub fn write_u64(writer: &mut Write, value: u64) -> io::Result<()> {
let mut bytes = [0; 8];
NetworkEndian::write_u64(&mut bytes, value);
writer.write_all(&bytes)
}
#[inline(always)]
pub fn read_bytes(reader: &mut Read) -> io::Result<Vec<u8>> {
let length = read_u32(reader)?;
let mut value = vec![0; length as usize];
reader.read_exact(&mut value)?;
Ok(value)
}
#[inline(always)]
pub fn write_bytes(writer: &mut Write, value: &[u8]) -> io::Result<()> {
write_u32(writer, value.len() as u32)?;
writer.write_all(value)
}
#[inline(always)]
pub fn read_string(reader: &mut Read) -> io::Result<String> {
let bytes = read_bytes(reader)?;
String::from_utf8(bytes)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8"))
}
#[inline(always)]
pub fn write_string(writer: &mut Write, value: &str) -> io::Result<()> {
write_bytes(writer, value.as_bytes())
}

View File

@ -0,0 +1,14 @@
[package]
authors = ["M-Labs"]
name = "io"
version = "0.0.0"
[lib]
name = "io"
path = "lib.rs"
[dependencies]
byteorder = { version = "1.0", default-features = false, optional = true }
[features]
alloc = []

176
artiq/firmware/libio/lib.rs Normal file
View File

@ -0,0 +1,176 @@
#![no_std]
#![feature(never_type)]
#![cfg_attr(feature = "alloc", feature(alloc))]
#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;
#[cfg(feature = "byteorder")]
extern crate byteorder;
use core::result;
use core::fmt;
#[cfg(feature = "byteorder")]
pub mod proto;
pub type Result<T, E> = result::Result<T, Error<E>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error<T> {
UnexpectedEof,
Other(T)
}
impl<T: fmt::Display> fmt::Display for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::UnexpectedEof =>
write!(f, "unexpected end of stream"),
&Error::Other(ref err) =>
write!(f, "{}", err)
}
}
}
impl<T> From<T> for Error<T> {
fn from(value: T) -> Error<T> {
Error::Other(value)
}
}
pub trait Read {
type ReadError;
/// Pull some bytes from this source into the specified buffer, returning
/// how many bytes were read.
fn read(&mut self, buf: &mut [u8]) -> result::Result<usize, Self::ReadError>;
/// Read the exact number of bytes required to fill `buf`.
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Self::ReadError> {
while !buf.is_empty() {
let read_bytes = self.read(buf)?;
if read_bytes == 0 {
return Err(Error::UnexpectedEof)
}
buf = &mut { buf }[read_bytes..];
}
Ok(())
}
}
pub trait Write {
type WriteError;
type FlushError;
/// Write a buffer into this object, returning how many bytes were written.
fn write(&mut self, buf: &[u8]) -> result::Result<usize, Self::WriteError>;
/// Flush this output stream, ensuring that all intermediately buffered contents
/// reach their destination.
fn flush(&mut self) -> result::Result<(), Self::FlushError>;
/// Attempts to write an entire buffer into `self`.
fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Self::WriteError> {
while buf.len() > 0 {
let written_bytes = self.write(buf)?;
if written_bytes == 0 {
return Err(Error::UnexpectedEof)
}
buf = &buf[written_bytes..];
}
Ok(())
}
/// Hints the writer how much bytes will be written after call to this function.
///
/// At least `min` bytes should be written after the call to this function and
/// if `max` is `Some(x)` than at most `x` bytes should be written.
fn size_hint(&mut self, _min: usize, _max: Option<usize>) {}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CursorError {
EndOfBuffer
}
#[derive(Debug, Clone)]
pub struct Cursor<T> {
inner: T,
pos: usize
}
impl<T> Cursor<T> {
pub fn new(inner: T) -> Cursor<T> {
Cursor { inner, pos: 0 }
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
pub fn position(&self) -> usize {
self.pos
}
pub fn set_position(&mut self, pos: usize) {
self.pos = pos
}
}
impl<T: AsRef<[u8]>> Read for Cursor<T> {
type ReadError = !;
fn read(&mut self, buf: &mut [u8]) -> result::Result<usize, Self::ReadError> {
let data = &self.inner.as_ref()[self.pos..];
let len = buf.len().min(data.len());
buf[..len].copy_from_slice(&data[..len]);
self.pos += len;
Ok(len)
}
}
impl<T: AsMut<[u8]>> Write for Cursor<T> {
type WriteError = !;
type FlushError = !;
fn write(&mut self, buf: &[u8]) -> result::Result<usize, Self::WriteError> {
let data = &mut self.inner.as_mut()[self.pos..];
let len = buf.len().min(data.len());
data[..len].copy_from_slice(&buf[..len]);
self.pos += len;
Ok(len)
}
fn flush(&mut self) -> result::Result<(), Self::FlushError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
impl<T: ::alloc::Vec<[u8]>> Write for Cursor<T> {
type WriteError = !;
type FlushError = !;
fn write(&mut self, buf: &[u8]) -> result::Result<usize, Self::WriteError> {
self.inner.extend(buf);
Ok(buf.len())
}
fn flush(&mut self) -> result::Result<(), Self::FlushError> {
Ok(())
}
}

View File

@ -0,0 +1,132 @@
use byteorder::{ByteOrder, NetworkEndian};
use ::{Read, Write, Error as IoError};
pub trait ProtoRead {
type ReadError;
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError>;
fn read_u8(&mut self) -> Result<u8, Self::ReadError> {
let mut bytes = [0; 1];
self.read_exact(&mut bytes)?;
Ok(bytes[0])
}
fn read_u16(&mut self) -> Result<u16, Self::ReadError> {
let mut bytes = [0; 2];
self.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u16(&bytes))
}
fn read_u32(&mut self) -> Result<u32, Self::ReadError> {
let mut bytes = [0; 4];
self.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u32(&bytes))
}
fn read_u64(&mut self) -> Result<u64, Self::ReadError> {
let mut bytes = [0; 8];
self.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u64(&bytes))
}
fn read_bool(&mut self) -> Result<bool, Self::ReadError> {
Ok(self.read_u8()? != 0)
}
#[cfg(feature = "alloc")]
fn read_bytes(&mut self) -> Result<::alloc::Vec<u8>, Self::ReadError> {
let length = self.read_u32()?;
let mut value = vec![0; length as usize];
self.read_exact(&mut value)?;
Ok(value)
}
// fn read_string(&mut self) -> Result<String, Self::ReadError> {
// let bytes = self.read_bytes()?;
// String::from_utf8(bytes)
// .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8"))
// }
}
pub trait ProtoWrite {
type WriteError;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError>;
fn write_u8(&mut self, value: u8) -> Result<(), Self::WriteError> {
let bytes = [value; 1];
self.write_all(&bytes)
}
fn write_i8(&mut self, value: i8) -> Result<(), Self::WriteError> {
let bytes = [value as u8; 1];
self.write_all(&bytes)
}
fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> {
let mut bytes = [0; 2];
NetworkEndian::write_u16(&mut bytes, value);
self.write_all(&bytes)
}
fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> {
let mut bytes = [0; 2];
NetworkEndian::write_i16(&mut bytes, value);
self.write_all(&bytes)
}
fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> {
let mut bytes = [0; 4];
NetworkEndian::write_u32(&mut bytes, value);
self.write_all(&bytes)
}
fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> {
let mut bytes = [0; 4];
NetworkEndian::write_i32(&mut bytes, value);
self.write_all(&bytes)
}
fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> {
let mut bytes = [0; 8];
NetworkEndian::write_u64(&mut bytes, value);
self.write_all(&bytes)
}
fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> {
let mut bytes = [0; 8];
NetworkEndian::write_i64(&mut bytes, value);
self.write_all(&bytes)
}
fn write_bool(&mut self, value: bool) -> Result<(), Self::WriteError> {
self.write_u8(value as u8)
}
fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::WriteError> {
self.write_u32(value.len() as u32)?;
self.write_all(value)
}
fn write_string(&mut self, value: &str) -> Result<(), Self::WriteError> {
self.write_bytes(value.as_bytes())
}
}
impl<T> ProtoRead for T where T: Read {
type ReadError = IoError<T::ReadError>;
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> {
T::read_exact(self, buf)
}
}
impl<T> ProtoWrite for T where T: Write {
type WriteError = IoError<T::WriteError>;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> {
T::write_all(self, buf)
}
}