use crate::sys;
pub const DEFAULT_PORT: u16 = sys::IEC_60870_5_104_DEFAULT_PORT as u16;
pub const DEFAULT_TLS_PORT: u16 = sys::IEC_60870_5_104_DEFAULT_TLS_PORT as u16;
pub const QOI_STATION: u8 = sys::IEC60870_QOI_STATION as u8;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CauseOfTransmission {
Periodic,
Background,
Spontaneous,
Initialized,
Request,
Activation,
ActivationCon,
Deactivation,
DeactivationCon,
ActivationTermination,
ReturnRemote,
ReturnLocal,
InterrogatedByStation,
UnknownType,
UnknownCot,
UnknownCa,
UnknownIoa,
}
impl CauseOfTransmission {
pub fn as_raw(self) -> sys::CS101_CauseOfTransmission {
match self {
Self::Periodic => sys::CS101_CauseOfTransmission_CS101_COT_PERIODIC,
Self::Background => sys::CS101_CauseOfTransmission_CS101_COT_BACKGROUND_SCAN,
Self::Spontaneous => sys::CS101_CauseOfTransmission_CS101_COT_SPONTANEOUS,
Self::Initialized => sys::CS101_CauseOfTransmission_CS101_COT_INITIALIZED,
Self::Request => sys::CS101_CauseOfTransmission_CS101_COT_REQUEST,
Self::Activation => sys::CS101_CauseOfTransmission_CS101_COT_ACTIVATION,
Self::ActivationCon => sys::CS101_CauseOfTransmission_CS101_COT_ACTIVATION_CON,
Self::Deactivation => sys::CS101_CauseOfTransmission_CS101_COT_DEACTIVATION,
Self::DeactivationCon => sys::CS101_CauseOfTransmission_CS101_COT_DEACTIVATION_CON,
Self::ActivationTermination => {
sys::CS101_CauseOfTransmission_CS101_COT_ACTIVATION_TERMINATION
}
Self::ReturnRemote => sys::CS101_CauseOfTransmission_CS101_COT_RETURN_INFO_REMOTE,
Self::ReturnLocal => sys::CS101_CauseOfTransmission_CS101_COT_RETURN_INFO_LOCAL,
Self::InterrogatedByStation => {
sys::CS101_CauseOfTransmission_CS101_COT_INTERROGATED_BY_STATION
}
Self::UnknownType => sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_TYPE_ID,
Self::UnknownCot => sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_COT,
Self::UnknownCa => sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_CA,
Self::UnknownIoa => sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_IOA,
}
}
pub fn from_raw(raw: sys::CS101_CauseOfTransmission) -> Option<Self> {
match raw {
sys::CS101_CauseOfTransmission_CS101_COT_PERIODIC => Some(Self::Periodic),
sys::CS101_CauseOfTransmission_CS101_COT_BACKGROUND_SCAN => Some(Self::Background),
sys::CS101_CauseOfTransmission_CS101_COT_SPONTANEOUS => Some(Self::Spontaneous),
sys::CS101_CauseOfTransmission_CS101_COT_INITIALIZED => Some(Self::Initialized),
sys::CS101_CauseOfTransmission_CS101_COT_REQUEST => Some(Self::Request),
sys::CS101_CauseOfTransmission_CS101_COT_ACTIVATION => Some(Self::Activation),
sys::CS101_CauseOfTransmission_CS101_COT_ACTIVATION_CON => Some(Self::ActivationCon),
sys::CS101_CauseOfTransmission_CS101_COT_DEACTIVATION => Some(Self::Deactivation),
sys::CS101_CauseOfTransmission_CS101_COT_DEACTIVATION_CON => {
Some(Self::DeactivationCon)
}
sys::CS101_CauseOfTransmission_CS101_COT_ACTIVATION_TERMINATION => {
Some(Self::ActivationTermination)
}
sys::CS101_CauseOfTransmission_CS101_COT_RETURN_INFO_REMOTE => Some(Self::ReturnRemote),
sys::CS101_CauseOfTransmission_CS101_COT_RETURN_INFO_LOCAL => Some(Self::ReturnLocal),
sys::CS101_CauseOfTransmission_CS101_COT_INTERROGATED_BY_STATION => {
Some(Self::InterrogatedByStation)
}
sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_TYPE_ID => Some(Self::UnknownType),
sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_COT => Some(Self::UnknownCot),
sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_CA => Some(Self::UnknownCa),
sys::CS101_CauseOfTransmission_CS101_COT_UNKNOWN_IOA => Some(Self::UnknownIoa),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TypeId {
SinglePoint,
SinglePointTime,
DoublePoint,
DoublePointTime,
StepPosition,
Bitstring32,
MeasuredNormalized,
MeasuredScaled,
MeasuredScaledTime,
MeasuredFloat,
MeasuredFloatTime,
IntegratedTotals,
EndOfInit,
SingleCommand,
SingleCommandTime,
DoubleCommand,
RegulatingStep,
SetpointNormalized,
SetpointScaled,
SetpointFloat,
Interrogation,
CounterInterrogation,
Read,
ClockSync,
TestCommand,
TestCommandTime,
ResetProcess,
}
impl TypeId {
pub fn as_raw(self) -> sys::IEC60870_5_TypeID {
match self {
Self::SinglePoint => sys::IEC60870_5_TypeID_M_SP_NA_1,
Self::SinglePointTime => sys::IEC60870_5_TypeID_M_SP_TB_1,
Self::DoublePoint => sys::IEC60870_5_TypeID_M_DP_NA_1,
Self::DoublePointTime => sys::IEC60870_5_TypeID_M_DP_TB_1,
Self::StepPosition => sys::IEC60870_5_TypeID_M_ST_NA_1,
Self::Bitstring32 => sys::IEC60870_5_TypeID_M_BO_NA_1,
Self::MeasuredNormalized => sys::IEC60870_5_TypeID_M_ME_NA_1,
Self::MeasuredScaled => sys::IEC60870_5_TypeID_M_ME_NB_1,
Self::MeasuredScaledTime => sys::IEC60870_5_TypeID_M_ME_TE_1,
Self::MeasuredFloat => sys::IEC60870_5_TypeID_M_ME_NC_1,
Self::MeasuredFloatTime => sys::IEC60870_5_TypeID_M_ME_TF_1,
Self::IntegratedTotals => sys::IEC60870_5_TypeID_M_IT_NA_1,
Self::EndOfInit => sys::IEC60870_5_TypeID_M_EI_NA_1,
Self::SingleCommand => sys::IEC60870_5_TypeID_C_SC_NA_1,
Self::SingleCommandTime => sys::IEC60870_5_TypeID_C_SC_TA_1,
Self::DoubleCommand => sys::IEC60870_5_TypeID_C_DC_NA_1,
Self::RegulatingStep => sys::IEC60870_5_TypeID_C_RC_NA_1,
Self::SetpointNormalized => sys::IEC60870_5_TypeID_C_SE_NA_1,
Self::SetpointScaled => sys::IEC60870_5_TypeID_C_SE_NB_1,
Self::SetpointFloat => sys::IEC60870_5_TypeID_C_SE_NC_1,
Self::Interrogation => sys::IEC60870_5_TypeID_C_IC_NA_1,
Self::CounterInterrogation => sys::IEC60870_5_TypeID_C_CI_NA_1,
Self::Read => sys::IEC60870_5_TypeID_C_RD_NA_1,
Self::ClockSync => sys::IEC60870_5_TypeID_C_CS_NA_1,
Self::TestCommand => sys::IEC60870_5_TypeID_C_TS_NA_1,
Self::TestCommandTime => sys::IEC60870_5_TypeID_C_TS_TA_1,
Self::ResetProcess => sys::IEC60870_5_TypeID_C_RP_NA_1,
}
}
pub fn from_raw(raw: sys::IEC60870_5_TypeID) -> Option<Self> {
match raw {
sys::IEC60870_5_TypeID_M_SP_NA_1 => Some(Self::SinglePoint),
sys::IEC60870_5_TypeID_M_SP_TB_1 => Some(Self::SinglePointTime),
sys::IEC60870_5_TypeID_M_DP_NA_1 => Some(Self::DoublePoint),
sys::IEC60870_5_TypeID_M_DP_TB_1 => Some(Self::DoublePointTime),
sys::IEC60870_5_TypeID_M_ST_NA_1 => Some(Self::StepPosition),
sys::IEC60870_5_TypeID_M_BO_NA_1 => Some(Self::Bitstring32),
sys::IEC60870_5_TypeID_M_ME_NA_1 => Some(Self::MeasuredNormalized),
sys::IEC60870_5_TypeID_M_ME_NB_1 => Some(Self::MeasuredScaled),
sys::IEC60870_5_TypeID_M_ME_TE_1 => Some(Self::MeasuredScaledTime),
sys::IEC60870_5_TypeID_M_ME_NC_1 => Some(Self::MeasuredFloat),
sys::IEC60870_5_TypeID_M_ME_TF_1 => Some(Self::MeasuredFloatTime),
sys::IEC60870_5_TypeID_M_IT_NA_1 => Some(Self::IntegratedTotals),
sys::IEC60870_5_TypeID_M_EI_NA_1 => Some(Self::EndOfInit),
sys::IEC60870_5_TypeID_C_SC_NA_1 => Some(Self::SingleCommand),
sys::IEC60870_5_TypeID_C_SC_TA_1 => Some(Self::SingleCommandTime),
sys::IEC60870_5_TypeID_C_DC_NA_1 => Some(Self::DoubleCommand),
sys::IEC60870_5_TypeID_C_RC_NA_1 => Some(Self::RegulatingStep),
sys::IEC60870_5_TypeID_C_SE_NA_1 => Some(Self::SetpointNormalized),
sys::IEC60870_5_TypeID_C_SE_NB_1 => Some(Self::SetpointScaled),
sys::IEC60870_5_TypeID_C_SE_NC_1 => Some(Self::SetpointFloat),
sys::IEC60870_5_TypeID_C_IC_NA_1 => Some(Self::Interrogation),
sys::IEC60870_5_TypeID_C_CI_NA_1 => Some(Self::CounterInterrogation),
sys::IEC60870_5_TypeID_C_RD_NA_1 => Some(Self::Read),
sys::IEC60870_5_TypeID_C_CS_NA_1 => Some(Self::ClockSync),
sys::IEC60870_5_TypeID_C_TS_NA_1 => Some(Self::TestCommand),
sys::IEC60870_5_TypeID_C_TS_TA_1 => Some(Self::TestCommandTime),
sys::IEC60870_5_TypeID_C_RP_NA_1 => Some(Self::ResetProcess),
_ => None,
}
}
pub fn name(self) -> &'static str {
let ptr = unsafe { sys::TypeID_toString(self.as_raw()) };
if ptr.is_null() {
"UNKNOWN"
} else {
unsafe { std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("UNKNOWN") }
}
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Quality: u8 {
const GOOD = 0;
const OVERFLOW = sys::IEC60870_QUALITY_OVERFLOW as u8;
const RESERVED = sys::IEC60870_QUALITY_RESERVED as u8;
const ELAPSED_TIME_INVALID = sys::IEC60870_QUALITY_ELAPSED_TIME_INVALID as u8;
const BLOCKED = sys::IEC60870_QUALITY_BLOCKED as u8;
const SUBSTITUTED = sys::IEC60870_QUALITY_SUBSTITUTED as u8;
const NOT_TOPICAL = sys::IEC60870_QUALITY_NON_TOPICAL as u8;
const INVALID = sys::IEC60870_QUALITY_INVALID as u8;
}
}
impl Default for Quality {
fn default() -> Self {
Quality::GOOD
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConnectionEvent {
Opened,
Closed,
Failed,
StartDtCon,
StopDtCon,
}
impl ConnectionEvent {
pub fn from_raw(raw: sys::CS104_ConnectionEvent) -> Option<Self> {
match raw {
sys::CS104_ConnectionEvent_CS104_CONNECTION_OPENED => Some(Self::Opened),
sys::CS104_ConnectionEvent_CS104_CONNECTION_CLOSED => Some(Self::Closed),
sys::CS104_ConnectionEvent_CS104_CONNECTION_FAILED => Some(Self::Failed),
sys::CS104_ConnectionEvent_CS104_CONNECTION_STARTDT_CON_RECEIVED => {
Some(Self::StartDtCon)
}
sys::CS104_ConnectionEvent_CS104_CONNECTION_STOPDT_CON_RECEIVED => {
Some(Self::StopDtCon)
}
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PeerConnectionEvent {
Opened,
Closed,
Activated,
Deactivated,
}
impl PeerConnectionEvent {
pub fn from_raw(raw: sys::CS104_PeerConnectionEvent) -> Option<Self> {
match raw {
sys::CS104_PeerConnectionEvent_CS104_CON_EVENT_CONNECTION_OPENED => Some(Self::Opened),
sys::CS104_PeerConnectionEvent_CS104_CON_EVENT_CONNECTION_CLOSED => Some(Self::Closed),
sys::CS104_PeerConnectionEvent_CS104_CON_EVENT_ACTIVATED => Some(Self::Activated),
sys::CS104_PeerConnectionEvent_CS104_CON_EVENT_DEACTIVATED => Some(Self::Deactivated),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum ServerMode {
#[default]
SingleRedundancyGroup,
ConnectionIsRedundancyGroup,
MultipleRedundancyGroups,
}
impl ServerMode {
pub fn as_raw(self) -> sys::CS104_ServerMode {
match self {
Self::SingleRedundancyGroup => sys::CS104_ServerMode_CS104_MODE_SINGLE_REDUNDANCY_GROUP,
Self::ConnectionIsRedundancyGroup => {
sys::CS104_ServerMode_CS104_MODE_CONNECTION_IS_REDUNDANCY_GROUP
}
Self::MultipleRedundancyGroups => {
sys::CS104_ServerMode_CS104_MODE_MULTIPLE_REDUNDANCY_GROUPS
}
}
}
}