diff --git a/src/libboard_artiqzynq/Cargo.toml b/src/libboard_artiqzynq/Cargo.toml new file mode 100644 index 00000000..0ffd7917 --- /dev/null +++ b/src/libboard_artiqzynq/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "libboard_artiqzynq" +version = "0.0.0" +authors = ["M-Labs"] + +[lib] +name = "board_artiqzync" + +[dependencies] +io = { path = "../libio", features = ["byteorder"] } \ No newline at end of file diff --git a/src/libboard_artiqzynq/proto_core_io.rs b/src/libboard_artiqzynq/proto_core_io.rs new file mode 100644 index 00000000..c165606b --- /dev/null +++ b/src/libboard_artiqzynq/proto_core_io.rs @@ -0,0 +1,158 @@ +use core::str::Utf8Error; +use byteorder::{ByteOrder, NativeEndian}; +use alloc::vec; +use alloc::string::String; + +use core_io::{Read, Write, Error as IoError}; + +#[allow(dead_code)] +#[derive(Debug, Clone, PartialEq)] +pub enum ReadStringError { + Utf8(Utf8Error), + Other(T) +} + +pub trait ProtoRead { + type ReadError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError>; + + #[inline] + fn read_u8(&mut self) -> Result { + let mut bytes = [0; 1]; + self.read_exact(&mut bytes)?; + Ok(bytes[0]) + } + + #[inline] + fn read_u16(&mut self) -> Result { + let mut bytes = [0; 2]; + self.read_exact(&mut bytes)?; + Ok(NativeEndian::read_u16(&bytes)) + } + + #[inline] + fn read_u32(&mut self) -> Result { + let mut bytes = [0; 4]; + self.read_exact(&mut bytes)?; + Ok(NativeEndian::read_u32(&bytes)) + } + + #[inline] + fn read_u64(&mut self) -> Result { + let mut bytes = [0; 8]; + self.read_exact(&mut bytes)?; + Ok(NativeEndian::read_u64(&bytes)) + } + + #[inline] + fn read_bool(&mut self) -> Result { + Ok(self.read_u8()? != 0) + } + + #[inline] + fn read_bytes(&mut self) -> Result<::alloc::vec::Vec, Self::ReadError> { + let length = self.read_u32()?; + let mut value = vec![0; length as usize]; + self.read_exact(&mut value)?; + Ok(value) + } + + #[inline] + fn read_string(&mut self) -> Result<::alloc::string::String, ReadStringError> { + let bytes = self.read_bytes().map_err(ReadStringError::Other)?; + String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8(err.utf8_error())) + } +} + +pub trait ProtoWrite { + type WriteError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError>; + + #[inline] + fn write_u8(&mut self, value: u8) -> Result<(), Self::WriteError> { + let bytes = [value; 1]; + self.write_all(&bytes) + } + + #[inline] + fn write_i8(&mut self, value: i8) -> Result<(), Self::WriteError> { + let bytes = [value as u8; 1]; + self.write_all(&bytes) + } + + #[inline] + fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> { + let mut bytes = [0; 2]; + NativeEndian::write_u16(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> { + let mut bytes = [0; 2]; + NativeEndian::write_i16(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> { + let mut bytes = [0; 4]; + NativeEndian::write_u32(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> { + let mut bytes = [0; 4]; + NativeEndian::write_i32(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> { + let mut bytes = [0; 8]; + NativeEndian::write_u64(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> { + let mut bytes = [0; 8]; + NativeEndian::write_i64(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_bool(&mut self, value: bool) -> Result<(), Self::WriteError> { + self.write_u8(value as u8) + } + + #[inline] + fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::WriteError> { + self.write_u32(value.len() as u32)?; + self.write_all(value) + } + + #[inline] + fn write_string(&mut self, value: &str) -> Result<(), Self::WriteError> { + self.write_bytes(value.as_bytes()) + } +} + +impl ProtoRead for T where T: Read + ?Sized { + type ReadError = IoError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> { + T::read_exact(self, buf) + } +} + +impl ProtoWrite for T where T: Write + ?Sized { + type WriteError = IoError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> { + T::write_all(self, buf) + } +} diff --git a/src/libio/Cargo.toml b/src/libio/Cargo.toml new file mode 100644 index 00000000..6aacf0c4 --- /dev/null +++ b/src/libio/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["M-Labs"] +name = "io" +version = "0.0.0" + +[lib] +name = "io" +path = "lib.rs" + +[dependencies] +failure = { version = "0.1", default-features = false } +failure_derive = { version = "0.1", default-features = false } +byteorder = { version = "1.0", default-features = false, optional = true } + +[features] +alloc = [] diff --git a/src/libio/cursor.rs b/src/libio/cursor.rs new file mode 100644 index 00000000..b820bddd --- /dev/null +++ b/src/libio/cursor.rs @@ -0,0 +1,86 @@ +use {Read, Write}; + +#[derive(Debug, Clone)] +pub struct Cursor { + inner: T, + pos: usize +} + +impl Cursor { + #[inline] + pub fn new(inner: T) -> Cursor { + Cursor { inner, pos: 0 } + } + + #[inline] + pub fn into_inner(self) -> T { + self.inner + } + + #[inline] + pub fn get_ref(&self) -> &T { + &self.inner + } + + #[inline] + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + #[inline] + pub fn position(&self) -> usize { + self.pos + } + + #[inline] + pub fn set_position(&mut self, pos: usize) { + self.pos = pos + } +} + +impl> Read for Cursor { + type ReadError = !; + + fn read(&mut self, buf: &mut [u8]) -> Result { + 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<'a> Write for Cursor<&'a mut [u8]> { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> Result { + let data = &mut self.inner[self.pos..]; + let len = buf.len().min(data.len()); + data[..len].copy_from_slice(&buf[..len]); + self.pos += len; + Ok(len) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::FlushError> { + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl Write for Cursor<::alloc::Vec> { + type WriteError = !; + type FlushError = !; + + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + self.inner.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::FlushError> { + Ok(()) + } +} diff --git a/src/libio/lib.rs b/src/libio/lib.rs new file mode 100644 index 00000000..b10c4134 --- /dev/null +++ b/src/libio/lib.rs @@ -0,0 +1,147 @@ +#![no_std] +#![feature(never_type)] +#![cfg_attr(feature = "alloc", feature(alloc))] + +extern crate failure; +#[macro_use] +extern crate failure_derive; +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; +#[cfg(feature = "byteorder")] +extern crate byteorder; + +mod cursor; +#[cfg(feature = "byteorder")] +mod proto; + +pub use cursor::Cursor; +#[cfg(feature = "byteorder")] +pub use proto::{ProtoRead, ProtoWrite}; +#[cfg(all(feature = "byteorder", feature = "alloc"))] +pub use proto::ReadStringError; + +#[derive(Fail, Debug, Clone, PartialEq)] +pub enum Error { + #[fail(display = "unexpected end of stream")] + UnexpectedEnd, + #[fail(display = "{}", _0)] + Other(#[cause] T) +} + +impl From for Error { + fn from(value: T) -> Error { + 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; + + /// Read the exact number of bytes required to fill `buf`. + fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Error> { + while !buf.is_empty() { + let read_bytes = self.read(buf)?; + if read_bytes == 0 { + return Err(Error::UnexpectedEnd) + } + + buf = &mut { buf }[read_bytes..]; + } + + Ok(()) + } +} + +impl<'a, T: Read> Read for &'a mut T { + type ReadError = T::ReadError; + + fn read(&mut self, buf: &mut [u8]) -> Result { + T::read(self, buf) + } +} + +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; + + /// Flush this output stream, ensuring that all intermediately buffered contents + /// reach their destination. + fn flush(&mut self) -> Result<(), Self::FlushError>; + + /// Attempts to write an entire buffer into `self`. + fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Error> { + while buf.len() > 0 { + let written_bytes = self.write(buf)?; + if written_bytes == 0 { + return Err(Error::UnexpectedEnd) + } + + 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) {} +} + +impl<'a, T: Write> Write for &'a mut T { + type WriteError = T::WriteError; + type FlushError = T::FlushError; + + fn write(&mut self, buf: &[u8]) -> Result { + T::write(self, buf) + } + + fn flush(&mut self) -> Result<(), Self::FlushError> { + T::flush(self) + } + + fn size_hint(&mut self, min: usize, max: Option) { + T::size_hint(self, min, max) + } +} + +impl<'a> Write for &'a mut [u8] { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> Result { + let len = buf.len().min(self.len()); + self[..len].copy_from_slice(&buf[..len]); + Ok(len) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::FlushError> { + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl<'a> Write for alloc::Vec { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::FlushError> { + Ok(()) + } +} diff --git a/src/libio/proto.rs b/src/libio/proto.rs new file mode 100644 index 00000000..3df4a04a --- /dev/null +++ b/src/libio/proto.rs @@ -0,0 +1,161 @@ +#[cfg(feature = "alloc")] +use {core::str::Utf8Error, alloc::String}; +use byteorder::{ByteOrder, NetworkEndian}; + +use ::{Read, Write, Error as IoError}; + +#[cfg(feature = "alloc")] +#[derive(Fail, Debug, Clone, PartialEq)] +pub enum ReadStringError { + #[fail(display = "invalid UTF-8: {}", _0)] + Utf8(Utf8Error), + #[fail(display = "{}", _0)] + Other(T) +} + +pub trait ProtoRead { + type ReadError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError>; + + #[inline] + fn read_u8(&mut self) -> Result { + let mut bytes = [0; 1]; + self.read_exact(&mut bytes)?; + Ok(bytes[0]) + } + + #[inline] + fn read_u16(&mut self) -> Result { + let mut bytes = [0; 2]; + self.read_exact(&mut bytes)?; + Ok(NetworkEndian::read_u16(&bytes)) + } + + #[inline] + fn read_u32(&mut self) -> Result { + let mut bytes = [0; 4]; + self.read_exact(&mut bytes)?; + Ok(NetworkEndian::read_u32(&bytes)) + } + + #[inline] + fn read_u64(&mut self) -> Result { + let mut bytes = [0; 8]; + self.read_exact(&mut bytes)?; + Ok(NetworkEndian::read_u64(&bytes)) + } + + #[inline] + fn read_bool(&mut self) -> Result { + Ok(self.read_u8()? != 0) + } + + #[cfg(feature = "alloc")] + #[inline] + fn read_bytes(&mut self) -> Result<::alloc::Vec, Self::ReadError> { + let length = self.read_u32()?; + let mut value = vec![0; length as usize]; + self.read_exact(&mut value)?; + Ok(value) + } + + #[cfg(feature = "alloc")] + #[inline] + fn read_string(&mut self) -> Result<::alloc::String, ReadStringError> { + let bytes = self.read_bytes().map_err(ReadStringError::Other)?; + String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8(err.utf8_error())) + } +} + +pub trait ProtoWrite { + type WriteError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError>; + + #[inline] + fn write_u8(&mut self, value: u8) -> Result<(), Self::WriteError> { + let bytes = [value; 1]; + self.write_all(&bytes) + } + + #[inline] + fn write_i8(&mut self, value: i8) -> Result<(), Self::WriteError> { + let bytes = [value as u8; 1]; + self.write_all(&bytes) + } + + #[inline] + 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) + } + + #[inline] + 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) + } + + #[inline] + 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) + } + + #[inline] + 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) + } + + #[inline] + 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) + } + + #[inline] + 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) + } + + #[inline] + fn write_bool(&mut self, value: bool) -> Result<(), Self::WriteError> { + self.write_u8(value as u8) + } + + #[inline] + fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::WriteError> { + self.write_u32(value.len() as u32)?; + self.write_all(value) + } + + #[inline] + fn write_string(&mut self, value: &str) -> Result<(), Self::WriteError> { + self.write_bytes(value.as_bytes()) + } +} + +impl ProtoRead for T where T: Read + ?Sized { + type ReadError = IoError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> { + T::read_exact(self, buf) + } +} + +impl ProtoWrite for T where T: Write + ?Sized { + type WriteError = IoError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> { + T::write_all(self, buf) + } +} diff --git a/src/libproto_artiq/Cargo.toml b/src/libproto_artiq/Cargo.toml new file mode 100644 index 00000000..92d5e0d0 --- /dev/null +++ b/src/libproto_artiq/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["M-Labs"] +name = "proto_artiq" +version = "0.0.0" + +[lib] +name = "proto_artiq" +path = "lib.rs" + +[dependencies] +failure = { version = "0.1", default-features = false } +failure_derive = { version = "0.1", default-features = false } +byteorder = { version = "1.0", default-features = false } +cslice = { version = "0.3" } +log = { version = "0.4", default-features = false, optional = true } +io = { path = "../libio", features = ["byteorder"] } +dyld = { path = "../libdyld" } + +[features] +alloc = ["io/alloc"] diff --git a/src/libproto_artiq/drtioaux_proto.rs b/src/libproto_artiq/drtioaux_proto.rs new file mode 100644 index 00000000..bd487565 --- /dev/null +++ b/src/libproto_artiq/drtioaux_proto.rs @@ -0,0 +1,362 @@ +use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError}; + +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "unknown packet {:#02x}", _0)] + UnknownPacket(u8), + #[fail(display = "{}", _0)] + Io(#[cause] IoError) +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} + +#[derive(PartialEq, Debug)] +pub enum Packet { + EchoRequest, + EchoReply, + ResetRequest, + ResetAck, + TSCAck, + + DestinationStatusRequest { destination: u8 }, + DestinationDownReply, + DestinationOkReply, + DestinationSequenceErrorReply { channel: u16 }, + DestinationCollisionReply { channel: u16 }, + DestinationBusyReply { channel: u16 }, + + RoutingSetPath { destination: u8, hops: [u8; 32] }, + RoutingSetRank { rank: u8 }, + RoutingAck, + + MonitorRequest { destination: u8, channel: u16, probe: u8 }, + MonitorReply { value: u32 }, + InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 }, + InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 }, + InjectionStatusReply { value: u8 }, + + I2cStartRequest { destination: u8, busno: u8 }, + I2cRestartRequest { destination: u8, busno: u8 }, + I2cStopRequest { destination: u8, busno: u8 }, + I2cWriteRequest { destination: u8, busno: u8, data: u8 }, + I2cWriteReply { succeeded: bool, ack: bool }, + I2cReadRequest { destination: u8, busno: u8, ack: bool }, + I2cReadReply { succeeded: bool, data: u8 }, + I2cBasicReply { succeeded: bool }, + + SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, + SpiWriteRequest { destination: u8, busno: u8, data: u32 }, + SpiReadRequest { destination: u8, busno: u8 }, + SpiReadReply { succeeded: bool, data: u32 }, + SpiBasicReply { succeeded: bool }, + + JdacBasicRequest { destination: u8, dacno: u8, reqno: u8, param: u8 }, + JdacBasicReply { succeeded: bool, retval: u8 }, +} + +impl Packet { + pub fn read_from(reader: &mut R) -> Result> + where R: Read + ?Sized + { + Ok(match reader.read_u8()? { + 0x00 => Packet::EchoRequest, + 0x01 => Packet::EchoReply, + 0x02 => Packet::ResetRequest, + 0x03 => Packet::ResetAck, + 0x04 => Packet::TSCAck, + + 0x20 => Packet::DestinationStatusRequest { + destination: reader.read_u8()? + }, + 0x21 => Packet::DestinationDownReply, + 0x22 => Packet::DestinationOkReply, + 0x23 => Packet::DestinationSequenceErrorReply { + channel: reader.read_u16()? + }, + 0x24 => Packet::DestinationCollisionReply { + channel: reader.read_u16()? + }, + 0x25 => Packet::DestinationBusyReply { + channel: reader.read_u16()? + }, + + 0x30 => { + let destination = reader.read_u8()?; + let mut hops = [0; 32]; + reader.read_exact(&mut hops)?; + Packet::RoutingSetPath { + destination: destination, + hops: hops + } + }, + 0x31 => Packet::RoutingSetRank { + rank: reader.read_u8()? + }, + 0x32 => Packet::RoutingAck, + + 0x40 => Packet::MonitorRequest { + destination: reader.read_u8()?, + channel: reader.read_u16()?, + probe: reader.read_u8()? + }, + 0x41 => Packet::MonitorReply { + value: reader.read_u32()? + }, + 0x50 => Packet::InjectionRequest { + destination: reader.read_u8()?, + channel: reader.read_u16()?, + overrd: reader.read_u8()?, + value: reader.read_u8()? + }, + 0x51 => Packet::InjectionStatusRequest { + destination: reader.read_u8()?, + channel: reader.read_u16()?, + overrd: reader.read_u8()? + }, + 0x52 => Packet::InjectionStatusReply { + value: reader.read_u8()? + }, + + 0x80 => Packet::I2cStartRequest { + destination: reader.read_u8()?, + busno: reader.read_u8()? + }, + 0x81 => Packet::I2cRestartRequest { + destination: reader.read_u8()?, + busno: reader.read_u8()? + }, + 0x82 => Packet::I2cStopRequest { + destination: reader.read_u8()?, + busno: reader.read_u8()? + }, + 0x83 => Packet::I2cWriteRequest { + destination: reader.read_u8()?, + busno: reader.read_u8()?, + data: reader.read_u8()? + }, + 0x84 => Packet::I2cWriteReply { + succeeded: reader.read_bool()?, + ack: reader.read_bool()? + }, + 0x85 => Packet::I2cReadRequest { + destination: reader.read_u8()?, + busno: reader.read_u8()?, + ack: reader.read_bool()? + }, + 0x86 => Packet::I2cReadReply { + succeeded: reader.read_bool()?, + data: reader.read_u8()? + }, + 0x87 => Packet::I2cBasicReply { + succeeded: reader.read_bool()? + }, + + 0x90 => Packet::SpiSetConfigRequest { + destination: reader.read_u8()?, + 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 { + destination: reader.read_u8()?, + busno: reader.read_u8()?, + data: reader.read_u32()? + }, + 0x93 => Packet::SpiReadRequest { + destination: reader.read_u8()?, + busno: reader.read_u8()? + }, + 0x94 => Packet::SpiReadReply { + succeeded: reader.read_bool()?, + data: reader.read_u32()? + }, + 0x95 => Packet::SpiBasicReply { + succeeded: reader.read_bool()? + }, + + 0xa0 => Packet::JdacBasicRequest { + destination: reader.read_u8()?, + dacno: reader.read_u8()?, + reqno: reader.read_u8()?, + param: reader.read_u8()?, + }, + 0xa1 => Packet::JdacBasicReply { + succeeded: reader.read_bool()?, + retval: reader.read_u8()? + }, + + ty => return Err(Error::UnknownPacket(ty)) + }) + } + + pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> + where W: Write + ?Sized + { + match *self { + Packet::EchoRequest => + writer.write_u8(0x00)?, + Packet::EchoReply => + writer.write_u8(0x01)?, + Packet::ResetRequest => + writer.write_u8(0x02)?, + Packet::ResetAck => + writer.write_u8(0x03)?, + Packet::TSCAck => + writer.write_u8(0x04)?, + + Packet::DestinationStatusRequest { destination } => { + writer.write_u8(0x20)?; + writer.write_u8(destination)?; + }, + Packet::DestinationDownReply => + writer.write_u8(0x21)?, + Packet::DestinationOkReply => + writer.write_u8(0x22)?, + Packet::DestinationSequenceErrorReply { channel } => { + writer.write_u8(0x23)?; + writer.write_u16(channel)?; + }, + Packet::DestinationCollisionReply { channel } => { + writer.write_u8(0x24)?; + writer.write_u16(channel)?; + }, + Packet::DestinationBusyReply { channel } => { + writer.write_u8(0x25)?; + writer.write_u16(channel)?; + }, + + Packet::RoutingSetPath { destination, hops } => { + writer.write_u8(0x30)?; + writer.write_u8(destination)?; + writer.write_all(&hops)?; + }, + Packet::RoutingSetRank { rank } => { + writer.write_u8(0x31)?; + writer.write_u8(rank)?; + }, + Packet::RoutingAck => + writer.write_u8(0x32)?, + + Packet::MonitorRequest { destination, channel, probe } => { + writer.write_u8(0x40)?; + writer.write_u8(destination)?; + writer.write_u16(channel)?; + writer.write_u8(probe)?; + }, + Packet::MonitorReply { value } => { + writer.write_u8(0x41)?; + writer.write_u32(value)?; + }, + Packet::InjectionRequest { destination, channel, overrd, value } => { + writer.write_u8(0x50)?; + writer.write_u8(destination)?; + writer.write_u16(channel)?; + writer.write_u8(overrd)?; + writer.write_u8(value)?; + }, + Packet::InjectionStatusRequest { destination, channel, overrd } => { + writer.write_u8(0x51)?; + writer.write_u8(destination)?; + writer.write_u16(channel)?; + writer.write_u8(overrd)?; + }, + Packet::InjectionStatusReply { value } => { + writer.write_u8(0x52)?; + writer.write_u8(value)?; + }, + + Packet::I2cStartRequest { destination, busno } => { + writer.write_u8(0x80)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + }, + Packet::I2cRestartRequest { destination, busno } => { + writer.write_u8(0x81)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + }, + Packet::I2cStopRequest { destination, busno } => { + writer.write_u8(0x82)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + }, + Packet::I2cWriteRequest { destination, busno, data } => { + writer.write_u8(0x83)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + writer.write_u8(data)?; + }, + Packet::I2cWriteReply { succeeded, ack } => { + writer.write_u8(0x84)?; + writer.write_bool(succeeded)?; + writer.write_bool(ack)?; + }, + Packet::I2cReadRequest { destination, busno, ack } => { + writer.write_u8(0x85)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + writer.write_bool(ack)?; + }, + Packet::I2cReadReply { succeeded, data } => { + writer.write_u8(0x86)?; + writer.write_bool(succeeded)?; + writer.write_u8(data)?; + }, + Packet::I2cBasicReply { succeeded } => { + writer.write_u8(0x87)?; + writer.write_bool(succeeded)?; + }, + + Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { + writer.write_u8(0x90)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + writer.write_u8(flags)?; + writer.write_u8(length)?; + writer.write_u8(div)?; + writer.write_u8(cs)?; + }, + Packet::SpiWriteRequest { destination, busno, data } => { + writer.write_u8(0x92)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + writer.write_u32(data)?; + }, + Packet::SpiReadRequest { destination, busno } => { + writer.write_u8(0x93)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + }, + Packet::SpiReadReply { succeeded, data } => { + writer.write_u8(0x94)?; + writer.write_bool(succeeded)?; + writer.write_u32(data)?; + }, + Packet::SpiBasicReply { succeeded } => { + writer.write_u8(0x95)?; + writer.write_bool(succeeded)?; + }, + + Packet::JdacBasicRequest { destination, dacno, reqno, param } => { + writer.write_u8(0xa0)?; + writer.write_u8(destination)?; + writer.write_u8(dacno)?; + writer.write_u8(reqno)?; + writer.write_u8(param)?; + } + Packet::JdacBasicReply { succeeded, retval } => { + writer.write_u8(0xa1)?; + writer.write_bool(succeeded)?; + writer.write_u8(retval)?; + }, + } + Ok(()) + } +}