Files
DP44/GLM5Analysis/PromptTemplates/AddNewHardwareSupport.md
2026-04-17 14:55:32 -04:00

14 KiB

Add New Hardware Support - DataPRO Prompt Template

Context

DataPRO supports various Data Acquisition System (DAS) hardware through the hardware abstraction layer in Common/DTS.Common.DAS.Concepts/ and the DataPRO/Modules/Hardware/ modules. Hardware support involves implementing interfaces for arm/disarm, data collection, real-time streaming, and trigger functionality.

System Architecture

Common/DTS.Common.DAS.Concepts/
├── DAS/
│   ├── Channel/              # Channel abstraction
│   ├── DAS.Id.cs             # Hardware identification
│   └── DAS.Channel.cs        # Channel definitions
├── Interfaces/               # Hardware interfaces
├── IArmable.cs               # Arming capability
├── IDataCollectionEnabled.cs # Data collection
├── IDownloadEnabled.cs       # Data download
├── IRealtimeable.cs          # Real-time streaming
├── ITriggerable.cs           # Trigger capability
└── IGpioEnabled.cs           # GPIO support

DataPRO/Modules/Hardware/
├── HardwareList/             # Hardware management UI
│   ├── Model/
│   ├── View/
│   └── ViewModel/
└── AddEditHardware/          # Hardware configuration

Step-by-Step Instructions

1. Create Hardware Model

File: Common/DTS.Common.DAS.Concepts/DAS/{HardwareName}.cs

using System;
using System.Collections.Generic;

namespace DTS.Common.DAS.Concepts
{
    public class {HARDWARE_NAME} : 
        IArmable, 
        IDataCollectionEnabled, 
        IRealtimeable,
        ITriggerable
    {
        public DASId Id { get; set; }
        public string SerialNumber { get; set; }
        public string FirmwareVersion { get; set; }
        public int ChannelCount { get; set; }
        public int SampleRate { get; set; }
        
        public ArmStatus ArmStatus { get; private set; }
        public bool IsDataCollectionEnabled { get; private set; }
        public bool IsRealtimeEnabled { get; private set; }
        
        public {HARDWARE_NAME}()
        {
            Id = new DASId();
            ChannelCount = 8;
            SampleRate = 100000;
            ArmStatus = ArmStatus.Disarmed;
        }
        
        // IArmable implementation
        public void Arm()
        {
            ValidateArmConditions();
            SendArmCommand();
            ArmStatus = ArmStatus.Armed;
        }
        
        public void Disarm()
        {
            SendDisarmCommand();
            ArmStatus = ArmStatus.Disarmed;
        }
        
        public AvailableArmModes GetAvailableArmModes()
        {
            return new AvailableArmModes
            {
                Modes = new List<ArmMode>
                {
                    ArmMode.Triggered,
                    ArmMode.Immediate
                }
            };
        }
        
        // IDataCollectionEnabled implementation
        public void EnableDataCollection()
        {
            ConfigureDataCollection();
            IsDataCollectionEnabled = true;
        }
        
        public void DisableDataCollection()
        {
            StopDataCollection();
            IsDataCollectionEnabled = false;
        }
        
        // IRealtimeable implementation
        public void StartRealtime()
        {
            ValidateRealtimeConditions();
            StartRealtimeStreaming();
            IsRealtimeEnabled = true;
        }
        
        public void StopRealtime()
        {
            StopRealtimeStreaming();
            IsRealtimeEnabled = false;
        }
        
        // ITriggerable implementation
        public void ConfigureTrigger(TriggerConfiguration config)
        {
            ValidateTriggerConfiguration(config);
            ApplyTriggerSettings(config);
        }
        
        // Hardware-specific methods
        private void ValidateArmConditions()
        {
            if (string.IsNullOrEmpty(SerialNumber))
                throw new InvalidOperationException("Serial number required");
        }
        
        private void SendArmCommand()
        {
            // Hardware communication implementation
        }
        
        private void SendDisarmCommand()
        {
            // Hardware communication implementation
        }
        
        private void ConfigureDataCollection()
        {
            // Configure sample rate, duration, etc.
        }
        
        private void StopDataCollection()
        {
            // Stop collection
        }
        
        private void ValidateRealtimeConditions()
        {
            if (!IsDataCollectionEnabled)
                throw new InvalidOperationException("Enable data collection first");
        }
        
        private void StartRealtimeStreaming()
        {
            // Start real-time data stream
        }
        
        private void StopRealtimeStreaming()
        {
            // Stop real-time data stream
        }
        
        private void ValidateTriggerConfiguration(TriggerConfiguration config)
        {
            if (config.Threshold < 0)
                throw new ArgumentException("Invalid threshold");
        }
        
        private void ApplyTriggerSettings(TriggerConfiguration config)
        {
            // Apply trigger configuration to hardware
        }
    }
    
    public class TriggerConfiguration
    {
        public double Threshold { get; set; }
        public TriggerEdge Edge { get; set; }
        public int Channel { get; set; }
    }
    
    public enum TriggerEdge
    {
        Rising,
        Falling,
        Both
    }
}

2. Create Hardware Channel Definition

File: Common/DTS.Common.DAS.Concepts/DAS/{HardwareName}Channel.cs

using System;
using DTS.Common.DAS.Concepts.Channel;

namespace DTS.Common.DAS.Concepts
{
    public class {HARDWARE_NAME}Channel : DAS.Channel
    {
        public int PhysicalChannel { get; set; }
        public string Label { get; set; }
        public double FullScaleRange { get; set; }
        public double ExcitationVoltage { get; set; }
        
        public {HARDWARE_NAME}Channel(int index)
        {
            PhysicalChannel = index;
            FullScaleRange = 10.0;
            ExcitationVoltage = 0.0;
        }
        
        public void Configure(ChannelConfiguration config)
        {
            FullScaleRange = config.FullScaleRange;
            ExcitationVoltage = config.ExcitationVoltage;
            ApplyChannelSettings();
        }
        
        private void ApplyChannelSettings()
        {
            // Apply channel configuration to hardware
        }
    }
    
    public class ChannelConfiguration
    {
        public double FullScaleRange { get; set; }
        public double ExcitationVoltage { get; set; }
        public CouplingMode Coupling { get; set; }
    }
    
    public enum CouplingMode
    {
        DC,
        AC
    }
}

3. Create Hardware Factory

File: Common/DTS.Common.DAS.Concepts/DAS/{HardwareName}Factory.cs

using System;
using DTS.Common.DAS.Concepts.Interfaces;

namespace DTS.Common.DAS.Concepts
{
    public class {HARDWARE_NAME}Factory : IDASFactory
    {
        public string HardwareType => "{HARDWARE_NAME}";
        
        public DAS.Channel CreateChannel(int index)
        {
            return new {HARDWARE_NAME}Channel(index);
        }
        
        public {HARDWARE_NAME} CreateHardware(string serialNumber)
        {
            var hardware = new {HARDWARE_NAME}
            {
                SerialNumber = serialNumber
            };
            
            InitializeHardware(hardware);
            return hardware;
        }
        
        private void InitializeHardware({HARDWARE_NAME} hardware)
        {
            // Hardware initialization
            // Connect, discover channels, read firmware version
        }
        
        public bool CanCreate(string hardwareIdentifier)
        {
            // Check if this factory supports the given hardware
            return hardwareIdentifier.StartsWith("{HARDWARE_PREFIX}");
        }
    }
}

4. Update Hardware List Module

File: DataPRO/Modules/Hardware/HardwareList/Model/{HardwareName}Model.cs

using System;
using System.ComponentModel;
using DTS.Common.DAS.Concepts;

namespace HardwareList.Model
{
    public class {HARDWARE_NAME}Model : INotifyPropertyChanged
    {
        private {HARDWARE_NAME} _hardware;
        
        public string SerialNumber
        {
            get => _hardware?.SerialNumber;
            set
            {
                if (_hardware != null)
                    _hardware.SerialNumber = value;
                OnPropertyChanged(nameof(SerialNumber));
            }
        }
        
        public string FirmwareVersion => _hardware?.FirmwareVersion;
        public int ChannelCount => _hardware?.ChannelCount ?? 0;
        public ArmStatus ArmStatus => _hardware?.ArmStatus ?? ArmStatus.Disarmed;
        
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        
        public void SetHardware({HARDWARE_NAME} hardware)
        {
            _hardware = hardware;
            OnPropertyChanged(nameof(SerialNumber));
            OnPropertyChanged(nameof(FirmwareVersion));
            OnPropertyChanged(nameof(ChannelCount));
            OnPropertyChanged(nameof(ArmStatus));
        }
    }
}

5. Create Hardware View

File: DataPRO/Modules/Hardware/HardwareList/View/{HardwareName}View.xaml

<UserControl x:Class="HardwareList.View.{HARDWARE_NAME}View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:resx="clr-namespace:HardwareList.Resources">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <TextBlock Grid.Row="0" Text="{x:Static resx:StringResources.{HARDWARE_NAME}_Header}"
                   Style="{StaticResource HardwareHeaderStyle}"/>
        
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5">
            <TextBlock Text="{x:Static resx:StringResources.SerialNumber}"/>
            <TextBox Text="{Binding SerialNumber, Mode=TwoWay}" Width="150" Margin="5,0"/>
            <TextBlock Text="{x:Static resx:StringResources.Firmware}"/>
            <TextBlock Text="{Binding FirmwareVersion}" Margin="5,0"/>
        </StackPanel>
        
        <TabControl Grid.Row="2">
            <TabItem Header="{x:Static resx:StringResources.Channels}">
                <ListView ItemsSource="{Binding Channels}" SelectedItem="{Binding SelectedChannel}">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Header="Channel" DisplayMemberBinding="{Binding PhysicalChannel}"/>
                            <GridViewColumn Header="Label" DisplayMemberBinding="{Binding Label}"/>
                            <GridViewColumn Header="Range" DisplayMemberBinding="{Binding FullScaleRange}"/>
                        </GridView>
                    </ListView.View>
                </ListView>
            </TabItem>
            <TabItem Header="{x:Static resx:StringResources.Settings}">
                <!-- Hardware-specific settings -->
            </TabItem>
        </TabControl>
    </Grid>
</UserControl>

6. Register Factory in Bootstrapper

File: Modify the bootstrapper or module initialization

private void RegisterDASFactories()
{
    // Register existing factories
    _unityContainer.RegisterType<IDASFactory, SLICE6Factory>("SLICE6");
    _unityContainer.RegisterType<IDASFactory, TDASFactory>("TDAS");
    
    // Register new hardware factory
    _unityContainer.RegisterType<IDASFactory, {HARDWARE_NAME}Factory>("{HARDWARE_NAME}");
}

7. Add Hardware Type to Enums

File: Common/DTS.Common/Enums/HardwareTypes.cs

public enum HardwareType
{
    Unknown,
    SLICE6,
    TDAS,
    {HARDWARE_NAME}  // Add new type
}

Interface Reference

IArmable

public interface IArmable
{
    ArmStatus ArmStatus { get; }
    void Arm();
    void Disarm();
    AvailableArmModes GetAvailableArmModes();
}

IDataCollectionEnabled

public interface IDataCollectionEnabled
{
    bool IsDataCollectionEnabled { get; }
    void EnableDataCollection();
    void DisableDataCollection();
}

IRealtimeable

public interface IRealtimeable
{
    bool IsRealtimeEnabled { get; }
    void StartRealtime();
    void StopRealtime();
}

ITriggerable

public interface ITriggerable
{
    void ConfigureTrigger(TriggerConfiguration config);
}

Files to Create/Modify Summary

File Action
DTS.Common.DAS.Concepts/DAS/{HardwareName}.cs Create
DTS.Common.DAS.Concepts/DAS/{HardwareName}Channel.cs Create
DTS.Common.DAS.Concepts/DAS/{HardwareName}Factory.cs Create
HardwareList/Model/{HardwareName}Model.cs Create
HardwareList/View/{HardwareName}View.xaml Create
HardwareList/View/{HardwareName}View.xaml.cs Create
HardwareList/HardwareListModule.cs Modify (register)
DTS.Common/Enums/HardwareType.cs Modify (add enum)

Validation Checklist

  • Hardware class implements required interfaces (IArmable, etc.)
  • Channel class inherits from DAS.Channel
  • Factory implements IDASFactory
  • All interface methods properly implemented
  • Validation added for hardware commands
  • Error handling for communication failures
  • Factory registered in DI container
  • Hardware type added to enum
  • View properly data-bound to ViewModel
  • Localization strings added
  • Channel configuration supports hardware features

Hardware Communication Patterns

  1. Synchronous Commands: Use for arm/disarm operations
  2. Asynchronous Data: Use for real-time streaming
  3. Status Polling: Implement periodic status checks
  4. Error Recovery: Handle disconnections gracefully
  5. Timeout Handling: Set appropriate timeouts for operations

Common Gotchas

  • Always check connection status before sending commands
  • Validate hardware state transitions (can't arm if already armed)
  • Handle firmware version differences
  • Consider backward compatibility with older firmware
  • Implement proper disposal of resources