diff --git a/src/libboard_artiq/src/cxp_proto.rs b/src/libboard_artiq/src/cxp_proto.rs index 64fc357..69223a3 100644 --- a/src/libboard_artiq/src/cxp_proto.rs +++ b/src/libboard_artiq/src/cxp_proto.rs @@ -16,16 +16,32 @@ const MEM_LEN: usize = 0x200; #[derive(Debug)] pub enum Error { BufferError, + CorruptedPacket, + CtrlAckError(u8), LinkDown, UnknownPacket(u8), } +#[derive(Debug)] +pub enum CtrlError { + AddressReadOnly, + AddressWriteOnly, + CRCFailed, + DataSizeDifferent, + InvalidAddress, + InvalidData, + InvalidOpcode, + MalformedPacket, + SizeToolarge, +} + impl From for Error { fn from(_: IoError) -> Error { Error::BufferError } } +#[derive(Debug)] pub enum Packet { // Upconn packet CtrlRead { @@ -56,13 +72,13 @@ pub enum Packet { // Downconn packet CtrlAck { ackcode: u8, - length: u8, + length: u32, data: [u8; DATA_MAXSIZE], }, CtrlAckWithTag { tag: u8, ackcode: u8, - length: u8, + length: u32, data: [u8; DATA_MAXSIZE], }, CtrlAckNoData { @@ -88,18 +104,26 @@ fn read_word(reader: &mut Cursor<&mut [u8]>) -> Result { } impl Packet { - pub fn read_from(reader: &mut Cursor<&mut [u8]>, packet_type: u8) -> Result<(), Error> { + pub fn read_from(reader: &mut Cursor<&mut [u8]>, packet_type: u8) -> Result { match packet_type { 0x03 => { - let ackcode4x = read_word(reader); - println!("ackcode4x = {:#010X}", ackcode4x.unwrap()); - let len = read_word(reader); - println!("len = {:#010X}", len.unwrap()); + let ackcode: u8 = (read_word(reader)? & 0xFF) as u8; + let length = read_word(reader)?; + + let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE]; + if ackcode == 0x00 || ackcode == 0x04 { + reader.read(&mut data[0..length as usize])?; + }; + + match ackcode { + 0x00 | 0x04 => return Ok(Packet::CtrlAck { ackcode, length, data }), + 0x01 => return Ok(Packet::CtrlAckNoData { ackcode }), + _ => return Err(Error::CtrlAckError(ackcode)), + } } - 0x06 => {} - _ => {} + 0x06 => return Err(Error::UnknownPacket(packet_type)), + _ => return Err(Error::UnknownPacket(packet_type)), } - Ok(()) } pub fn write_to(&self, writer: &mut Cursor<&mut [u8]>) -> Result<(), Error> { // CoaXpress use big endian @@ -146,9 +170,12 @@ impl Packet { if ackcode == 0x00 || ackcode == 0x04 { writer.write(&[0x00, 0x00, 0x00, length])?; writer.write(&data[0..length as usize])?; - let checksum = crc32::checksum_ieee(&writer.get_ref()[4..writer.position()]); - writer.write(&(!checksum).to_le_bytes())?; } + + print_packet(&writer.get_ref()[4..writer.position()]); + + let checksum = crc32::checksum_ieee(&writer.get_ref()[4..writer.position()]); + writer.write(&(!checksum).to_le_bytes())?; } _ => return Err(Error::UnknownPacket(0)), } @@ -177,9 +204,26 @@ pub fn receive(channel: usize) -> Result<(), Error> { let mut reader = Cursor::new(slice::from_raw_parts_mut(ptr as *mut u8, MEM_LEN)); let packet_type = (CXP[channel].downconn_packet_type_read)(); - Packet::read_from(&mut reader, packet_type); + let packet = Packet::read_from(&mut reader, packet_type)?; + println!("{:?}", packet); - // print_packet(slice::from_raw_parts_mut(ptr as *mut u8, MEM_LEN)); + // Section 9.2.2.2 (CXP-001-2021) + // Only Control packet need CRC32 appended in the end of the packet + // CoaXpress use the polynomial of IEEE-802.3 (Ethernet) CRC but the checksum calculation is different + // Also, the calculation does not include the first 4 bytes of packet_type + if packet_type == 0x03 || packet_type == 0x06 { + let checksum_at = reader.position(); + let checksum = (!crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at])).swap_bytes(); + println!("checksum location = {:#010X}", checksum_at); + println!("calculated checksum = {:#010X}", checksum); + println!("read checksum = {:#010X}", read_word(&mut reader)?); + reader.set_position(checksum_at); + if read_word(&mut reader)? != checksum { + return Err(Error::CorruptedPacket); + } + } + + print_packet(slice::from_raw_parts_mut(ptr as *mut u8, MEM_LEN)); } Ok(()) }