1mod gtsr_gpio;
2
3use std::marker::PhantomData;
4
5use tm4c123x_hal as hal;
6
7use self::hal::prelude;
8
9pub const LS_OVERCURRENT_DISABLE: f64 = 99999.9;
10pub const LS_MIN_EXPECT_CURRENT_DISABLE: f64 = -99999.9;
11pub const RATIO_DISNST_DT: f64 = 0.011;
12pub const TEMP_CONVERSION_OFFSET: f64 = -0.85 / RATIO_DISNST_DT + 25.0;
13pub const OVERCURRENT_RECLOSES: u8 = 3;
14
15#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16pub enum LoadSwitchChannel {
17 LoadSwitchCh1 = 0,
18 LoadSwitchCh2 = 1,
19}
20
21#[derive(Copy, Clone, Debug, PartialEq, Eq)]
22pub enum LoadSwitchChannelStatus {
23 LsStatusNominalOn = 1,
24 LsStatusNominalOff = 0,
25 LsStatusWarningLowCurrent = -1,
26 LsStatusFaultOpenCircuit = -2,
27 LsStatusFaultOverCurrent = -3,
28}
29
30#[derive(Copy, Clone, Debug, PartialEq, Eq)]
31pub enum SensorEnablingStatus {
32 Chan1Sensing = 1, Chan12Sensing = 2, TempSensing = 3, }
36
37#[allow(deprecated)]
38pub struct LoadSwitch<
39 'a,
40 L: gtsr_gpio::Pin
41 + prelude::_embedded_hal_digital_OutputPin
42 + prelude::_embedded_hal_digital_ToggleableOutputPin,
43 S1: gtsr_gpio::Pin
44 + prelude::_embedded_hal_digital_OutputPin
45 + prelude::_embedded_hal_digital_ToggleableOutputPin,
46 S2: gtsr_gpio::Pin
47 + prelude::_embedded_hal_digital_OutputPin
48 + prelude::_embedded_hal_digital_ToggleableOutputPin,
49 EN1: gtsr_gpio::Pin
50 + prelude::_embedded_hal_digital_OutputPin
51 + prelude::_embedded_hal_digital_ToggleableOutputPin,
52 EN2: gtsr_gpio::Pin
53 + prelude::_embedded_hal_digital_OutputPin
54 + prelude::_embedded_hal_digital_ToggleableOutputPin,
55 DIA: gtsr_gpio::Pin
56 + prelude::_embedded_hal_digital_OutputPin
57 + prelude::_embedded_hal_digital_ToggleableOutputPin,
58> where
59 &'a mut L: Default,
60 &'a mut S1: Default,
61 &'a mut S2: Default,
62 &'a mut EN1: Default,
63 &'a mut EN2: Default,
64 &'a mut DIA: Default,
65{
66 latch: gtsr_gpio::Signal<'a, L>,
67 sel1: gtsr_gpio::Signal<'a, S1>,
68 sel2: gtsr_gpio::Signal<'a, S2>,
69 en1: gtsr_gpio::Signal<'a, EN1>,
70 en2: gtsr_gpio::Signal<'a, EN2>,
71 dia_en: gtsr_gpio::Signal<'a, DIA>,
72 channel_state: SensorEnablingStatus,
73
74 overcurrent_threshold: [f64; 2],
75 min_expected_current: [f64; 2],
76 current: [f64; 2],
77 status: [LoadSwitchChannelStatus; 2],
78 latching: bool,
79 overcurrent_retries: [u8; 2],
80 temperature: f64,
81 current_scale_factor: f64,
82 temperature_scale_factor: f64,
83
84 _latch_pin: PhantomData<L>,
85 _sel1_pin: PhantomData<S1>,
86 _sel2_pin: PhantomData<S2>,
87 _en1_pin: PhantomData<EN1>,
88 _en2_pin: PhantomData<EN2>,
89 _dia_en_pin: PhantomData<DIA>,
90}
91
92#[allow(deprecated)]
93impl<
94 L: gtsr_gpio::Pin
95 + prelude::_embedded_hal_digital_OutputPin
96 + prelude::_embedded_hal_digital_ToggleableOutputPin,
97 S1: gtsr_gpio::Pin
98 + prelude::_embedded_hal_digital_OutputPin
99 + prelude::_embedded_hal_digital_ToggleableOutputPin,
100 S2: gtsr_gpio::Pin
101 + prelude::_embedded_hal_digital_OutputPin
102 + prelude::_embedded_hal_digital_ToggleableOutputPin,
103 EN1: gtsr_gpio::Pin
104 + prelude::_embedded_hal_digital_OutputPin
105 + prelude::_embedded_hal_digital_ToggleableOutputPin,
106 EN2: gtsr_gpio::Pin
107 + prelude::_embedded_hal_digital_OutputPin
108 + prelude::_embedded_hal_digital_ToggleableOutputPin,
109 DIA: gtsr_gpio::Pin
110 + prelude::_embedded_hal_digital_OutputPin
111 + prelude::_embedded_hal_digital_ToggleableOutputPin,
112 > LoadSwitch<'static, L, S1, S2, EN1, EN2, DIA>
113where
114 &'static mut L: Default,
115 &'static mut S1: Default,
116 &'static mut S2: Default,
117 &'static mut EN1: Default,
118 &'static mut EN2: Default,
119 &'static mut DIA: Default,
120{
121 pub fn new(
122 latch_pin: &'static mut L,
123 sel1_pin: Option<&'static mut S1>,
124 sel2_pin: Option<&'static mut S2>,
125 en1_pin: &'static mut EN1,
126 en2_pin: &'static mut EN2,
127 dia_pin: &'static mut DIA,
128 latching: bool,
129 k_sns_value: f64,
130 r_sns_value: f64,
131 overcurrent_threshold: [f64; 2],
132 min_expected_current: [f64; 2],
133 ) -> Self {
134 let channel_state = if sel1_pin.is_some() && sel2_pin.is_some() {
135 SensorEnablingStatus::TempSensing
136 } else if sel1_pin.is_some() && sel2_pin.is_none() {
137 SensorEnablingStatus::Chan12Sensing
138 } else {
139 SensorEnablingStatus::Chan1Sensing
140 };
141
142 let mut load_switch = LoadSwitch {
143 latch: gtsr_gpio::Signal::new(latch_pin),
144 sel1: gtsr_gpio::Signal::new(sel1_pin.unwrap_or_default()),
145 sel2: gtsr_gpio::Signal::new(sel2_pin.unwrap_or_default()),
146 en1: gtsr_gpio::Signal::new(en1_pin),
147 en2: gtsr_gpio::Signal::new(en2_pin),
148 dia_en: gtsr_gpio::Signal::new(dia_pin),
149 channel_state,
150 overcurrent_threshold: [
151 overcurrent_threshold[LoadSwitchChannel::LoadSwitchCh1 as usize],
152 overcurrent_threshold[LoadSwitchChannel::LoadSwitchCh2 as usize],
153 ],
154 min_expected_current: [
155 min_expected_current[LoadSwitchChannel::LoadSwitchCh1 as usize],
156 min_expected_current[LoadSwitchChannel::LoadSwitchCh2 as usize],
157 ],
158 current: [0.0, 0.0],
159 status: [
160 LoadSwitchChannelStatus::LsStatusNominalOff,
161 LoadSwitchChannelStatus::LsStatusNominalOff,
162 ],
163 latching,
164 overcurrent_retries: [0, 0],
165 temperature: 0.0,
166 current_scale_factor: k_sns_value / r_sns_value,
167 temperature_scale_factor: 1000.0 / (r_sns_value * RATIO_DISNST_DT),
168 _latch_pin: PhantomData,
169 _sel1_pin: PhantomData,
170 _sel2_pin: PhantomData,
171 _en1_pin: PhantomData,
172 _en2_pin: PhantomData,
173 _dia_en_pin: PhantomData,
174 };
175
176 load_switch.latch.set(latching);
177
178 load_switch.channel_off(LoadSwitchChannel::LoadSwitchCh1);
179 load_switch.channel_off(LoadSwitchChannel::LoadSwitchCh2);
180
181 load_switch.dia_en.set_high();
182
183 return load_switch;
184 }
185
186 pub fn channel_on(&mut self, channel: LoadSwitchChannel) {
187 match channel {
188 LoadSwitchChannel::LoadSwitchCh1 => {
189 self.en1.set_high();
190 self.status[LoadSwitchChannel::LoadSwitchCh1 as usize] =
191 LoadSwitchChannelStatus::LsStatusNominalOn;
192 }
193 LoadSwitchChannel::LoadSwitchCh2 => {
194 self.en2.set_high();
195 self.status[LoadSwitchChannel::LoadSwitchCh2 as usize] =
196 LoadSwitchChannelStatus::LsStatusNominalOn;
197 }
198 }
199 }
200
201 pub fn channel_off(&mut self, channel: LoadSwitchChannel) {
202 match channel {
203 LoadSwitchChannel::LoadSwitchCh1 => {
204 self.en1.set_low();
205 self.status[LoadSwitchChannel::LoadSwitchCh1 as usize] =
206 LoadSwitchChannelStatus::LsStatusNominalOff;
207 }
208 LoadSwitchChannel::LoadSwitchCh2 => {
209 self.en2.set_low();
210 self.status[LoadSwitchChannel::LoadSwitchCh2 as usize] =
211 LoadSwitchChannelStatus::LsStatusNominalOff;
212 }
213 }
214 }
215
216 fn set_sel(&mut self, sel: i8) -> i8 {
217 match sel {
218 0 | 1 | 2 => {
219 if self.channel_state == SensorEnablingStatus::TempSensing {
220 self.sel1.set((sel & 0x3) >> 1 != 0);
221 self.sel2.set(sel & 0x1 != 0);
222 } else if self.channel_state == SensorEnablingStatus::Chan12Sensing {
223 self.sel2.set(sel & 0x1 != 0);
224 }
225 }
226 _ => return -1,
227 }
228
229 return 0;
230 }
231
232 pub fn update_sns(&mut self, sns_voltage: f64, step_sel: bool) {
233 let sel = self.sel2.is_set() as u8 | (self.sel1.is_set() as u8) << 1;
234 if !self.dia_en.is_set() {
235 match sel {
236 0 => {
237 self.current[0] = self.current_scale_factor * sns_voltage;
238
239 if self.current[0] > self.overcurrent_threshold[0] {
240 match self.en1.get_state() {
241 gtsr_gpio::SignalState::Low => {
242 self.status[0] = LoadSwitchChannelStatus::LsStatusFaultOpenCircuit;
243 }
244 gtsr_gpio::SignalState::High => {
245 self.channel_off(LoadSwitchChannel::LoadSwitchCh1);
246 self.status[0] = LoadSwitchChannelStatus::LsStatusFaultOverCurrent;
247 }
248 }
249 } else if self.en1.is_set() && self.current[0] < self.min_expected_current[0] {
250 self.status[0] = LoadSwitchChannelStatus::LsStatusWarningLowCurrent;
251 } else if self.status[0] == LoadSwitchChannelStatus::LsStatusFaultOverCurrent
252 && !self.latching
253 && self.current[0] < self.overcurrent_threshold[0]
254 && self.overcurrent_retries[0] < OVERCURRENT_RECLOSES
255 {
256 self.channel_on(LoadSwitchChannel::LoadSwitchCh1);
257 } else if self.status[0] != LoadSwitchChannelStatus::LsStatusFaultOverCurrent {
258 self.status[0] = if self.en1.is_set() {
259 LoadSwitchChannelStatus::LsStatusNominalOn
260 } else {
261 LoadSwitchChannelStatus::LsStatusNominalOff
262 };
263 }
264 }
265 1 => {
266 self.current[1] = self.current_scale_factor * sns_voltage;
267
268 if self.current[1] > self.overcurrent_threshold[1] {
269 match self.en2.get_state() {
270 gtsr_gpio::SignalState::Low => {
271 self.status[1] = LoadSwitchChannelStatus::LsStatusFaultOpenCircuit;
272 }
273 gtsr_gpio::SignalState::High => {
274 self.channel_off(LoadSwitchChannel::LoadSwitchCh2);
275 self.status[1] = LoadSwitchChannelStatus::LsStatusFaultOverCurrent;
276 }
277 }
278 } else if self.en2.is_set() && self.current[1] < self.min_expected_current[1] {
279 self.status[1] = LoadSwitchChannelStatus::LsStatusWarningLowCurrent;
280 } else if self.status[1] == LoadSwitchChannelStatus::LsStatusFaultOverCurrent
281 && !self.latching
282 && self.current[1] < self.overcurrent_threshold[1]
283 && self.overcurrent_retries[1] < OVERCURRENT_RECLOSES
284 {
285 self.channel_on(LoadSwitchChannel::LoadSwitchCh2);
286 } else if self.status[1] != LoadSwitchChannelStatus::LsStatusFaultOverCurrent {
287 self.status[1] = if self.en2.is_set() {
288 LoadSwitchChannelStatus::LsStatusNominalOn
289 } else {
290 LoadSwitchChannelStatus::LsStatusNominalOff
291 };
292 }
293 }
294 2 => {
295 self.temperature =
296 self.temperature_scale_factor * sns_voltage + TEMP_CONVERSION_OFFSET;
297 }
298 _ => {
299 self.current[LoadSwitchChannel::LoadSwitchCh1 as usize] =
300 self.current_scale_factor * sns_voltage;
301 self.current[LoadSwitchChannel::LoadSwitchCh2 as usize] =
302 self.current_scale_factor * sns_voltage;
303 }
304 }
305 }
306
307 if step_sel {
308 self.set_sel((sel as i8 + 1) % self.channel_state as i8);
309 }
310 }
311}