mirror of
https://github.com/m-labs/artiq.git
synced 2024-12-26 11:48:27 +08:00
firmware: implement libio and use in in drtioaux.
This commit is contained in:
parent
d543c9aa63
commit
46c8afc56c
10
artiq/firmware/Cargo.lock
generated
10
artiq/firmware/Cargo.lock
generated
@ -107,10 +107,9 @@ version = "0.0.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"board 0.0.0",
|
"board 0.0.0",
|
||||||
"build_misoc 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)",
|
"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)",
|
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"std_artiq 0.0.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -125,6 +124,13 @@ dependencies = [
|
|||||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "kernel32-sys"
|
name = "kernel32-sys"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -14,6 +14,5 @@ build_misoc = { path = "../libbuild_misoc" }
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
log = { version = "0.4", default-features = false }
|
log = { version = "0.4", default-features = false }
|
||||||
crc = { version = "1.7", 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" }
|
board = { path = "../libboard" }
|
||||||
byteorder = { version = "1.0", default-features = false }
|
|
||||||
|
139
artiq/firmware/libdrtioaux/hw.rs
Normal file
139
artiq/firmware/libdrtioaux/hw.rs
Normal 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)
|
||||||
|
}
|
@ -1,17 +1,63 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![feature(never_type)]
|
||||||
|
|
||||||
extern crate byteorder;
|
|
||||||
extern crate crc;
|
extern crate crc;
|
||||||
#[macro_use]
|
|
||||||
extern crate std_artiq as std;
|
extern crate io;
|
||||||
extern crate board;
|
extern crate board;
|
||||||
|
|
||||||
mod proto;
|
|
||||||
|
|
||||||
use std::io::{self, Read, Write};
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
use core::slice;
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum Packet {
|
pub enum Packet {
|
||||||
@ -49,215 +95,220 @@ pub enum Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Packet {
|
||||||
pub fn read_from(reader: &mut Read) -> io::Result<Packet> {
|
pub fn read_from<T: Read>(reader: &mut T) -> Result<Packet, T::ReadError> {
|
||||||
Ok(match read_u8(reader)? {
|
Ok(match reader.read_u8()? {
|
||||||
0x00 => Packet::EchoRequest,
|
0x00 => Packet::EchoRequest,
|
||||||
0x01 => Packet::EchoReply,
|
0x01 => Packet::EchoReply,
|
||||||
0x02 => Packet::ResetRequest {
|
0x02 => Packet::ResetRequest {
|
||||||
phy: read_bool(reader)?
|
phy: reader.read_bool()?
|
||||||
},
|
},
|
||||||
0x03 => Packet::ResetAck,
|
0x03 => Packet::ResetAck,
|
||||||
|
|
||||||
0x20 => Packet::RtioErrorRequest,
|
0x20 => Packet::RtioErrorRequest,
|
||||||
0x21 => Packet::RtioNoErrorReply,
|
0x21 => Packet::RtioNoErrorReply,
|
||||||
0x22 => Packet::RtioErrorSequenceErrorReply {
|
0x22 => Packet::RtioErrorSequenceErrorReply {
|
||||||
channel: read_u16(reader)?
|
channel: reader.read_u16()?
|
||||||
},
|
},
|
||||||
0x23 => Packet::RtioErrorCollisionReply {
|
0x23 => Packet::RtioErrorCollisionReply {
|
||||||
channel: read_u16(reader)?
|
channel: reader.read_u16()?
|
||||||
},
|
},
|
||||||
0x24 => Packet::RtioErrorBusyReply {
|
0x24 => Packet::RtioErrorBusyReply {
|
||||||
channel: read_u16(reader)?
|
channel: reader.read_u16()?
|
||||||
},
|
},
|
||||||
|
|
||||||
0x40 => Packet::MonitorRequest {
|
0x40 => Packet::MonitorRequest {
|
||||||
channel: read_u16(reader)?,
|
channel: reader.read_u16()?,
|
||||||
probe: read_u8(reader)?
|
probe: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x41 => Packet::MonitorReply {
|
0x41 => Packet::MonitorReply {
|
||||||
value: read_u32(reader)?
|
value: reader.read_u32()?
|
||||||
},
|
},
|
||||||
0x50 => Packet::InjectionRequest {
|
0x50 => Packet::InjectionRequest {
|
||||||
channel: read_u16(reader)?,
|
channel: reader.read_u16()?,
|
||||||
overrd: read_u8(reader)?,
|
overrd: reader.read_u8()?,
|
||||||
value: read_u8(reader)?
|
value: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x51 => Packet::InjectionStatusRequest {
|
0x51 => Packet::InjectionStatusRequest {
|
||||||
channel: read_u16(reader)?,
|
channel: reader.read_u16()?,
|
||||||
overrd: read_u8(reader)?
|
overrd: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x52 => Packet::InjectionStatusReply {
|
0x52 => Packet::InjectionStatusReply {
|
||||||
value: read_u8(reader)?
|
value: reader.read_u8()?
|
||||||
},
|
},
|
||||||
|
|
||||||
0x80 => Packet::I2cStartRequest {
|
0x80 => Packet::I2cStartRequest {
|
||||||
busno: read_u8(reader)?
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x81 => Packet::I2cRestartRequest {
|
0x81 => Packet::I2cRestartRequest {
|
||||||
busno: read_u8(reader)?
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x82 => Packet::I2cStopRequest {
|
0x82 => Packet::I2cStopRequest {
|
||||||
busno: read_u8(reader)?
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x83 => Packet::I2cWriteRequest {
|
0x83 => Packet::I2cWriteRequest {
|
||||||
busno: read_u8(reader)?,
|
busno: reader.read_u8()?,
|
||||||
data: read_u8(reader)?
|
data: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x84 => Packet::I2cWriteReply {
|
0x84 => Packet::I2cWriteReply {
|
||||||
succeeded: read_bool(reader)?,
|
succeeded: reader.read_bool()?,
|
||||||
ack: read_bool(reader)?
|
ack: reader.read_bool()?
|
||||||
},
|
},
|
||||||
0x85 => Packet::I2cReadRequest {
|
0x85 => Packet::I2cReadRequest {
|
||||||
busno: read_u8(reader)?,
|
busno: reader.read_u8()?,
|
||||||
ack: read_bool(reader)?
|
ack: reader.read_bool()?
|
||||||
},
|
},
|
||||||
0x86 => Packet::I2cReadReply {
|
0x86 => Packet::I2cReadReply {
|
||||||
succeeded: read_bool(reader)?,
|
succeeded: reader.read_bool()?,
|
||||||
data: read_u8(reader)?
|
data: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x87 => Packet::I2cBasicReply {
|
0x87 => Packet::I2cBasicReply {
|
||||||
succeeded: read_bool(reader)?
|
succeeded: reader.read_bool()?
|
||||||
},
|
},
|
||||||
|
|
||||||
0x90 => Packet::SpiSetConfigRequest {
|
0x90 => Packet::SpiSetConfigRequest {
|
||||||
busno: read_u8(reader)?,
|
busno: reader.read_u8()?,
|
||||||
flags: read_u8(reader)?,
|
flags: reader.read_u8()?,
|
||||||
length: read_u8(reader)?,
|
length: reader.read_u8()?,
|
||||||
div: read_u8(reader)?,
|
div: reader.read_u8()?,
|
||||||
cs: read_u8(reader)?
|
cs: reader.read_u8()?
|
||||||
},
|
},
|
||||||
/* 0x91: was Packet::SpiSetXferRequest */
|
/* 0x91: was Packet::SpiSetXferRequest */
|
||||||
0x92 => Packet::SpiWriteRequest {
|
0x92 => Packet::SpiWriteRequest {
|
||||||
busno: read_u8(reader)?,
|
busno: reader.read_u8()?,
|
||||||
data: read_u32(reader)?
|
data: reader.read_u32()?
|
||||||
},
|
},
|
||||||
0x93 => Packet::SpiReadRequest {
|
0x93 => Packet::SpiReadRequest {
|
||||||
busno: read_u8(reader)?
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x94 => Packet::SpiReadReply {
|
0x94 => Packet::SpiReadReply {
|
||||||
succeeded: read_bool(reader)?,
|
succeeded: reader.read_bool()?,
|
||||||
data: read_u32(reader)?
|
data: reader.read_u32()?
|
||||||
},
|
},
|
||||||
0x95 => Packet::SpiBasicReply {
|
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 {
|
match *self {
|
||||||
Packet::EchoRequest => write_u8(writer, 0x00)?,
|
Packet::EchoRequest =>
|
||||||
Packet::EchoReply => write_u8(writer, 0x01)?,
|
writer.write_u8(0x00)?,
|
||||||
|
Packet::EchoReply =>
|
||||||
|
writer.write_u8(0x01)?,
|
||||||
Packet::ResetRequest { phy } => {
|
Packet::ResetRequest { phy } => {
|
||||||
write_u8(writer, 0x02)?;
|
writer.write_u8(0x02)?;
|
||||||
write_bool(writer, phy)?;
|
writer.write_bool(phy)?;
|
||||||
},
|
},
|
||||||
Packet::ResetAck => write_u8(writer, 0x03)?,
|
Packet::ResetAck =>
|
||||||
|
writer.write_u8(0x03)?,
|
||||||
|
|
||||||
Packet::RtioErrorRequest => write_u8(writer, 0x20)?,
|
Packet::RtioErrorRequest =>
|
||||||
Packet::RtioNoErrorReply => write_u8(writer, 0x21)?,
|
writer.write_u8(0x20)?,
|
||||||
|
Packet::RtioNoErrorReply =>
|
||||||
|
writer.write_u8(0x21)?,
|
||||||
Packet::RtioErrorSequenceErrorReply { channel } => {
|
Packet::RtioErrorSequenceErrorReply { channel } => {
|
||||||
write_u8(writer, 0x22)?;
|
writer.write_u8(0x22)?;
|
||||||
write_u16(writer, channel)?;
|
writer.write_u16(channel)?;
|
||||||
},
|
},
|
||||||
Packet::RtioErrorCollisionReply { channel } => {
|
Packet::RtioErrorCollisionReply { channel } => {
|
||||||
write_u8(writer, 0x23)?;
|
writer.write_u8(0x23)?;
|
||||||
write_u16(writer, channel)?;
|
writer.write_u16(channel)?;
|
||||||
},
|
},
|
||||||
Packet::RtioErrorBusyReply { channel } => {
|
Packet::RtioErrorBusyReply { channel } => {
|
||||||
write_u8(writer, 0x24)?;
|
writer.write_u8(0x24)?;
|
||||||
write_u16(writer, channel)?;
|
writer.write_u16(channel)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Packet::MonitorRequest { channel, probe } => {
|
Packet::MonitorRequest { channel, probe } => {
|
||||||
write_u8(writer, 0x40)?;
|
writer.write_u8(0x40)?;
|
||||||
write_u16(writer, channel)?;
|
writer.write_u16(channel)?;
|
||||||
write_u8(writer, probe)?;
|
writer.write_u8(probe)?;
|
||||||
},
|
},
|
||||||
Packet::MonitorReply { value } => {
|
Packet::MonitorReply { value } => {
|
||||||
write_u8(writer, 0x41)?;
|
writer.write_u8(0x41)?;
|
||||||
write_u32(writer, value)?;
|
writer.write_u32(value)?;
|
||||||
},
|
},
|
||||||
Packet::InjectionRequest { channel, overrd, value } => {
|
Packet::InjectionRequest { channel, overrd, value } => {
|
||||||
write_u8(writer, 0x50)?;
|
writer.write_u8(0x50)?;
|
||||||
write_u16(writer, channel)?;
|
writer.write_u16(channel)?;
|
||||||
write_u8(writer, overrd)?;
|
writer.write_u8(overrd)?;
|
||||||
write_u8(writer, value)?;
|
writer.write_u8(value)?;
|
||||||
},
|
},
|
||||||
Packet::InjectionStatusRequest { channel, overrd } => {
|
Packet::InjectionStatusRequest { channel, overrd } => {
|
||||||
write_u8(writer, 0x51)?;
|
writer.write_u8(0x51)?;
|
||||||
write_u16(writer, channel)?;
|
writer.write_u16(channel)?;
|
||||||
write_u8(writer, overrd)?;
|
writer.write_u8(overrd)?;
|
||||||
},
|
},
|
||||||
Packet::InjectionStatusReply { value } => {
|
Packet::InjectionStatusReply { value } => {
|
||||||
write_u8(writer, 0x52)?;
|
writer.write_u8(0x52)?;
|
||||||
write_u8(writer, value)?;
|
writer.write_u8(value)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Packet::I2cStartRequest { busno } => {
|
Packet::I2cStartRequest { busno } => {
|
||||||
write_u8(writer, 0x80)?;
|
writer.write_u8(0x80)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
},
|
},
|
||||||
Packet::I2cRestartRequest { busno } => {
|
Packet::I2cRestartRequest { busno } => {
|
||||||
write_u8(writer, 0x81)?;
|
writer.write_u8(0x81)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
},
|
},
|
||||||
Packet::I2cStopRequest { busno } => {
|
Packet::I2cStopRequest { busno } => {
|
||||||
write_u8(writer, 0x82)?;
|
writer.write_u8(0x82)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
},
|
},
|
||||||
Packet::I2cWriteRequest { busno, data } => {
|
Packet::I2cWriteRequest { busno, data } => {
|
||||||
write_u8(writer, 0x83)?;
|
writer.write_u8(0x83)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
write_u8(writer, data)?;
|
writer.write_u8(data)?;
|
||||||
},
|
},
|
||||||
Packet::I2cWriteReply { succeeded, ack } => {
|
Packet::I2cWriteReply { succeeded, ack } => {
|
||||||
write_u8(writer, 0x84)?;
|
writer.write_u8(0x84)?;
|
||||||
write_bool(writer, succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
write_bool(writer, ack)?;
|
writer.write_bool(ack)?;
|
||||||
},
|
},
|
||||||
Packet::I2cReadRequest { busno, ack } => {
|
Packet::I2cReadRequest { busno, ack } => {
|
||||||
write_u8(writer, 0x85)?;
|
writer.write_u8(0x85)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
write_bool(writer, ack)?;
|
writer.write_bool(ack)?;
|
||||||
},
|
},
|
||||||
Packet::I2cReadReply { succeeded, data } => {
|
Packet::I2cReadReply { succeeded, data } => {
|
||||||
write_u8(writer, 0x86)?;
|
writer.write_u8(0x86)?;
|
||||||
write_bool(writer, succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
write_u8(writer, data)?;
|
writer.write_u8(data)?;
|
||||||
},
|
},
|
||||||
Packet::I2cBasicReply { succeeded } => {
|
Packet::I2cBasicReply { succeeded } => {
|
||||||
write_u8(writer, 0x87)?;
|
writer.write_u8(0x87)?;
|
||||||
write_bool(writer, succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => {
|
Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => {
|
||||||
write_u8(writer, 0x90)?;
|
writer.write_u8(0x90)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
write_u8(writer, flags)?;
|
writer.write_u8(flags)?;
|
||||||
write_u8(writer, length)?;
|
writer.write_u8(length)?;
|
||||||
write_u8(writer, div)?;
|
writer.write_u8(div)?;
|
||||||
write_u8(writer, cs)?;
|
writer.write_u8(cs)?;
|
||||||
},
|
},
|
||||||
Packet::SpiWriteRequest { busno, data } => {
|
Packet::SpiWriteRequest { busno, data } => {
|
||||||
write_u8(writer, 0x92)?;
|
writer.write_u8(0x92)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
write_u32(writer, data)?;
|
writer.write_u32(data)?;
|
||||||
},
|
},
|
||||||
Packet::SpiReadRequest { busno } => {
|
Packet::SpiReadRequest { busno } => {
|
||||||
write_u8(writer, 0x93)?;
|
writer.write_u8(0x93)?;
|
||||||
write_u8(writer, busno)?;
|
writer.write_u8(busno)?;
|
||||||
},
|
},
|
||||||
Packet::SpiReadReply { succeeded, data } => {
|
Packet::SpiReadReply { succeeded, data } => {
|
||||||
write_u8(writer, 0x94)?;
|
writer.write_u8(0x94)?;
|
||||||
write_bool(writer, succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
write_u32(writer, data)?;
|
writer.write_u32(data)?;
|
||||||
},
|
},
|
||||||
Packet::SpiBasicReply { succeeded } => {
|
Packet::SpiBasicReply { succeeded } => {
|
||||||
write_u8(writer, 0x95)?;
|
writer.write_u8(0x95)?;
|
||||||
write_bool(writer, succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -265,163 +316,4 @@ impl Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
pub mod hw {
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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())
|
|
||||||
}
|
|
14
artiq/firmware/libio/Cargo.toml
Normal file
14
artiq/firmware/libio/Cargo.toml
Normal 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
176
artiq/firmware/libio/lib.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
132
artiq/firmware/libio/proto.rs
Normal file
132
artiq/firmware/libio/proto.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user