Skip to main content

async_ltc681x/driver/
command.rs

1use core::convert::{From, Into};
2macro_rules! commands {
3    ($ty:ident, $val:expr,$poll:expr,$doc:expr, $($trait:ident),*) => {
4        #[doc=$doc]
5        pub struct $ty {
6            cmd: u16,
7            has_poll_status: bool,
8        }
9        impl IsCmd for $ty{
10            fn as_cmd_header(&self) -> u16{
11                self.cmd
12            }
13
14            fn has_poll_status(&self) -> bool{
15                self.has_poll_status
16            }
17        }
18        $(impl $trait for $ty {})*
19        impl From<u16> for $ty {
20            fn from(value: u16) -> Self {
21                Self { cmd: value, has_poll_status: $poll}
22            }
23        }
24        impl From<$ty> for u16 {
25            fn from(value: $ty) -> Self {
26                value.cmd
27            }
28        }
29        impl Default for$ty {
30            fn default() -> Self {
31                Self { cmd: $val , has_poll_status: $poll}
32            }
33        }
34    };
35    ($ty:ident, $val:expr,$poll:expr,$doc:expr) => {
36        #[doc=$doc]
37        pub struct $ty {
38            cmd: u16,
39            has_poll_status: bool
40        }
41        impl IsCmd for $ty{
42            fn as_cmd_header(&self) -> u16{
43                self.cmd
44            }
45
46            fn has_poll_status(&self) -> bool{
47                self.has_poll_status
48            }
49        }
50        impl Default for $ty {
51            fn default () -> Self {
52                Self { cmd: $val, has_poll_status: $poll }
53            }
54        }
55    }
56}
57commands!(
58    Adcv,
59    0x260,
60    true,
61    "Start Cell Voltage ADC Conversion and Poll Status",
62    HasDCPOption,
63    HasMDOption,
64    HasCellChannelConfig
65);
66commands!(
67    Adow,
68    0x228,
69    true,
70    "Start Open Wire ADC Conversion and Poll Status",
71    HasPullUpOption,
72    HasDCPOption,
73    HasMDOption,
74    HasCellChannelConfig
75);
76commands!(
77    Cvst,
78    0x207,
79    true,
80    "Start Self Test Cell Voltage Conversion and Poll Status",
81    HasMDOption,
82    HasSTConfig
83);
84commands!(
85    Adol,
86    0x201,
87    true,
88    "Start Overlap Measurements on Cell 7 and Cell 13 (only LTC6812/13) Voltages",
89    HasMDOption,
90    HasDCPOption
91);
92commands!(
93    Adax,
94    0x460,
95    true,
96    "Start GPIOs ADC Conversion and Poll Status",
97    HasMDOption,
98    HasGpioChannelConfig
99);
100commands!(
101    Adaxd,
102    0x400,
103    true,
104    "Start GPIOs ADC Conversion with Digital Redundancy and Poll Status",
105    HasMDOption,
106    HasGpioChannelConfig
107);
108#[cfg(any(feature = "ltc6812", feature = "ltc6813"))]
109commands!(
110    Axow,
111    0x410,
112    true,
113    "Start GPIOs Open Wire ADC Conversion and Poll Status",
114    HasMDOption,
115    HasPullUpOption,
116    HasGpioChannelConfig
117);
118commands!(
119    Axst,
120    0x407,
121    true,
122    "Start Self Test GPIOs COnversion and Poll Status",
123    HasMDOption,
124    HasSTConfig
125);
126commands!(
127    Adstat,
128    0x468,
129    true,
130    "Start Status Group ADC Conversion and Poll Status",
131    HasMDOption,
132    HasStatusChannelConfig
133);
134commands!(
135    Adstatd,
136    0x408,
137    true,
138    "Start Status Group ADC Conversion with Digital Redundancy and Poll Status",
139    HasMDOption,
140    HasStatusChannelConfig
141);
142commands!(
143    Statst,
144    0x40F,
145    true,
146    "Start Self Test Status Group Conversion and Poll Status",
147    HasMDOption,
148    HasSTConfig
149);
150commands!(
151    Adcvax,
152    0x46F,
153    true,
154    "Start Combined Cell Voltage and GPIO1, GPIO2 Conversion and Poll Status",
155    HasMDOption,
156    HasDCPOption
157);
158commands!(
159    Adcvsc,
160    0x467,
161    true,
162    "Start Combined Cell Voltage and SC Conversion and Poll Status",
163    HasMDOption,
164    HasDCPOption
165);
166commands!(Pladc, 0x714, true, "Poll ADC COnversion Status");
167commands!(Diagn, 0x715, true, "Diagnose MUX and Poll Status");
168// Normal non conversion mode polling cmds
169commands!(Clrcell, 0x711, false, "Clear Cell Voltage Register Groups");
170commands!(Clraux, 0x712, false, "Clear Auxiliary Register Groups");
171commands!(Clrstat, 0x713, false, "Clear Status Register Groups");
172// Read Cmds
173commands!(RdCfgA, 0x002, false, "Read Configuration Register Group A");
174commands!(RdCfgB, 0x026, false, "Read Configuration Register Group B");
175commands!(RdCvA, 0x004, false, "Read Cell Voltage Register Group A");
176commands!(RdCvB, 0x006, false, "Read Cell Voltage Register Group B");
177commands!(RdCvC, 0x008, false, "Read Cell Voltage Register Group C");
178commands!(RdCvD, 0x00A, false, "Read Cell Voltage Register Group D");
179#[cfg(any(feature = "ltc6812", feature = "ltc6813"))]
180commands!(RdCvE, 0x009, false, "Read Cell Voltage Register Group E");
181#[cfg(feature = "ltc6813")]
182commands!(RdCvF, 0x00B, false, "Read Cell Voltage Register Group F");
183commands!(RdAuxA, 0x00C, false, "Read Auxiliary Register Group A");
184commands!(RdAuxB, 0x00E, false, "Read Auxiliary Register Group B");
185#[cfg(any(feature = "ltc6812", feature = "ltc6813"))]
186commands!(RdAuxC, 0x00D, false, "Read Auxiliary Register Group C");
187#[cfg(any(feature = "ltc6812", feature = "ltc6813"))]
188commands!(RdAuxD, 0x00F, false, "Read Auxiliary Register Group D");
189commands!(RdStatA, 0x010, false, "Read Status Register Group A");
190commands!(RdStatB, 0x012, false, "Read Status Register Group A");
191// Write Cmds
192commands!(WrCfgA, 0x001, false, "Write Configuration Register Group A");
193commands!(WrCfgB, 0x024, false, "Write Configuration Register Group B");
194
195commands!(WrComm, 0x721, false, "Write COMM Register Group");
196commands!(RdComm, 0x722, false, "Read COMM Register Group");
197commands!(StComm, 0x723, false, "Start I2C/SPO Communication");
198
199/// Defines the different allowed MD Bit Settings
200///
201/// |MD|ADCOPT = 0 | ADCOPT = 1|
202/// |--|-----------|-----------|
203/// |00| 422 Hz    | 1 kHz     |
204/// |01| 27 kHz | 14 kHz|
205/// |10| 7 kHz| 3kHz |
206/// |11| 26 Hz | 2 kHz|
207pub enum MDSetting {
208    MD0_0 = 0b00,
209    MD0_1 = 0b01,
210    MD1_0 = 0b10,
211    MD1_1 = 0b11,
212}
213/// Marks all Commands implementing MD Bit Settings and provide method to set MD Settings
214///
215/// Conversion Rates for ADCOPT Bit set are
216/// ADCOPT = 1
217///
218/// MD Bits [0, 0]: Conversion Rate 1kHz
219///
220/// MD Bits [0, 1]: Conversion Rate 14kHz
221///
222/// MD Bits [1, 0]: Conversion Rate 3kHz
223///
224/// MD Bits [1, 1]: Conversion Rate 2kHz
225///
226/// Conversion Rates for ADCOPT Bit not set are
227///
228/// ADCOPT = 0
229///
230/// MD Bits [0, 0]: Conversion Rate 422Hz
231///
232/// MD Bits [0, 1]: Conversion Rate 27kHz
233///
234/// MD Bits [1, 0]: Conversion Rate 7kHz
235///
236/// MD Bits [1, 1]: Conversion Rate 26Hz
237pub trait HasMDOption: Into<u16> + From<u16> {
238    #[must_use]
239    fn set_md_option(self, md_bits: MDSetting) -> Self {
240        let cmd = self.into();
241        (cmd | (md_bits as u16) << 7).into()
242    }
243}
244/// Marks all Commands implementing the DCP Option and provides method to set DCP
245///
246/// Default Command DCP is NOT set. With this call DCP Option is set and Discharge Permitted during measurememt
247///
248/// From Datsheet:
249/// If the discharge permitted (DCP) bit is high at the time of
250/// a cell measurement command, the S pin discharge states
251/// do not change during cell measurements. If the DCP bit
252/// is low, S pin discharge states will be disabled while the
253/// corresponding cell or adjacent cells are being measured.
254///
255pub trait HasDCPOption: Into<u16> + From<u16> {
256    #[must_use]
257    fn set_dcp_option(self) -> Self {
258        let cmd: u16 = self.into();
259        (cmd | 1 << 4).into()
260    }
261}
262/// Defines valid Channel config for all cell voltage conversion commands implementing [`HasCellChannelConfig`]
263///
264/// For Timing information see Datasheet LTC6813 Table 37. Command Bit Description
265pub enum CellChannelConfig {
266    AllCells = 0b000,
267    Cell1_7_13 = 0b001,
268    Cell2_8_14 = 0b010,
269    Cell3_9_15 = 0b011,
270    Cell4_10_16 = 0b100,
271    Cell5_11_17 = 0b101,
272    Cell6_12_18 = 0b110,
273}
274/// Marks all Commands that have a Channel Config for the cell voltage ADCs and provides method to set the channel config
275pub trait HasCellChannelConfig: Into<u16> + From<u16> {
276    /// Sets the channel config for the cell voltage conversion command. Not setting anything Defaults to [`CellChannelConfig::AllCells`]
277    #[must_use]
278    fn set_channel_config(self, config: CellChannelConfig) -> Self {
279        let cmd = self.into();
280        (cmd | config as u16).into()
281    }
282}
283
284/// Defines valid Channel config for all GPIO conversion commands implementing [`HasGpioChannelConfig`]
285///
286/// For Timing information see Datasheet LTC6813 Table 37. Command Bit Description
287pub enum GpioChannelConfig {
288    AllGpios = 0b000,
289    Gpio1_6 = 0b001,
290    Gpio2_7 = 0b010,
291    Gpio3_8 = 0b011,
292    Gpio4_9 = 0b100,
293    Gpio5 = 0b101,
294    ScndRef = 0b110,
295}
296/// Marks all Commands that have a Channel Config for the GPIO ADCs and provides method to set the channel config
297pub trait HasGpioChannelConfig: Into<u16> + From<u16> {
298    /// Sets the channel config for the GPIO conversion command. Not setting anything Defaults to [`GpioChannelConfig::AllGpios`]
299    #[must_use]
300    fn set_channel_config(self, config: GpioChannelConfig) -> Self {
301        let cmd = self.into();
302        (cmd | config as u16).into()
303    }
304}
305
306/// Defines valid Channel config for all Status conversion commands implementing [`HasStatusChannelConfig`]
307///
308/// For Timing information see Datasheet LTC6813 Table 37. Command Bit Description
309pub enum StatusChannelConfig {
310    AllStatus = 0b000,
311    SumOfCells = 0b001,
312    InternalTemp = 0b010,
313    AnalogSupply = 0b011,
314    DigitalSupply = 0b100,
315}
316/// Marks all Commands that have a Channel Config for the Status ADCs and provides method to set the channel config
317pub trait HasStatusChannelConfig: Into<u16> + From<u16> {
318    /// Sets the channel config for the Status conversion command. Not setting anything Defaults to [`StatusChannelConfig::AllStatus`]
319    #[must_use]
320    fn set_channel_config(self, config: StatusChannelConfig) -> Self {
321        let cmd = self.into();
322        (cmd | config as u16).into()
323    }
324}
325pub trait HasPullUpOption: Into<u16> + From<u16> {
326    /// Defines the `PullUp` or `PullDown` Option for the Open Wire Check Commands [Adow] and its GPIO counterpart (LTC6812/13 only).
327    /// Default is `PullUp` unset meaning that the current sink (pulldown) is active during Open Wire check.
328    /// Running command with this enabled activates current source (pullup) during Open Wire check
329    #[must_use]
330    fn set_pullup_option(self) -> Self {
331        let cmd = self.into();
332        (cmd | 1 << 6).into()
333    }
334}
335/// Defining the two Selftest Configs
336///
337/// |Conversion Freq.| 27kHz | 14kHz | 7 kHz | 3 kHz | 2 kHz | 1 kHz | 422 Hz| 26 Hz |
338/// |----------------|-------|-------|-------|-------|-------|-------|-------|-------|
339/// |SelfTest1 Expected Result |0x9565 |0x9553 |0x9555 |0x9555 |0x9555 |0x9555 |0x9555 |0x9555 |
340/// |SelfTest2 Expected Result |0x6A9A |0x6AAC |0x6AAA |0x6AAA |0x6AAA |0x6AAA |0x6AAA |0x6AAA |
341pub enum SelfTestConfig {
342    SelfTest1 = 0b01,
343    SelfTest2 = 0b10,
344}
345/// Marks all Commands that have a Selftest Config Option and provides a method to set the config
346pub trait HasSTConfig: Into<u16> + From<u16> {
347    /// Defines the Selftest Config for digital filter selftest commands [Statst], [Axst] and [Cvst].
348    ///
349    /// Selftest provides a known bitstream to the digital filters in the IC. If these Filter work correctly we
350    /// expect a given result in the output registers. If the Registers do not provide the epxeted results digital filters
351    /// work not correctly and measurement results can not be trusted
352    ///
353    /// For exepcted result of this Selftest see [`SelfTestConfig`]
354    #[must_use]
355    fn set_st_config(self, config: SelfTestConfig) -> Self {
356        let cmd = self.into();
357        (cmd | (config as u16) << 5).into()
358    }
359}
360/// Interface Trait for data which all commands provide
361pub trait IsCmd {
362    fn as_cmd_header(&self) -> u16;
363    fn has_poll_status(&self) -> bool;
364}
365
366#[cfg(test)]
367mod tests {
368    use super::*;
369    #[test]
370    fn test_all_options() {
371        let cmd = Adow::default()
372            .set_md_option(MDSetting::MD0_1)
373            .set_dcp_option()
374            .set_channel_config(CellChannelConfig::Cell1_7_13)
375            .set_pullup_option()
376            .set_channel_config(CellChannelConfig::AllCells);
377
378        assert_eq!(cmd.cmd, 761);
379
380        let cmd = Statst::default()
381            .set_st_config(SelfTestConfig::SelfTest1)
382            .set_md_option(MDSetting::MD1_1)
383            .set_st_config(SelfTestConfig::SelfTest1);
384        assert_eq!(cmd.cmd, 1455);
385
386        let cmd = Adax::default().set_channel_config(GpioChannelConfig::AllGpios);
387        assert_eq!(cmd.cmd, 1120);
388        let cmd = Adstatd::default().set_channel_config(StatusChannelConfig::AllStatus);
389        assert_eq!(cmd.cmd, 1032);
390    }
391}