diff --git a/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs b/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs index 51dd1caf..08aa2399 100644 --- a/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs +++ b/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs @@ -19,11 +19,21 @@ public partial class ChannelConfigurationDialog : Form internal event EventHandler OnResizeZedGraph; internal event EventHandler OnDrawProbeGroup; - internal ProbeGroup ProbeGroup; + ProbeGroup probeGroup; + + internal ProbeGroup ProbeGroup + { + get => probeGroup; + set + { + probeGroup = value; + SelectedContacts = new bool[probeGroup.NumberOfContacts]; + } + } internal readonly List ReferenceContacts = new(); - internal readonly bool[] SelectedContacts = null; + internal bool[] SelectedContacts { get; private set; } = null; [Obsolete("Designer only.", true)] ChannelConfigurationDialog() @@ -49,8 +59,6 @@ public ChannelConfigurationDialog(ProbeGroup probeGroup) ProbeGroup = probeGroup; } - SelectedContacts = new bool[ProbeGroup.NumberOfContacts]; - ReferenceContacts = new List(); zedGraphChannels.MouseDownEvent += MouseDownEvent; @@ -288,8 +296,6 @@ internal virtual bool OpenFile() where T : ProbeGroup newConfiguration.Validate(); ProbeGroup = newConfiguration; - DrawProbeGroup(); - RefreshZedGraph(); return true; } @@ -1013,6 +1019,8 @@ private void MenuItemOpenFile(object sender, EventArgs e) if (OpenFile()) { DrawProbeGroup(); + ResetZoom(); + UpdateFontSize(); RefreshZedGraph(); } } @@ -1021,6 +1029,7 @@ private void MenuItemLoadDefaultConfig(object sender, EventArgs e) { LoadDefaultChannelLayout(); DrawProbeGroup(); + ResetZoom(); UpdateFontSize(); RefreshZedGraph(); } diff --git a/OpenEphys.Onix1.Design/NeuropixelsV2eChannelConfigurationDialog.cs b/OpenEphys.Onix1.Design/NeuropixelsV2eChannelConfigurationDialog.cs index 32d2cd81..fe6e0d09 100644 --- a/OpenEphys.Onix1.Design/NeuropixelsV2eChannelConfigurationDialog.cs +++ b/OpenEphys.Onix1.Design/NeuropixelsV2eChannelConfigurationDialog.cs @@ -15,16 +15,16 @@ public partial class NeuropixelsV2eChannelConfigurationDialog : ChannelConfigura internal event EventHandler OnFileLoad; /// - /// Public object that is manipulated by + /// Public object that is manipulated by /// . /// - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfiguration; + public NeuropixelsV2ProbeConfiguration ProbeConfiguration; /// /// Initializes a new instance of . /// - /// A object holding the current configuration settings. - public NeuropixelsV2eChannelConfigurationDialog(NeuropixelsV2QuadShankProbeConfiguration probeConfiguration) + /// A object holding the current configuration settings. + public NeuropixelsV2eChannelConfigurationDialog(NeuropixelsV2ProbeConfiguration probeConfiguration) : base(probeConfiguration.ProbeGroup) { zedGraphChannels.ZoomButtons = MouseButtons.None; @@ -32,7 +32,7 @@ public NeuropixelsV2eChannelConfigurationDialog(NeuropixelsV2QuadShankProbeConfi zedGraphChannels.ZoomStepFraction = 0.5; - ProbeConfiguration = probeConfiguration; + ProbeConfiguration = new(probeConfiguration); HighlightEnabledContacts(); UpdateContactLabels(); @@ -42,13 +42,16 @@ public NeuropixelsV2eChannelConfigurationDialog(NeuropixelsV2QuadShankProbeConfi internal override ProbeGroup DefaultChannelLayout() { - return new NeuropixelsV2eProbeGroup(); + return new NeuropixelsV2eProbeGroup(ProbeConfiguration.ProbeType); } internal override void LoadDefaultChannelLayout() { - ProbeConfiguration = new(ProbeConfiguration.Probe, ProbeConfiguration.Reference); - ProbeGroup = ProbeConfiguration.ProbeGroup; + base.LoadDefaultChannelLayout(); + ProbeConfiguration = new((NeuropixelsV2eProbeGroup)ProbeGroup, + ProbeConfiguration.Probe, + ProbeConfiguration.ProbeType, + ProbeConfiguration.Reference); OnFileOpenHandler(); } @@ -57,8 +60,6 @@ internal override bool OpenFile() { if (base.OpenFile()) { - ProbeConfiguration = new((NeuropixelsV2eProbeGroup)ProbeGroup, ProbeConfiguration.Reference, ProbeConfiguration.Probe); - OnFileOpenHandler(); return true; @@ -106,7 +107,7 @@ internal override void DrawScale() internal override void HighlightEnabledContacts() { - if (ProbeConfiguration == null || ProbeConfiguration.ChannelMap == null) + if (ProbeConfiguration == null) return; var contactObjects = zedGraphChannels.GraphPane.GraphObjList.OfType() @@ -119,11 +120,13 @@ internal override void HighlightEnabledContacts() contact.Fill.Color = DisabledContactFill; } + var channelMap = ProbeConfiguration.ChannelMap; + var contactsToEnable = contactObjects.Where(c => { var tag = c.Tag as ContactTag; - var channel = NeuropixelsV2QuadShankElectrode.GetChannelNumber(tag.ContactIndex); - return ProbeConfiguration.ChannelMap[channel].Index == tag.ContactIndex; + var channel = NeuropixelsV2Electrode.GetChannelNumber(tag.ContactIndex, ProbeConfiguration.ProbeType); + return channelMap[channel].Index == tag.ContactIndex; }); foreach (var contact in contactsToEnable) @@ -149,11 +152,13 @@ internal override void UpdateContactLabels() textObj.FontSpec.FontColor = DisabledContactTextColor; } + var channelMap = ProbeConfiguration.ChannelMap; + textObjsToUpdate = textObjs.Where(c => { var tag = c.Tag as ContactTag; - var channel = NeuropixelsV2QuadShankElectrode.GetChannelNumber(tag.ContactIndex); - return ProbeConfiguration.ChannelMap[channel].Index == tag.ContactIndex; + var channel = NeuropixelsV2Electrode.GetChannelNumber(tag.ContactIndex, ProbeConfiguration.ProbeType); + return channelMap[channel].Index == tag.ContactIndex; }); foreach (var textObj in textObjsToUpdate) @@ -167,7 +172,7 @@ internal override string ContactString(int deviceChannelIndex, int index) return index.ToString(); } - internal void EnableElectrodes(NeuropixelsV2QuadShankElectrode[] electrodes) + internal void EnableElectrodes(NeuropixelsV2Electrode[] electrodes) { ProbeConfiguration.SelectElectrodes(electrodes); } diff --git a/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationDialog.cs b/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationDialog.cs index 045fff35..2188fab5 100644 --- a/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationDialog.cs +++ b/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationDialog.cs @@ -1,21 +1,25 @@ using System; -using System.Linq; -using System.Windows.Forms; +using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using System.IO; +using System.Linq; +using System.Windows.Forms; namespace OpenEphys.Onix1.Design { /// - /// Partial class to create a GUI for . + /// Partial class to create a GUI for . /// public partial class NeuropixelsV2eProbeConfigurationDialog : Form { + const int BankDStartIndex = 896; + readonly NeuropixelsV2eChannelConfigurationDialog ChannelConfiguration; internal event EventHandler InvertPolarityChanged; - private enum ChannelPreset + enum QuadShankChannelPreset { Shank0BankA, Shank0BankB, @@ -50,30 +54,31 @@ private enum ChannelPreset } /// - /// Public object that is manipulated by - /// . + /// Public object that is manipulated by + /// . /// - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfiguration { get; set; } + public NeuropixelsV2ProbeConfiguration ProbeConfiguration + { + get => ChannelConfiguration.ProbeConfiguration; + } /// public bool InvertPolarity { get; set; } /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - /// A object holding the current configuration settings. + /// A object holding the current configuration settings. /// String containing the path to the calibration file for this probe. /// Boolean denoting whether or not to invert the polarity of neural data. - public NeuropixelsV2eProbeConfigurationDialog(NeuropixelsV2QuadShankProbeConfiguration configuration, string calibrationFile, bool invertPolarity) + public NeuropixelsV2eProbeConfigurationDialog(NeuropixelsV2ProbeConfiguration configuration, string calibrationFile, bool invertPolarity) { InitializeComponent(); Shown += FormShown; - ProbeConfiguration = new(configuration); - textBoxProbeCalibrationFile.Text = calibrationFile; - ChannelConfiguration = new(ProbeConfiguration) + ChannelConfiguration = new(configuration) { TopLevel = false, FormBorderStyle = FormBorderStyle.None, @@ -89,11 +94,11 @@ public NeuropixelsV2eProbeConfigurationDialog(NeuropixelsV2QuadShankProbeConfigu ChannelConfiguration.OnZoom += UpdateTrackBarLocation; ChannelConfiguration.OnFileLoad += OnFileLoadEvent; - comboBoxReference.DataSource = Enum.GetValues(typeof(NeuropixelsV2QuadShankReference)); + comboBoxReference.DataSource = Enum.GetValues(typeof(NeuropixelsV2ShankReference)); comboBoxReference.SelectedItem = ProbeConfiguration.Reference; comboBoxReference.SelectedIndexChanged += SelectedReferenceChanged; - comboBoxChannelPresets.DataSource = Enum.GetValues(typeof(ChannelPreset)); + comboBoxChannelPresets.DataSource = GetComboBoxChannelPresets(ProbeConfiguration.ProbeType); comboBoxChannelPresets.SelectedIndexChanged += SelectedChannelPresetChanged; checkBoxInvertPolarity.Checked = InvertPolarity; @@ -106,6 +111,15 @@ public NeuropixelsV2eProbeConfigurationDialog(NeuropixelsV2QuadShankProbeConfigu Text += ": " + ProbeConfiguration.Probe.ToString(); } + static Array GetComboBoxChannelPresets(NeuropixelsV2ProbeType probeType) + { + return probeType switch + { + NeuropixelsV2ProbeType.QuadShank => Enum.GetValues(typeof(QuadShankChannelPreset)), + _ => throw new InvalidEnumArgumentException(nameof(NeuropixelsV2ProbeType)) + }; + } + private void InvertPolarityIndexChanged(object sender, EventArgs e) { InvertPolarity = ((CheckBox)sender).Checked; @@ -142,390 +156,402 @@ private void FormShown(object sender, EventArgs e) private void SelectedReferenceChanged(object sender, EventArgs e) { - ProbeConfiguration.Reference = (NeuropixelsV2QuadShankReference)((ComboBox)sender).SelectedItem; + ProbeConfiguration.Reference = (NeuropixelsV2ShankReference)((ComboBox)sender).SelectedItem; } private void SelectedChannelPresetChanged(object sender, EventArgs e) { - var channelPreset = (ChannelPreset)((ComboBox)sender).SelectedItem; - - if (channelPreset != ChannelPreset.None) + switch (ProbeConfiguration.ProbeType) { - SetChannelPreset(channelPreset); + case NeuropixelsV2ProbeType.QuadShank: + SetQuadShankChannelPreset((QuadShankChannelPreset)((ComboBox)sender).SelectedItem); + break; + default: + throw new NotSupportedException($"Unknown probe configuration found."); } + + ChannelConfiguration.HighlightEnabledContacts(); + ChannelConfiguration.HighlightSelectedContacts(); + ChannelConfiguration.UpdateContactLabels(); + ChannelConfiguration.RefreshZedGraph(); } - private void SetChannelPreset(ChannelPreset preset) + void SetQuadShankChannelPreset(QuadShankChannelPreset preset) { - var probeConfiguration = ChannelConfiguration.ProbeConfiguration; - var electrodes = NeuropixelsV2eProbeGroup.ToElectrodes(ChannelConfiguration.ProbeConfiguration.ProbeGroup); + var electrodes = NeuropixelsV2eProbeGroup.ToElectrodes(ProbeConfiguration.ProbeGroup, NeuropixelsV2ProbeType.QuadShank); switch (preset) { - case ChannelPreset.Shank0BankA: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.A && + case QuadShankChannelPreset.Shank0BankA: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 0).ToArray()); break; - case ChannelPreset.Shank0BankB: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.B && + case QuadShankChannelPreset.Shank0BankB: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 0).ToArray()); break; - case ChannelPreset.Shank0BankC: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.C && + case QuadShankChannelPreset.Shank0BankC: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 0).ToArray()); break; - case ChannelPreset.Shank0BankD: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && + case QuadShankChannelPreset.Shank0BankD: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || + (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 0).ToArray()); break; - case ChannelPreset.Shank1BankA: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.A && + case QuadShankChannelPreset.Shank1BankA: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 1).ToArray()); break; - case ChannelPreset.Shank1BankB: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.B && + case QuadShankChannelPreset.Shank1BankB: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 1).ToArray()); break; - case ChannelPreset.Shank1BankC: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.C && - e.Shank == 1).ToArray()); + case QuadShankChannelPreset.Shank1BankC: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && + e.Shank == 1).ToArray()); break; - case ChannelPreset.Shank1BankD: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && + case QuadShankChannelPreset.Shank1BankD: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || + (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 1).ToArray()); break; - case ChannelPreset.Shank2BankA: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.A && + case QuadShankChannelPreset.Shank2BankA: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 2).ToArray()); break; - case ChannelPreset.Shank2BankB: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.B && + case QuadShankChannelPreset.Shank2BankB: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 2).ToArray()); break; - case ChannelPreset.Shank2BankC: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.C && - e.Shank == 2).ToArray()); + case QuadShankChannelPreset.Shank2BankC: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && + e.Shank == 2).ToArray()); break; - case ChannelPreset.Shank2BankD: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && + case QuadShankChannelPreset.Shank2BankD: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || + (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 2).ToArray()); break; - case ChannelPreset.Shank3BankA: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.A && + case QuadShankChannelPreset.Shank3BankA: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 3).ToArray()); break; - case ChannelPreset.Shank3BankB: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.B && + case QuadShankChannelPreset.Shank3BankB: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 3).ToArray()); break; - case ChannelPreset.Shank3BankC: - probeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2QuadShankBank.C && - e.Shank == 3).ToArray()); + case QuadShankChannelPreset.Shank3BankC: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && + e.Shank == 3).ToArray()); break; - case ChannelPreset.Shank3BankD: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && + case QuadShankChannelPreset.Shank3BankD: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || + (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 3).ToArray()); break; - case ChannelPreset.AllShanks0_95: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95) || + case QuadShankChannelPreset.AllShanks0_95: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95)).ToArray()); break; - case ChannelPreset.AllShanks96_191: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 96 && e.IntraShankElectrodeIndex <= 191) || + case QuadShankChannelPreset.AllShanks96_191: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 96 && e.IntraShankElectrodeIndex <= 191) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 96 && e.IntraShankElectrodeIndex <= 191) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 96 && e.IntraShankElectrodeIndex <= 191) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 96 && e.IntraShankElectrodeIndex <= 191)).ToArray()); break; - case ChannelPreset.AllShanks192_287: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287) || + case QuadShankChannelPreset.AllShanks192_287: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287)).ToArray()); break; - case ChannelPreset.AllShanks288_383: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383) || + case QuadShankChannelPreset.AllShanks288_383: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383)).ToArray()); break; - case ChannelPreset.AllShanks384_479: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 384 && e.IntraShankElectrodeIndex <= 479) || + case QuadShankChannelPreset.AllShanks384_479: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 384 && e.IntraShankElectrodeIndex <= 479) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 384 && e.IntraShankElectrodeIndex <= 479) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 384 && e.IntraShankElectrodeIndex <= 479) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 384 && e.IntraShankElectrodeIndex <= 479)).ToArray()); break; - case ChannelPreset.AllShanks480_575: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575) || + case QuadShankChannelPreset.AllShanks480_575: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575)).ToArray()); break; - case ChannelPreset.AllShanks576_671: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671) || + case QuadShankChannelPreset.AllShanks576_671: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671)).ToArray()); break; - case ChannelPreset.AllShanks672_767: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767) || + case QuadShankChannelPreset.AllShanks672_767: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767)).ToArray()); break; - case ChannelPreset.AllShanks768_863: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863) || + case QuadShankChannelPreset.AllShanks768_863: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863)).ToArray()); break; - case ChannelPreset.AllShanks864_959: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959) || + case QuadShankChannelPreset.AllShanks864_959: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959)).ToArray()); break; - case ChannelPreset.AllShanks960_1055: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055) || + case QuadShankChannelPreset.AllShanks960_1055: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055)).ToArray()); break; - case ChannelPreset.AllShanks1056_1151: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151) || + case QuadShankChannelPreset.AllShanks1056_1151: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151)).ToArray()); break; - case ChannelPreset.AllShanks1152_1247: - probeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247) || + case QuadShankChannelPreset.AllShanks1152_1247: + ProbeConfiguration.SelectElectrodes(electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247)).ToArray()); break; } - - ChannelConfiguration.HighlightEnabledContacts(); - ChannelConfiguration.HighlightSelectedContacts(); - ChannelConfiguration.UpdateContactLabels(); - ChannelConfiguration.RefreshZedGraph(); } - private void CheckForExistingChannelPreset() + void CheckForExistingChannelPreset() { - var channelMap = ChannelConfiguration.ProbeConfiguration.ChannelMap; + switch (ProbeConfiguration.ProbeType) + { + case NeuropixelsV2ProbeType.QuadShank: + CheckQuadShankForChannelPreset(ProbeConfiguration.ChannelMap); break; + default: + throw new NotSupportedException($"Unknown probe configuration found."); + } + } - if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.A && + void CheckQuadShankForChannelPreset(NeuropixelsV2Electrode[] channelMap) + { + if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 0)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank0BankA; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank0BankA; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.B && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 0)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank0BankB; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank0BankB; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.C && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 0)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank0BankC; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank0BankC; } - else if (channelMap.All(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && - e.Shank == 0)) + else if (channelMap.All(e => (e.Bank == NeuropixelsV2Bank.D + || (e.Bank == NeuropixelsV2Bank.C + && e.IntraShankElectrodeIndex >= BankDStartIndex)) + && e.Shank == 0)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank0BankD; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank0BankD; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.A && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 1)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank1BankA; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank1BankA; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.B && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 1)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank1BankB; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank1BankB; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.C && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 1)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank1BankC; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank1BankC; } - else if (channelMap.All(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && - e.Shank == 1)) + else if (channelMap.All(e => (e.Bank == NeuropixelsV2Bank.D + || (e.Bank == NeuropixelsV2Bank.C + && e.IntraShankElectrodeIndex >= BankDStartIndex)) + && e.Shank == 1)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank1BankD; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank1BankD; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.A && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 2)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank2BankA; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank2BankA; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.B && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 2)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank2BankB; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank2BankB; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.C && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 2)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank2BankC; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank2BankC; } - else if (channelMap.All(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && - e.Shank == 2)) + else if (channelMap.All(e => (e.Bank == NeuropixelsV2Bank.D + || (e.Bank == NeuropixelsV2Bank.C + && e.IntraShankElectrodeIndex >= BankDStartIndex)) + && e.Shank == 2)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank2BankD; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank2BankD; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.A && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 3)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank3BankA; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank3BankA; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.B && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 3)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank3BankB; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank3BankB; } - else if (channelMap.All(e => e.Bank == NeuropixelsV2QuadShankBank.C && + else if (channelMap.All(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 3)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank3BankC; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank3BankC; } - else if (channelMap.All(e => (e.Bank == NeuropixelsV2QuadShankBank.D || - (e.Bank == NeuropixelsV2QuadShankBank.C && e.Index >= 896)) && - e.Shank == 3)) + else if (channelMap.All(e => (e.Bank == NeuropixelsV2Bank.D + || (e.Bank == NeuropixelsV2Bank.C + && e.IntraShankElectrodeIndex >= BankDStartIndex)) + && e.Shank == 3)) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.Shank3BankD; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.Shank3BankD; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 0 && e.IntraShankElectrodeIndex <= 95))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks0_95; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks0_95; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 192 && e.IntraShankElectrodeIndex <= 287))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks192_287; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks192_287; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 288 && e.IntraShankElectrodeIndex <= 383))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks288_383; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks288_383; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 394 && e.IntraShankElectrodeIndex <= 479) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 394 && e.IntraShankElectrodeIndex <= 479) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 394 && e.IntraShankElectrodeIndex <= 479) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 394 && e.IntraShankElectrodeIndex <= 479))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks384_479; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks384_479; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 480 && e.IntraShankElectrodeIndex <= 575))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks480_575; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks480_575; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 576 && e.IntraShankElectrodeIndex <= 671))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks576_671; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks576_671; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 672 && e.IntraShankElectrodeIndex <= 767))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks672_767; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks672_767; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 768 && e.IntraShankElectrodeIndex <= 863))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks768_863; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks768_863; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 864 && e.IntraShankElectrodeIndex <= 959))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks864_959; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks864_959; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 960 && e.IntraShankElectrodeIndex <= 1055))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks960_1055; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks960_1055; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 1056 && e.IntraShankElectrodeIndex <= 1151))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks1056_1151; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks1056_1151; } else if (channelMap.All(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247) || (e.Shank == 1 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247) || (e.Shank == 2 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247) || (e.Shank == 3 && e.IntraShankElectrodeIndex >= 1152 && e.IntraShankElectrodeIndex <= 1247))) { - comboBoxChannelPresets.SelectedItem = ChannelPreset.AllShanks1152_1247; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.AllShanks1152_1247; } else { - comboBoxChannelPresets.SelectedItem = ChannelPreset.None; + comboBoxChannelPresets.SelectedItem = QuadShankChannelPreset.None; } } private void OnFileLoadEvent(object sender, EventArgs e) { - // NB: Ensure that the newly loaded ProbeConfiguration in the ChannelConfigurationDialog is reflected here. - ProbeConfiguration = ChannelConfiguration.ProbeConfiguration; CheckForExistingChannelPreset(); } @@ -607,9 +633,10 @@ internal void EnableContacts_Click(object sender, EventArgs e) private void EnableSelectedContacts() { - var selected = NeuropixelsV2eProbeGroup.ToElectrodes(ChannelConfiguration.ProbeConfiguration.ProbeGroup) - .Where((e, ind) => ChannelConfiguration.SelectedContacts[ind]) - .ToArray(); + var selected = NeuropixelsV2eProbeGroup + .ToElectrodes(ProbeConfiguration.ProbeGroup, ProbeConfiguration.ProbeType) + .Where((e, ind) => ChannelConfiguration.SelectedContacts[ind]) + .ToArray(); ChannelConfiguration.EnableElectrodes(selected); diff --git a/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationEditor.cs b/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationEditor.cs index db034bf6..e613d2c2 100644 --- a/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationEditor.cs +++ b/OpenEphys.Onix1.Design/NeuropixelsV2eProbeConfigurationEditor.cs @@ -8,7 +8,7 @@ namespace OpenEphys.Onix1.Design { /// - /// Class that opens a new dialog for a . + /// Class that opens a new dialog for a . /// public class NeuropixelsV2eProbeConfigurationEditor : UITypeEditor { @@ -27,15 +27,17 @@ public override object EditValue(ITypeDescriptorContext context, IServiceProvide var editorState = (IWorkflowEditorState)provider.GetService(typeof(IWorkflowEditorState)); if (editorService != null && editorState != null && !editorState.WorkflowRunning && - value is NeuropixelsV2QuadShankProbeConfiguration configuration) + value is NeuropixelsV2ProbeConfiguration configuration) { var instance = (IConfigureNeuropixelsV2)context.Instance; var calibrationFile = configuration.Probe == NeuropixelsV2Probe.ProbeA ? instance.GainCalibrationFileA : instance.GainCalibrationFileB; + bool isBeta = instance is ConfigureNeuropixelsV2eBeta; + using var editorDialog = new NeuropixelsV2eProbeConfigurationDialog(configuration, calibrationFile, instance.InvertPolarity); - if (instance is ConfigureNeuropixelsV2eBeta) + if (isBeta) { editorDialog.Text = editorDialog.Text.Replace("NeuropixelsV2e ", "NeuropixelsV2eBeta "); } diff --git a/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs b/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs index 4855b0b0..9e5318fe 100644 --- a/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs +++ b/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs @@ -56,7 +56,7 @@ public ConfigureNeuropixelsV2e(ConfigureNeuropixelsV2e configureNode) [Category(ConfigurationCategory)] [Description("Probe A configuration.")] [Editor("OpenEphys.Onix1.Design.NeuropixelsV2eProbeConfigurationEditor, OpenEphys.Onix1.Design", typeof(UITypeEditor))] - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfigurationA { get; set; } = new(NeuropixelsV2Probe.ProbeA); + public NeuropixelsV2ProbeConfiguration ProbeConfigurationA { get; set; } = new(NeuropixelsV2Probe.ProbeA, NeuropixelsV2ProbeType.QuadShank, NeuropixelsV2ShankReference.External); /// [Category(ConfigurationCategory)] @@ -69,7 +69,7 @@ public ConfigureNeuropixelsV2e(ConfigureNeuropixelsV2e configureNode) [Category(ConfigurationCategory)] [Description("Probe B configuration.")] [Editor("OpenEphys.Onix1.Design.NeuropixelsV2eProbeConfigurationEditor, OpenEphys.Onix1.Design", typeof(UITypeEditor))] - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfigurationB { get; set; } = new(NeuropixelsV2Probe.ProbeB); + public NeuropixelsV2ProbeConfiguration ProbeConfigurationB { get; set; } = new(NeuropixelsV2Probe.ProbeB, NeuropixelsV2ProbeType.QuadShank, NeuropixelsV2ShankReference.External); /// [Category(ConfigurationCategory)] @@ -109,7 +109,7 @@ public override IObservable Process(IObservable source // set I2C clock rate to ~400 kHz DS90UB9x.Set933I2CRate(device, 400e3); - + // read probe metadata var probeAMetadata = ReadProbeMetadata(serializer, NeuropixelsV2e.ProbeASelected); var probeBMetadata = ReadProbeMetadata(serializer, NeuropixelsV2e.ProbeBSelected); diff --git a/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs b/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs index a3c0a009..a90a26bf 100644 --- a/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs +++ b/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs @@ -71,7 +71,7 @@ public ConfigureNeuropixelsV2eBeta(ConfigureNeuropixelsV2eBeta configureNode) [Category(ConfigurationCategory)] [Description("Probe A configuration.")] [Editor("OpenEphys.Onix1.Design.NeuropixelsV2eProbeConfigurationEditor, OpenEphys.Onix1.Design", typeof(UITypeEditor))] - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfigurationA { get; set; } = new(NeuropixelsV2Probe.ProbeA); + public NeuropixelsV2ProbeConfiguration ProbeConfigurationA { get; set; } = new(NeuropixelsV2Probe.ProbeA, NeuropixelsV2ProbeType.QuadShank, NeuropixelsV2ShankReference.External); /// [Category(ConfigurationCategory)] @@ -84,7 +84,7 @@ public ConfigureNeuropixelsV2eBeta(ConfigureNeuropixelsV2eBeta configureNode) [Category(ConfigurationCategory)] [Description("Probe B configuration.")] [Editor("OpenEphys.Onix1.Design.NeuropixelsV2eProbeConfigurationEditor, OpenEphys.Onix1.Design", typeof(UITypeEditor))] - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfigurationB { get; set; } = new(NeuropixelsV2Probe.ProbeB); + public NeuropixelsV2ProbeConfiguration ProbeConfigurationB { get; set; } = new(NeuropixelsV2Probe.ProbeB, NeuropixelsV2ProbeType.QuadShank, NeuropixelsV2ShankReference.External); /// [Category(ConfigurationCategory)] @@ -152,7 +152,7 @@ public override IObservable Process(IObservable source // configure probe A streaming if (probeAMetadata.ProbeSerialNumber != null) { - if (ProbeConfigurationA.Reference == NeuropixelsV2QuadShankReference.Ground) + if (ProbeConfigurationA.Reference == NeuropixelsV2ShankReference.Ground) { throw new InvalidOperationException($"Neuropixels 2.0-Beta probes do not provide a Ground reference selection. Please select a different reference" + $" for {NeuropixelsV2Probe.ProbeA}."); @@ -181,7 +181,7 @@ public override IObservable Process(IObservable source // configure probe B streaming if (probeBMetadata.ProbeSerialNumber != null) { - if (ProbeConfigurationB.Reference == NeuropixelsV2QuadShankReference.Ground) + if (ProbeConfigurationB.Reference == NeuropixelsV2ShankReference.Ground) { throw new InvalidOperationException($"Neuropixels 2.0-Beta probes do not provide a Ground reference selection. Please select a different reference" + $" for {NeuropixelsV2Probe.ProbeB}."); diff --git a/OpenEphys.Onix1/IConfigureNeuropixelsV2.cs b/OpenEphys.Onix1/IConfigureNeuropixelsV2.cs index 43e7e9f6..78e37091 100644 --- a/OpenEphys.Onix1/IConfigureNeuropixelsV2.cs +++ b/OpenEphys.Onix1/IConfigureNeuropixelsV2.cs @@ -13,7 +13,7 @@ public interface IConfigureNeuropixelsV2 /// /// Gets or sets the electrode configuration for Probe A. /// - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfigurationA { get; set; } + public NeuropixelsV2ProbeConfiguration ProbeConfigurationA { get; set; } /// /// Gets or sets the path to the gain calibration file for Probe A. @@ -35,7 +35,7 @@ public interface IConfigureNeuropixelsV2 /// /// Gets or sets the electrode configuration for Probe B. /// - public NeuropixelsV2QuadShankProbeConfiguration ProbeConfigurationB { get; set; } + public NeuropixelsV2ProbeConfiguration ProbeConfigurationB { get; set; } /// /// Gets or sets the path to the gain calibration file for Probe B. diff --git a/OpenEphys.Onix1/NeuropixelsV2.cs b/OpenEphys.Onix1/NeuropixelsV2.cs index b76db70d..85f92638 100644 --- a/OpenEphys.Onix1/NeuropixelsV2.cs +++ b/OpenEphys.Onix1/NeuropixelsV2.cs @@ -29,43 +29,66 @@ static class NeuropixelsV2 public const int ChannelCount = 384; public const int BaseBitsPerChannel = 4; public const int ElectrodePerShank = 1280; - public const int ElectrodePerBlock = 48; + public const int ElectrodePerBlockQuadShank = 48; public const int ReferencePixelCount = 4; public const int DummyRegisterCount = 4; public const int RegistersPerShank = ElectrodePerShank + ReferencePixelCount + DummyRegisterCount; - internal static BitArray[] GenerateShankBits(NeuropixelsV2QuadShankProbeConfiguration probe) + internal static BitArray[] GenerateShankBits(NeuropixelsV2ProbeConfiguration probe) { - BitArray[] shankBits = - { - new(RegistersPerShank, false), - new(RegistersPerShank, false), - new(RegistersPerShank, false), - new(RegistersPerShank, false) - }; + BitArray[] shankBits; + + const int ShiftRegisterBitExternalElectrode0 = 1285; + const int ShiftRegisterBitExternalElectrode1 = 2; + const int ShiftRegisterBitTipElectrode0 = 644; + const int ShiftRegisterBitTipElectrode1 = 643; - if (probe.Reference != NeuropixelsV2QuadShankReference.External) + if (probe.ProbeType == NeuropixelsV2ProbeType.QuadShank) { - // If tip reference is used, activate the tip electrodes - shankBits[(int)probe.Reference - 1][643] = true; - shankBits[(int)probe.Reference - 1][644] = true; + shankBits = new BitArray[] + { + new(RegistersPerShank, false), + new(RegistersPerShank, false), + new(RegistersPerShank, false), + new(RegistersPerShank, false) + }; + + if (probe.Reference != NeuropixelsV2ShankReference.External && probe.Reference != NeuropixelsV2ShankReference.Ground) + { + var shank = probe.Reference switch + { + NeuropixelsV2ShankReference.Tip1 => 0, + NeuropixelsV2ShankReference.Tip2 => 1, + NeuropixelsV2ShankReference.Tip3 => 2, + NeuropixelsV2ShankReference.Tip4 => 3, + _ => throw new InvalidOperationException($"Invalid reference chosen for {probe.ProbeType} probe.") + }; + + // If tip reference is used, activate the tip electrode + shankBits[shank][ShiftRegisterBitTipElectrode1] = true; + shankBits[shank][ShiftRegisterBitTipElectrode0] = true; + } + else if (probe.Reference == NeuropixelsV2ShankReference.External) + { + // TODO: is this the right approach or should only those + // connections to external reference on shanks with active + // electrodes be activated? + + // If external electrode is used, activate on each shank + shankBits[0][ShiftRegisterBitExternalElectrode1] = true; + shankBits[0][ShiftRegisterBitExternalElectrode0] = true; + shankBits[1][ShiftRegisterBitExternalElectrode1] = true; + shankBits[1][ShiftRegisterBitExternalElectrode0] = true; + shankBits[2][ShiftRegisterBitExternalElectrode1] = true; + shankBits[2][ShiftRegisterBitExternalElectrode0] = true; + shankBits[3][ShiftRegisterBitExternalElectrode1] = true; + shankBits[3][ShiftRegisterBitExternalElectrode0] = true; + } } else { - // TODO: is this the right approach or should only those - // connections to external reference on shanks with active - // electrodes be activated? - - // If external electrode is used, activate on each shank - shankBits[0][2] = true; - shankBits[0][1285] = true; - shankBits[1][2] = true; - shankBits[1][1285] = true; - shankBits[2][2] = true; - shankBits[2][1285] = true; - shankBits[3][2] = true; - shankBits[3][1285] = true; + throw new InvalidOperationException("Unknown probe configuration type given."); } const int PixelOffset = (ElectrodePerShank - 1) / 2; @@ -84,7 +107,7 @@ internal static BitArray[] GenerateShankBits(NeuropixelsV2QuadShankProbeConfigur return shankBits; } - internal static BitArray[] GenerateBaseBits(NeuropixelsV2QuadShankProbeConfiguration probe) + internal static BitArray[] GenerateBaseBits(NeuropixelsV2ProbeConfiguration probe) { BitArray[] baseBits = { @@ -92,15 +115,19 @@ internal static BitArray[] GenerateBaseBits(NeuropixelsV2QuadShankProbeConfigura new(ChannelCount * BaseBitsPerChannel / 2, false) }; - var referenceBit = probe.Reference switch + var referenceBit = probe.ProbeType switch { - NeuropixelsV2QuadShankReference.External => 1, - NeuropixelsV2QuadShankReference.Tip1 => 2, - NeuropixelsV2QuadShankReference.Tip2 => 2, - NeuropixelsV2QuadShankReference.Tip3 => 2, - NeuropixelsV2QuadShankReference.Tip4 => 2, - NeuropixelsV2QuadShankReference.Ground => 3, - _ => throw new InvalidOperationException("Invalid reference selection."), + NeuropixelsV2ProbeType.QuadShank => probe.Reference switch + { + NeuropixelsV2ShankReference.External => 1, + NeuropixelsV2ShankReference.Tip1 => 2, + NeuropixelsV2ShankReference.Tip2 => 2, + NeuropixelsV2ShankReference.Tip3 => 2, + NeuropixelsV2ShankReference.Tip4 => 2, + NeuropixelsV2ShankReference.Ground => 3, + _ => throw new InvalidOperationException("Invalid reference selection."), + }, + _ => throw new InvalidOperationException("Invalid probe type given.") }; for (int i = 0; i < ChannelCount; i++) diff --git a/OpenEphys.Onix1/NeuropixelsV2Electrode.cs b/OpenEphys.Onix1/NeuropixelsV2Electrode.cs new file mode 100644 index 00000000..04750df3 --- /dev/null +++ b/OpenEphys.Onix1/NeuropixelsV2Electrode.cs @@ -0,0 +1,146 @@ +using System; +using System.Drawing; +using System.Xml.Serialization; + +namespace OpenEphys.Onix1 +{ + /// + /// Class defining a . + /// + public class NeuropixelsV2Electrode : Electrode + { + /// + /// Gets the bank, or logical block of channels, this electrode belongs to. + /// + [XmlIgnore] + public NeuropixelsV2Bank Bank { get; private set; } + + /// + /// Gets the block this electrode belongs to. + /// + [XmlIgnore] + public int Block { get; private set; } + + /// + /// Gets the index within the block this electrode belongs to. + /// + [XmlIgnore] + public int BlockIndex { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// Integer defining the index of the contact. + /// Probe type that this electrode is a part of. + public NeuropixelsV2Electrode(int index, NeuropixelsV2ProbeType probeType) + { + Index = index; + Shank = GetShank(index); + IntraShankElectrodeIndex = GetIntraShankIndex(index); + Bank = GetBank(index); + Block = GetBlock(index, probeType); + BlockIndex = GetBlockIndex(index, probeType); + Position = GetPosition(index); + + if (probeType == NeuropixelsV2ProbeType.QuadShank) + { + Channel = GetQuadShankChannelNumber(Shank, Block, BlockIndex); + } + else + throw new InvalidOperationException("Unknown probe type given."); + } + + private PointF GetPosition(int electrodeNumber) + { + var position = NeuropixelsV2eProbeGroup.DefaultContactPosition(electrodeNumber); + return new PointF(x: position[0], y: position[1]); + } + + static NeuropixelsV2Bank GetBank(int index) => (NeuropixelsV2Bank)(GetIntraShankIndex(index) / NeuropixelsV2.ChannelCount); + + internal static int GetShank(int index) => index / NeuropixelsV2.ElectrodePerShank; + + internal static int GetIntraShankIndex(int index) => index % NeuropixelsV2.ElectrodePerShank; + + static int GetBlock(int index, NeuropixelsV2ProbeType probeType) + { + if (probeType == NeuropixelsV2ProbeType.QuadShank) + return (GetIntraShankIndex(index) % NeuropixelsV2.ChannelCount) / NeuropixelsV2.ElectrodePerBlockQuadShank; + + else + throw new InvalidOperationException("Invalid probe type given."); + } + + const int ElectrodesPerRow = 2; + + static int GetBlockIndex(int index, NeuropixelsV2ProbeType probeType) + { + if (probeType == NeuropixelsV2ProbeType.QuadShank) + return GetIntraShankIndex(index) % NeuropixelsV2.ElectrodePerBlockQuadShank; + + else + throw new InvalidOperationException("Invalid probe type given."); + } + + /// + /// Static method returning the channel number of a given electrode. + /// + /// Integer defining the index of the electrode in the probe. + /// Probe type that this electrode is a part of. + /// An integer between 0 and 383 defining the channel number. + public static int GetChannelNumber(int electrodeIndex, NeuropixelsV2ProbeType probeType) + { + if (probeType == NeuropixelsV2ProbeType.QuadShank) + { + var shank = GetShank(electrodeIndex); + var block = GetBlock(electrodeIndex, probeType); + var blockIndex = GetBlockIndex(electrodeIndex, probeType); + + return GetQuadShankChannelNumber(shank, block, blockIndex); + } + else + throw new InvalidOperationException("Unknown probe type given."); + } + + internal static int GetQuadShankChannelNumber(int shank, int block, int blockIndex) => (shank, block) switch + { + (0, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 0, + (0, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 2, + (0, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 4, + (0, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 6, + (0, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 5, + (0, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 7, + (0, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 1, + (0, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 3, + + (1, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 1, + (1, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 3, + (1, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 5, + (1, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 7, + (1, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 4, + (1, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 6, + (1, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 0, + (1, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 2, + + (2, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 4, + (2, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 6, + (2, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 0, + (2, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 2, + (2, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 1, + (2, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 3, + (2, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 5, + (2, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 7, + + (3, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 5, + (3, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 7, + (3, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 1, + (3, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 3, + (3, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 0, + (3, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 2, + (3, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 4, + (3, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlockQuadShank * 6, + + _ => throw new ArgumentOutOfRangeException($"Invalid shank and/or electrode value: {(shank, block)}"), + }; + } +} diff --git a/OpenEphys.Onix1/NeuropixelsV2ProbeConfiguration.cs b/OpenEphys.Onix1/NeuropixelsV2ProbeConfiguration.cs new file mode 100644 index 00000000..dbc91538 --- /dev/null +++ b/OpenEphys.Onix1/NeuropixelsV2ProbeConfiguration.cs @@ -0,0 +1,223 @@ +using System; +using System.ComponentModel; +using System.Text; +using System.Xml.Serialization; +using Bonsai; +using Newtonsoft.Json; + +namespace OpenEphys.Onix1 +{ + /// + /// Specifies the reference for a Neuropixels 2.0 probe. + /// + public enum NeuropixelsV2ShankReference : uint + { + /// + /// Specifies that the External reference will be used. + /// + External, + /// + /// Specifies that the tip reference of shank 1 will be used. + /// + Tip1, + /// + /// Specifies that the tip reference of shank 2 will be used. + /// + Tip2, + /// + /// Specifies that the tip reference of shank 3 will be used. + /// + Tip3, + /// + /// Specifies that the tip reference of shank 4 will be used. + /// + Tip4, + /// + /// Specifies that the Ground reference will be used. + /// + Ground + } + + /// + /// Specifies the bank of electrodes within each shank. + /// + public enum NeuropixelsV2Bank + { + /// + /// Specifies that Bank A is the current bank. + /// + /// Bank A is defined as shank index 0 to 383 along each shank. + A, + /// + /// Specifies that Bank B is the current bank. + /// + /// Bank B is defined as shank index 384 to 767 along each shank. + B, + /// + /// Specifies that Bank C is the current bank. + /// + /// Bank C is defined as shank index 768 to 1151 along each shank. + C, + /// + /// Specifies that Bank D is the current bank. + /// + /// + /// Bank D is defined as shank index 1152 to 1279 along each shank. Note that Bank D is not a full contingent + /// of 384 channels; to compensate for this, electrodes from Bank C (starting at shank index 896) are used to + /// generate a full 384 channel map. + /// + D, + } + + /// + /// Specifies the current probe type. + /// + public enum NeuropixelsV2ProbeType + { + /// + /// Specifies that there are four shanks. + /// + QuadShank = 0, + } + + /// + /// Defines a configuration for Neuropixels 2.0 and 2.0-beta probes. + /// + public class NeuropixelsV2ProbeConfiguration + { + private NeuropixelsV2ProbeConfiguration() + { + } + + /// + /// Initializes a new instance of the class. + /// + public NeuropixelsV2ProbeConfiguration(NeuropixelsV2Probe probe, NeuropixelsV2ProbeType type, NeuropixelsV2ShankReference reference) + { + Probe = probe; + ProbeType = type; + Reference = reference; + ProbeGroup = new(ProbeType); + } + + /// + /// Copy constructor for the class. + /// + /// The existing object to copy. + public NeuropixelsV2ProbeConfiguration(NeuropixelsV2ProbeConfiguration probeConfiguration) + { + ProbeType = probeConfiguration.ProbeType; + Reference = probeConfiguration.Reference; + ProbeGroup = probeConfiguration.ProbeGroup.Clone(); + Probe = probeConfiguration.Probe; + } + + /// + /// Initializes a new instance of the class with the given + /// channel configuration. The is automatically + /// generated from the . + /// + /// The existing instance to use. + /// The reference value. + /// The for this probe. + /// The for this probe. + [JsonConstructor] + public NeuropixelsV2ProbeConfiguration(NeuropixelsV2eProbeGroup probeGroup, NeuropixelsV2Probe probe, NeuropixelsV2ProbeType type, NeuropixelsV2ShankReference reference) + { + ProbeType = type; + ProbeGroup = probeGroup.Clone(); + Reference = reference; + Probe = probe; + } + + /// + /// Gets or sets the for this probe. + /// + [Browsable(false)] + public NeuropixelsV2Probe Probe { get; set; } = NeuropixelsV2Probe.ProbeA; + + /// + /// Gets or sets the for this probe. + /// + [Browsable(false)] + [Description("Defines the type of probe, differentiated by the number of shanks present.")] + public NeuropixelsV2ProbeType ProbeType { get; set; } = NeuropixelsV2ProbeType.QuadShank; + + /// + /// Gets or sets the reference for all electrodes. + /// + /// + /// All electrodes are set to the same reference, which can be + /// or any of the tip references + /// (, , etc.). + /// Setting to will use the external reference, while + /// sets the reference to the electrode at the tip of the first shank. + /// + [Description("Defines what the reference for the probe will be, whether it is external, on a shank tip, or the ground reference.")] + public NeuropixelsV2ShankReference Reference { get; set; } = NeuropixelsV2ShankReference.External; + + /// + /// Gets the existing channel map listing all currently enabled electrodes. + /// + /// + /// The channel map will always be 384 channels, and will return the 384 enabled electrodes. + /// + [XmlIgnore] + public NeuropixelsV2Electrode[] ChannelMap { get => NeuropixelsV2eProbeGroup.ToChannelMap(ProbeGroup, ProbeType); } + + /// + /// Update the with the selected electrodes. + /// + /// List of selected electrodes that are being added to the + public void SelectElectrodes(NeuropixelsV2Electrode[] electrodes) + { + var channelMap = ChannelMap; + + foreach (var e in electrodes) + { + try + { + channelMap[e.Channel] = e; + } + catch (IndexOutOfRangeException ex) + { + throw new IndexOutOfRangeException($"Electrode {e.Index} specifies channel {e.Channel} but only channels " + + $"0 to {channelMap.Length - 1} are supported.", ex); + } + } + + ProbeGroup.UpdateDeviceChannelIndices(channelMap); + } + + /// + /// Gets the channel configuration for this probe. + /// + [XmlIgnore] + [Category("Configuration")] + [Description("Defines the shape of the probe, and which contacts are currently selected for streaming")] + public NeuropixelsV2eProbeGroup ProbeGroup { get; private set; } = new(NeuropixelsV2ProbeType.QuadShank); + + /// + /// Gets or sets a string defining the in Base64. + /// This variable is needed to properly save a workflow in Bonsai, but it is not + /// directly accessible in the Bonsai editor. + /// + [Browsable(false)] + [Externalizable(false)] + [XmlElement(nameof(ProbeGroup))] + public string ProbeGroupString + { + get + { + var jsonString = JsonConvert.SerializeObject(ProbeGroup); + return Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonString)); + } + set + { + var jsonString = Encoding.UTF8.GetString(Convert.FromBase64String(value)); + ProbeGroup = JsonConvert.DeserializeObject(jsonString); + SelectElectrodes(NeuropixelsV2eProbeGroup.ToChannelMap(ProbeGroup, ProbeType)); + } + } + } +} diff --git a/OpenEphys.Onix1/NeuropixelsV2QuadShankElectrode.cs b/OpenEphys.Onix1/NeuropixelsV2QuadShankElectrode.cs index a24c01e9..226d55da 100644 --- a/OpenEphys.Onix1/NeuropixelsV2QuadShankElectrode.cs +++ b/OpenEphys.Onix1/NeuropixelsV2QuadShankElectrode.cs @@ -1,108 +1,17 @@ using System; -using System.Drawing; -using System.Xml.Serialization; namespace OpenEphys.Onix1 { /// /// Class defining a . /// - public class NeuropixelsV2QuadShankElectrode : Electrode + [Obsolete($"Use {nameof(NeuropixelsV2Electrode)} instead. This class is obsolete and will be removed.")] + public class NeuropixelsV2QuadShankElectrode : NeuropixelsV2Electrode { - /// - /// Gets the bank, or logical block of channels, this electrode belongs to. - /// - [XmlIgnore] - public NeuropixelsV2QuadShankBank Bank { get; private set; } - - /// - /// Gets the block this electrode belongs to. - /// - [XmlIgnore] - public int Block { get; private set; } - - /// - /// Gets the index within the block this electrode belongs to. - /// - [XmlIgnore] - public int BlockIndex { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// Integer defining the index of the contact. - public NeuropixelsV2QuadShankElectrode(int index) - { - Index = index; - Shank = index / NeuropixelsV2.ElectrodePerShank; - IntraShankElectrodeIndex = index % NeuropixelsV2.ElectrodePerShank; - Bank = (NeuropixelsV2QuadShankBank)(IntraShankElectrodeIndex / NeuropixelsV2.ChannelCount); - Block = IntraShankElectrodeIndex % NeuropixelsV2.ChannelCount / NeuropixelsV2.ElectrodePerBlock; - BlockIndex = IntraShankElectrodeIndex % NeuropixelsV2.ElectrodePerBlock; - Channel = GetChannelNumber(Shank, Block, BlockIndex); - Position = GetPosition(index); - } - - private PointF GetPosition(int electrodeNumber) - { - var position = NeuropixelsV2eProbeGroup.DefaultContactPosition(electrodeNumber); - return new PointF(x: position[0], y: position[1]); - } - - /// - /// Static method returning the channel number of a given electrode. - /// - /// Integer defining the index of the electrode in the probe. - /// An integer between 0 and 383 defining the channel number. - public static int GetChannelNumber(int electrodeIndex) + /// + [Obsolete($"Use {nameof(NeuropixelsV2Electrode)} instead. This class is obsolete and will be removed.")] + public NeuropixelsV2QuadShankElectrode(int index) : base(index, NeuropixelsV2ProbeType.QuadShank) { - var shank = electrodeIndex / NeuropixelsV2.ElectrodePerShank; - var shankIndex = electrodeIndex % NeuropixelsV2.ElectrodePerShank; - var block = shankIndex % NeuropixelsV2.ChannelCount / NeuropixelsV2.ElectrodePerBlock; - var blockIndex = shankIndex % NeuropixelsV2.ElectrodePerBlock; - - return GetChannelNumber(shank, block, blockIndex); } - - internal static int GetChannelNumber(int shank, int block, int blockIndex) => (shank, block) switch - { - (0, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 0, - (0, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 2, - (0, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 4, - (0, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 6, - (0, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 5, - (0, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 7, - (0, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 1, - (0, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 3, - - (1, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 1, - (1, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 3, - (1, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 5, - (1, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 7, - (1, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 4, - (1, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 6, - (1, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 0, - (1, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 2, - - (2, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 4, - (2, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 6, - (2, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 0, - (2, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 2, - (2, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 1, - (2, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 3, - (2, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 5, - (2, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 7, - - (3, 0) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 5, - (3, 1) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 7, - (3, 2) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 1, - (3, 3) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 3, - (3, 4) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 0, - (3, 5) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 2, - (3, 6) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 4, - (3, 7) => blockIndex + NeuropixelsV2.ElectrodePerBlock * 6, - - _ => throw new ArgumentOutOfRangeException($"Invalid shank and/or electrode value: {(shank, block)}"), - }; } } diff --git a/OpenEphys.Onix1/NeuropixelsV2QuadShankProbeConfiguration.cs b/OpenEphys.Onix1/NeuropixelsV2QuadShankProbeConfiguration.cs index 6a3e9280..2cd72f31 100644 --- a/OpenEphys.Onix1/NeuropixelsV2QuadShankProbeConfiguration.cs +++ b/OpenEphys.Onix1/NeuropixelsV2QuadShankProbeConfiguration.cs @@ -1,234 +1,20 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using Bonsai; -using Newtonsoft.Json; -using System.Text; -using System.Xml.Serialization; -using System.Linq; -using OpenEphys.ProbeInterface.NET; namespace OpenEphys.Onix1 { - /// - /// Specifies the reference for a quad-shank probe. - /// - public enum NeuropixelsV2QuadShankReference : uint - { - /// - /// Specifies that the External reference will be used. - /// - External, - /// - /// Specifies that the tip reference of shank 1 will be used. - /// - Tip1, - /// - /// Specifies that the tip reference of shank 2 will be used. - /// - Tip2, - /// - /// Specifies that the tip reference of shank 3 will be used. - /// - Tip3, - /// - /// Specifies that the tip reference of shank 4 will be used. - /// - Tip4, - /// - /// Specifies that the ground reference will be used. - /// - Ground - } - - /// - /// Specifies the bank of electrodes within each shank. - /// - public enum NeuropixelsV2QuadShankBank - { - /// - /// Specifies that Bank A is the current bank. - /// - /// Bank A is defined as shank index 0 to 383 along each shank. - A, - /// - /// Specifies that Bank B is the current bank. - /// - /// Bank B is defined as shank index 384 to 767 along each shank. - B, - /// - /// Specifies that Bank C is the current bank. - /// - /// Bank C is defined as shank index 768 to 1151 along each shank. - C, - /// - /// Specifies that Bank D is the current bank. - /// - /// - /// Bank D is defined as shank index 1152 to 1279 along each shank. Note that Bank D is not a full contingent - /// of 384 channels; to compensate for this, electrodes from Bank C (starting at shank index 896) are used to - /// generate a full 384 channel map. - /// - D, - } - /// /// Defines a configuration for quad-shank, Neuropixels 2.0 and 2.0-beta probes. /// - public class NeuropixelsV2QuadShankProbeConfiguration + [Obsolete($"Use {nameof(NeuropixelsV2ProbeConfiguration)} instead. This class will be removed.")] + public class NeuropixelsV2QuadShankProbeConfiguration : NeuropixelsV2ProbeConfiguration { - /// - /// Creates a model of the probe with all electrodes instantiated. - /// - [XmlIgnore] - public static readonly IReadOnlyList ProbeModel = CreateProbeModel(); - - /// - /// Initializes a new instance of the class. - /// - public NeuropixelsV2QuadShankProbeConfiguration() - { - ChannelMap = new NeuropixelsV2QuadShankElectrode[NeuropixelsV2.ChannelCount]; - for (int i = 0; i < ChannelMap.Length; i++) - { - ChannelMap[i] = ProbeModel.FirstOrDefault(e => e.Channel == i); - } - } - /// /// Initializes a new instance of the class. /// - public NeuropixelsV2QuadShankProbeConfiguration(NeuropixelsV2Probe probe) : this() - { - Probe = probe; - } - - /// - /// Initializes a new instance of the class. - /// - public NeuropixelsV2QuadShankProbeConfiguration(NeuropixelsV2Probe probe, NeuropixelsV2QuadShankReference reference) : this() - { - Probe = probe; - Reference = reference; - } - - /// - /// Copy constructor for the class. - /// - /// The existing object to copy. - public NeuropixelsV2QuadShankProbeConfiguration(NeuropixelsV2QuadShankProbeConfiguration probeConfiguration) - { - Reference = probeConfiguration.Reference; - var probes = probeConfiguration.ProbeGroup.Probes.ToList().Select(probe => new Probe(probe)); - ProbeGroup = new(probeConfiguration.ProbeGroup.Specification, probeConfiguration.ProbeGroup.Version, probes.ToArray()); - ChannelMap = NeuropixelsV2eProbeGroup.ToChannelMap(ProbeGroup); - Probe = probeConfiguration.Probe; - } - - /// - /// Initializes a new instance of the class with the given - /// channel configuration. The is automatically - /// generated from the . - /// - /// The existing instance to use. - /// The reference value. - /// The for this probe. - [JsonConstructor] - public NeuropixelsV2QuadShankProbeConfiguration(NeuropixelsV2eProbeGroup probeGroup, NeuropixelsV2QuadShankReference reference, NeuropixelsV2Probe probe) - { - ChannelMap = NeuropixelsV2eProbeGroup.ToChannelMap(probeGroup); - ProbeGroup = probeGroup; - Reference = reference; - Probe = probe; - } - - private static List CreateProbeModel() - { - var electrodes = new List(NeuropixelsV2.ElectrodePerShank * 4); - for (int i = 0; i < NeuropixelsV2.ElectrodePerShank * 4; i++) - { - electrodes.Add(new NeuropixelsV2QuadShankElectrode(i)); - } - return electrodes; - } - - /// - /// Gets or sets the for this probe. - /// - public NeuropixelsV2Probe Probe { get; set; } = NeuropixelsV2Probe.ProbeA; - - /// - /// Gets or sets the reference for all electrodes. - /// - /// - /// All electrodes are set to the same reference, which can be - /// or any of the tip references - /// (, , etc.). - /// Setting to will use the external reference, while - /// sets the reference to the electrode at the tip of the first shank. - /// - public NeuropixelsV2QuadShankReference Reference { get; set; } = NeuropixelsV2QuadShankReference.External; - - /// - /// Gets the existing channel map listing all currently enabled electrodes. - /// - /// - /// The channel map will always be 384 channels, and will return the 384 enabled electrodes. - /// - [XmlIgnore] - public NeuropixelsV2QuadShankElectrode[] ChannelMap { get; } - - /// - /// Update the with the selected electrodes. - /// - /// List of selected electrodes that are being added to the - public void SelectElectrodes(NeuropixelsV2QuadShankElectrode[] electrodes) - { - foreach (var e in electrodes) - { - try - { - ChannelMap[e.Channel] = e; - } - catch (IndexOutOfRangeException ex) - { - throw new IndexOutOfRangeException($"Electrode {e.Index} specifies channel {e.Channel} but only channels " + - $"0 to {ChannelMap.Length - 1} are supported.", ex); - } - } - - ProbeGroup.UpdateDeviceChannelIndices(ChannelMap); - } - - /// - /// Gets the channel configuration for this probe. - /// - [XmlIgnore] - [Category("Configuration")] - [Description("Defines the shape of the probe, and which contacts are currently selected for streaming")] - public NeuropixelsV2eProbeGroup ProbeGroup { get; private set; } = new(); - - /// - /// Gets or sets a string defining the in Base64. - /// This variable is needed to properly save a workflow in Bonsai, but it is not - /// directly accessible in the Bonsai editor. - /// - [Browsable(false)] - [Externalizable(false)] - [XmlElement(nameof(ProbeGroup))] - public string ProbeGroupString + [Obsolete($"Use {nameof(NeuropixelsV2ProbeConfiguration)} instead. This class will be removed.")] + public NeuropixelsV2QuadShankProbeConfiguration(NeuropixelsV2Probe probe, NeuropixelsV2ShankReference reference) + : base(probe, NeuropixelsV2ProbeType.QuadShank, reference) { - get - { - var jsonString = JsonConvert.SerializeObject(ProbeGroup); - return Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonString)); - } - set - { - var jsonString = Encoding.UTF8.GetString(Convert.FromBase64String(value)); - ProbeGroup = JsonConvert.DeserializeObject(jsonString); - SelectElectrodes(NeuropixelsV2eProbeGroup.ToChannelMap(ProbeGroup)); - } } } } diff --git a/OpenEphys.Onix1/NeuropixelsV2eBetaRegisterContext.cs b/OpenEphys.Onix1/NeuropixelsV2eBetaRegisterContext.cs index 48b30a26..4d946aab 100644 --- a/OpenEphys.Onix1/NeuropixelsV2eBetaRegisterContext.cs +++ b/OpenEphys.Onix1/NeuropixelsV2eBetaRegisterContext.cs @@ -15,7 +15,7 @@ public NeuropixelsV2eBetaRegisterContext(DeviceContext deviceContext, uint i2cAd { } - public void WriteConfiguration(NeuropixelsV2QuadShankProbeConfiguration probe) + public void WriteConfiguration(NeuropixelsV2ProbeConfiguration probe) { var baseBits = NeuropixelsV2.GenerateBaseBits(probe); WriteShiftRegister(NeuropixelsV2eBeta.SR_CHAIN5, baseBits[0]); @@ -49,7 +49,7 @@ void WriteShiftRegister(uint srAddress, BitArray data) } } - if (ReadByte(NeuropixelsV2e.STATUS) != (uint) NeuropixelsV2Status.SR_OK) + if (ReadByte(NeuropixelsV2e.STATUS) != (uint)NeuropixelsV2Status.SR_OK) { Console.Error.WriteLine($"Warning: shift register {srAddress:X} status check failed. " + $"{ShankName(srAddress)} may be damaged."); diff --git a/OpenEphys.Onix1/NeuropixelsV2eProbeGroup.cs b/OpenEphys.Onix1/NeuropixelsV2eProbeGroup.cs index ccc4cc20..c8535e92 100644 --- a/OpenEphys.Onix1/NeuropixelsV2eProbeGroup.cs +++ b/OpenEphys.Onix1/NeuropixelsV2eProbeGroup.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using Newtonsoft.Json; using OpenEphys.ProbeInterface.NET; @@ -14,7 +15,6 @@ public class NeuropixelsV2eProbeGroup : ProbeGroup const float shankOffsetX = 200f; const float shankWidthX = 70f; const float shankPitchX = 250f; - const int numberOfShanks = 4; /// /// Initializes a new instance of the class. @@ -23,25 +23,53 @@ public class NeuropixelsV2eProbeGroup : ProbeGroup /// The default constructor will initialize the new with /// the default settings for all contacts, including their positions, shapes, and IDs. /// - public NeuropixelsV2eProbeGroup() - : base("probeinterface", "0.2.21", DefaultProbes()) + public NeuropixelsV2eProbeGroup(NeuropixelsV2ProbeType probeType) + : base("probeinterface", "0.2.21", DefaultProbes(probeType)) { } - private static Probe[] DefaultProbes() + internal static string QuadShankProbeName = "Neuropixels 2.0 - multishank"; + + internal static string GetProbeName(NeuropixelsV2ProbeType probeType) + { + return probeType switch + { + NeuropixelsV2ProbeType.QuadShank => QuadShankProbeName, + _ => throw new InvalidEnumArgumentException("Unknown probe type given.") + }; + } + + internal static NeuropixelsV2ProbeType GetProbeTypeFromProbeName(string name) + { + if (name == QuadShankProbeName) + return NeuropixelsV2ProbeType.QuadShank; + + else + throw new ArgumentException($"The type '{name}' does not match any implemented Neuropixels 2.0 probe types."); + } + + private static Probe[] DefaultProbes(NeuropixelsV2ProbeType probeType) { var probe = new Probe[1]; + int numberOfShanks = probeType switch + { + NeuropixelsV2ProbeType.QuadShank => 4, + _ => throw new InvalidEnumArgumentException("Unknown probe type given.") + }; + + string probeName = GetProbeName(probeType); + probe[0] = new(ProbeNdim.Two, ProbeSiUnits.um, - new ProbeAnnotations("Neuropixels 2.0 - Multishank", "IMEC"), + new ProbeAnnotations(probeName, "IMEC"), null, DefaultContactPositions(NeuropixelsV2.ElectrodePerShank * numberOfShanks), Probe.DefaultContactPlaneAxes(NeuropixelsV2.ElectrodePerShank * numberOfShanks), Probe.DefaultContactShapes(NeuropixelsV2.ElectrodePerShank * numberOfShanks, ContactShape.Square), Probe.DefaultSquareParams(NeuropixelsV2.ElectrodePerShank * numberOfShanks, 12.0f), - DefaultProbePlanarContourQuadShank(), - DefaultDeviceChannelIndices(NeuropixelsV2.ChannelCount, NeuropixelsV2.ElectrodePerShank * numberOfShanks), + DefaultProbePlanarContour(probeType), + DefaultDeviceChannelIndices(NeuropixelsV2.ChannelCount, NeuropixelsV2.ElectrodePerShank * numberOfShanks, probeType), Probe.DefaultContactIds(NeuropixelsV2.ElectrodePerShank * numberOfShanks), DefaultShankIds(NeuropixelsV2.ElectrodePerShank * numberOfShanks)); @@ -73,6 +101,11 @@ public NeuropixelsV2eProbeGroup(NeuropixelsV2eProbeGroup probeGroup) { } + internal NeuropixelsV2eProbeGroup Clone() + { + return new NeuropixelsV2eProbeGroup(Specification, Version, Probes.Select(probe => new Probe(probe)).ToArray()); + } + /// /// Generates a 2D array of default contact positions based on the given number of channels. /// @@ -116,6 +149,20 @@ private static float ContactPositionX(int index) }; } + /// + /// Generates a default planar contour for the type of probe that is given. + /// + /// Type of probe. + /// + /// + public static float[][] DefaultProbePlanarContour(NeuropixelsV2ProbeType probeType) + { + if (probeType == NeuropixelsV2ProbeType.QuadShank) + return DefaultProbePlanarContourQuadShank(); + + throw new InvalidEnumArgumentException(nameof(probeType)); + } + /// /// Generates a default planar contour for the probe, based on the given probe index /// @@ -173,16 +220,15 @@ public static float[][] DefaultProbePlanarContourSingleShank() /// /// Number of contacts that are connected for recording /// Total number of physical contacts on the probe + /// Type of probe. /// - public static int[] DefaultDeviceChannelIndices(int channelCount, int electrodeCount) + public static int[] DefaultDeviceChannelIndices(int channelCount, int electrodeCount, NeuropixelsV2ProbeType probeType) { int[] deviceChannelIndices = new int[electrodeCount]; for (int i = 0; i < channelCount; i++) { - deviceChannelIndices[i] = NeuropixelsV2QuadShankElectrode.GetChannelNumber(i / NeuropixelsV2.ElectrodePerShank, - i % NeuropixelsV2.ChannelCount / NeuropixelsV2.ElectrodePerBlock, - i % NeuropixelsV2.ElectrodePerBlock); + deviceChannelIndices[i] = NeuropixelsV2Electrode.GetChannelNumber(i, probeType); } for (int i = channelCount; i < electrodeCount; i++) @@ -222,14 +268,15 @@ public static string[] DefaultShankIds(int numberOfContacts) /// Convert a ProbeInterface object to a list of electrodes, which includes all possible electrodes /// /// A object - /// List of electrodes - public static List ToElectrodes(NeuropixelsV2eProbeGroup probeGroup) + /// Type of probe. + /// List of electrodes + public static List ToElectrodes(NeuropixelsV2eProbeGroup probeGroup, NeuropixelsV2ProbeType probeType) { - List electrodes = new(); + List electrodes = new(); foreach (var c in probeGroup.GetContacts()) { - electrodes.Add(new NeuropixelsV2QuadShankElectrode(c.Index)); + electrodes.Add(new NeuropixelsV2Electrode(c.Index, probeType)); } return electrodes; @@ -239,10 +286,10 @@ public static List ToElectrodes(NeuropixelsV2eP /// Convert a object to a list of electrodes, which only includes currently enabled electrodes /// /// A object - /// List of electrodes that are enabled - public static NeuropixelsV2QuadShankElectrode[] ToChannelMap(NeuropixelsV2eProbeGroup probeGroup) + /// /// Probe type that this electrode is a part of. + /// List of electrodes that are enabled + public static NeuropixelsV2Electrode[] ToChannelMap(NeuropixelsV2eProbeGroup probeGroup, NeuropixelsV2ProbeType probeType) { - var enabledContacts = probeGroup.GetContacts().Where(c => c.DeviceId != -1); if (enabledContacts.Count() != NeuropixelsV2.ChannelCount) @@ -252,16 +299,12 @@ public static NeuropixelsV2QuadShankElectrode[] ToChannelMap(NeuropixelsV2eProbe $"index >= 0."); } - return enabledContacts.Select(c => new NeuropixelsV2QuadShankElectrode(c.Index)) + return enabledContacts.Select(c => new NeuropixelsV2Electrode(c.Index, probeType)) .OrderBy(e => e.Channel) .ToArray(); } - /// - /// Updates the based on the given channel map. - /// - /// Existing . - internal void UpdateDeviceChannelIndices(NeuropixelsV2QuadShankElectrode[] channelMap) + internal void UpdateDeviceChannelIndices(Electrode[] channelMap) { int[] newDeviceChannelIndices = new int[NumberOfContacts]; diff --git a/OpenEphys.Onix1/NeuropixelsV2eRegisterContext.cs b/OpenEphys.Onix1/NeuropixelsV2eRegisterContext.cs index 19c5b41a..b7af937b 100644 --- a/OpenEphys.Onix1/NeuropixelsV2eRegisterContext.cs +++ b/OpenEphys.Onix1/NeuropixelsV2eRegisterContext.cs @@ -15,7 +15,7 @@ public NeuropixelsV2eRegisterContext(DeviceContext deviceContext, uint i2cAddres { } - public void WriteConfiguration(NeuropixelsV2QuadShankProbeConfiguration probe) + public void WriteConfiguration(NeuropixelsV2ProbeConfiguration probe) { var baseBits = NeuropixelsV2.GenerateBaseBits(probe); WriteShiftRegister(NeuropixelsV2e.SR_CHAIN5, baseBits[0]);