ad7124_rs/ad7124/
core.rs

1//! Core AD7124 logic (transport-layer independent)
2//!
3//! Contains all business logic without any transport dependencies
4
5use crate::{
6    device_type::{DeviceCapabilities, DeviceType},
7    errors::*,
8    registers::*,
9};
10use heapless::Vec;
11
12/// Default timeout for ADC operations in milliseconds
13pub const AD7124_DEFAULT_TIMEOUT_MS: u32 = 5000; // 5 seconds for first conversion
14
15/// Core AD7124 logic (shared between sync and async)
16#[derive(Debug)]
17pub struct AD7124Core {
18    /// Detected device type
19    device_type: DeviceType,
20    /// Device capabilities
21    capabilities: DeviceCapabilities,
22    /// Current configuration
23    config: AD7124Config,
24    /// Initialization state
25    initialized: bool,
26    /// Reference voltage (V)
27    reference_voltage: f32,
28    /// CRC enabled flag
29    crc_enabled: bool,
30    // Runtime state caching removed per final design - all status queries read hardware directly
31    /// Channel configurations cache
32    channel_configs: [ChannelConfig; 16],
33    /// Setup configurations cache  
34    setup_configs: [SetupConfig; 8],
35}
36
37/// Device configuration structure
38#[derive(Debug, Clone, Copy)]
39pub struct AD7124Config {
40    /// ADC operating mode (continuous, single conversion, etc.)
41    pub operating_mode: OperatingMode,
42    /// Device power consumption mode
43    pub power_mode: PowerMode,
44    /// Clock source selection (internal/external)
45    pub clock_source: ClockSource,
46    /// Reference voltage source selection
47    pub reference_source: ReferenceSource,
48    /// Whether internal reference voltage is enabled
49    pub internal_ref_enabled: bool,
50    /// Whether data ready output pin is enabled
51    pub data_ready_output_enabled: bool,
52}
53
54impl Default for AD7124Config {
55    fn default() -> Self {
56        Self {
57            operating_mode: OperatingMode::Continuous,
58            power_mode: PowerMode::FullPower,
59            clock_source: ClockSource::Internal,
60            reference_source: ReferenceSource::Internal,
61            internal_ref_enabled: true,
62            data_ready_output_enabled: true,
63        }
64    }
65}
66
67/// Channel configuration structure
68#[derive(Debug, Clone, Copy)]
69pub struct ChannelConfig {
70    /// Whether this channel is enabled for conversion
71    pub enabled: bool,
72    /// Positive analog input selection
73    pub positive_input: ChannelInput,
74    /// Negative analog input selection (for differential measurements)
75    pub negative_input: ChannelInput,
76    /// Index of the setup configuration to use for this channel
77    pub setup_index: u8,
78}
79
80impl Default for ChannelConfig {
81    fn default() -> Self {
82        Self {
83            enabled: false,
84            positive_input: ChannelInput::Ain0,
85            negative_input: ChannelInput::Ain1,
86            setup_index: 0,
87        }
88    }
89}
90
91/// Filter configuration structure
92#[derive(Debug, Clone, Copy)]
93pub struct FilterConfig {
94    /// Digital filter type selection
95    pub filter_type: FilterType,
96    /// Output data rate in Hz
97    pub output_data_rate: u16,
98    /// Whether to use single cycle settling
99    pub single_cycle: bool,
100    /// Whether to enable 50/60Hz rejection
101    pub reject_60hz: bool,
102}
103
104impl Default for FilterConfig {
105    fn default() -> Self {
106        Self {
107            filter_type: FilterType::Sinc4,
108            output_data_rate: 50, // 50 Hz
109            single_cycle: false,
110            reject_60hz: true,
111        }
112    }
113}
114
115/// Setup configuration structure
116#[derive(Debug, Clone, Copy)]
117pub struct SetupConfig {
118    /// Programmable gain amplifier setting
119    pub pga_gain: PgaGain,
120    /// Reference voltage source for this setup
121    pub reference_source: ReferenceSource,
122    /// Whether to use bipolar (signed) or unipolar (unsigned) mode
123    pub bipolar: bool,
124    /// Burnout current source configuration for sensor diagnostics
125    pub burnout_current: BurnoutCurrent,
126    /// Whether reference voltage input buffers are enabled
127    pub reference_buffers_enabled: bool,
128    /// Whether analog input buffers are enabled
129    pub input_buffers_enabled: bool,
130}
131
132impl Default for SetupConfig {
133    fn default() -> Self {
134        Self {
135            pga_gain: PgaGain::Gain1,
136            reference_source: ReferenceSource::Internal,
137            bipolar: true,
138            burnout_current: BurnoutCurrent::Off,
139            reference_buffers_enabled: true,
140            input_buffers_enabled: true,
141        }
142    }
143}
144
145/// Command sequence for batched operations
146#[derive(Debug)]
147pub struct CommandSequence {
148    /// List of register write commands (register, value pairs)
149    commands: Vec<(Register, u32), 16>, // Maximum 16 commands
150}
151
152impl CommandSequence {
153    /// Create new empty command sequence
154    pub fn new() -> Self {
155        Self {
156            commands: Vec::new(),
157        }
158    }
159
160    /// Add register write command to sequence
161    pub fn add_write(&mut self, register: Register, value: u32) -> Result<(), AD7124CoreError> {
162        self.commands
163            .push((register, value))
164            .map_err(|_| AD7124CoreError::BufferOverflow)
165    }
166
167    /// Get commands as slice
168    pub fn commands(&self) -> &[(Register, u32)] {
169        &self.commands
170    }
171
172    /// Clear all commands
173    pub fn clear(&mut self) {
174        self.commands.clear();
175    }
176}
177
178impl AD7124Core {
179    /// Create new core instance
180    pub fn new(device_type: DeviceType) -> Result<Self, AD7124CoreError> {
181        let capabilities = DeviceCapabilities::for_device(device_type);
182
183        Ok(Self {
184            device_type,
185            capabilities,
186            config: AD7124Config::default(),
187            initialized: false,
188            reference_voltage: 2.5, // Internal reference voltage
189            crc_enabled: false,
190            // No runtime state variables in final design
191            channel_configs: [ChannelConfig::default(); 16],
192            setup_configs: [SetupConfig::default(); 8],
193        })
194    }
195
196    /// Generate initialization sequence
197    pub fn initialization_sequence(&self) -> Result<CommandSequence, AD7124CoreError> {
198        let mut sequence = CommandSequence::new();
199
200        // Reset the device
201        sequence.add_write(Register::AdcCtrl, 0x8000)?; // Software reset
202
203        // Configure ADC control register
204        let adc_ctrl = self.build_adc_control_value()?;
205        sequence.add_write(Register::AdcCtrl, adc_ctrl)?;
206
207        // Configure IO_CTRL1 register - 使用默认值,REF_EN只在ADC_CTRL寄存器有效
208        let io_ctrl1 = 0x000000; // 默认值,根据用户提供的寄存器表,IO_CTRL1没有REF_EN位
209        sequence.add_write(Register::IoCtrl1, io_ctrl1)?;
210
211        Ok(sequence)
212    }
213
214    /// Configure channel
215    pub fn configure_channel(
216        &self,
217        channel: u8,
218        config: ChannelConfig,
219    ) -> Result<CommandSequence, AD7124CoreError> {
220        if !self.capabilities.validate_channel(channel) {
221            return Err(AD7124CoreError::InvalidParameter);
222        }
223
224        let mut sequence = CommandSequence::new();
225        let register = match channel {
226            0 => Register::Channel0,
227            1 => Register::Channel1,
228            2 => Register::Channel2,
229            3 => Register::Channel3,
230            4 => Register::Channel4,
231            5 => Register::Channel5,
232            6 => Register::Channel6,
233            7 => Register::Channel7,
234            _ => return Err(AD7124CoreError::InvalidParameter),
235        };
236
237        let channel_value = self.build_channel_value(config)?;
238        sequence.add_write(register, channel_value)?;
239
240        Ok(sequence)
241    }
242
243    /// Configure setup (PGA, reference, etc.)
244    pub fn configure_setup(
245        &self,
246        setup_index: u8,
247        config: SetupConfig,
248    ) -> Result<CommandSequence, AD7124CoreError> {
249        if setup_index > 7 {
250            return Err(AD7124CoreError::InvalidParameter);
251        }
252
253        let mut sequence = CommandSequence::new();
254        let register = match setup_index {
255            0 => Register::Config0,
256            1 => Register::Config1,
257            2 => Register::Config2,
258            3 => Register::Config3,
259            4 => Register::Config4,
260            5 => Register::Config5,
261            6 => Register::Config6,
262            7 => Register::Config7,
263            _ => return Err(AD7124CoreError::InvalidParameter),
264        };
265
266        let config_value = self.build_setup_value(config)?;
267        sequence.add_write(register, config_value)?;
268
269        Ok(sequence)
270    }
271
272    /// Configure filter
273    pub fn configure_filter(
274        &self,
275        setup_index: u8,
276        config: FilterConfig,
277    ) -> Result<CommandSequence, AD7124CoreError> {
278        if setup_index > 7 {
279            return Err(AD7124CoreError::InvalidParameter);
280        }
281
282        let mut sequence = CommandSequence::new();
283        let register = match setup_index {
284            0 => Register::Filter0,
285            1 => Register::Filter1,
286            2 => Register::Filter2,
287            3 => Register::Filter3,
288            4 => Register::Filter4,
289            5 => Register::Filter5,
290            6 => Register::Filter6,
291            7 => Register::Filter7,
292            _ => return Err(AD7124CoreError::InvalidParameter),
293        };
294
295        let filter_value = self.build_filter_value(config)?;
296        sequence.add_write(register, filter_value)?;
297
298        Ok(sequence)
299    }
300
301    /// Verify device ID
302    pub fn verify_device_id(&self, id: u8) -> Result<DeviceType, AD7124CoreError> {
303        let device_type = DeviceType::from_device_id(id);
304        if device_type == DeviceType::Unknown {
305            return Err(AD7124CoreError::InvalidDeviceId);
306        }
307        Ok(device_type)
308    }
309
310    /// Convert raw ADC reading to voltage
311    pub fn raw_to_voltage(
312        &self,
313        raw_data: u32,
314        pga_gain: PgaGain,
315        bipolar: bool,
316    ) -> Result<f32, AD7124CoreError> {
317        if raw_data > 0xFFFFFF {
318            // 24-bit max
319            return Err(AD7124CoreError::ValueOutOfRange);
320        }
321
322        let gain = pga_gain.value() as f32;
323        let full_scale = if bipolar {
324            0x800000 as f32 // 2^23 for bipolar
325        } else {
326            0xFFFFFF as f32 // 2^24 - 1 for unipolar
327        };
328
329        let voltage = if bipolar {
330            // Bipolar: -Vref to +Vref
331            let signed_data = raw_data as i32 - 0x800000;
332            (signed_data as f32 / full_scale) * self.reference_voltage / gain
333        } else {
334            // Unipolar: 0 to +Vref
335            (raw_data as f32 / full_scale) * self.reference_voltage / gain
336        };
337
338        Ok(voltage)
339    }
340
341    /// Get current configuration
342    pub fn config(&self) -> &AD7124Config {
343        &self.config
344    }
345
346    /// Update configuration
347    pub fn set_config(&mut self, config: AD7124Config) {
348        self.config = config;
349    }
350
351    /// Get device capabilities
352    pub fn capabilities(&self) -> &DeviceCapabilities {
353        &self.capabilities
354    }
355
356    /// Get device type
357    pub fn device_type(&self) -> DeviceType {
358        self.device_type
359    }
360
361    /// Check if initialized
362    pub fn is_initialized(&self) -> bool {
363        self.initialized
364    }
365
366    /// Mark as initialized (called after successful init sequence)
367    pub fn set_initialized(&mut self) {
368        self.initialized = true;
369    }
370
371    /// Set reference voltage
372    pub fn set_reference_voltage(&mut self, voltage: f32) -> Result<(), AD7124CoreError> {
373        if voltage <= 0.0 || voltage > 5.0 {
374            return Err(AD7124CoreError::ValueOutOfRange);
375        }
376        self.reference_voltage = voltage;
377        Ok(())
378    }
379
380    /// Get reference voltage
381    pub fn reference_voltage(&self) -> f32 {
382        self.reference_voltage
383    }
384
385    /// Enable/disable CRC
386    pub fn set_crc_enabled(&mut self, enabled: bool) {
387        self.crc_enabled = enabled;
388    }
389
390    /// Get CRC status
391    pub fn is_crc_enabled(&self) -> bool {
392        self.crc_enabled
393    }
394
395    // Private helper methods
396    fn build_adc_control_value(&self) -> Result<u32, AD7124CoreError> {
397        let mut value = 0u32;
398
399        // Operating mode (bits 2:0)
400        value |= (self.config.operating_mode as u32) & 0x07;
401
402        // Power mode (bits 7:6)
403        value |= ((self.config.power_mode as u32) & 0x03) << 6;
404
405        // Clock source (bits 5:4)
406        value |= ((self.config.clock_source as u32) & 0x03) << 4;
407
408        // Internal reference enable (bit 8) - IMPORTANT!
409        // Note: This bit must be set when using internal reference
410        if self.config.internal_ref_enabled {
411            value |= 1 << 8;
412        }
413
414        // Data ready output enable (bit 9)
415        if self.config.data_ready_output_enabled {
416            value |= 1 << 9;
417        }
418
419        Ok(value)
420    }
421
422    /// Public method to get ADC control value for configure_adc
423    pub fn build_adc_control_value_public(&self) -> u32 {
424        self.build_adc_control_value().unwrap_or(0)
425    }
426
427    fn build_channel_value(&self, config: ChannelConfig) -> Result<u32, AD7124CoreError> {
428        let mut value = 0u32;
429
430        // Channel enable (bit 15)
431        if config.enabled {
432            value |= 1 << 15;
433        }
434
435        // Setup selection (bits 14:12)
436        value |= ((config.setup_index as u32) & 0x07) << 12;
437
438        // Positive input (bits 9:5)
439        value |= ((config.positive_input as u32) & 0x1F) << 5;
440
441        // Negative input (bits 4:0)
442        value |= (config.negative_input as u32) & 0x1F;
443
444        Ok(value)
445    }
446
447    fn build_setup_value(&self, config: SetupConfig) -> Result<u32, AD7124CoreError> {
448        let mut value = 0u32;
449
450        // Bipolar (bit 11)
451        if config.bipolar {
452            value |= 1 << 11;
453        }
454
455        // Reference source (bits 5:4) - According to AD7124 datasheet
456        // Internal reference = 2, requires setting bit 4 to 1
457        if config.reference_source == ReferenceSource::Internal {
458            value |= 0x0010; // Set bit 4 to 1, matching the correct implementation
459        } else {
460            // Other reference sources use the original bits 5:4 setting
461            let ref_source_bits = ((config.reference_source as u32) & 0x03) << 4;
462            value |= ref_source_bits;
463        }
464
465        // PGA gain (bits 2:0)
466        value |= (config.pga_gain as u32) & 0x07;
467
468        // Burnout current (bits 9:8)
469        value |= ((config.burnout_current as u32) & 0x03) << 8;
470
471        // Reference buffers (bits 7:6)
472        if config.reference_buffers_enabled {
473            value |= 0x03 << 6;
474        }
475
476        // Input buffers (bits 5:4)
477        if config.input_buffers_enabled {
478            value |= 0x03 << 4;
479        }
480
481        Ok(value)
482    }
483
484    fn build_filter_value(&self, config: FilterConfig) -> Result<u32, AD7124CoreError> {
485        let mut value = 0u32;
486
487        // Filter type (bits 23:21)
488        value |= ((config.filter_type as u32) & 0x07) << 21;
489
490        // Output data rate (bits 10:0)
491        value |= (config.output_data_rate as u32) & 0x7FF;
492
493        // Single cycle (bit 20)
494        if config.single_cycle {
495            value |= 1 << 20;
496        }
497
498        // 60Hz reject (bit 14)
499        if config.reject_60hz {
500            value |= 1 << 14;
501        }
502
503        // 50Hz reject (bit 13) - commonly enabled with 60Hz
504        if config.reject_60hz {
505            value |= 1 << 13;
506        }
507
508        Ok(value)
509    }
510
511    // ==================== Pure Logic Methods (No I/O) ====================
512
513    /// Generate channel configuration command sequence (removed - logic moved to I/O layer)
514    // This method removed per final design - channel enable/disable done directly in I/O layer
515
516    /// Get channel register address (static calculation)
517    pub fn get_channel_register(channel: u8) -> Result<Register, AD7124CoreError> {
518        match channel {
519            0 => Ok(Register::Channel0),
520            1 => Ok(Register::Channel1),
521            2 => Ok(Register::Channel2),
522            3 => Ok(Register::Channel3),
523            4 => Ok(Register::Channel4),
524            5 => Ok(Register::Channel5),
525            6 => Ok(Register::Channel6),
526            7 => Ok(Register::Channel7),
527            _ => Err(AD7124CoreError::InvalidParameter),
528        }
529    }
530
531    /// Get setup configuration register address (static calculation)
532    pub fn get_config_register(setup: u8) -> Result<Register, AD7124CoreError> {
533        match setup {
534            0 => Ok(Register::Config0),
535            1 => Ok(Register::Config1),
536            2 => Ok(Register::Config2),
537            3 => Ok(Register::Config3),
538            4 => Ok(Register::Config4),
539            5 => Ok(Register::Config5),
540            6 => Ok(Register::Config6),
541            7 => Ok(Register::Config7),
542            _ => Err(AD7124CoreError::InvalidParameter),
543        }
544    }
545
546    /// Get filter configuration register address (static calculation)
547    pub fn get_filter_register(setup: u8) -> Result<Register, AD7124CoreError> {
548        match setup {
549            0 => Ok(Register::Filter0),
550            1 => Ok(Register::Filter1),
551            2 => Ok(Register::Filter2),
552            3 => Ok(Register::Filter3),
553            4 => Ok(Register::Filter4),
554            5 => Ok(Register::Filter5),
555            6 => Ok(Register::Filter6),
556            7 => Ok(Register::Filter7),
557            _ => Err(AD7124CoreError::InvalidParameter),
558        }
559    }
560
561    /// Get channel configuration
562    pub fn get_channel_config(&self, channel: u8) -> Option<&ChannelConfig> {
563        if channel >= 16 {
564            return None;
565        }
566        Some(&self.channel_configs[channel as usize])
567    }
568
569    /// Update channel configuration (internal cache only)
570    pub fn update_channel_config(
571        &mut self,
572        channel: u8,
573        config: ChannelConfig,
574    ) -> Result<(), AD7124CoreError> {
575        if !self.capabilities.validate_channel(channel) {
576            return Err(AD7124CoreError::InvalidParameter);
577        }
578
579        self.channel_configs[channel as usize] = config;
580        Ok(())
581    }
582
583    /// Get setup configuration
584    pub fn get_setup_config(&self, setup_index: u8) -> Option<&SetupConfig> {
585        if setup_index >= 8 {
586            return None;
587        }
588        Some(&self.setup_configs[setup_index as usize])
589    }
590
591    /// Update setup configuration (cached)
592    pub fn update_setup_config(
593        &mut self,
594        setup_index: u8,
595        config: SetupConfig,
596    ) -> Result<(), AD7124CoreError> {
597        if setup_index >= 8 {
598            return Err(AD7124CoreError::InvalidParameter);
599        }
600
601        self.setup_configs[setup_index as usize] = config;
602        Ok(())
603    }
604
605    /// Convert raw data to voltage with explicit setup parameters
606    pub fn raw_to_voltage_with_setup(
607        &self,
608        raw_data: u32,
609        _setup: u8,
610        bipolar: bool,
611        gain: PgaGain,
612        vref: f32,
613    ) -> f32 {
614        let full_scale = if bipolar {
615            0x800000 as f32 // 2^23 for bipolar
616        } else {
617            0xFFFFFF as f32 // 2^24 - 1 for unipolar
618        };
619
620        let gain_value = gain.gain_value();
621
622        if bipolar {
623            // Bipolar: -Vref to +Vref
624            let signed_data = (raw_data as i32) - 0x800000; // Convert to signed
625            (signed_data as f32 / full_scale) * vref / gain_value
626        } else {
627            // Unipolar: 0 to Vref
628            (raw_data as f32 / full_scale) * vref / gain_value
629        }
630    }
631
632    /// Get default timeout in milliseconds (static method)
633    pub fn get_default_timeout() -> u32 {
634        AD7124_DEFAULT_TIMEOUT_MS
635    }
636
637    /// Validate channel number for this device (pure logic)
638    pub fn validate_channel(&self, channel: u8) -> bool {
639        self.capabilities.validate_channel(channel)
640    }
641
642    /// Build ADC control register value (public interface)
643    pub fn build_adc_control_register(&self) -> u32 {
644        self.build_adc_control_value().unwrap_or(0)
645    }
646
647    /// Build channel configuration value (pure logic)
648    pub fn build_channel_config_value(config: ChannelConfig) -> u32 {
649        let mut value = 0u32;
650
651        // Channel enable (bit 15)
652        if config.enabled {
653            value |= 1 << 15;
654        }
655
656        // Setup selection (bits 14:12)
657        value |= ((config.setup_index as u32) & 0x07) << 12;
658
659        // Positive input (bits 9:5)
660        value |= ((config.positive_input as u32) & 0x1F) << 5;
661
662        // Negative input (bits 4:0)
663        value |= (config.negative_input as u32) & 0x1F;
664
665        value
666    }
667
668    /// Build setup configuration value (pure logic)
669    pub fn build_setup_config_value(config: SetupConfig) -> u32 {
670        let mut value = 0u32;
671
672        // Bipolar (bit 11)
673        if config.bipolar {
674            value |= 1 << 11;
675        }
676
677        // Reference source (bits 5:4) - According to AD7124 datasheet
678        // Internal reference = 2, requires setting bit 4 to 1
679        if config.reference_source == ReferenceSource::Internal {
680            value |= 0x0010; // Set bit 4 to 1, matching the correct implementation
681        } else {
682            // Other reference sources use the original bits 5:4 setting
683            let ref_source_bits = ((config.reference_source as u32) & 0x03) << 4;
684            value |= ref_source_bits;
685        }
686
687        // PGA gain (bits 2:0)
688        value |= (config.pga_gain as u32) & 0x07;
689
690        // Burnout current (bits 9:8)
691        value |= ((config.burnout_current as u32) & 0x03) << 8;
692
693        // Reference buffers (bits 7:6)
694        if config.reference_buffers_enabled {
695            value |= 0x03 << 6;
696        }
697
698        // Input buffers (bits 5:4)
699        if config.input_buffers_enabled {
700            value |= 0x03 << 4;
701        }
702
703        value
704    }
705
706    /// Build filter configuration value (pure logic)
707    pub fn build_filter_config_value(config: FilterConfig) -> u32 {
708        let mut value = 0u32;
709
710        // Filter type (bits 23:21)
711        value |= ((config.filter_type as u32) & 0x07) << 21;
712
713        // Output data rate (bits 10:0)
714        value |= (config.output_data_rate as u32) & 0x7FF;
715
716        // Single cycle (bit 20)
717        if config.single_cycle {
718            value |= 1 << 20;
719        }
720
721        // 60Hz reject (bit 14)
722        if config.reject_60hz {
723            value |= 1 << 14;
724        }
725
726        // 50Hz reject (bit 13) - commonly enabled with 60Hz
727        if config.reject_60hz {
728            value |= 1 << 13;
729        }
730
731        value
732    }
733}
734
735impl Default for AD7124Core {
736    fn default() -> Self {
737        Self::new(DeviceType::AD7124_8).unwrap()
738    }
739}