use crate::error::{CaError, CaResult};
use crate::server::record::{FieldDesc, ProcessOutcome, Record};
use crate::types::{DbFieldType, EpicsValue};
pub struct AoRecord {
pub val: f64,
pub egu: String,
pub hopr: f64,
pub lopr: f64,
pub prec: i16,
pub drvh: f64,
pub drvl: f64,
pub rval: i32,
pub oraw: i32, pub rbv: i32, pub orbv: i32, pub oval: f64,
pub linr: i16, pub eguf: f64,
pub egul: f64,
pub eslo: f64, pub eoff: f64, pub roff: i32,
pub aslo: f64, pub aoff: f64,
pub omsl: i16, pub dol: String, pub oif: i16, pub oroc: f64, pub pval: f64, pub ivoa: i16, pub ivov: f64,
pub adel: f64,
pub mdel: f64,
pub lalm: f64,
pub alst: f64,
pub mlst: f64,
pub init: bool,
pub simm: i16,
pub siml: String,
pub siol: String,
pub sims: i16,
}
impl Default for AoRecord {
fn default() -> Self {
Self {
val: 0.0,
egu: String::new(),
hopr: 0.0,
lopr: 0.0,
prec: 0,
drvh: 0.0,
drvl: 0.0,
rval: 0,
oraw: 0,
rbv: 0,
orbv: 0,
oval: 0.0,
linr: 0,
eguf: 0.0,
egul: 0.0,
eslo: 1.0,
eoff: 0.0,
roff: 0,
aslo: 1.0,
aoff: 0.0,
omsl: 0,
dol: String::new(),
oif: 0,
oroc: 0.0,
pval: 0.0,
ivoa: 0,
ivov: 0.0,
adel: 0.0,
mdel: 0.0,
lalm: 0.0,
alst: 0.0,
mlst: 0.0,
init: false,
simm: 0,
siml: String::new(),
siol: String::new(),
sims: 0,
}
}
}
impl AoRecord {
pub fn new(val: f64) -> Self {
Self {
val,
..Default::default()
}
}
}
static FIELDS: &[FieldDesc] = &[
FieldDesc {
name: "VAL",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "EGU",
dbf_type: DbFieldType::String,
read_only: false,
},
FieldDesc {
name: "HOPR",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "LOPR",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "PREC",
dbf_type: DbFieldType::Short,
read_only: false,
},
FieldDesc {
name: "DRVH",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "DRVL",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "RVAL",
dbf_type: DbFieldType::Long,
read_only: false,
},
FieldDesc {
name: "ORAW",
dbf_type: DbFieldType::Long,
read_only: true,
},
FieldDesc {
name: "RBV",
dbf_type: DbFieldType::Long,
read_only: true,
},
FieldDesc {
name: "ORBV",
dbf_type: DbFieldType::Long,
read_only: true,
},
FieldDesc {
name: "OVAL",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "LINR",
dbf_type: DbFieldType::Short,
read_only: false,
},
FieldDesc {
name: "EGUF",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "EGUL",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "ESLO",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "EOFF",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "ROFF",
dbf_type: DbFieldType::Long,
read_only: false,
},
FieldDesc {
name: "ASLO",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "AOFF",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "OMSL",
dbf_type: DbFieldType::Short,
read_only: false,
},
FieldDesc {
name: "DOL",
dbf_type: DbFieldType::String,
read_only: false,
},
FieldDesc {
name: "OIF",
dbf_type: DbFieldType::Short,
read_only: false,
},
FieldDesc {
name: "OROC",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "PVAL",
dbf_type: DbFieldType::Double,
read_only: true,
},
FieldDesc {
name: "IVOA",
dbf_type: DbFieldType::Short,
read_only: false,
},
FieldDesc {
name: "IVOV",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "ADEL",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "MDEL",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "LALM",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "ALST",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "MLST",
dbf_type: DbFieldType::Double,
read_only: false,
},
FieldDesc {
name: "INIT",
dbf_type: DbFieldType::Char,
read_only: true,
},
FieldDesc {
name: "SIMM",
dbf_type: DbFieldType::Short,
read_only: false,
},
FieldDesc {
name: "SIML",
dbf_type: DbFieldType::String,
read_only: false,
},
FieldDesc {
name: "SIOL",
dbf_type: DbFieldType::String,
read_only: false,
},
FieldDesc {
name: "SIMS",
dbf_type: DbFieldType::Short,
read_only: false,
},
];
fn dol_as_constant(dol: &str) -> Option<f64> {
let s = dol.trim();
if s.is_empty() {
return None;
}
s.parse::<f64>().ok()
}
impl Record for AoRecord {
fn record_type(&self) -> &'static str {
"ao"
}
fn init_record(&mut self, pass: u8) -> CaResult<()> {
if pass == 0 {
let saved_eoff = self.eoff;
let saved_eslo = self.eslo;
if self.eslo == 1.0 && self.eoff == 0.0 {
self.eoff = self.egul;
}
if self.linr == 1 {
self.eoff = saved_eoff;
self.eslo = saved_eslo;
}
if let Some(v) = dol_as_constant(&self.dol) {
self.val = v;
}
self.oval = self.val;
self.pval = self.val;
self.mlst = self.val;
self.alst = self.val;
self.lalm = self.val;
self.oraw = self.rval;
self.orbv = self.rbv;
self.init = true;
}
Ok(())
}
fn process(&mut self) -> CaResult<ProcessOutcome> {
if self.omsl == 1 && !self.dol.is_empty() {
if let Some(v) = dol_as_constant(&self.dol) {
self.val = v;
}
}
if self.drvh > self.drvl {
self.val = self.val.clamp(self.drvl, self.drvh);
}
let mut value = self.val;
self.pval = value;
if self.oroc != 0.0 {
let diff = value - self.oval;
if diff < 0.0 {
if self.oroc < -diff {
value = self.oval - self.oroc;
}
} else if self.oroc < diff {
value = self.oval + self.oroc;
}
}
self.oval = value;
match self.linr {
1 | 2 => {
if self.eslo == 0.0 {
value = 0.0;
} else {
value = (value - self.eoff) / self.eslo;
}
}
0 => {} _ => {} }
value -= self.aoff;
if self.aslo != 0.0 {
value /= self.aslo;
}
value -= self.roff as f64;
if value >= 0.0 {
if value >= (i32::MAX as f64 - 0.5) {
self.rval = i32::MAX;
} else {
self.rval = (value + 0.5) as i32;
}
} else if value > (i32::MIN as f64 - 0.5) {
self.rval = (value - 0.5) as i32;
} else {
self.rval = i32::MIN;
}
self.oraw = self.rval;
self.init = true;
Ok(ProcessOutcome::complete())
}
fn get_field(&self, name: &str) -> Option<EpicsValue> {
match name {
"VAL" => Some(EpicsValue::Double(self.val)),
"EGU" => Some(EpicsValue::String(self.egu.clone())),
"HOPR" => Some(EpicsValue::Double(self.hopr)),
"LOPR" => Some(EpicsValue::Double(self.lopr)),
"PREC" => Some(EpicsValue::Short(self.prec)),
"DRVH" => Some(EpicsValue::Double(self.drvh)),
"DRVL" => Some(EpicsValue::Double(self.drvl)),
"RVAL" => Some(EpicsValue::Long(self.rval)),
"ORAW" => Some(EpicsValue::Long(self.oraw)),
"RBV" => Some(EpicsValue::Long(self.rbv)),
"ORBV" => Some(EpicsValue::Long(self.orbv)),
"OVAL" => Some(EpicsValue::Double(self.oval)),
"LINR" => Some(EpicsValue::Short(self.linr)),
"EGUF" => Some(EpicsValue::Double(self.eguf)),
"EGUL" => Some(EpicsValue::Double(self.egul)),
"ESLO" => Some(EpicsValue::Double(self.eslo)),
"EOFF" => Some(EpicsValue::Double(self.eoff)),
"ROFF" => Some(EpicsValue::Long(self.roff)),
"ASLO" => Some(EpicsValue::Double(self.aslo)),
"AOFF" => Some(EpicsValue::Double(self.aoff)),
"OMSL" => Some(EpicsValue::Short(self.omsl)),
"DOL" => Some(EpicsValue::String(self.dol.clone())),
"OIF" => Some(EpicsValue::Short(self.oif)),
"OROC" => Some(EpicsValue::Double(self.oroc)),
"PVAL" => Some(EpicsValue::Double(self.pval)),
"IVOA" => Some(EpicsValue::Short(self.ivoa)),
"IVOV" => Some(EpicsValue::Double(self.ivov)),
"ADEL" => Some(EpicsValue::Double(self.adel)),
"MDEL" => Some(EpicsValue::Double(self.mdel)),
"LALM" => Some(EpicsValue::Double(self.lalm)),
"ALST" => Some(EpicsValue::Double(self.alst)),
"MLST" => Some(EpicsValue::Double(self.mlst)),
"INIT" => Some(EpicsValue::Char(if self.init { 1 } else { 0 })),
"SIMM" => Some(EpicsValue::Short(self.simm)),
"SIML" => Some(EpicsValue::String(self.siml.clone())),
"SIOL" => Some(EpicsValue::String(self.siol.clone())),
"SIMS" => Some(EpicsValue::Short(self.sims)),
_ => None,
}
}
fn put_field(&mut self, name: &str, value: EpicsValue) -> CaResult<()> {
match name {
"VAL" => match value {
EpicsValue::Double(v) => {
self.val = v;
Ok(())
}
EpicsValue::Long(v) => {
self.val = v as f64;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"EGU" => match value {
EpicsValue::String(v) => {
self.egu = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"HOPR" => match value {
EpicsValue::Double(v) => {
self.hopr = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"LOPR" => match value {
EpicsValue::Double(v) => {
self.lopr = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"PREC" => match value {
EpicsValue::Short(v) => {
self.prec = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"DRVH" => match value {
EpicsValue::Double(v) => {
self.drvh = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"DRVL" => match value {
EpicsValue::Double(v) => {
self.drvl = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"RVAL" => match value {
EpicsValue::Long(v) => {
self.rval = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"OVAL" => match value {
EpicsValue::Double(v) => {
self.oval = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"LINR" => match value {
EpicsValue::Short(v) => {
self.linr = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"EGUF" => match value {
EpicsValue::Double(v) => {
self.eguf = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"EGUL" => match value {
EpicsValue::Double(v) => {
self.egul = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"ESLO" => match value {
EpicsValue::Double(v) => {
self.eslo = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"EOFF" => match value {
EpicsValue::Double(v) => {
self.eoff = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"ROFF" => match value {
EpicsValue::Long(v) => {
self.roff = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"ASLO" => match value {
EpicsValue::Double(v) => {
self.aslo = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"AOFF" => match value {
EpicsValue::Double(v) => {
self.aoff = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"OMSL" => match value {
EpicsValue::Short(v) => {
self.omsl = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"DOL" => match value {
EpicsValue::String(v) => {
self.dol = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"OIF" => match value {
EpicsValue::Short(v) => {
self.oif = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"OROC" => match value {
EpicsValue::Double(v) => {
self.oroc = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"IVOA" => match value {
EpicsValue::Short(v) => {
self.ivoa = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"IVOV" => match value {
EpicsValue::Double(v) => {
self.ivov = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"ADEL" => match value {
EpicsValue::Double(v) => {
self.adel = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"MDEL" => match value {
EpicsValue::Double(v) => {
self.mdel = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"LALM" => match value {
EpicsValue::Double(v) => {
self.lalm = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"ALST" => match value {
EpicsValue::Double(v) => {
self.alst = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"MLST" => match value {
EpicsValue::Double(v) => {
self.mlst = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"SIMM" => match value {
EpicsValue::Short(v) => {
self.simm = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"SIML" => match value {
EpicsValue::String(v) => {
self.siml = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"SIOL" => match value {
EpicsValue::String(v) => {
self.siol = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
"SIMS" => match value {
EpicsValue::Short(v) => {
self.sims = v;
Ok(())
}
_ => Err(CaError::TypeMismatch(name.into())),
},
_ => Err(CaError::FieldNotFound(name.into())),
}
}
fn field_list(&self) -> &'static [FieldDesc] {
FIELDS
}
}