Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public Headstage64ElectricalStimulatorOptions(ConfigureHeadstage64ElectricalStim
textBoxBurstPulseCount.Text = electricalStimulator.BurstPulseCount.ToString();
textBoxInterBurstInterval.Text = electricalStimulator.InterBurstInterval.ToString();
textBoxTrainBurstCount.Text = electricalStimulator.TrainBurstCount.ToString();
textBoxTrainDelay.Text = electricalStimulator.TriggerDelay.ToString();
}

void BurstPulseCountChanged(object sender, System.EventArgs e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ public Headstage64ElectricalStimulatorSequenceDialog(ConfigureHeadstage64Electri
new TextBoxBinding<uint>(
StimulusSequenceOptions.textBoxPulsePeriod,
value => { ElectricalStimulator.InterPulseInterval = value; return ElectricalStimulator.InterPulseInterval; },
uint.Parse) },
{ StimulusSequenceOptions.textBoxTrainDelay,
new TextBoxBinding<uint>(
StimulusSequenceOptions.textBoxTrainDelay,
value => { ElectricalStimulator.TriggerDelay = value; return ElectricalStimulator.TriggerDelay; },
uint.Parse) }
};

Expand Down Expand Up @@ -303,7 +298,7 @@ internal override PointPairList[] CreateStimulusWaveforms()
{
for (int channel = 0; channel < NumberOfChannels; channel++)
{
waveforms[channel] = new PointPairList { new PointPair(0, 0), new PointPair(ElectricalStimulator.TriggerDelay, 0) };
waveforms[channel] = new PointPairList { new PointPair(0, 0), new PointPair(0, 0) };

for (int i = 0; i < ElectricalStimulator.TrainBurstCount; i++)
{
Expand Down
116 changes: 55 additions & 61 deletions OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.Designer.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ internal void UpdateSequenceParameters(ConfigureHeadstage64OpticalStimulator opt
textBoxInterBurstInterval.Text = opticalStimulator.InterBurstInterval.ToString();
textBoxInterBurstInterval.Enabled = opticalStimulator.BurstsPerTrain > 1;
textBoxBurstsPerTrain.Text = opticalStimulator.BurstsPerTrain.ToString();
textBoxDelay.Text = opticalStimulator.Delay.ToString();
}

internal readonly double channelOneScalingFactor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using ZedGraph;
Expand Down Expand Up @@ -78,11 +77,6 @@ public Headstage64OpticalStimulatorSequenceDialog(ConfigureHeadstage64OpticalSti
StimulusSequenceOptions.textBoxInterBurstInterval,
value => { OpticalStimulator.InterBurstInterval = value; return OpticalStimulator.InterBurstInterval; },
double.Parse) },
{ StimulusSequenceOptions.textBoxDelay,
new TextBoxBinding<double>(
StimulusSequenceOptions.textBoxDelay,
value => { OpticalStimulator.Delay = value; return OpticalStimulator.Delay; },
double.Parse) },
{ StimulusSequenceOptions.textBoxPulseDuration,
new TextBoxBinding<double>(
StimulusSequenceOptions.textBoxPulseDuration,
Expand Down Expand Up @@ -225,7 +219,7 @@ internal override PointPairList[] CreateStimulusWaveforms()

waveforms[channel] = new PointPairList
{
new PointPairList { new PointPair(0, offset), new PointPair(OpticalStimulator.Delay, offset) }
new PointPairList { new PointPair(0, offset), new PointPair(0, offset) }
};

var stimulusCurrent = offset + GetChannelCurrentScaled(OpticalStimulator.MaxCurrent,
Expand Down
15 changes: 15 additions & 0 deletions OpenEphys.Onix1/ConfigureHeadstage64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ public ConfigureHeadstage64()
[Editor("OpenEphys.Onix1.Design.Headstage64OpticalStimulatorUITypeEditor, OpenEphys.Onix1.Design", typeof(UITypeEditor))]
public ConfigureHeadstage64OpticalStimulator OpticalStimulator { get; set; } = new();

/// <summary>
/// Gets or sets the heartbeat configuration.
/// </summary>
/// <remarks>
/// This heartbeat is always enabled and beats at a minimum of 10 Hz.
/// </remarks>
[Category(DevicesCategory)]
[TypeConverter(typeof(SingleDeviceFactoryConverter))]
[Description("Specifies the configuration for the heartbeat device in the headstage-64.")]
public ConfigurePersistentHeartbeat Heartbeat { get; set; } = new ConfigurePersistentHeartbeat { BeatsPerSecond = 10 };

/// <summary>
/// Gets or sets the port.
/// </summary>
Expand All @@ -109,7 +120,10 @@ public PortName Port
Bno055.DeviceAddress = offset + 1;
TS4231.DeviceAddress = offset + 2;
ElectricalStimulator.DeviceAddress = offset + 3;
ElectricalStimulator.PortControllerDeviceAddress = PortControl.DeviceAddress;
OpticalStimulator.DeviceAddress = offset + 4;
OpticalStimulator.PortControllerDeviceAddress = PortControl.DeviceAddress;
Heartbeat.DeviceAddress = offset + 5;
}
}

Expand Down Expand Up @@ -148,6 +162,7 @@ internal override IEnumerable<IDeviceConfiguration> GetDevices()
yield return TS4231;
yield return ElectricalStimulator;
yield return OpticalStimulator;
yield return Heartbeat;
}

class ConfigureHeadstage64PortController : ConfigurePortController
Expand Down
87 changes: 18 additions & 69 deletions OpenEphys.Onix1/ConfigureHeadstage64ElectricalStimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ namespace OpenEphys.Onix1
[Editor("OpenEphys.Onix1.Design.Headstage64ElectricalStimulatorComponentEditor, OpenEphys.Onix1.Design", typeof(ComponentEditor))]
public class ConfigureHeadstage64ElectricalStimulator : SingleDeviceFactory
{
readonly BehaviorSubject<bool> stimEnable = new(false);
internal uint? PortControllerDeviceAddress { get; set; }

readonly BehaviorSubject<double> phaseOneCurrent = new(0);
readonly BehaviorSubject<double> interPhaseCurrent = new(0);
readonly BehaviorSubject<double> phaseTwoCurrent = new(0);
Expand All @@ -30,8 +31,6 @@ public class ConfigureHeadstage64ElectricalStimulator : SingleDeviceFactory
readonly BehaviorSubject<uint> burstPulseCount = new(0);
readonly BehaviorSubject<uint> interBurstInterval = new(0);
readonly BehaviorSubject<uint> trainBurstCount = new(0);
readonly BehaviorSubject<uint> triggerDelay = new(0);
readonly BehaviorSubject<bool> powerEnable = new(false);

/// <summary>
/// Initializes a new instance of the <see cref="ConfigureHeadstage64ElectricalStimulator"/> class.
Expand All @@ -50,9 +49,6 @@ public ConfigureHeadstage64ElectricalStimulator(ConfigureHeadstage64ElectricalSt
DeviceName = electricalStimulator.DeviceName;
DeviceAddress = electricalStimulator.DeviceAddress;
Enable = electricalStimulator.Enable;
StimEnable = electricalStimulator.StimEnable;
PowerEnable = electricalStimulator.PowerEnable;
TriggerDelay = electricalStimulator.TriggerDelay;
PhaseOneCurrent = electricalStimulator.PhaseOneCurrent;
InterPhaseCurrent = electricalStimulator.InterPhaseCurrent;
PhaseTwoCurrent = electricalStimulator.PhaseTwoCurrent;
Expand All @@ -76,45 +72,6 @@ public ConfigureHeadstage64ElectricalStimulator(ConfigureHeadstage64ElectricalSt
[Description("Specifies whether the headstage-64 electrical stimulator will produce stimulus reports.")]
public bool Enable { get; set; }

/// <summary>
/// Gets or sets the device enable state.
/// </summary>
/// <remarks>
/// If set to true, then the electrical stimulator circuit will respect triggers. If set to false, triggers will be ignored.
/// </remarks>
[Description("Specifies whether the electrical stimulator will respect triggers.")]
[Category(AcquisitionCategory)]
public bool StimEnable { get; set; } = true;

/// <summary>
/// Gets or sets the electrical stimulator's power state.
/// </summary>
/// <remarks>
/// If set to true, then the electrical stimulator's ±15V power supplies will be turned on. If set to false,
/// they will be turned off. It may be desirable to power down the electrical stimulator's power supplies outside
/// of stimulation windows to reduce power consumption and electrical noise. This property must be set to true
/// in order for electrical stimuli to be delivered properly. It takes ~10 milliseconds for these supplies to stabilize.
/// </remarks>
[Description("Stimulator power on/off.")]
[Category(AcquisitionCategory)]
public bool PowerEnable
{
get => powerEnable.Value;
set => powerEnable.OnNext(value);
}

/// <summary>
/// Gets or sets a delay from receiving a trigger to the start of stimulus sequence application in μsec.
/// </summary>
[Description("A delay from receiving a trigger to the start of stimulus sequence application (uSec).")]
[Range(0, uint.MaxValue)]
[Category(AcquisitionCategory)]
public uint TriggerDelay
{
get => triggerDelay.Value;
set => triggerDelay.OnNext(value);
}

static double ClampCurrent(double value)
{
if (value > Headstage64ElectricalStimulator.AbsMaxMicroAmps)
Expand Down Expand Up @@ -271,27 +228,23 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
return source.ConfigureDevice((context, observer) =>
{
var device = context.GetDeviceContext(deviceAddress, DeviceType);
var deviceInfo = new Headstage64StimulatorDeviceInfo(context, DeviceType, deviceAddress, PortControllerDeviceAddress);

device.WriteRegister(Headstage64ElectricalStimulator.ENABLE, enable ? 1u : 0u);

return new CompositeDisposable(
stimEnable.SubscribeSafe(observer, value =>
device.WriteRegister(Headstage64ElectricalStimulator.STIMENABLE, value ? 1u : 0u)),
phaseOneCurrent.SubscribeSafe(observer, value =>
device.WriteRegister(Headstage64ElectricalStimulator.CURRENT1, Headstage64ElectricalStimulator.MicroampsToCode(value))),
interPhaseCurrent.SubscribeSafe(observer, value =>
device.WriteRegister(Headstage64ElectricalStimulator.RESTCURR, Headstage64ElectricalStimulator.MicroampsToCode(value))),
phaseTwoCurrent.SubscribeSafe(observer, value =>
device.WriteRegister(Headstage64ElectricalStimulator.CURRENT2, Headstage64ElectricalStimulator.MicroampsToCode(value))),
triggerDelay.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.TRAINDELAY, value)),
phaseOneDuration.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.PULSEDUR1, value)),
interPhaseInterval.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.INTERPHASEINTERVAL, value)),
phaseTwoDuration.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.PULSEDUR2, value)),
interPulseInterval.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.INTERPULSEINTERVAL, value)),
interBurstInterval.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.INTERBURSTINTERVAL, value)),
burstPulseCount.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.BURSTCOUNT, value)),
trainBurstCount.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.TRAINCOUNT, value)),
powerEnable.SubscribeSafe(observer, value => device.WriteRegister(Headstage64ElectricalStimulator.POWERON, value ? 1u : 0u)),
DeviceManager.RegisterDevice(deviceName, device, DeviceType));
DeviceManager.RegisterDevice(deviceName, deviceInfo));
});
}
}
Expand All @@ -307,23 +260,19 @@ static class Headstage64ElectricalStimulator

// managed registers
public const uint ENABLE = 0; // Enable stimulus report stream
public const uint BIPHASIC = 1; // Biphasic pulse (0 = monophasic, 1 = biphasic; NB: currently ignored)
public const uint CURRENT1 = 2; // Phase 1 current
public const uint CURRENT2 = 3; // Phase 2 current
public const uint PULSEDUR1 = 4; // Phase 1 duration, 1 microsecond steps
public const uint INTERPHASEINTERVAL = 5; // Inter-phase interval, 10 microsecond steps
public const uint PULSEDUR2 = 6; // Phase 2 duration, 1 microsecond steps
public const uint INTERPULSEINTERVAL = 7; // Inter-pulse interval, 10 microsecond steps
public const uint BURSTCOUNT = 8; // Burst duration, number of pulses in burst
public const uint INTERBURSTINTERVAL = 9; // Inter-burst interval, microseconds
public const uint TRAINCOUNT = 10; // Pulse train duration, number of bursts in train
public const uint TRAINDELAY = 11; // Pulse train delay, microseconds
public const uint TRIGGER = 12; // Trigger stimulation (1 = deliver)
public const uint POWERON = 13; // Control estim sub-circuit power (0 = off, 1 = on)
public const uint STIMENABLE = 14; // If 0 then stimulation triggers will be ignored, otherwise they will be applied
public const uint RESTCURR = 15; // Resting current between pulse phases
public const uint RESET = 16; // Reset all parameters to default
public const uint REZ = 17; // Internal DAC resolution in bits
public const uint CURRENT1 = 1; // Phase 1 current
public const uint CURRENT2 = 2; // Phase 2 current
public const uint PULSEDUR1 = 3; // Phase 1 duration, 1 microsecond steps
public const uint INTERPHASEINTERVAL = 4; // Inter-phase interval, 10 microsecond steps
public const uint PULSEDUR2 = 5; // Phase 2 duration, 1 microsecond steps
public const uint INTERPULSEINTERVAL = 6; // Inter-pulse interval, 10 microsecond steps
public const uint BURSTCOUNT = 7; // Burst duration, number of pulses in burst
public const uint INTERBURSTINTERVAL = 8; // Inter-burst interval, microseconds
public const uint TRAINCOUNT = 9; // Pulse train duration, number of bursts in train
public const uint TRIGGER = 10; // Trigger stimulation (1 = deliver)
public const uint STIMENABLE = 11; // If 0 then stimulation triggers will be ignored, otherwise they will be applied
public const uint RESTCURRENT = 12; // Resting current between pulse phases
public const uint REZ = 13; // Internal DAC resolution in bits

internal static uint MicroampsToCode(double currentuA)
{
Expand Down
Loading