use bit_field::BitField;
use volatile::Volatile;
pub const TX_CMD_EOP: u8 = 1 << 0;
pub const TX_CMD_IFCS: u8 = 1 << 1;
pub const TX_CMD_IC: u8 = 1 << 2;
pub const TX_CMD_RS: u8 = 1 << 3;
pub const TX_CMD_RPS: u8 = 1 << 4;
pub const TX_CMD_DEXT: u8 = 1 << 5;
pub const TX_CMD_VLE: u8 = 1 << 6;
pub const TX_CMD_IDE: u8 = 1 << 7;
pub const TX_STATUS_DD: u8 = 1 << 0;
pub const TX_DTYP_ADV: u8 = 0x3 << 4;
pub const TX_PAYLEN_SHIFT: u8 = 46 - 32;
pub const RX_STATUS_DD: u8 = 1 << 0;
pub const RX_STATUS_EOP: u8 = 1 << 1;
pub struct AdvancedRxDescriptor {
pub packet_buffer_address: Volatile<u64>,
pub header_buffer_address: Volatile<u64>,
}
impl AdvancedRxDescriptor {
pub fn init(&mut self) {
self.packet_buffer_address.write(0);
self.header_buffer_address.write(0);
}
pub fn set_packet_address(&mut self, packet_buffer_address: u64) {
self.packet_buffer_address.write(packet_buffer_address);
}
pub fn reset_status(&mut self) {
self.header_buffer_address.write(0);
}
pub fn descriptor_done(&self) -> bool {
(self.get_ext_status() & RX_STATUS_DD as u64) == RX_STATUS_DD as u64
}
pub fn end_of_packet(&self) -> bool {
(self.get_ext_status() & RX_STATUS_EOP as u64) == RX_STATUS_EOP as u64
}
pub fn length(&self) -> u64 {
self.get_pkt_len()
}
pub fn get_rss_type(&self) -> u64 {
self.packet_buffer_address.read().get_bits(0..3)
}
pub fn get_packet_type(&self) -> u64 {
self.packet_buffer_address.read().get_bits(4..16)
}
pub fn get_rsccnt(&self) -> u64 {
self.packet_buffer_address.read().get_bits(17..20)
}
pub fn get_hdr_len(&self) -> u64 {
self.packet_buffer_address.read().get_bits(21..30)
}
pub fn get_rss_hash(&self) -> u64 {
self.packet_buffer_address.read().get_bits(32..63)
}
pub fn get_fdf_id(&self) -> u64 {
self.packet_buffer_address.read().get_bits(32..63)
}
pub fn get_ext_status(&self) -> u64 {
self.header_buffer_address.read().get_bits(0..19)
}
pub fn get_ext_error(&self) -> u64 {
self.header_buffer_address.read().get_bits(20..31)
}
pub fn get_pkt_len(&self) -> u64 {
self.header_buffer_address.read().get_bits(32..47)
}
pub fn get_vlan_tag(&self) -> u64 {
self.header_buffer_address.read().get_bits(48..63)
}
}
#[repr(C)]
pub struct AdvancedTxDescriptor {
pub packet_buffer_address: Volatile<u64>,
pub data_len: Volatile<u16>,
pub dtyp_mac_rsv: Volatile<u8>,
pub dcmd: Volatile<u8>,
pub paylen_popts_cc_idx_sta: Volatile<u32>,
}
impl AdvancedTxDescriptor {
pub fn init(&mut self) {
self.packet_buffer_address.write(0);
self.paylen_popts_cc_idx_sta.write(0);
self.dcmd.write(0);
self.dtyp_mac_rsv.write(0);
self.data_len.write(0);
}
pub fn send(&mut self, transmit_buffer_addr: u64, transmit_buffer_length: u16) {
self.packet_buffer_address.write(transmit_buffer_addr);
self.data_len.write(transmit_buffer_length);
self.dtyp_mac_rsv.write(TX_DTYP_ADV);
self.paylen_popts_cc_idx_sta
.write((transmit_buffer_length as u32) << TX_PAYLEN_SHIFT);
self.dcmd
.write(TX_CMD_DEXT | TX_CMD_RS | TX_CMD_IFCS | TX_CMD_EOP);
}
#[allow(clippy::while_immutable_condition)]
pub fn wait_for_packet_tx(&self) {
while (self.paylen_popts_cc_idx_sta.read() as u8 & TX_STATUS_DD) == 0 {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tx_command_constants() {
assert_eq!(TX_CMD_EOP, 1 << 0);
assert_eq!(TX_CMD_IFCS, 1 << 1);
assert_eq!(TX_CMD_IC, 1 << 2);
assert_eq!(TX_CMD_RS, 1 << 3);
assert_eq!(TX_CMD_RPS, 1 << 4);
assert_eq!(TX_CMD_DEXT, 1 << 5);
assert_eq!(TX_CMD_VLE, 1 << 6);
assert_eq!(TX_CMD_IDE, 1 << 7);
}
#[test]
fn test_tx_status_constants() {
assert_eq!(TX_STATUS_DD, 1 << 0);
}
#[test]
fn test_tx_descriptor_type() {
assert_eq!(TX_DTYP_ADV, 0x3 << 4);
}
#[test]
fn test_tx_paylen_shift() {
assert_eq!(TX_PAYLEN_SHIFT, 46 - 32);
assert_eq!(TX_PAYLEN_SHIFT, 14);
}
#[test]
fn test_rx_status_constants() {
assert_eq!(RX_STATUS_DD, 1 << 0);
assert_eq!(RX_STATUS_EOP, 1 << 1);
}
#[test]
fn test_tx_command_bit_operations() {
let mut cmd: u8 = 0;
cmd |= TX_CMD_EOP;
assert!(cmd & TX_CMD_EOP != 0);
cmd |= TX_CMD_IFCS;
assert!(cmd & TX_CMD_IFCS != 0);
cmd |= TX_CMD_DEXT | TX_CMD_RS | TX_CMD_EOP;
assert!(cmd & TX_CMD_EOP != 0);
assert!(cmd & TX_CMD_RS != 0);
assert!(cmd & TX_CMD_DEXT != 0);
}
#[test]
fn test_rx_status_bit_operations() {
let mut status: u8 = 0;
status |= RX_STATUS_DD;
assert!(status & RX_STATUS_DD != 0);
status |= RX_STATUS_EOP;
assert!(status & RX_STATUS_EOP != 0);
let combined = RX_STATUS_DD | RX_STATUS_EOP;
assert!(combined & RX_STATUS_DD != 0);
assert!(combined & RX_STATUS_EOP != 0);
}
}