Skip to content

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
32 changes: 32 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 @@ -110,6 +121,7 @@ public PortName Port
TS4231.DeviceAddress = offset + 2;
ElectricalStimulator.DeviceAddress = offset + 3;
OpticalStimulator.DeviceAddress = offset + 4;
Heartbeat.DeviceAddress = offset + 5;
}
}

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

class ConfigureHeadstage64PortController : ConfigurePortController
{
public ConfigureHeadstage64PortController()
: base(typeof(Headstage64PortController))
{
}

protected override bool ConfigurePortVoltageOverride(DeviceContext device, double voltage)
{
// NB: Wait for 1 second to discharge the headstage in the case that they have e.g. just
Expand Down Expand Up @@ -202,5 +220,19 @@ protected override bool ConfigurePortVoltage(DeviceContext device, out double vo
return CheckLinkState(device);
}
}

internal static class Headstage64PortController
{
public const int ID = PortController.ID;
public const uint MinimumVersion = PortController.MinimumVersion;

internal class NameConverter : DeviceNameConverter
{
public NameConverter()
: base(typeof(Headstage64PortController))
{
}
}
}
}
}
80 changes: 23 additions & 57 deletions OpenEphys.Onix1/ConfigureHeadstage64ElectricalStimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,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 +48,7 @@ public ConfigureHeadstage64ElectricalStimulator(ConfigureHeadstage64ElectricalSt
DeviceName = electricalStimulator.DeviceName;
DeviceAddress = electricalStimulator.DeviceAddress;
Enable = electricalStimulator.Enable;
StimEnable = electricalStimulator.StimEnable;
PowerEnable = electricalStimulator.PowerEnable;
TriggerDelay = electricalStimulator.TriggerDelay;
Arm = electricalStimulator.Arm;
PhaseOneCurrent = electricalStimulator.PhaseOneCurrent;
InterPhaseCurrent = electricalStimulator.InterPhaseCurrent;
PhaseTwoCurrent = electricalStimulator.PhaseTwoCurrent;
Expand All @@ -77,42 +73,20 @@ public ConfigureHeadstage64ElectricalStimulator(ConfigureHeadstage64ElectricalSt
public bool Enable { get; set; }

/// <summary>
/// Gets or sets the device enable state.
/// Gets or sets the device arm state.
/// </summary>
/// <remarks>
/// If set to true, then the electrical stimulator circuit will respect triggers. If set to false, triggers will be ignored.
/// If set to true, then the electrical stimulator's ±15V power supplies will be turned on and the
/// electrical stimulator circuit will respect triggers. If set to false, the power supplies will be
/// shut down and triggers will be ignored. It takes ~10 milliseconds for the power supplies to to
/// stabilize.
/// </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
public bool Arm
{
get => triggerDelay.Value;
set => triggerDelay.OnNext(value);
get => stimEnable.Value;
set => stimEnable.OnNext(value);
}

static double ClampCurrent(double value)
Expand Down Expand Up @@ -275,22 +249,18 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source

return new CompositeDisposable(
stimEnable.SubscribeSafe(observer, value =>
device.WriteRegister(Headstage64ElectricalStimulator.STIMENABLE, value ? 1u : 0u)),
device.WriteRegister(Headstage64ElectricalStimulator.STIMENABLE, value ? 3u : 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));
});
}
Expand All @@ -307,23 +277,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