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

493 lines
14 KiB
Markdown

# 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`
```csharp
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`
```csharp
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`
```csharp
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`
```csharp
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`
```xml
<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
```csharp
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`
```csharp
public enum HardwareType
{
Unknown,
SLICE6,
TDAS,
{HARDWARE_NAME} // Add new type
}
```
## Interface Reference
### IArmable
```csharp
public interface IArmable
{
ArmStatus ArmStatus { get; }
void Arm();
void Disarm();
AvailableArmModes GetAvailableArmModes();
}
```
### IDataCollectionEnabled
```csharp
public interface IDataCollectionEnabled
{
bool IsDataCollectionEnabled { get; }
void EnableDataCollection();
void DisableDataCollection();
}
```
### IRealtimeable
```csharp
public interface IRealtimeable
{
bool IsRealtimeEnabled { get; }
void StartRealtime();
void StopRealtime();
}
```
### ITriggerable
```csharp
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