Skip to content

Commit 7cfa1b4

Browse files
committed
Refactor Rhs2116 to save ProbeInterface files externally
1 parent 8e0f8cd commit 7cfa1b4

File tree

2 files changed

+112
-3
lines changed

2 files changed

+112
-3
lines changed

OpenEphys.Onix1/ConfigureRhs2116Trigger.cs

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Reactive.Disposables;
44
using System.Reactive.Subjects;
55
using System.Text;
6+
using System.Threading.Tasks;
67
using System.Xml.Serialization;
78
using Bonsai;
89
using Newtonsoft.Json;
@@ -44,7 +45,7 @@ public ConfigureRhs2116Trigger(ConfigureRhs2116Trigger rhs2116Trigger)
4445
DeviceAddress = rhs2116Trigger.DeviceAddress;
4546
DeviceName = rhs2116Trigger.DeviceName;
4647
TriggerSource = rhs2116Trigger.TriggerSource;
47-
ProbeGroup = rhs2116Trigger.ProbeGroup;
48+
ProbeGroup = rhs2116Trigger.ProbeGroup.Clone();
4849
Armed = rhs2116Trigger.Armed;
4950
StimulusSequence = new(rhs2116Trigger.StimulusSequence);
5051
}
@@ -76,13 +77,116 @@ public ConfigureRhs2116Trigger(ConfigureRhs2116Trigger rhs2116Trigger)
7677
[Description("Specifies whether the trigger source is local or external.")]
7778
public Rhs2116TriggerSource TriggerSource { get; set; } = Rhs2116TriggerSource.Local;
7879

80+
Task<Rhs2116ProbeGroup> probeGroupTask = null;
81+
82+
Rhs2116ProbeGroup probeGroup = null;
83+
7984
/// <summary>
8085
/// Gets or sets the <see cref="Rhs2116ProbeGroup"/> channel configuration.
8186
/// </summary>
8287
[XmlIgnore]
8388
[Category(ConfigurationCategory)]
8489
[Description("Defines the channel configuration")]
85-
public Rhs2116ProbeGroup ProbeGroup { get; set; } = new();
90+
[Browsable(false)]
91+
[Externalizable(false)]
92+
public Rhs2116ProbeGroup ProbeGroup
93+
{
94+
get
95+
{
96+
if (probeGroup == null)
97+
{
98+
try
99+
{
100+
probeGroup = probeGroupTask?.Result ?? new Rhs2116ProbeGroup();
101+
}
102+
catch (AggregateException ae)
103+
{
104+
probeGroup = new();
105+
throw new InvalidOperationException($"There was an error loading the ProbeInterface file, loading the default configuration instead.\n\nError: {ae.InnerException.Message}", ae.InnerException);
106+
}
107+
}
108+
109+
return probeGroup;
110+
}
111+
set => probeGroup = value;
112+
}
113+
114+
string probeInterfaceFileName;
115+
116+
/// <summary>
117+
/// Gets or sets the file path where the ProbeInterface configuration will be saved.
118+
/// </summary>
119+
/// <remarks>
120+
/// If left empty, the ProbeInterface configuration will not be saved.
121+
/// </remarks>
122+
[XmlIgnore]
123+
[Category(ConfigurationCategory)]
124+
[Description("File path to where the ProbeInterface file will be saved for this probe. If the file exists, it will be overwritten.")]
125+
[FileNameFilter(ProbeInterfaceHelper.ProbeInterfaceFileNameFilter)]
126+
[Editor("Bonsai.Design.SaveFileNameEditor, Bonsai.Design", DesignTypes.UITypeEditor)]
127+
public string ProbeInterfaceFileName
128+
{
129+
get => probeInterfaceFileName;
130+
set => probeInterfaceFileName = value;
131+
}
132+
133+
/// <summary>
134+
/// Gets or sets the ProbeInterface file name, loading the given file asynchronously when set.
135+
/// </summary>
136+
[XmlIgnore]
137+
[Browsable(false)]
138+
[Externalizable(false)]
139+
public string ProbeInterfaceLoadFileName
140+
{
141+
get => probeInterfaceFileName;
142+
set
143+
{
144+
probeInterfaceFileName = value;
145+
probeGroupTask = Task.Run(() =>
146+
{
147+
if (string.IsNullOrEmpty(probeInterfaceFileName))
148+
return new Rhs2116ProbeGroup();
149+
150+
return ProbeInterfaceHelper.LoadExternalProbeInterfaceFile<Rhs2116ProbeGroup>(probeInterfaceFileName);
151+
});
152+
}
153+
}
154+
155+
/// <summary>
156+
/// Gets or sets a string defining the path to an external ProbeInterface JSON file.
157+
/// This variable is needed to properly save a workflow in Bonsai, but it is not
158+
/// directly accessible in the Bonsai editor.
159+
/// </summary>
160+
/// <remarks>
161+
/// [Obsolete]. Cannot tag this property with the Obsolete attribute due to https://github.com/dotnet/runtime/issues/100453
162+
/// </remarks>
163+
[Browsable(false)]
164+
[Externalizable(false)]
165+
[XmlElement(nameof(ProbeInterfaceFileName))]
166+
public string ProbeInterfaceFileNameSerialize
167+
{
168+
get
169+
{
170+
if (string.IsNullOrEmpty(ProbeInterfaceFileName))
171+
return "";
172+
173+
if (probeGroup != null)
174+
ProbeInterfaceHelper.SaveExternalProbeInterfaceFile(ProbeGroup, ProbeInterfaceFileName);
175+
176+
return ProbeInterfaceFileName;
177+
}
178+
set => ProbeInterfaceLoadFileName = value;
179+
}
180+
181+
/// <summary>
182+
/// Prevent the ProbeGroup property from being serialized.
183+
/// </summary>
184+
/// <returns>False</returns>
185+
[Obsolete]
186+
public bool ShouldSerializeProbeGroupString()
187+
{
188+
return false;
189+
}
86190

87191
/// <summary>
88192
/// Gets or sets if trigger is armed.

OpenEphys.Onix1/Rhs2116ProbeGroup.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System;
2-
using System.Collections.Generic;
2+
using System.Linq;
33
using Newtonsoft.Json;
44
using OpenEphys.ProbeInterface.NET;
55

@@ -82,6 +82,11 @@ public Rhs2116ProbeGroup(Rhs2116ProbeGroup probeGroup)
8282
{
8383
}
8484

85+
internal Rhs2116ProbeGroup Clone()
86+
{
87+
return new Rhs2116ProbeGroup(Specification, Version, Probes.Select(probe => new Probe(probe)).ToArray());
88+
}
89+
8590
internal static ContactAnnotations DefaultContactAnnotations(int numberOfChannels, int probeIndex)
8691
{
8792
string[] contactAnnotations = new string[numberOfChannels];

0 commit comments

Comments
 (0)