///|
/// Mailbox protocol types as defined in ETG.1000.6.
pub(all) enum MailboxType {
  /// Error mailbox
  Err
  /// ADS over EtherCAT
  AoE
  /// Ethernet over EtherCAT (out of scope)
  EoE
  /// CAN application protocol over EtherCAT
  CoE
  /// File access over EtherCAT (out of scope)
  FoE
  /// Servo profile over EtherCAT
  SoE
  /// Vendor specific
  VoE
} derive(Eq, Debug)

///|
pub fn MailboxType::to_byte(self : MailboxType) -> Byte {
  match self {
    Err => b'\x00'
    AoE => b'\x01'
    EoE => b'\x02'
    CoE => b'\x03'
    FoE => b'\x04'
    SoE => b'\x05'
    VoE => b'\x0F'
  }
}

///|
/// Mailbox header structure (6 bytes in protocol).
pub(all) struct MailboxHeader {
  length : UInt
  address : UInt
  channel : Byte
  priority : Byte
  mb_type : MailboxType
  counter : Byte
} derive(Eq, Debug)

///|
/// Repeat request / acknowledge state for resilient mailbox read recovery.
///
/// Repeat Request is toggled by the MainDevice in the SyncManager activate
/// byte (offset 0x0006 bit 1). Repeat Acknowledge is toggled by the SubDevice
/// in the PDI-owned status byte (offset 0x0007 bit 1) after restoring the last
/// readable mailbox payload.
pub(all) struct MailboxRepeatState {
  request : Bool
  acknowledge : Bool
} derive(Eq, Debug)

///|
let mailbox_repeat_bit : Byte = b'\x02'

///|
fn set_mask_bit(value : Byte, mask : Byte, enabled : Bool) -> Byte {
  if enabled {
    value | mask
  } else {
    value & (mask ^ b'\xFF')
  }
}

///|
/// Decode resilient mailbox repeat state from the two SyncManager bytes.
pub fn MailboxRepeatState::from_sync_manager_bytes(
  activate : Byte,
  pdi_control : Byte,
) -> MailboxRepeatState {
  {
    request: (activate & mailbox_repeat_bit) != b'\x00',
    acknowledge: (pdi_control & mailbox_repeat_bit) != b'\x00',
  }
}

///|
/// Return true once the SubDevice has observed and acknowledged the current
/// repeat request toggle.
pub fn MailboxRepeatState::is_acknowledged(self : MailboxRepeatState) -> Bool {
  self.request == self.acknowledge
}

///|
/// Toggle the MainDevice repeat request state for a mailbox-read replay.
pub fn MailboxRepeatState::toggle_request(self : MailboxRepeatState) -> Bool {
  !self.request
}

///|
/// Apply the current repeat request value to a SyncManager activate byte.
pub fn MailboxRepeatState::apply_to_activate_byte(
  self : MailboxRepeatState,
  activate : Byte,
) -> Byte {
  set_mask_bit(activate, mailbox_repeat_bit, self.request)
}

///|
/// Apply the current repeat acknowledge value to the SyncManager PDI byte.
pub fn MailboxRepeatState::apply_to_pdi_control_byte(
  self : MailboxRepeatState,
  pdi_control : Byte,
) -> Byte {
  set_mask_bit(pdi_control, mailbox_repeat_bit, self.acknowledge)
}