forked from M-Labs/artiq-zynq
proto fw: add event packet reader
This commit is contained in:
parent
c6413d44e5
commit
b7278af56e
|
@ -11,6 +11,7 @@ use crate::{mem::mem::{CXP_LOOPBACK_MEM, CXP_RX_MEM, CXP_TX_MEM},
|
||||||
|
|
||||||
const BUF_LEN: usize = 0x800;
|
const BUF_LEN: usize = 0x800;
|
||||||
const DATA_MAXSIZE: usize = 48;
|
const DATA_MAXSIZE: usize = 48;
|
||||||
|
const EV_MAXSIZE: usize = 253;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -35,23 +36,80 @@ fn get_cxp_crc(bytes: &[u8]) -> u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait CxpRead {
|
trait CxpRead {
|
||||||
|
fn read_exact_4x(&mut self, buf: &mut [u8]) -> Result<(), Error>;
|
||||||
|
|
||||||
fn read_4x_u8(&mut self) -> Result<u8, Error>;
|
fn read_4x_u8(&mut self) -> Result<u8, Error>;
|
||||||
|
|
||||||
|
fn read_4x_u16(&mut self) -> Result<u16, Error>;
|
||||||
|
|
||||||
|
fn read_4x_u32(&mut self) -> Result<u32, Error>;
|
||||||
|
|
||||||
|
fn read_4x_u64(&mut self) -> Result<u64, Error>;
|
||||||
|
|
||||||
|
fn read_u16(&mut self) -> Result<u16, Error>;
|
||||||
|
|
||||||
fn read_u32(&mut self) -> Result<u32, Error>;
|
fn read_u32(&mut self) -> Result<u32, Error>;
|
||||||
|
|
||||||
|
fn read_u64(&mut self) -> Result<u64, Error>;
|
||||||
}
|
}
|
||||||
impl<Cursor: Read> CxpRead for Cursor {
|
impl<Cursor: Read> CxpRead for Cursor {
|
||||||
|
fn read_exact_4x(&mut self, buf: &mut [u8]) -> Result<(), Error> {
|
||||||
|
for b in buf {
|
||||||
|
// TODO: add error correction
|
||||||
|
let mut bytes = [0; 4];
|
||||||
|
self.read_exact(&mut bytes)?;
|
||||||
|
*b = bytes[0];
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn read_4x_u8(&mut self) -> Result<u8, Error> {
|
fn read_4x_u8(&mut self) -> Result<u8, Error> {
|
||||||
// TODO: add error correction
|
let mut bytes = [0; 1];
|
||||||
let mut bytes = [0; 4];
|
self.read_exact_4x(&mut bytes)?;
|
||||||
self.read_exact(&mut bytes)?;
|
|
||||||
Ok(bytes[0])
|
Ok(bytes[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_4x_u16(&mut self) -> Result<u16, Error> {
|
||||||
|
let mut bytes = [0; 2];
|
||||||
|
self.read_exact_4x(&mut bytes)?;
|
||||||
|
Ok(NetworkEndian::read_u16(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_4x_u32(&mut self) -> Result<u32, Error> {
|
||||||
|
let mut bytes = [0; 4];
|
||||||
|
self.read_exact_4x(&mut bytes)?;
|
||||||
|
Ok(NetworkEndian::read_u32(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_4x_u64(&mut self) -> Result<u64, Error> {
|
||||||
|
let mut bytes = [0; 6];
|
||||||
|
self.read_exact_4x(&mut bytes)?;
|
||||||
|
Ok(NetworkEndian::read_u64(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u16(&mut self) -> Result<u16, Error> {
|
||||||
|
let mut bytes = [0; 2];
|
||||||
|
self.read_exact(&mut bytes)?;
|
||||||
|
Ok(NetworkEndian::read_u16(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
fn read_u32(&mut self) -> Result<u32, Error> {
|
fn read_u32(&mut self) -> Result<u32, Error> {
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
self.read_exact(&mut bytes)?;
|
self.read_exact(&mut bytes)?;
|
||||||
Ok(NetworkEndian::read_u32(&bytes))
|
Ok(NetworkEndian::read_u32(&bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_u64(&mut self) -> Result<u64, Error> {
|
||||||
|
let mut bytes = [0; 8];
|
||||||
|
self.read_exact(&mut bytes)?;
|
||||||
|
Ok(NetworkEndian::read_u64(&bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum NameSpace {
|
||||||
|
GenICam,
|
||||||
|
DeviceSpecific,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -69,6 +127,16 @@ pub enum DownConnPacket {
|
||||||
CtrlAck {
|
CtrlAck {
|
||||||
tag: Option<u8>,
|
tag: Option<u8>,
|
||||||
},
|
},
|
||||||
|
Event {
|
||||||
|
conn_id: u32,
|
||||||
|
packet_tag: u8,
|
||||||
|
length: u16,
|
||||||
|
ev_size: u16,
|
||||||
|
namespace: NameSpace,
|
||||||
|
event_id: u16,
|
||||||
|
timestamp: u64,
|
||||||
|
ev: [u8; EV_MAXSIZE],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DownConnPacket {
|
impl DownConnPacket {
|
||||||
|
@ -76,6 +144,7 @@ impl DownConnPacket {
|
||||||
match packet_type {
|
match packet_type {
|
||||||
0x03 => DownConnPacket::get_ctrl_packet(reader, false),
|
0x03 => DownConnPacket::get_ctrl_packet(reader, false),
|
||||||
0x06 => DownConnPacket::get_ctrl_packet(reader, true),
|
0x06 => DownConnPacket::get_ctrl_packet(reader, true),
|
||||||
|
0x07 => DownConnPacket::get_event_packet(reader),
|
||||||
_ => Err(Error::UnknownPacket(packet_type)),
|
_ => Err(Error::UnknownPacket(packet_type)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,38 +158,78 @@ impl DownConnPacket {
|
||||||
let ackcode = reader.read_4x_u8()?;
|
let ackcode = reader.read_4x_u8()?;
|
||||||
|
|
||||||
match ackcode {
|
match ackcode {
|
||||||
0x00 => {
|
0x00 | 0x04 => {
|
||||||
let length = reader.read_u32()?;
|
let length = reader.read_u32()?;
|
||||||
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
||||||
reader.read(&mut data[0..length as usize])?;
|
reader.read(&mut data[0..length as usize])?;
|
||||||
|
|
||||||
let checksum = get_cxp_crc(&reader.get_ref()[0..reader.position()]);
|
let checksum = get_cxp_crc(&reader.get_ref()[0..reader.position()]);
|
||||||
let recv_checksum = reader.read_u32()?;
|
if reader.read_u32()? != checksum {
|
||||||
println!("calculated checksum = {:#010X}", checksum);
|
|
||||||
println!("read checksum = {:#010X}", recv_checksum);
|
|
||||||
if recv_checksum != checksum {
|
|
||||||
return Err(Error::CorruptedPacket);
|
return Err(Error::CorruptedPacket);
|
||||||
}
|
}
|
||||||
return Ok(DownConnPacket::CtrlReply { tag, length, data });
|
|
||||||
|
if ackcode == 0x00 {
|
||||||
|
return Ok(DownConnPacket::CtrlReply { tag, length, data });
|
||||||
|
} else {
|
||||||
|
return Ok(DownConnPacket::CtrlDelay {
|
||||||
|
tag,
|
||||||
|
length,
|
||||||
|
time: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
0x01 => return Ok(DownConnPacket::CtrlAck { tag }),
|
0x01 => return Ok(DownConnPacket::CtrlAck { tag }),
|
||||||
0x04 => {
|
|
||||||
let length = reader.read_u32()?;
|
|
||||||
let mut time: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
|
||||||
reader.read(&mut time[0..length as usize])?;
|
|
||||||
|
|
||||||
let checksum = get_cxp_crc(&reader.get_ref()[0..reader.position()]);
|
|
||||||
let recv_checksum = reader.read_u32()?;
|
|
||||||
println!("calculated checksum = {:#010X}", checksum);
|
|
||||||
println!("read checksum = {:#010X}", recv_checksum);
|
|
||||||
if recv_checksum != checksum {
|
|
||||||
return Err(Error::CorruptedPacket);
|
|
||||||
}
|
|
||||||
return Ok(DownConnPacket::CtrlDelay { tag, length, time });
|
|
||||||
}
|
|
||||||
_ => return Err(Error::CtrlAckError(ackcode)),
|
_ => return Err(Error::CtrlAckError(ackcode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_event_packet(reader: &mut Cursor<&mut [u8]>) -> Result<Self, Error> {
|
||||||
|
let conn_id = reader.read_4x_u32()?;
|
||||||
|
let packet_tag = reader.read_4x_u8()?;
|
||||||
|
let length = reader.read_4x_u16()?;
|
||||||
|
|
||||||
|
let ev_size = reader.read_u16()?;
|
||||||
|
if ev_size + 3 != length {
|
||||||
|
println!("length mismatch");
|
||||||
|
return Err(Error::CorruptedPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bytes = [0; 2];
|
||||||
|
reader.read_exact(&mut bytes)?;
|
||||||
|
let namespace_bits = (bytes[0] & 0xC0) >> 6;
|
||||||
|
let namespace = match namespace_bits {
|
||||||
|
0 => NameSpace::GenICam,
|
||||||
|
2 => NameSpace::DeviceSpecific,
|
||||||
|
_ => {
|
||||||
|
println!("namespace = {} error", namespace_bits);
|
||||||
|
return Err(Error::CorruptedPacket);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let event_id = (bytes[0] & 0xF) as u16 | (bytes[1] as u16);
|
||||||
|
|
||||||
|
let timestamp = reader.read_u64()?;
|
||||||
|
|
||||||
|
let mut ev: [u8; EV_MAXSIZE] = [0; EV_MAXSIZE];
|
||||||
|
reader.read(&mut ev[0..ev_size as usize])?;
|
||||||
|
|
||||||
|
let checksum = get_cxp_crc(&reader.get_ref()[0..reader.position()]);
|
||||||
|
if reader.read_u32()? != checksum {
|
||||||
|
println!("crc error");
|
||||||
|
return Err(Error::CorruptedPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(DownConnPacket::Event {
|
||||||
|
conn_id,
|
||||||
|
packet_tag,
|
||||||
|
length,
|
||||||
|
ev_size,
|
||||||
|
namespace,
|
||||||
|
event_id,
|
||||||
|
timestamp,
|
||||||
|
ev,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn receive(channel: usize) -> Result<Option<DownConnPacket>, Error> {
|
pub fn receive(channel: usize) -> Result<Option<DownConnPacket>, Error> {
|
||||||
|
@ -134,7 +243,7 @@ pub fn receive(channel: usize) -> Result<Option<DownConnPacket>, Error> {
|
||||||
let packet_type = (CXP[channel].downconn_packet_type_read)();
|
let packet_type = (CXP[channel].downconn_packet_type_read)();
|
||||||
|
|
||||||
let packet = DownConnPacket::read_from(&mut reader, packet_type);
|
let packet = DownConnPacket::read_from(&mut reader, packet_type);
|
||||||
println!("{:?}", packet);
|
println!("{:X?}", packet);
|
||||||
|
|
||||||
(CXP[channel].downconn_pending_packet_write)(1);
|
(CXP[channel].downconn_pending_packet_write)(1);
|
||||||
Ok(Some(packet?))
|
Ok(Some(packet?))
|
||||||
|
|
Loading…
Reference in New Issue