493 lines
14 KiB
Markdown
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
|