use core::fmt;
use bilge::prelude::*;
use crate::data::{self, Field, BitField, Storage};
pub mod address {
use super::*;
pub const fixed: Field<u16> = Field::simple(0x0010);
pub const alias: Field<u16> = Field::simple(0x0012);
}
pub mod dl {
use super::*;
pub const information: Field<DLInformation> = Field::simple(0x0000);
pub const control: Field<DLControl> = Field::simple(0x0100);
pub const status: Field<DLStatus> = Field::simple(0x0110);
}
pub mod dls_user {
use super::*;
pub const r1: Field<u8> = Field::simple(0x0120);
pub const r2: Field<u8> = Field::simple(0x0121);
pub const r3: Field<u8> = Field::simple(0x0130);
pub const r4: Field<u8> = Field::simple(0x0131);
pub const r5: Field<u16> = Field::simple(0x0132);
pub const r6: Field<u16> = Field::simple(0x0134);
pub const r7: Field<u8> = Field::simple(0x0140);
pub const copy_r1_r3: BitField<bool> = BitField::new(0x0141*8, 1);
pub const r9: BitField<u8> = BitField::new(0x0141*8+1, 7);
pub const r8: Field<u8> = Field::simple(0x0150);
pub const p1: Field<u8> = Field::simple(0x0981);
pub const p2: Field<u16> = Field::simple(0x0982);
pub const p13: Field<u8> = Field::simple(0x0982);
pub const p14: Field<u8> = Field::simple(0x0984);
pub const p3: Field<u16> = Field::simple(0x098e);
pub const p4: Field<u32> = Field::simple(0x0990);
pub const p5: Field<u32> = Field::simple(0x09a0);
pub const p6: Field<u32> = Field::simple(0x09a4);
pub const p7: Field<u16> = Field::simple(0x09a8);
pub const p8: Field<u16> = Field::simple(0x09ae);
pub const p9: Field<u32> = Field::simple(0x09b0);
pub const p10: Field<u32> = Field::simple(0x09b8);
pub const p11: Field<u32> = Field::simple(0x09c0);
pub const p12: Field<u32> = Field::simple(0x09c8);
pub const event: Field<DLSUserEvents> = Field::simple(0x0220);
pub const event_mask: Field<DLSUserEvents> = Field::simple(0x0202);
pub const watchdog: Field<u16> = Field::simple(0x0410);
}
pub const external_event: Field<ExternalEvent> = Field::simple(0x0210);
pub const external_event_mask: Field<ExternalEvent> = Field::simple(0x0200);
pub const ports_errors: Field<PortsErrorCount> = Field::simple(0x0300);
pub const lost_link_count: Field<LostLinkCount> = Field::simple(0x0310);
pub const frame_error_count: Field<FrameErrorCount> = Field::simple(0x0308);
pub const watchdog_divider: Field<u16> = Field::simple(0x0400);
pub const watchdog_counter: Field<WatchdogCounter> = Field::simple(0x0442);
pub mod sync_manager {
use super::*;
pub const watchdog: Field<u16> = Field::simple(0x0420);
pub const watchdog_status: Field<bool> = Field::simple(0x0440);
pub const interface: SyncManager = SyncManager {address: 0x0800, num: 16};
}
pub mod sii {
use super::*;
pub const access: Field<SiiAccess> = Field::simple(0x0500);
pub const control: Field<SiiControl> = Field::simple(0x0502);
pub const address: Field<u16> = Field::simple(0x0504);
pub const data: Field<[u8; 8]> = Field::simple(0x0508);
pub const control_address: Field<SiiControlAddress> = Field::simple(control.byte);
pub const control_address_data: Field<SiiControlAddressData> = Field::simple(control.byte);
}
pub const fmmu: FMMU = FMMU {address: 0x0600, num: 16};
pub mod al {
use super::*;
pub const control: Field<AlControlRequest> = Field::simple(dls_user::r1.byte);
pub const response: Field<AlControlResponse> = Field::simple(dls_user::r3.byte);
pub const error: Field<AlError> = Field::simple(dls_user::r6.byte);
pub const status: Field<AlStatus> = Field::simple(dls_user::r3.byte);
pub const pdi: Field<AlPdiControlType> = Field::simple(dls_user::r7.byte);
pub const sync_config: Field<AlSyncConfig> = Field::simple(dls_user::r8.byte);
}
pub mod dc {
use super::*;
pub const all: Field<DistributedClock> = Field::simple(0x0900);
pub const measure_time: Field<u32> = Field::simple(0x0900);
pub const received_time: Field<[u32; 4]> = Field::simple(0x0900);
pub const system_time: Field<u64> = Field::simple(0x0910);
pub const local_time: Field<u64> = Field::simple(0x0918);
pub const system_offset: Field<u64> = Field::simple(0x920);
pub const system_delay: Field<u32> = Field::simple(0x928);
pub const system_difference: Field<TimeDifference> = Field::simple(0x092C);
pub const param_0: Field<u16> = Field::simple(0x0930);
pub const param_2: Field<u16> = Field::simple(0x0934);
}
pub mod isochronous {
use super::*;
pub const all: Field<Isochronous> = Field::simple(0x0980);
pub mod sync {
use super::*;
pub const enable: Field<IsochronousEnables> = Field::simple(dls_user::p1.byte);
pub const pulse: Field<u16> = Field::simple(dls_user::p2.byte);
pub const interrupt0: Field<IsochronousInterrupt> = Field::simple(dls_user::p3.byte);
pub const interrupt1: Field<IsochronousInterrupt> = Field::simple(dls_user::p3.byte+1);
pub const start_time: Field<u32> = dls_user::p4;
pub const sync0_cycle_time: Field<u32> = Field::simple(dls_user::p5.byte);
pub const sync1_cycle_time: Field<u32> = Field::simple(dls_user::p6.byte);
}
pub mod latch {
use super::*;
pub const edge0: Field<IsochronousLatch> = Field::simple(dls_user::p7.byte);
pub const edge1: Field<IsochronousLatch> = Field::simple(dls_user::p7.byte+1);
pub const event0: Field<IsochronousLatch> = Field::simple(dls_user::p8.byte);
pub const event1: Field<IsochronousLatch> = Field::simple(dls_user::p8.byte+1);
pub mod times {
use super::*;
pub const latch0_positive: Field<u32> = Field::simple(dls_user::p9.byte);
pub const latch0_negative: Field<u32> = Field::simple(dls_user::p10.byte);
pub const latch1_positive: Field<u32> = Field::simple(dls_user::p11.byte);
pub const latch1_negative: Field<u32> = Field::simple(dls_user::p12.byte);
}
}
}
#[bitsize(8)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Eq, PartialEq, Default)]
pub struct AlControlRequest {
pub state: AlMixedState,
pub ack: bool,
pub request_id: bool,
reserved: u2,
}
data::bilge_pdudata!(AlControlRequest, u8);
#[bitsize(8)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Eq, PartialEq)]
pub struct AlControlResponse {
pub state: AlMixedState,
pub error: bool,
pub id: bool,
reserved: u2,
}
data::bilge_pdudata!(AlControlResponse, u8);
#[bitsize(8)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Eq, PartialEq)]
pub struct AlStatus {
pub state: AlMixedState,
pub changed: bool,
reserved: u3,
}
data::bilge_pdudata!(AlStatus, u8);
#[bitsize(4)]
#[derive(TryFromBits, Debug, Copy, Clone, Eq, PartialEq)]
pub enum AlState {
Bootstrap = 3,
Init = 1,
PreOperational = 2,
SafeOperational = 4,
Operational = 8,
}
#[bitsize(4)]
#[derive(FromBits, DebugBits, Copy, Clone, Eq, PartialEq, Default)]
pub struct AlMixedState {
pub init: bool,
pub pre_operational: bool,
pub safe_operational: bool,
pub operational: bool,
}
impl fmt::Display for AlMixedState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{{", core::any::type_name::<Self>()) ?;
for (active, mark) in [ (self.init(), "init"),
(self.pre_operational(), "pre"),
(self.safe_operational(), "safe"),
(self.operational(), "op"),
] {
write!(f, " ")?;
if active {
write!(f, "{}", mark)?;
} else {
for _ in 0 .. mark.len() {write!(f, " ")?;}
}
}
write!(f, "}}")?;
Ok(())
}
}
impl TryFrom<AlMixedState> for AlState {
type Error = &'static str;
fn try_from(state: AlMixedState) -> Result<Self, Self::Error> {
Self::try_from(u4::from(state)).map_err(|e| "cannot unwrap when not only 1 state in mix")
}
}
impl From<AlState> for AlMixedState {
fn from(state: AlState) -> Self {
Self::from(u4::from(state))
}
}
#[bitsize(16)]
#[derive(TryFromBits, Debug, Copy, Clone, Eq, PartialEq)]
pub enum AlError {
NoError = 0x0000,
Unspecified = 0x0001,
NoMemory = 0x0002,
InvalidDeviceSetup = 0x0003,
InvalidStateRequest = 0x0011,
UnknownStateRequest = 0x0012,
BootstrapNotSupported = 0x0013,
NoValidFirmware = 0x0014,
InvalidMailboxConfigBoot = 0x0015,
InvalidMailboxConfigPreop = 0x0016,
InvalidSyncConfig = 0x0017,
NoInputsAvailable = 0x0018,
NoValidInputs = 0x0019,
Synchronization = 0x001A,
SyncWatchdog = 0x001B,
InvalidSyncTypes = 0x001C,
InvalidOutputConfig = 0x001D,
InvalidInputConfig = 0x001E,
InvalidWatchdogConfig = 0x001F,
NeedColdStart = 0x0020,
NeedInit = 0x0021,
NeedPreop = 0x0022,
NeedSafeOp = 0x0023,
InvalidInputMapping = 0x0024,
InvalidOutputMapping = 0x0025,
InconsistentSettings = 0x0026,
FreeRunNotSupported = 0x0027,
SyncModeNotSupported = 0x0028,
FreeRunNeedsBuffer = 0x0029,
BackgroundWatchdog = 0x002A,
NoValidIO = 0x002B,
FatalSync = 0x002C,
NoSync = 0x002D,
InvalidDcConfig = 0x0030,
InvalidLatchConfig = 0x0031,
PLL = 0x0032,
DCSyncIO = 0x0033,
DCSyncTimeout = 0x0034,
DCInvalidPeriod = 0x0035,
MailboxAOE = 0x0041,
MailboxEOE = 0x0042,
MailboxCOE = 0x0043,
MailboxFOE = 0x0044,
MailboxSOE = 0x0045,
MailboxVOE = 0x004F,
EepromNoAccess = 0x0050,
Eeeprom = 0x0051,
SlaveRestarted = 0x0060,
DeviceIdentificationUpdated = 0x0061,
ApplicationAvailable = 0x00F0,
Specific = 0xffff,
}
data::bilge_pdudata!(AlError, u16);
#[bitsize(9)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Eq, PartialEq, Default)]
pub struct AlPdiControlType {
pub pdi: u8,
pub strict: bool,
}
data::bilge_pdudata!(AlPdiControlType, u9);
#[bitsize(8)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Eq, PartialEq, Default)]
pub struct AlSyncConfig {
pub signal_conditioning_sync0: u2,
pub enable_signal_sync0: bool,
pub enable_interrupt_sync0: bool,
pub signal_conditioning_sync1: u2,
pub enable_signal_sync1: bool,
pub enable_interrupt_sync1: bool,
}
data::bilge_pdudata!(AlSyncConfig, u8);
#[bitsize(80)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Eq, PartialEq)]
pub struct DLInformation {
pub ty: u8,
pub revision: u8,
pub build: u16,
pub fmmus: u8,
pub sync_managers: u8,
pub ram_size: u8,
pub ports: [PortDescriptor; 4],
pub fmmu_bit_operation_not_supported: bool,
pub reserved_registers_not_supported: bool,
pub dc_supported: bool,
pub dc_range: DcRange,
pub ebus_low_jitter: bool,
pub ebus_enhanced_link_detection: bool,
pub mii_enhanced_link_detection: bool,
pub separate_fcs_errors: bool,
pub dc_sync_activation_enhanced: bool,
pub logical_exchange_not_supported: bool,
pub physicial_exchange_not_supported: bool,
pub special_fmmu_config: bool,
reserved: u4,
}
data::bilge_pdudata!(DLInformation, u80);
#[bitsize(2)]
#[derive(FromBits, Debug, Copy, Clone)]
pub enum PortDescriptor {
NotImplemented = 0b00,
NotConfigured = 0b01,
Ebus = 0b10,
Mii = 0b11,
}
#[bitsize(1)]
#[derive(FromBits, Debug, Copy, Clone)]
pub enum DcRange {
Bit32 = 0,
Bit64 = 1,
}
#[bitsize(16)]
#[derive(TryFromBits, DebugBits, Copy, Clone)]
pub struct MailboxSupport {
pub aoe: bool,
pub eoe: bool,
pub coe: bool,
pub foe: bool,
pub soe: bool,
pub voe: bool,
reserved: u10,
}
data::bilge_pdudata!(MailboxSupport, u16);
#[bitsize(32)]
#[derive(TryFromBits, DebugBits, Copy, Clone)]
pub struct DLControl {
forwarding: Forwarding,
temporary: bool,
reserved: u6,
ports: [LoopControl; 4],
transmit_buffer_size: u3,
low_jitter_ebus: bool,
reserved: u4,
alias_enable: bool,
reserved: u7,
}
data::bilge_pdudata!(DLControl, u32);
#[bitsize(1)]
#[derive(TryFromBits, Debug, Copy, Clone)]
pub enum Forwarding {
Transmit = 0,
Filter = 1,
}
data::bilge_pdudata!(Forwarding, u1);
#[bitsize(2)]
#[derive(TryFromBits, Debug, Copy, Clone)]
pub enum LoopControl {
Auto = 0,
AutoClose = 1,
AlwaysOpen = 2,
AlwaysClosed = 3,
}
data::bilge_pdudata!(LoopControl, u2);
#[bitsize(16)]
#[derive(FromBits, DebugBits, Copy, Clone)]
pub struct DLStatus {
pub dls_user_operational: bool,
pub dls_user_watchdog: bool,
pub extended_link_detection: bool,
reserved: u1,
pub port_link_status: [bool; 4],
pub port_loop_status: [LoopStatus; 4],
}
data::bilge_pdudata!(DLStatus, u16);
#[bitsize(2)]
#[derive(FromBits, DebugBits, Copy, Clone)]
pub struct LoopStatus {
pub loop_back: bool,
pub signal_detection: bool,
}
data::bilge_pdudata!(LoopStatus, u2);
#[bitsize(32)]
#[derive(FromBits, DebugBits, Copy, Clone, Default)]
pub struct DLSUserEvents {
pub r1_change: bool,
pub dc: [bool; 3],
pub sync_manager_change: bool,
pub eeprom_emulation: bool,
reserved: u2,
pub sync_manager_channel: [bool; 16],
reserved: u8,
}
data::bilge_pdudata!(DLSUserEvents, u32);
#[bitsize(16)]
#[derive(FromBits, DebugBits, Copy, Clone, Default)]
pub struct ExternalEvent {
pub dc0: bool,
reserved: u1,
pub dl: bool,
pub al: bool,
pub sync_manager_channel: [bool; 8],
reserved: u4,
}
data::bilge_pdudata!(ExternalEvent, u16);
#[repr(packed)]
#[derive(Clone, Debug, Default)]
pub struct PortsErrorCount {
pub port: [PortErrorCount; 4],
}
data::packed_pdudata!(PortsErrorCount);
#[bitsize(16)]
#[derive(FromBits, DebugBits, Copy, Clone, Default)]
pub struct PortErrorCount {
pub frame: u8,
pub physical: u8,
}
data::bilge_pdudata!(PortErrorCount, u16);
#[bitsize(32)]
#[derive(FromBits, DebugBits, Copy, Clone)]
pub struct LostLinkCount {
pub port: [u8; 4],
}
data::bilge_pdudata!(LostLinkCount, u32);
#[bitsize(48)]
#[derive(FromBits, DebugBits, Copy, Clone)]
pub struct FrameErrorCount {
pub previous_error_count: [u8; 4],
pub malformat_frame_count: u8,
pub local_problem_count: u8,
}
data::bilge_pdudata!(FrameErrorCount, u48);
#[bitsize(16)]
#[derive(FromBits, DebugBits, Copy, Clone)]
pub struct WatchdogCounter {
pub sync_manager: u8,
pub pdi: u8,
}
data::bilge_pdudata!(WatchdogCounter, u16);
#[bitsize(16)]
#[derive(FromBits, DebugBits, Copy, Clone, Default)]
pub struct SiiAccess {
pub owner: SiiOwner,
pub lock: bool,
pub reserved: u6,
pub pdi: bool,
pub reserved: u7,
}
data::bilge_pdudata!(SiiAccess, u16);
#[bitsize(1)]
#[derive(FromBits, Debug, Copy, Clone, Eq, PartialEq, Default)]
pub enum SiiOwner {
#[default]
EthercatDL = 0,
Pdi = 1,
}
data::bilge_pdudata!(SiiOwner, u1);
#[bitsize(16)]
#[derive(FromBits, DebugBits, Copy, Clone, Default)]
pub struct SiiControl {
pub write_access: bool,
reserved: u4,
pub eeprom_emulation: bool,
pub read_size: SiiTransaction,
pub address_unit: SiiUnit,
pub read_operation: bool,
pub write_operation: bool,
pub reload_operation: bool,
pub checksum_error: bool,
pub device_info_error: bool,
pub command_error: bool,
pub write_error: bool,
pub busy: bool,
}
data::bilge_pdudata!(SiiControl, u16);
#[bitsize(1)]
#[derive(FromBits, Debug, Copy, Clone, Eq, PartialEq, Default)]
pub enum SiiTransaction {
#[default]
Bytes4 = 0,
Bytes8 = 1,
}
#[bitsize(1)]
#[derive(FromBits, Debug, Copy, Clone, Eq, PartialEq, Default)]
pub enum SiiUnit {
#[default]
Byte = 0,
Word = 1,
}
#[repr(packed)]
#[derive(Debug, Copy, Clone)]
pub struct SiiControlAddress {
pub control: SiiControl,
pub address: u16,
}
data::packed_pdudata!(SiiControlAddress);
#[repr(packed)]
#[derive(Debug, Copy, Clone)]
pub struct SiiControlAddressData {
pub control: SiiControl,
pub address: u16,
pub reserved: u16,
pub data: [u8; 2],
}
data::packed_pdudata!(SiiControlAddressData);
pub struct FMMU {
pub address: u16,
pub num: u8,
}
impl FMMU {
pub fn entry(&self, index: u8) -> Field<FmmuEntry> {
assert!(index < self.num, "index out of range");
Field::simple(usize::from(self.address + u16::from(index)*0x10))
}
}
#[bitsize(128)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Default)]
pub struct FmmuEntry {
pub logical_start_byte: u32,
pub logical_len_byte: u16,
pub logical_start_bit: u3,
reserved: u5,
pub logical_end_bit: u3,
reserved: u5,
pub physical_start_byte: u16,
pub physical_start_bit: u3,
reserved: u5,
pub read: bool,
pub write: bool,
reserved: u6,
pub enable: bool,
reserved: u7,
reserved: u24,
}
data::bilge_pdudata!(FmmuEntry, u128);
pub struct SyncManager {
pub address: u16,
pub num: u8,
}
impl SyncManager {
pub fn channel(&self, index: u8) -> Field<SyncManagerChannel> {
assert!(index < self.num, "index out of range");
Field::simple(usize::from(self.address + u16::from(index) * (core::mem::size_of::<SyncManagerChannel>() as u16) ))
}
pub fn mailbox_write(&self) -> Field<SyncManagerChannel> {self.channel(0)}
pub fn mailbox_read(&self) -> Field<SyncManagerChannel> {self.channel(1)}
pub fn logical_write(&self) -> Field<SyncManagerChannel> {self.channel(2)}
pub fn logical_read(&self) -> Field<SyncManagerChannel> {self.channel(3)}
pub fn mappable(&self, index: u8) -> Field<SyncManagerChannel> {self.channel(2+index)}
}
#[bitsize(64)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Default)]
pub struct SyncManagerChannel {
pub address: u16,
pub length: u16,
pub mode: SyncMode,
pub direction: SyncDirection,
pub ec_event: bool,
pub dls_user_event: bool,
pub watchdog: bool,
reserved: u1,
pub write_event: bool,
pub read_event: bool,
reserved: u1,
pub mailbox_full: bool,
pub buffer_state: u2,
pub read_buffer_open: bool,
pub write_buffer_open: bool,
pub enable: bool,
pub repeat: bool,
reserved: u4,
pub dc_event_bus: bool,
pub dc_event_local: bool,
pub disable_pdi: bool,
pub repeat_ack: bool,
reserved: u6,
}
data::bilge_pdudata!(SyncManagerChannel, u64);
#[bitsize(2)]
#[derive(TryFromBits, Debug, Copy, Clone, Eq, PartialEq, Default)]
pub enum SyncMode {
#[default]
Buffered = 0,
Mailbox = 2,
}
#[bitsize(2)]
#[derive(TryFromBits, Debug, Copy, Clone, Eq, PartialEq, Default)]
pub enum SyncDirection {
#[default]
Read = 0,
Write = 1,
}
#[repr(packed)]
#[derive(Clone, Copy, Default, Debug, PartialEq)]
pub struct DistributedClock {
pub received_time: [u32;4],
pub system_time: u64,
pub local_time: u64,
pub system_offset: u64,
pub system_delay: u32,
pub system_difference: TimeDifference,
pub control_loop_params: [u16; 3],
}
data::packed_pdudata!(DistributedClock);
#[bitsize(32)]
#[derive(TryFromBits, DebugBits, Copy, Clone, Default, PartialEq)]
pub struct TimeDifference {
pub mean: u31,
pub sign: bool,
}
data::bilge_pdudata!(TimeDifference, u32);
impl From<TimeDifference> for i32 {
fn from(value: TimeDifference) -> i32 {
u32::from(value.mean().value()) as i32
* if value.sign() {-1} else {1}
}
}
impl From<i32> for TimeDifference {
fn from(value: i32) -> TimeDifference {
TimeDifference::new(u31::new(value.abs() as u32), value < 0)
}
}
#[repr(packed)]
#[derive(Clone, Default, Debug, PartialEq)]
pub struct Isochronous {
reserved1: IsochronousAccess,
pub enable: IsochronousEnables,
pub pulse: u16,
reserved2: [u8; 10],
pub interrupt0: IsochronousInterrupt,
pub interrupt1: IsochronousInterrupt,
pub start_time: u32,
reserved3: [u8; 12],
pub sync0_cycle_time: u32,
pub sync1_cycle_time: u32,
pub latch0_edge: IsochronousLatch,
pub latch1_edge: IsochronousLatch,
pub reserved4: [u8; 4],
pub latch0_event: IsochronousLatch,
pub latch1_event: IsochronousLatch,
pub latch0_time_positive: u32,
reserved5: u32,
pub latch0_time_negative: u32,
reserved6: u32,
pub latch1_time_positive: u32,
reserved7: u32,
pub latch1_time_negative: u32,
reserved8: u32,
}
data::packed_pdudata!(Isochronous);
#[bitsize(8)]
#[derive(Copy, Clone, Default, DebugBits, PartialEq)]
pub struct IsochronousAccess{
pub write_access_cyclic : bool,
reserved : u3,
pub write_access_latch0 : bool,
pub write_access_latch1 : bool,
reserved : u2,
}
data::bilge_pdudata!(IsochronousAccess, u8);
#[bitsize(8)]
#[derive(Copy, Clone, Default, DebugBits, PartialEq)]
pub struct IsochronousEnables {
pub operation: bool,
pub sync0: bool,
pub sync1: bool,
pub auto_activation : bool,
pub start_time_ext : bool,
pub start_time_check : bool,
pub half_range : bool,
pub debug_pulse : bool,
}
data::bilge_pdudata!(IsochronousEnables, u8);
#[bitsize(8)]
#[derive(Copy, Clone, Default, DebugBits, PartialEq)]
pub struct IsochronousInterrupt {
pub enable : bool,
reserved : u7
}
data::bilge_pdudata!(IsochronousInterrupt, u8);
#[bitsize(8)]
#[derive(Copy, Clone, Default, DebugBits, PartialEq)]
pub struct IsochronousLatch {
pub positive: bool,
pub negative: bool,
reserved: u6
}
data::bilge_pdudata!(IsochronousLatch, u16);