use crate::sys;
use crate::types::Quality;
pub type Ioa = u32;
#[derive(Debug, Clone, Copy)]
pub struct SinglePoint {
pub ioa: Ioa,
pub value: bool,
pub quality: Quality,
}
impl SinglePoint {
pub unsafe fn from_raw(io: sys::InformationObject) -> Option<Self> {
if io.is_null() {
return None;
}
let spi = io as sys::SinglePointInformation;
let result = Self {
ioa: sys::InformationObject_getObjectAddress(io) as Ioa,
value: sys::SinglePointInformation_getValue(spi),
quality: Quality::from_bits_truncate(sys::SinglePointInformation_getQuality(spi) as u8),
};
sys::SinglePointInformation_destroy(spi);
Some(result)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum DoublePointValue {
Intermediate = 0,
Off = 1,
On = 2,
Indeterminate = 3,
}
impl DoublePointValue {
pub fn from_raw(raw: sys::DoublePointValue) -> Self {
match raw {
sys::DoublePointValue_IEC60870_DOUBLE_POINT_INTERMEDIATE => Self::Intermediate,
sys::DoublePointValue_IEC60870_DOUBLE_POINT_OFF => Self::Off,
sys::DoublePointValue_IEC60870_DOUBLE_POINT_ON => Self::On,
_ => Self::Indeterminate,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct DoublePoint {
pub ioa: Ioa,
pub value: DoublePointValue,
pub quality: Quality,
}
impl DoublePoint {
pub unsafe fn from_raw(io: sys::InformationObject) -> Option<Self> {
if io.is_null() {
return None;
}
let dpi = io as sys::DoublePointInformation;
let result = Self {
ioa: sys::InformationObject_getObjectAddress(io) as Ioa,
value: DoublePointValue::from_raw(sys::DoublePointInformation_getValue(dpi)),
quality: Quality::from_bits_truncate(sys::DoublePointInformation_getQuality(dpi) as u8),
};
sys::DoublePointInformation_destroy(dpi);
Some(result)
}
}
#[derive(Debug, Clone, Copy)]
pub struct MeasuredScaled {
pub ioa: Ioa,
pub value: i16,
pub quality: Quality,
}
impl MeasuredScaled {
pub unsafe fn from_raw(io: sys::InformationObject) -> Option<Self> {
if io.is_null() {
return None;
}
let mvs = io as sys::MeasuredValueScaled;
let result = Self {
ioa: sys::InformationObject_getObjectAddress(io) as Ioa,
value: sys::MeasuredValueScaled_getValue(mvs) as i16,
quality: Quality::from_bits_truncate(sys::MeasuredValueScaled_getQuality(mvs) as u8),
};
sys::MeasuredValueScaled_destroy(mvs);
Some(result)
}
}
#[derive(Debug, Clone, Copy)]
pub struct MeasuredNormalized {
pub ioa: Ioa,
pub value: f32,
pub quality: Quality,
}
impl MeasuredNormalized {
pub unsafe fn from_raw(io: sys::InformationObject) -> Option<Self> {
if io.is_null() {
return None;
}
let mvn = io as sys::MeasuredValueNormalized;
let result = Self {
ioa: sys::InformationObject_getObjectAddress(io) as Ioa,
value: sys::MeasuredValueNormalized_getValue(mvn),
quality: Quality::from_bits_truncate(sys::MeasuredValueNormalized_getQuality(mvn) as u8),
};
sys::MeasuredValueNormalized_destroy(mvn);
Some(result)
}
}
#[derive(Debug, Clone, Copy)]
pub struct MeasuredFloat {
pub ioa: Ioa,
pub value: f32,
pub quality: Quality,
}
impl MeasuredFloat {
pub unsafe fn from_raw(io: sys::InformationObject) -> Option<Self> {
if io.is_null() {
return None;
}
let mvf = io as sys::MeasuredValueShort;
let result = Self {
ioa: sys::InformationObject_getObjectAddress(io) as Ioa,
value: sys::MeasuredValueShort_getValue(mvf),
quality: Quality::from_bits_truncate(sys::MeasuredValueShort_getQuality(mvf) as u8),
};
sys::MeasuredValueShort_destroy(mvf);
Some(result)
}
}
#[derive(Debug, Clone, Copy)]
pub struct SingleCommand {
pub ioa: Ioa,
pub state: bool,
pub select: bool,
pub qualifier: u8,
}
impl SingleCommand {
pub unsafe fn from_raw(io: sys::InformationObject) -> Option<Self> {
if io.is_null() {
return None;
}
let sc = io as sys::SingleCommand;
let result = Self {
ioa: sys::InformationObject_getObjectAddress(io) as Ioa,
state: sys::SingleCommand_getState(sc),
select: sys::SingleCommand_isSelect(sc),
qualifier: sys::SingleCommand_getQU(sc) as u8,
};
sys::SingleCommand_destroy(sc);
Some(result)
}
}
use crate::asdu::Asdu;
use crate::types::TypeId;
#[derive(Debug, Clone)]
pub enum InfoObject {
SinglePoint(SinglePoint),
DoublePoint(DoublePoint),
MeasuredScaled(MeasuredScaled),
MeasuredNormalized(MeasuredNormalized),
MeasuredFloat(MeasuredFloat),
SingleCommand(SingleCommand),
Unknown {
type_id: sys::IEC60870_5_TypeID,
ioa: Ioa,
},
}
impl Asdu {
pub fn parse_objects(&self) -> Vec<InfoObject> {
let count = self.element_count();
let type_id = self.type_id();
let mut objects = Vec::with_capacity(count);
for i in 0..count {
let io = unsafe { self.get_element_raw(i) };
if io.is_null() {
continue;
}
let obj = match type_id {
Some(TypeId::SinglePoint) | Some(TypeId::SinglePointTime) => {
unsafe { SinglePoint::from_raw(io) }.map(InfoObject::SinglePoint)
}
Some(TypeId::DoublePoint) | Some(TypeId::DoublePointTime) => {
unsafe { DoublePoint::from_raw(io) }.map(InfoObject::DoublePoint)
}
Some(TypeId::MeasuredScaled) | Some(TypeId::MeasuredScaledTime) => {
unsafe { MeasuredScaled::from_raw(io) }.map(InfoObject::MeasuredScaled)
}
Some(TypeId::MeasuredNormalized) => {
unsafe { MeasuredNormalized::from_raw(io) }.map(InfoObject::MeasuredNormalized)
}
Some(TypeId::MeasuredFloat) | Some(TypeId::MeasuredFloatTime) => {
unsafe { MeasuredFloat::from_raw(io) }.map(InfoObject::MeasuredFloat)
}
Some(TypeId::SingleCommand) | Some(TypeId::SingleCommandTime) => {
unsafe { SingleCommand::from_raw(io) }.map(InfoObject::SingleCommand)
}
_ => {
let ioa = unsafe { sys::InformationObject_getObjectAddress(io) as Ioa };
unsafe { sys::InformationObject_destroy(io) };
Some(InfoObject::Unknown {
type_id: self.type_id_raw(),
ioa,
})
}
};
if let Some(obj) = obj {
objects.push(obj);
}
}
objects
}
}