Skip to content

Commit 62db863

Browse files
authored
Merge pull request #32 from harp-tech/bugfix/app_fixes
Bugfix/app fixes
2 parents 185951c + 68dd575 commit 62db863

6 files changed

Lines changed: 179 additions & 71 deletions

File tree

App/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
<PropertyGroup>
33
<Nullable>enable</Nullable>
44
<AvaloniaVersion>11.2.6</AvaloniaVersion>
5-
<AppVersion>1.2.1</AppVersion>
5+
<AppVersion>1.2.2</AppVersion>
66
</PropertyGroup>
77
</Project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<ContentControl
2+
xmlns="https://github.com/avaloniaui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:local="clr-namespace:Harp.Olfactometer.Design.Controls"
5+
xmlns:conv="clr-namespace:Harp.Olfactometer.Design.Converters"
6+
x:Class="Harp.Olfactometer.Design.Controls.VisualStatus">
7+
<ContentControl.Resources>
8+
<conv:VisualStatusColorConverter x:Key="StatusColorConverter" />
9+
</ContentControl.Resources>
10+
<Ellipse
11+
Fill="{Binding Status, RelativeSource={RelativeSource AncestorType=local:VisualStatus}, Converter={StaticResource StatusColorConverter}}" />
12+
</ContentControl>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Avalonia;
2+
using Avalonia.Controls;
3+
4+
namespace Harp.Olfactometer.Design.Controls
5+
{
6+
public partial class VisualStatus : ContentControl
7+
{
8+
public static readonly StyledProperty<bool?> StatusProperty =
9+
AvaloniaProperty.Register<VisualStatus, bool?>(nameof(Status), null);
10+
11+
public bool? Status
12+
{
13+
get => GetValue(StatusProperty);
14+
set => SetValue(StatusProperty, value);
15+
}
16+
17+
public VisualStatus()
18+
{
19+
InitializeComponent();
20+
}
21+
}
22+
}
23+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Globalization;
3+
using Avalonia.Data.Converters;
4+
using Avalonia.Media;
5+
6+
namespace Harp.Olfactometer.Design.Converters;
7+
8+
public class VisualStatusColorConverter : IValueConverter
9+
{
10+
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
11+
{
12+
var status = value as bool?;
13+
return status switch
14+
{
15+
true => new SolidColorBrush(Colors.Green),
16+
false => new SolidColorBrush(Colors.Red),
17+
_ => new SolidColorBrush(Colors.Gray)
18+
};
19+
}
20+
21+
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) =>
22+
throw new NotImplementedException();
23+
}

App/Harp.Olfactometer.Design/ViewModels/MyDeviceViewModel.cs

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,8 @@ public bool IsCheckValve3Enabled_EnableCheckValveSync
20592059
public ReactiveCommand<Unit, Unit> ClearMessagesCommand { get; private set; }
20602060
public ReactiveCommand<Unit, Unit> ShowMessagesCommand { get; private set; }
20612061
public ReactiveCommand<Unit, Unit> ToggleFlowCommand { get; }
2062+
public ReactiveCommand<bool, Unit> DO0SetClearCommand { get; }
2063+
public ReactiveCommand<bool, Unit> DO1SetClearCommand { get; }
20622064

20632065
[Reactive] public int Channel3MaxValue { get; set; }
20642066
[Reactive] public bool RunningFlow { get; set; }
@@ -2131,17 +2133,30 @@ public OlfactometerViewModel()
21312133
ToggleFlowCommand.ThrownExceptions.Subscribe(ex =>
21322134
//Log.Error(ex, "Error starting protocol with error: {Exception}", ex));
21332135
Console.WriteLine($"Error starting protocol with error: {ex}"));
2136+
2137+
DO0SetClearCommand = ReactiveCommand.CreateFromObservable<bool, Unit>(DO0SetClear, canChangeConfig);
2138+
DO0SetClearCommand.IsExecuting.ToPropertyEx(this, x => x.IsSaving);
2139+
DO0SetClearCommand.ThrownExceptions.Subscribe(ex =>
2140+
//Log.Error(ex, "Error setting/clearing DO0 with error: {Exception}", ex));
2141+
Console.WriteLine($"Error setting/clearing DO0 with error: {ex}"));
2142+
2143+
DO1SetClearCommand = ReactiveCommand.CreateFromObservable<bool, Unit>(DO1SetClear, canChangeConfig);
2144+
DO1SetClearCommand.IsExecuting.ToPropertyEx(this, x => x.IsSaving);
2145+
DO1SetClearCommand.ThrownExceptions.Subscribe(ex =>
2146+
//Log.Error(ex, "Error setting/clearing DO1 with error: {Exception}", ex));
2147+
Console.WriteLine($"Error setting/clearing DO1 with error: {ex}"));
2148+
21342149

21352150
this.WhenAnyValue(x => x.HardwareVersion)
21362151
.Subscribe(version =>
21372152
{
2138-
if (version != null)
2139-
{
2140-
// show certain fields depending on the hardware version
2141-
ShowChecksFields = version.Major >= 2;
2142-
ShowTemperatureValue = (version.Major, version.Minor) is (2, 0) or (1, 1);
2143-
ShowTemperatureFields = !((version.Major, version.Minor) is (2, 1) or (1, 0));
2144-
}
2153+
if (version == null)
2154+
return;
2155+
2156+
// show certain fields depending on the hardware version
2157+
ShowChecksFields = version.Major >= 2;
2158+
ShowTemperatureValue = (version.Major, version.Minor) is (2, 0) or (1, 1);
2159+
ShowTemperatureFields = (version.Major, version.Minor) is not ((2, 1) or (1, 0));
21452160
});
21462161

21472162
this.WhenAnyValue(x => x.Connected)
@@ -2424,6 +2439,50 @@ await _device.WriteChannelsTargetFlowAsync(new ChannelsTargetFlowPayload(
24242439
LoadUsbInformation();
24252440
}
24262441

2442+
private IObservable<Unit> DO0SetClear(bool arg)
2443+
{
2444+
return Observable.StartAsync(async () =>
2445+
{
2446+
if (_device == null)
2447+
throw new Exception("Device not connected");
2448+
2449+
IsDO0Enabled_DigitalOutputSet = arg;
2450+
IsDO0Enabled_DigitalOutputClear = !arg;
2451+
2452+
await WriteAndLogAsync(
2453+
value => _device.WriteDigitalOutputSetAsync(value),
2454+
DigitalOutputSet,
2455+
"DigitalOutputSet");
2456+
2457+
await WriteAndLogAsync(
2458+
value => _device.WriteDigitalOutputClearAsync(value),
2459+
DigitalOutputClear,
2460+
"DigitalOutputClear");
2461+
});
2462+
}
2463+
2464+
private IObservable<Unit> DO1SetClear(bool arg)
2465+
{
2466+
return Observable.StartAsync(async () =>
2467+
{
2468+
if (_device == null)
2469+
throw new Exception("Device not connected");
2470+
2471+
IsDO1Enabled_DigitalOutputSet = arg;
2472+
IsDO1Enabled_DigitalOutputClear = !arg;
2473+
2474+
await WriteAndLogAsync(
2475+
value => _device.WriteDigitalOutputSetAsync(value),
2476+
DigitalOutputSet,
2477+
"DigitalOutputSet");
2478+
2479+
await WriteAndLogAsync(
2480+
value => _device.WriteDigitalOutputClearAsync(value),
2481+
DigitalOutputClear,
2482+
"DigitalOutputClear");
2483+
});
2484+
}
2485+
24272486
private IObservable<Unit> LoadUsbInformation()
24282487
{
24292488
return Observable.Start(() =>
@@ -2691,6 +2750,9 @@ public IObservable<string> GenerateEventMessages()
26912750
Channel4ActualFlow = await device.ReadChannel4ActualFlowAsync(cancellationToken);
26922751
observer.OnNext($"Channel4ActualFlow: {Channel4ActualFlow}");
26932752
}
2753+
2754+
DigitalOutputState = await _device.ReadDigitalOutputStateAsync(cancellationToken);
2755+
observer.OnNext($"DigitalOutputState: {DigitalOutputState}");
26942756

26952757
// Wait a short while before polling again. Adjust delay as necessary.
26962758
await Task.Delay(TimeSpan.FromMilliseconds(10), cancellationToken);

App/Harp.Olfactometer.Design/Views/MyDeviceView.axaml

Lines changed: 51 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
xmlns:heroIcons="clr-namespace:HeroIconsAvalonia.Controls;assembly=HeroIconsAvalonia"
88
xmlns:harp="clr-namespace:Bonsai.Harp;assembly=Bonsai.Harp"
99
xmlns:local="clr-namespace:Harp.Olfactometer;assembly=Harp.Olfactometer"
10-
xmlns:md="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia"
1110
xmlns:system="clr-namespace:System;assembly=System.Runtime"
1211
xmlns:vm="clr-namespace:Harp.Olfactometer.Design.ViewModels"
1312
mc:Ignorable="d" d:DesignWidth="1100" d:DesignHeight="900"
@@ -17,6 +16,8 @@
1716
<UserControl.Resources>
1817
<conv:EnableFlagConverter x:Key="EnableFlagConverter"/>
1918
<conv:PayloadFieldConverter x:Key="PayloadFieldConverter"/>
19+
<system:Boolean x:Key="BoolTrue">True</system:Boolean>
20+
<system:Boolean x:Key="BoolFalse">False</system:Boolean>
2021
</UserControl.Resources>
2122

2223
<Design.DataContext>
@@ -789,7 +790,7 @@
789790
</ComboBox>
790791
</StackPanel>
791792
<!-- Register: MimicCheckValve0 (Write) -->
792-
<StackPanel Orientation="Vertical" Spacing="10">
793+
<StackPanel Orientation="Vertical" Spacing="10" IsVisible="{Binding ShowChecksFields}">
793794
<StackPanel Orientation="Horizontal" Spacing="5">
794795
<Label FontWeight="Bold" FontSize="14" Padding="0">MimicCheckValve0</Label>
795796
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
@@ -823,7 +824,7 @@
823824
</ComboBox>
824825
</StackPanel>
825826
<!-- Register: MimicCheckValve1 (Write) -->
826-
<StackPanel Orientation="Vertical" Spacing="10">
827+
<StackPanel Orientation="Vertical" Spacing="10" IsVisible="{Binding ShowChecksFields}">
827828
<StackPanel Orientation="Horizontal" Spacing="5">
828829
<Label FontWeight="Bold" FontSize="14" Padding="0">MimicCheckValve1</Label>
829830
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
@@ -857,7 +858,7 @@
857858
</ComboBox>
858859
</StackPanel>
859860
<!-- Register: MimicCheckValve2 (Write) -->
860-
<StackPanel Orientation="Vertical" Spacing="10">
861+
<StackPanel Orientation="Vertical" Spacing="10" IsVisible="{Binding ShowChecksFields}">
861862
<StackPanel Orientation="Horizontal" Spacing="5">
862863
<Label FontWeight="Bold" FontSize="14" Padding="0">MimicCheckValve2</Label>
863864
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
@@ -891,7 +892,7 @@
891892
</ComboBox>
892893
</StackPanel>
893894
<!-- Register: MimicCheckValve3 (Write) -->
894-
<StackPanel Orientation="Vertical" Spacing="10">
895+
<StackPanel Orientation="Vertical" Spacing="10" IsVisible="{Binding ShowChecksFields}">
895896
<StackPanel Orientation="Horizontal" Spacing="5">
896897
<Label FontWeight="Bold" FontSize="14" Padding="0">MimicCheckValve3</Label>
897898
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
@@ -1026,81 +1027,68 @@
10261027
<x:Static Member="local:DI0TriggerConfig.ValveToggle" />
10271028
</ComboBox>
10281029
</StackPanel>
1029-
<!-- Register: DigitalOutputClear (Write) -->
1030+
<!-- Registers: DigitalOutput0Set and DigitalOutput0Clear (Write) -->
10301031
<StackPanel Orientation="Vertical" Spacing="10">
10311032
<StackPanel Orientation="Horizontal" Spacing="5">
1032-
<Label FontWeight="Bold" FontSize="14" Padding="0">DigitalOutputClear</Label>
1033+
<Label FontWeight="Bold" FontSize="14" Padding="0">Digital Output 0</Label>
10331034
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
10341035
Foreground="{Binding IconColor}"
10351036
VerticalAlignment="Top">
1036-
<ToolTip.Tip>Clears the specified digital output lines.</ToolTip.Tip>
1037+
<ToolTip.Tip>Sets or clears the digital output 0 line.</ToolTip.Tip>
10371038
</heroIcons:HeroIcon>
10381039
</StackPanel>
1039-
<CheckBox IsChecked="{Binding IsDO0Enabled_DigitalOutputClear}"
1040-
IsEnabled="True">
1041-
DO0
1042-
</CheckBox>
1043-
<CheckBox IsChecked="{Binding IsDO1Enabled_DigitalOutputClear}"
1044-
IsEnabled="True">
1045-
DO1
1046-
</CheckBox>
1047-
</StackPanel>
1048-
<!-- Register: DigitalOutputSet (Write) -->
1049-
<StackPanel Orientation="Vertical" Spacing="10">
1050-
<StackPanel Orientation="Horizontal" Spacing="5">
1051-
<Label FontWeight="Bold" FontSize="14" Padding="0">DigitalOutputSet</Label>
1052-
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
1053-
Foreground="{Binding IconColor}"
1054-
VerticalAlignment="Top">
1055-
<ToolTip.Tip>Set the specified digital output lines.</ToolTip.Tip>
1056-
</heroIcons:HeroIcon>
1040+
<StackPanel Orientation="Horizontal" Spacing="10">
1041+
<StackPanel Orientation="Horizontal" Spacing="5">
1042+
<controls:VisualStatus Status="{Binding IsDO0Enabled_DigitalOutputState}" Width="15"
1043+
Height="15" />
1044+
<TextBlock Text="Active" FontSize="12" VerticalAlignment="Center" />
1045+
</StackPanel>
1046+
<ToggleButton
1047+
IsChecked="{Binding IsDO0Enabled_DigitalOutputSet}"
1048+
Command="{Binding DO0SetClearCommand}"
1049+
CommandParameter="{StaticResource BoolTrue}"
1050+
IsEnabled="True">
1051+
Set
1052+
</ToggleButton>
1053+
<ToggleButton
1054+
IsChecked="{Binding IsDO0Enabled_DigitalOutputClear}"
1055+
Command="{Binding DO0SetClearCommand}"
1056+
CommandParameter="{StaticResource BoolFalse}"
1057+
IsEnabled="True">
1058+
Clear
1059+
</ToggleButton>
10571060
</StackPanel>
1058-
<CheckBox IsChecked="{Binding IsDO0Enabled_DigitalOutputSet}"
1059-
IsEnabled="True">
1060-
DO0
1061-
</CheckBox>
1062-
<CheckBox IsChecked="{Binding IsDO1Enabled_DigitalOutputSet}"
1063-
IsEnabled="True">
1064-
DO1
1065-
</CheckBox>
10661061
</StackPanel>
1067-
<!-- Register: DigitalOutputState (Write) -->
1062+
<!-- Registers: DigitalOutput1Set and DigitalOutput1Clear (Write) -->
10681063
<StackPanel Orientation="Vertical" Spacing="10">
10691064
<StackPanel Orientation="Horizontal" Spacing="5">
1070-
<Label FontWeight="Bold" FontSize="14" Padding="0">DigitalOutputState</Label>
1065+
<Label FontWeight="Bold" FontSize="14" Padding="0">Digital Output 1</Label>
10711066
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
10721067
Foreground="{Binding IconColor}"
10731068
VerticalAlignment="Top">
1074-
<ToolTip.Tip>Write the state of all digital output lines.</ToolTip.Tip>
1069+
<ToolTip.Tip>Sets or clears the digital output 1 line.</ToolTip.Tip>
10751070
</heroIcons:HeroIcon>
10761071
</StackPanel>
1077-
<CheckBox IsChecked="{Binding IsDO0Enabled_DigitalOutputState}"
1078-
IsEnabled="True">
1079-
DO0
1080-
</CheckBox>
1081-
<CheckBox IsChecked="{Binding IsDO1Enabled_DigitalOutputState}"
1082-
IsEnabled="True">
1083-
DO1
1084-
</CheckBox>
1085-
</StackPanel>
1086-
<!-- Register: DigitalOutputToggle (Write) -->
1087-
<StackPanel Orientation="Vertical" Spacing="10">
1088-
<StackPanel Orientation="Horizontal" Spacing="5">
1089-
<Label FontWeight="Bold" FontSize="14" Padding="0">DigitalOutputToggle</Label>
1090-
<heroIcons:HeroIcon Type="InformationCircle" Width="14" Height="14"
1091-
Foreground="{Binding IconColor}"
1092-
VerticalAlignment="Top">
1093-
<ToolTip.Tip>Toggles the specified digital output lines.</ToolTip.Tip>
1094-
</heroIcons:HeroIcon>
1072+
<StackPanel Orientation="Horizontal" Spacing="10">
1073+
<StackPanel Orientation="Horizontal" Spacing="5">
1074+
<controls:VisualStatus Status="{Binding IsDO1Enabled_DigitalOutputState}" Width="15"
1075+
Height="15" />
1076+
<TextBlock Text="Active" FontSize="12" VerticalAlignment="Center" /></StackPanel>
1077+
<ToggleButton
1078+
IsChecked="{Binding IsDO1Enabled_DigitalOutputSet}"
1079+
Command="{Binding DO1SetClearCommand}"
1080+
CommandParameter="{StaticResource BoolTrue}"
1081+
IsEnabled="True">
1082+
Set
1083+
</ToggleButton>
1084+
<ToggleButton
1085+
IsChecked="{Binding IsDO1Enabled_DigitalOutputClear}"
1086+
Command="{Binding DO1SetClearCommand}"
1087+
CommandParameter="{StaticResource BoolFalse}"
1088+
IsEnabled="True">
1089+
Clear
1090+
</ToggleButton>
10951091
</StackPanel>
1096-
<CheckBox IsChecked="{Binding IsDO0Enabled_DigitalOutputToggle}"
1097-
IsEnabled="True">
1098-
DO0
1099-
</CheckBox>
1100-
<CheckBox IsChecked="{Binding IsDO1Enabled_DigitalOutputToggle}"
1101-
IsEnabled="True">
1102-
DO1
1103-
</CheckBox>
11041092
</StackPanel>
11051093
</StackPanel>
11061094

0 commit comments

Comments
 (0)