1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use crate::environment::calibration::{BooleanCalibration, NumericCalibration};
use crate::result::CompilerResult;
use crate::test_binary::{RelayAction, RelayInstr, SensorAction, SensorInstr};
use crate::test_descriptor::ast::{Abort, RelayOp, SensorBound, Test};
use crate::{
environment::{calibration::Calibration, Environment},
test_binary::DeviceAddress,
};
use super::ast::{RelayStatement, SensorConstraint};
pub struct ConcreteTest {
pub environment: Environment,
pub test: Test,
}
impl ConcreteTest {
pub fn try_new(environment: Environment, test: Test) -> CompilerResult<Self> {
let res = CompilerResult::new("Constructing concrete test model");
res.with_value(ConcreteTest { environment, test })
}
pub fn get_sensor_device_address(&self, sensor_id: &str) -> CompilerResult<DeviceAddress> {
self.environment.config.get_sensor_device_address(sensor_id)
}
pub fn get_relay_device_address(&self, relay_id: &str) -> CompilerResult<DeviceAddress> {
self.environment.config.get_relay_device_address(relay_id)
}
pub fn get_abort_id(&self, abort_name: &str) -> CompilerResult<u32> {
let mut res = CompilerResult::new("Get abort index for an abort");
if abort_name.eq(Abort::HARD_ABORT) {
return res.with_value(0);
}
for abort_idx in 0..self.test.aborts.len() {
if abort_name == self.test.aborts[abort_idx].name {
return res.with_value((abort_idx + 1) as u32);
}
}
res.error(format!(
"No abort with abort_name: {} found in test",
abort_name
));
res
}
pub fn get_calibration(&self, sensor_id: &str) -> CompilerResult<Option<&Calibration>> {
self.environment.get_calibration(sensor_id)
}
}
impl RelayInstr {
pub fn try_from(concrete: &ConcreteTest, statement: &RelayStatement) -> CompilerResult<Self> {
let mut res = CompilerResult::new("Construct RelayInstr from RelayStatement");
let relay_device_address = check!(res, concrete.get_relay_device_address(&statement.id));
let action = match statement.op {
RelayOp::Set => RelayAction::Set,
RelayOp::Unset => RelayAction::Unset,
};
RelayInstr::try_new(action, relay_device_address)
}
}
impl SensorInstr {
pub fn try_from(
concrete: &ConcreteTest,
constraint: &SensorConstraint,
action: SensorAction,
) -> CompilerResult<Self> {
let mut res = CompilerResult::new("Construct SensorInstr from SensorConstraint");
let abort_idx = check!(res, concrete.get_abort_id(&constraint.abort)) as u8;
let device_address = check!(res, concrete.get_sensor_device_address(&constraint.id));
let (left_bound, right_bound) = check!(
res,
SensorInstr::calibrated_bounds_from_constraint(concrete, &constraint)
);
match action {
SensorAction::stop_check => SensorInstr::try_new_stop(device_address),
_ => SensorInstr::try_new(action, abort_idx, device_address, left_bound, right_bound),
}
}
fn calibrated_bounds_from_constraint(
concrete: &ConcreteTest,
constraint: &SensorConstraint,
) -> CompilerResult<(u16, u16)> {
let mut res = CompilerResult::new("Compute calibrated bounds for sensor constraint");
let calibration_opt = check!(res, concrete.get_calibration(&constraint.id));
match calibration_opt {
Some(Calibration::Boolean(calibration)) => {
if let SensorBound::Boolean(bool_value) = constraint.sensor_bound {
return Environment::boolean_calibration_lookup(calibration, bool_value);
} else {
res.error((
constraint.metadata,
"Must use boolean sensor bounds for a sensor with a boolean calibration file!",
));
return res;
}
}
Some(Calibration::Numeric(calibration)) => {
if let SensorBound::Numeric(numeric_bound) = &constraint.sensor_bound {
return Environment::numeric_calibration_lookup(
calibration,
(numeric_bound.left, numeric_bound.right),
);
} else {
res.error((
constraint.metadata,
"Must use numeric sensor bounds for a sensor with a numeric calibration file!",
));
return res;
}
}
None => {
if let SensorBound::Numeric(numeric_bound) = &constraint.sensor_bound {
return Environment::raw_calibration_lookup((
numeric_bound.left,
numeric_bound.right,
));
} else {
res.error((
constraint.metadata,
"Cannot encode a boolean value without a calibration file",
));
return res;
}
}
}
}
}