Skip to content

Commit d37589c

Browse files
committed
Add Neuropixels V2 Probe Data Interfaces and Implementations
- Moved all probe-specific logic from the dialog to the data class in the Design library - Generated new attributes to allow the factory to utilize reflection and automatically initialize the correct object
1 parent 30eda75 commit d37589c

File tree

4 files changed

+265
-432
lines changed

4 files changed

+265
-432
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace OpenEphys.Onix1.Design
4+
{
5+
interface INeuropixelsV2ProbeData
6+
{
7+
Array GetReferenceEnumValues();
8+
9+
Array GetComboBoxChannelPresets();
10+
11+
Enum CheckForExistingChannelPreset(NeuropixelsV2Electrode[] channelMap);
12+
13+
NeuropixelsV2Electrode[] GetChannelPreset(Enum channelPreset);
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace OpenEphys.Onix1.Design
4+
{
5+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
6+
internal sealed class NeuropixelsV2ProbeTypeAttribute : Attribute
7+
{
8+
internal NeuropixelsV2ProbeType ProbeType { get; }
9+
10+
public NeuropixelsV2ProbeTypeAttribute(NeuropixelsV2ProbeType probeType)
11+
{
12+
ProbeType = probeType;
13+
}
14+
}
15+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Linq;
5+
6+
namespace OpenEphys.Onix1.Design
7+
{
8+
[NeuropixelsV2ProbeType(NeuropixelsV2ProbeType.QuadShank)]
9+
internal class NeuropixelsV2QuadShankData : INeuropixelsV2ProbeData
10+
{
11+
const int BankDStartIndex = 896;
12+
13+
enum QuadShankChannelPreset
14+
{
15+
Shank0BankA,
16+
Shank0BankB,
17+
Shank0BankC,
18+
Shank0BankD,
19+
Shank1BankA,
20+
Shank1BankB,
21+
Shank1BankC,
22+
Shank1BankD,
23+
Shank2BankA,
24+
Shank2BankB,
25+
Shank2BankC,
26+
Shank2BankD,
27+
Shank3BankA,
28+
Shank3BankB,
29+
Shank3BankC,
30+
Shank3BankD,
31+
AllShanks0_95,
32+
AllShanks96_191,
33+
AllShanks192_287,
34+
AllShanks288_383,
35+
AllShanks384_479,
36+
AllShanks480_575,
37+
AllShanks576_671,
38+
AllShanks672_767,
39+
AllShanks768_863,
40+
AllShanks864_959,
41+
AllShanks960_1055,
42+
AllShanks1056_1151,
43+
AllShanks1152_1247,
44+
None
45+
}
46+
47+
IEnumerable<NeuropixelsV2Electrode> Electrodes { get; init; }
48+
49+
public NeuropixelsV2QuadShankData(NeuropixelsV2ProbeConfiguration probeConfiguration)
50+
{
51+
Electrodes = NeuropixelsV2eProbeGroup.ToElectrodes(probeConfiguration.ProbeGroup, NeuropixelsV2ProbeType.QuadShank);
52+
}
53+
54+
public Array GetReferenceEnumValues()
55+
{
56+
return Enum.GetValues(typeof(NeuropixelsV2ShankReference))
57+
.Cast<NeuropixelsV2ShankReference>()
58+
.Where(r =>
59+
{
60+
return r == NeuropixelsV2ShankReference.External
61+
|| r == NeuropixelsV2ShankReference.Tip1
62+
|| r == NeuropixelsV2ShankReference.Tip2
63+
|| r == NeuropixelsV2ShankReference.Tip3
64+
|| r == NeuropixelsV2ShankReference.Tip4
65+
|| r == NeuropixelsV2ShankReference.Ground;
66+
})
67+
.ToArray();
68+
}
69+
70+
public Array GetComboBoxChannelPresets()
71+
{
72+
return Enum.GetValues(typeof(QuadShankChannelPreset));
73+
}
74+
75+
public Enum CheckForExistingChannelPreset(NeuropixelsV2Electrode[] channelMap)
76+
{
77+
static bool CheckShankBank(NeuropixelsV2Electrode[] channelMap, int shank, NeuropixelsV2Bank bank, out QuadShankChannelPreset preset)
78+
{
79+
preset = (shank, bank) switch
80+
{
81+
(0, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank0BankA,
82+
(0, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank0BankB,
83+
(0, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank0BankC,
84+
(1, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank1BankA,
85+
(1, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank1BankB,
86+
(1, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank1BankC,
87+
(2, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank2BankA,
88+
(2, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank2BankB,
89+
(2, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank2BankC,
90+
(3, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank3BankA,
91+
(3, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank3BankB,
92+
(3, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank3BankC,
93+
_ => QuadShankChannelPreset.None
94+
};
95+
96+
return channelMap.All(e => e.Bank == bank && e.Shank == shank);
97+
}
98+
99+
static bool CheckShankBankD(NeuropixelsV2Electrode[] channelMap, int shank, out QuadShankChannelPreset preset)
100+
{
101+
preset = shank switch
102+
{
103+
0 => QuadShankChannelPreset.Shank0BankD,
104+
1 => QuadShankChannelPreset.Shank1BankD,
105+
2 => QuadShankChannelPreset.Shank2BankD,
106+
3 => QuadShankChannelPreset.Shank3BankD,
107+
_ => QuadShankChannelPreset.None
108+
};
109+
110+
return channelMap.All(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.IntraShankElectrodeIndex >= BankDStartIndex)) && e.Shank == shank);
111+
}
112+
113+
for (int shank = 0; shank <= 3; shank++)
114+
{
115+
if (CheckShankBank(channelMap, shank, NeuropixelsV2Bank.A, out var preset))
116+
return preset;
117+
118+
if (CheckShankBank(channelMap, shank, NeuropixelsV2Bank.B, out preset))
119+
return preset;
120+
121+
if (CheckShankBank(channelMap, shank, NeuropixelsV2Bank.C, out preset))
122+
return preset;
123+
124+
if (CheckShankBankD(channelMap, shank, out preset))
125+
return preset;
126+
}
127+
128+
var ranges = new[]
129+
{
130+
(0, 95, QuadShankChannelPreset.AllShanks0_95),
131+
(192, 287, QuadShankChannelPreset.AllShanks192_287),
132+
(288, 383, QuadShankChannelPreset.AllShanks288_383),
133+
(394, 479, QuadShankChannelPreset.AllShanks384_479),
134+
(480, 575, QuadShankChannelPreset.AllShanks480_575),
135+
(576, 671, QuadShankChannelPreset.AllShanks576_671),
136+
(672, 767, QuadShankChannelPreset.AllShanks672_767),
137+
(768, 863, QuadShankChannelPreset.AllShanks768_863),
138+
(864, 959, QuadShankChannelPreset.AllShanks864_959),
139+
(960, 1055, QuadShankChannelPreset.AllShanks960_1055),
140+
(1056, 1151, QuadShankChannelPreset.AllShanks1056_1151),
141+
(1152, 1247, QuadShankChannelPreset.AllShanks1152_1247)
142+
};
143+
144+
static bool CheckAllShanksRange(NeuropixelsV2Electrode[] channelMap, int start, int end)
145+
{
146+
return channelMap.All(e => e.Shank >= 0 && e.Shank <= 3 &&
147+
e.IntraShankElectrodeIndex >= start &&
148+
e.IntraShankElectrodeIndex <= end);
149+
}
150+
151+
foreach (var (start, end, presetValue) in ranges)
152+
{
153+
if (CheckAllShanksRange(channelMap, start, end))
154+
return presetValue;
155+
}
156+
157+
return QuadShankChannelPreset.None;
158+
}
159+
160+
public NeuropixelsV2Electrode[] GetChannelPreset(Enum channelPreset)
161+
{
162+
var preset = (QuadShankChannelPreset)channelPreset;
163+
164+
static NeuropixelsV2Electrode[] GetAllShanks(IEnumerable<NeuropixelsV2Electrode> electrodes, int startIndex, int endIndex)
165+
{
166+
return electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)
167+
|| (e.Shank == 1 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)
168+
|| (e.Shank == 2 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)
169+
|| (e.Shank == 3 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)).ToArray();
170+
};
171+
172+
return preset switch
173+
{
174+
QuadShankChannelPreset.Shank0BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 0).ToArray(),
175+
QuadShankChannelPreset.Shank0BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 0).ToArray(),
176+
QuadShankChannelPreset.Shank0BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 0).ToArray(),
177+
QuadShankChannelPreset.Shank0BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 0).ToArray(),
178+
QuadShankChannelPreset.Shank1BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 1).ToArray(),
179+
QuadShankChannelPreset.Shank1BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 1).ToArray(),
180+
QuadShankChannelPreset.Shank1BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 1).ToArray(),
181+
QuadShankChannelPreset.Shank1BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 1).ToArray(),
182+
QuadShankChannelPreset.Shank2BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 2).ToArray(),
183+
QuadShankChannelPreset.Shank2BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 2).ToArray(),
184+
QuadShankChannelPreset.Shank2BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 2).ToArray(),
185+
QuadShankChannelPreset.Shank2BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 2).ToArray(),
186+
QuadShankChannelPreset.Shank3BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 3).ToArray(),
187+
QuadShankChannelPreset.Shank3BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 3).ToArray(),
188+
QuadShankChannelPreset.Shank3BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 3).ToArray(),
189+
QuadShankChannelPreset.Shank3BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 3).ToArray(),
190+
QuadShankChannelPreset.AllShanks0_95 => GetAllShanks(Electrodes, 0, 95),
191+
QuadShankChannelPreset.AllShanks96_191 => GetAllShanks(Electrodes, 96, 191),
192+
QuadShankChannelPreset.AllShanks192_287 => GetAllShanks(Electrodes, 192, 287),
193+
QuadShankChannelPreset.AllShanks288_383 => GetAllShanks(Electrodes, 288, 383),
194+
QuadShankChannelPreset.AllShanks384_479 => GetAllShanks(Electrodes, 384, 479),
195+
QuadShankChannelPreset.AllShanks480_575 => GetAllShanks(Electrodes, 480, 575),
196+
QuadShankChannelPreset.AllShanks576_671 => GetAllShanks(Electrodes, 576, 671),
197+
QuadShankChannelPreset.AllShanks672_767 => GetAllShanks(Electrodes, 672, 767),
198+
QuadShankChannelPreset.AllShanks768_863 => GetAllShanks(Electrodes, 768, 863),
199+
QuadShankChannelPreset.AllShanks864_959 => GetAllShanks(Electrodes, 864, 959),
200+
QuadShankChannelPreset.AllShanks960_1055 => GetAllShanks(Electrodes, 960, 1055),
201+
QuadShankChannelPreset.AllShanks1056_1151 => GetAllShanks(Electrodes, 1056, 1151),
202+
QuadShankChannelPreset.AllShanks1152_1247 => GetAllShanks(Electrodes, 1152, 1247),
203+
QuadShankChannelPreset.None => Array.Empty<NeuropixelsV2Electrode>(),
204+
_ => throw new InvalidEnumArgumentException($"Unknown value of {nameof(QuadShankChannelPreset)}: {channelPreset}")
205+
};
206+
}
207+
}
208+
}

0 commit comments

Comments
 (0)