diff --git a/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.Designer.cs b/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.Designer.cs index 9abba431..8e3d42ff 100644 --- a/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.Designer.cs +++ b/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.Designer.cs @@ -48,8 +48,6 @@ private void InitializeComponent() this.labelInterBurstInterval = new System.Windows.Forms.Label(); this.textBoxTrainBurstCount = new System.Windows.Forms.TextBox(); this.labelTrainBurstCount = new System.Windows.Forms.Label(); - this.textBoxTrainDelay = new System.Windows.Forms.TextBox(); - this.labelTriggerDelay = new System.Windows.Forms.Label(); this.tableLayoutPanel1.SuspendLayout(); this.SuspendLayout(); // @@ -57,9 +55,10 @@ private void InitializeComponent() // this.labelPulseCurrent.AutoSize = true; this.labelPulseCurrent.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelPulseCurrent.Location = new System.Drawing.Point(3, 31); + this.labelPulseCurrent.Location = new System.Drawing.Point(2, 25); + this.labelPulseCurrent.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPulseCurrent.Name = "labelPulseCurrent"; - this.labelPulseCurrent.Size = new System.Drawing.Size(99, 31); + this.labelPulseCurrent.Size = new System.Drawing.Size(74, 25); this.labelPulseCurrent.TabIndex = 0; this.labelPulseCurrent.Text = "Current [µA]"; this.labelPulseCurrent.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -68,9 +67,10 @@ private void InitializeComponent() // this.labelPhaseOne.AutoSize = true; this.labelPhaseOne.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelPhaseOne.Location = new System.Drawing.Point(108, 0); + this.labelPhaseOne.Location = new System.Drawing.Point(80, 0); + this.labelPhaseOne.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPhaseOne.Name = "labelPhaseOne"; - this.labelPhaseOne.Size = new System.Drawing.Size(99, 31); + this.labelPhaseOne.Size = new System.Drawing.Size(74, 25); this.labelPhaseOne.TabIndex = 2; this.labelPhaseOne.Text = "Phase One"; this.labelPhaseOne.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -93,22 +93,24 @@ private void InitializeComponent() this.tableLayoutPanel1.Controls.Add(this.textBoxPhaseOneDuration, 1, 2); this.tableLayoutPanel1.Controls.Add(this.textBoxInterPhaseDuration, 2, 2); this.tableLayoutPanel1.Controls.Add(this.textBoxPhaseTwoDuration, 3, 2); - this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 31); + this.tableLayoutPanel1.Location = new System.Drawing.Point(9, 25); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.RowCount = 3; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(420, 95); + this.tableLayoutPanel1.Size = new System.Drawing.Size(315, 77); this.tableLayoutPanel1.TabIndex = 0; // // labelPulseDuration // this.labelPulseDuration.AutoSize = true; this.labelPulseDuration.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelPulseDuration.Location = new System.Drawing.Point(3, 62); + this.labelPulseDuration.Location = new System.Drawing.Point(2, 50); + this.labelPulseDuration.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPulseDuration.Name = "labelPulseDuration"; - this.labelPulseDuration.Size = new System.Drawing.Size(99, 33); + this.labelPulseDuration.Size = new System.Drawing.Size(74, 27); this.labelPulseDuration.TabIndex = 1; this.labelPulseDuration.Text = "Duration [µs]"; this.labelPulseDuration.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -117,9 +119,10 @@ private void InitializeComponent() // this.labelInterPhase.AutoSize = true; this.labelInterPhase.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelInterPhase.Location = new System.Drawing.Point(213, 0); + this.labelInterPhase.Location = new System.Drawing.Point(158, 0); + this.labelInterPhase.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelInterPhase.Name = "labelInterPhase"; - this.labelInterPhase.Size = new System.Drawing.Size(99, 31); + this.labelInterPhase.Size = new System.Drawing.Size(74, 25); this.labelInterPhase.TabIndex = 3; this.labelInterPhase.Text = "Inter-Phase"; this.labelInterPhase.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -128,9 +131,10 @@ private void InitializeComponent() // this.labelPhaseTwo.AutoSize = true; this.labelPhaseTwo.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelPhaseTwo.Location = new System.Drawing.Point(318, 0); + this.labelPhaseTwo.Location = new System.Drawing.Point(236, 0); + this.labelPhaseTwo.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPhaseTwo.Name = "labelPhaseTwo"; - this.labelPhaseTwo.Size = new System.Drawing.Size(99, 31); + this.labelPhaseTwo.Size = new System.Drawing.Size(77, 25); this.labelPhaseTwo.TabIndex = 4; this.labelPhaseTwo.Text = "Phase Two"; this.labelPhaseTwo.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -138,146 +142,136 @@ private void InitializeComponent() // textBoxPhaseOneCurrent // this.textBoxPhaseOneCurrent.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxPhaseOneCurrent.Location = new System.Drawing.Point(120, 34); - this.textBoxPhaseOneCurrent.Margin = new System.Windows.Forms.Padding(15, 3, 15, 3); + this.textBoxPhaseOneCurrent.Location = new System.Drawing.Point(89, 27); + this.textBoxPhaseOneCurrent.Margin = new System.Windows.Forms.Padding(11, 2, 11, 2); this.textBoxPhaseOneCurrent.Name = "textBoxPhaseOneCurrent"; - this.textBoxPhaseOneCurrent.Size = new System.Drawing.Size(75, 22); + this.textBoxPhaseOneCurrent.Size = new System.Drawing.Size(56, 20); this.textBoxPhaseOneCurrent.TabIndex = 0; // // textBoxInterPhaseCurrent // this.textBoxInterPhaseCurrent.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxInterPhaseCurrent.Location = new System.Drawing.Point(225, 34); - this.textBoxInterPhaseCurrent.Margin = new System.Windows.Forms.Padding(15, 3, 15, 3); + this.textBoxInterPhaseCurrent.Location = new System.Drawing.Point(167, 27); + this.textBoxInterPhaseCurrent.Margin = new System.Windows.Forms.Padding(11, 2, 11, 2); this.textBoxInterPhaseCurrent.Name = "textBoxInterPhaseCurrent"; - this.textBoxInterPhaseCurrent.Size = new System.Drawing.Size(75, 22); + this.textBoxInterPhaseCurrent.Size = new System.Drawing.Size(56, 20); this.textBoxInterPhaseCurrent.TabIndex = 1; // // textBoxPhaseTwoCurrent // this.textBoxPhaseTwoCurrent.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxPhaseTwoCurrent.Location = new System.Drawing.Point(330, 34); - this.textBoxPhaseTwoCurrent.Margin = new System.Windows.Forms.Padding(15, 3, 15, 3); + this.textBoxPhaseTwoCurrent.Location = new System.Drawing.Point(245, 27); + this.textBoxPhaseTwoCurrent.Margin = new System.Windows.Forms.Padding(11, 2, 11, 2); this.textBoxPhaseTwoCurrent.Name = "textBoxPhaseTwoCurrent"; - this.textBoxPhaseTwoCurrent.Size = new System.Drawing.Size(75, 22); + this.textBoxPhaseTwoCurrent.Size = new System.Drawing.Size(59, 20); this.textBoxPhaseTwoCurrent.TabIndex = 2; // // textBoxPhaseOneDuration // this.textBoxPhaseOneDuration.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxPhaseOneDuration.Location = new System.Drawing.Point(120, 65); - this.textBoxPhaseOneDuration.Margin = new System.Windows.Forms.Padding(15, 3, 15, 3); + this.textBoxPhaseOneDuration.Location = new System.Drawing.Point(89, 52); + this.textBoxPhaseOneDuration.Margin = new System.Windows.Forms.Padding(11, 2, 11, 2); this.textBoxPhaseOneDuration.Name = "textBoxPhaseOneDuration"; - this.textBoxPhaseOneDuration.Size = new System.Drawing.Size(75, 22); + this.textBoxPhaseOneDuration.Size = new System.Drawing.Size(56, 20); this.textBoxPhaseOneDuration.TabIndex = 3; // // textBoxInterPhaseDuration // this.textBoxInterPhaseDuration.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxInterPhaseDuration.Location = new System.Drawing.Point(225, 65); - this.textBoxInterPhaseDuration.Margin = new System.Windows.Forms.Padding(15, 3, 15, 3); + this.textBoxInterPhaseDuration.Location = new System.Drawing.Point(167, 52); + this.textBoxInterPhaseDuration.Margin = new System.Windows.Forms.Padding(11, 2, 11, 2); this.textBoxInterPhaseDuration.Name = "textBoxInterPhaseDuration"; - this.textBoxInterPhaseDuration.Size = new System.Drawing.Size(75, 22); + this.textBoxInterPhaseDuration.Size = new System.Drawing.Size(56, 20); this.textBoxInterPhaseDuration.TabIndex = 4; // // textBoxPhaseTwoDuration // this.textBoxPhaseTwoDuration.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxPhaseTwoDuration.Location = new System.Drawing.Point(330, 65); - this.textBoxPhaseTwoDuration.Margin = new System.Windows.Forms.Padding(15, 3, 15, 3); + this.textBoxPhaseTwoDuration.Location = new System.Drawing.Point(245, 52); + this.textBoxPhaseTwoDuration.Margin = new System.Windows.Forms.Padding(11, 2, 11, 2); this.textBoxPhaseTwoDuration.Name = "textBoxPhaseTwoDuration"; - this.textBoxPhaseTwoDuration.Size = new System.Drawing.Size(75, 22); + this.textBoxPhaseTwoDuration.Size = new System.Drawing.Size(59, 20); this.textBoxPhaseTwoDuration.TabIndex = 5; // // labelPulsePeriod // this.labelPulsePeriod.AutoSize = true; - this.labelPulsePeriod.Location = new System.Drawing.Point(106, 146); + this.labelPulsePeriod.Location = new System.Drawing.Point(80, 119); + this.labelPulsePeriod.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPulsePeriod.Name = "labelPulsePeriod"; - this.labelPulsePeriod.Size = new System.Drawing.Size(109, 16); + this.labelPulsePeriod.Size = new System.Drawing.Size(86, 13); this.labelPulsePeriod.TabIndex = 4; this.labelPulsePeriod.Text = "Pulse Period [µs]"; // // textBoxBurstPulseCount // - this.textBoxBurstPulseCount.Location = new System.Drawing.Point(132, 200); + this.textBoxBurstPulseCount.Location = new System.Drawing.Point(99, 162); + this.textBoxBurstPulseCount.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxBurstPulseCount.Name = "textBoxBurstPulseCount"; - this.textBoxBurstPulseCount.Size = new System.Drawing.Size(75, 22); + this.textBoxBurstPulseCount.Size = new System.Drawing.Size(57, 20); this.textBoxBurstPulseCount.TabIndex = 2; this.textBoxBurstPulseCount.TextChanged += new System.EventHandler(this.BurstPulseCountChanged); // // labelBurstPulseCount // this.labelBurstPulseCount.AutoSize = true; - this.labelBurstPulseCount.Location = new System.Drawing.Point(15, 203); + this.labelBurstPulseCount.Location = new System.Drawing.Point(11, 165); + this.labelBurstPulseCount.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelBurstPulseCount.Name = "labelBurstPulseCount"; - this.labelBurstPulseCount.Size = new System.Drawing.Size(111, 16); + this.labelBurstPulseCount.Size = new System.Drawing.Size(91, 13); this.labelBurstPulseCount.TabIndex = 6; this.labelBurstPulseCount.Text = "Burst Pulse Count"; // // textBoxPulsePeriod // - this.textBoxPulsePeriod.Location = new System.Drawing.Point(237, 146); + this.textBoxPulsePeriod.Location = new System.Drawing.Point(178, 119); + this.textBoxPulsePeriod.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxPulsePeriod.Name = "textBoxPulsePeriod"; - this.textBoxPulsePeriod.Size = new System.Drawing.Size(75, 22); + this.textBoxPulsePeriod.Size = new System.Drawing.Size(57, 20); this.textBoxPulsePeriod.TabIndex = 1; // // textBoxInterBurstInterval // - this.textBoxInterBurstInterval.Location = new System.Drawing.Point(342, 203); + this.textBoxInterBurstInterval.Location = new System.Drawing.Point(256, 165); + this.textBoxInterBurstInterval.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxInterBurstInterval.Name = "textBoxInterBurstInterval"; - this.textBoxInterBurstInterval.Size = new System.Drawing.Size(75, 22); + this.textBoxInterBurstInterval.Size = new System.Drawing.Size(57, 20); this.textBoxInterBurstInterval.TabIndex = 3; // // labelInterBurstInterval // this.labelInterBurstInterval.AutoSize = true; - this.labelInterBurstInterval.Location = new System.Drawing.Point(245, 200); + this.labelInterBurstInterval.Location = new System.Drawing.Point(184, 162); + this.labelInterBurstInterval.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelInterBurstInterval.Name = "labelInterBurstInterval"; - this.labelInterBurstInterval.Size = new System.Drawing.Size(75, 32); + this.labelInterBurstInterval.Size = new System.Drawing.Size(62, 26); this.labelInterBurstInterval.TabIndex = 8; this.labelInterBurstInterval.Text = "Inter-Burst \r\nInterval [µs]"; // // textBoxTrainBurstCount // - this.textBoxTrainBurstCount.Location = new System.Drawing.Point(132, 251); + this.textBoxTrainBurstCount.Location = new System.Drawing.Point(99, 204); + this.textBoxTrainBurstCount.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxTrainBurstCount.Name = "textBoxTrainBurstCount"; - this.textBoxTrainBurstCount.Size = new System.Drawing.Size(75, 22); + this.textBoxTrainBurstCount.Size = new System.Drawing.Size(57, 20); this.textBoxTrainBurstCount.TabIndex = 4; this.textBoxTrainBurstCount.TextChanged += new System.EventHandler(this.TrainBurstCountChanged); // // labelTrainBurstCount // this.labelTrainBurstCount.AutoSize = true; - this.labelTrainBurstCount.Location = new System.Drawing.Point(15, 254); + this.labelTrainBurstCount.Location = new System.Drawing.Point(11, 206); + this.labelTrainBurstCount.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelTrainBurstCount.Name = "labelTrainBurstCount"; - this.labelTrainBurstCount.Size = new System.Drawing.Size(108, 16); + this.labelTrainBurstCount.Size = new System.Drawing.Size(89, 13); this.labelTrainBurstCount.TabIndex = 10; this.labelTrainBurstCount.Text = "Train Burst Count"; // - // textBoxTrainDelay - // - this.textBoxTrainDelay.Location = new System.Drawing.Point(342, 251); - this.textBoxTrainDelay.Name = "textBoxTrainDelay"; - this.textBoxTrainDelay.Size = new System.Drawing.Size(75, 22); - this.textBoxTrainDelay.TabIndex = 5; - // - // labelTriggerDelay - // - this.labelTriggerDelay.AutoSize = true; - this.labelTriggerDelay.Location = new System.Drawing.Point(225, 254); - this.labelTriggerDelay.Name = "labelTriggerDelay"; - this.labelTriggerDelay.Size = new System.Drawing.Size(102, 16); - this.labelTriggerDelay.TabIndex = 12; - this.labelTriggerDelay.Text = "Train Delay [µs]"; - // // Headstage64ElectricalStimulatorOptions // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(438, 289); - this.Controls.Add(this.textBoxTrainDelay); - this.Controls.Add(this.labelTriggerDelay); + this.ClientSize = new System.Drawing.Size(328, 235); this.Controls.Add(this.textBoxTrainBurstCount); this.Controls.Add(this.labelTrainBurstCount); this.Controls.Add(this.textBoxInterBurstInterval); @@ -287,6 +281,7 @@ private void InitializeComponent() this.Controls.Add(this.textBoxPulsePeriod); this.Controls.Add(this.labelPulsePeriod); this.Controls.Add(this.tableLayoutPanel1); + this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.Name = "Headstage64ElectricalStimulatorOptions"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Headstage64ElectricalStimulatorOptions"; @@ -319,7 +314,5 @@ private void InitializeComponent() private System.Windows.Forms.Label labelInterBurstInterval; internal System.Windows.Forms.TextBox textBoxTrainBurstCount; private System.Windows.Forms.Label labelTrainBurstCount; - internal System.Windows.Forms.TextBox textBoxTrainDelay; - private System.Windows.Forms.Label labelTriggerDelay; } } diff --git a/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.cs b/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.cs index d5968551..4438cf10 100644 --- a/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.cs +++ b/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorOptions.cs @@ -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) diff --git a/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorSequenceDialog.cs b/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorSequenceDialog.cs index 0be9ad77..b9158aa0 100644 --- a/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorSequenceDialog.cs +++ b/OpenEphys.Onix1.Design/Headstage64ElectricalStimulatorSequenceDialog.cs @@ -83,11 +83,6 @@ public Headstage64ElectricalStimulatorSequenceDialog(ConfigureHeadstage64Electri new TextBoxBinding( StimulusSequenceOptions.textBoxPulsePeriod, value => { ElectricalStimulator.InterPulseInterval = value; return ElectricalStimulator.InterPulseInterval; }, - uint.Parse) }, - { StimulusSequenceOptions.textBoxTrainDelay, - new TextBoxBinding( - StimulusSequenceOptions.textBoxTrainDelay, - value => { ElectricalStimulator.TriggerDelay = value; return ElectricalStimulator.TriggerDelay; }, uint.Parse) } }; @@ -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++) { diff --git a/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.Designer.cs b/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.Designer.cs index 9c3c103b..4eda2caf 100644 --- a/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.Designer.cs +++ b/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.Designer.cs @@ -28,8 +28,6 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.textBoxDelay = new System.Windows.Forms.TextBox(); - this.labelDelay = new System.Windows.Forms.Label(); this.textBoxBurstsPerTrain = new System.Windows.Forms.TextBox(); this.labelBurstsPerTrain = new System.Windows.Forms.Label(); this.textBoxInterBurstInterval = new System.Windows.Forms.TextBox(); @@ -52,111 +50,105 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.trackBarChannelTwoPercent)).BeginInit(); this.SuspendLayout(); // - // textBoxDelay - // - this.textBoxDelay.Location = new System.Drawing.Point(356, 244); - this.textBoxDelay.Name = "textBoxDelay"; - this.textBoxDelay.Size = new System.Drawing.Size(75, 22); - this.textBoxDelay.TabIndex = 19; - // - // labelDelay - // - this.labelDelay.AutoSize = true; - this.labelDelay.Location = new System.Drawing.Point(218, 247); - this.labelDelay.Name = "labelDelay"; - this.labelDelay.Size = new System.Drawing.Size(72, 16); - this.labelDelay.TabIndex = 18; - this.labelDelay.Text = "Delay [ms]"; - // // textBoxBurstsPerTrain // - this.textBoxBurstsPerTrain.Location = new System.Drawing.Point(133, 244); + this.textBoxBurstsPerTrain.Location = new System.Drawing.Point(100, 198); + this.textBoxBurstsPerTrain.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxBurstsPerTrain.Name = "textBoxBurstsPerTrain"; - this.textBoxBurstsPerTrain.Size = new System.Drawing.Size(75, 22); + this.textBoxBurstsPerTrain.Size = new System.Drawing.Size(57, 20); this.textBoxBurstsPerTrain.TabIndex = 17; this.textBoxBurstsPerTrain.TextChanged += new System.EventHandler(this.BurstsPerTrainChanged); // // labelBurstsPerTrain // this.labelBurstsPerTrain.AutoSize = true; - this.labelBurstsPerTrain.Location = new System.Drawing.Point(6, 247); + this.labelBurstsPerTrain.Location = new System.Drawing.Point(4, 201); + this.labelBurstsPerTrain.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelBurstsPerTrain.Name = "labelBurstsPerTrain"; - this.labelBurstsPerTrain.Size = new System.Drawing.Size(102, 16); + this.labelBurstsPerTrain.Size = new System.Drawing.Size(82, 13); this.labelBurstsPerTrain.TabIndex = 16; this.labelBurstsPerTrain.Text = "Bursts Per Train"; // // textBoxInterBurstInterval // - this.textBoxInterBurstInterval.Location = new System.Drawing.Point(356, 195); + this.textBoxInterBurstInterval.Location = new System.Drawing.Point(267, 158); + this.textBoxInterBurstInterval.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxInterBurstInterval.Name = "textBoxInterBurstInterval"; - this.textBoxInterBurstInterval.Size = new System.Drawing.Size(75, 22); + this.textBoxInterBurstInterval.Size = new System.Drawing.Size(57, 20); this.textBoxInterBurstInterval.TabIndex = 15; // // labelInterBurstInterval // - this.labelInterBurstInterval.Location = new System.Drawing.Point(216, 198); + this.labelInterBurstInterval.Location = new System.Drawing.Point(162, 161); + this.labelInterBurstInterval.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelInterBurstInterval.Name = "labelInterBurstInterval"; - this.labelInterBurstInterval.Size = new System.Drawing.Size(146, 19); + this.labelInterBurstInterval.Size = new System.Drawing.Size(110, 15); this.labelInterBurstInterval.TabIndex = 14; this.labelInterBurstInterval.Text = "Inter-Burst Interval [ms]"; // // textBoxPulsesPerBurst // - this.textBoxPulsesPerBurst.Location = new System.Drawing.Point(133, 195); + this.textBoxPulsesPerBurst.Location = new System.Drawing.Point(100, 158); + this.textBoxPulsesPerBurst.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxPulsesPerBurst.Name = "textBoxPulsesPerBurst"; - this.textBoxPulsesPerBurst.Size = new System.Drawing.Size(75, 22); + this.textBoxPulsesPerBurst.Size = new System.Drawing.Size(57, 20); this.textBoxPulsesPerBurst.TabIndex = 13; this.textBoxPulsesPerBurst.TextChanged += new System.EventHandler(this.PulsesPerBurstChanged); // // labelPulsesPerBurst // this.labelPulsesPerBurst.AutoSize = true; - this.labelPulsesPerBurst.Location = new System.Drawing.Point(6, 198); + this.labelPulsesPerBurst.Location = new System.Drawing.Point(4, 161); + this.labelPulsesPerBurst.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPulsesPerBurst.Name = "labelPulsesPerBurst"; - this.labelPulsesPerBurst.Size = new System.Drawing.Size(105, 16); + this.labelPulsesPerBurst.Size = new System.Drawing.Size(84, 13); this.labelPulsesPerBurst.TabIndex = 12; this.labelPulsesPerBurst.Text = "Pulses Per Burst"; // // labelMaxCurrent // this.labelMaxCurrent.AutoSize = true; - this.labelMaxCurrent.Location = new System.Drawing.Point(6, 20); + this.labelMaxCurrent.Location = new System.Drawing.Point(4, 16); + this.labelMaxCurrent.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelMaxCurrent.Name = "labelMaxCurrent"; - this.labelMaxCurrent.Size = new System.Drawing.Size(108, 16); + this.labelMaxCurrent.Size = new System.Drawing.Size(88, 13); this.labelMaxCurrent.TabIndex = 0; this.labelMaxCurrent.Text = "Max Current [mA]"; // // textBoxMaxCurrent // - this.textBoxMaxCurrent.Location = new System.Drawing.Point(133, 17); + this.textBoxMaxCurrent.Location = new System.Drawing.Point(100, 14); + this.textBoxMaxCurrent.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxMaxCurrent.Name = "textBoxMaxCurrent"; - this.textBoxMaxCurrent.Size = new System.Drawing.Size(75, 22); + this.textBoxMaxCurrent.Size = new System.Drawing.Size(57, 20); this.textBoxMaxCurrent.TabIndex = 1; // // textBoxChannelOnePercent // - this.textBoxChannelOnePercent.Location = new System.Drawing.Point(133, 58); + this.textBoxChannelOnePercent.Location = new System.Drawing.Point(100, 47); + this.textBoxChannelOnePercent.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxChannelOnePercent.Name = "textBoxChannelOnePercent"; - this.textBoxChannelOnePercent.Size = new System.Drawing.Size(75, 22); + this.textBoxChannelOnePercent.Size = new System.Drawing.Size(57, 20); this.textBoxChannelOnePercent.TabIndex = 3; // // labelChannelOnePercent // this.labelChannelOnePercent.AutoSize = true; - this.labelChannelOnePercent.Location = new System.Drawing.Point(6, 61); + this.labelChannelOnePercent.Location = new System.Drawing.Point(4, 50); + this.labelChannelOnePercent.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelChannelOnePercent.Name = "labelChannelOnePercent"; - this.labelChannelOnePercent.Size = new System.Drawing.Size(107, 16); + this.labelChannelOnePercent.Size = new System.Drawing.Size(86, 13); this.labelChannelOnePercent.TabIndex = 2; this.labelChannelOnePercent.Text = "Channel One [%]"; // // trackBarChannelOnePercent // this.trackBarChannelOnePercent.LargeChange = 125; - this.trackBarChannelOnePercent.Location = new System.Drawing.Point(11, 83); + this.trackBarChannelOnePercent.Location = new System.Drawing.Point(8, 67); this.trackBarChannelOnePercent.Margin = new System.Windows.Forms.Padding(0); this.trackBarChannelOnePercent.Maximum = 1000; this.trackBarChannelOnePercent.Name = "trackBarChannelOnePercent"; - this.trackBarChannelOnePercent.Size = new System.Drawing.Size(197, 45); + this.trackBarChannelOnePercent.Size = new System.Drawing.Size(148, 45); this.trackBarChannelOnePercent.SmallChange = 125; this.trackBarChannelOnePercent.TabIndex = 6; this.trackBarChannelOnePercent.TickFrequency = 125; @@ -165,28 +157,30 @@ private void InitializeComponent() // // textBoxPulseDuration // - this.textBoxPulseDuration.Location = new System.Drawing.Point(133, 146); + this.textBoxPulseDuration.Location = new System.Drawing.Point(100, 119); + this.textBoxPulseDuration.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxPulseDuration.Name = "textBoxPulseDuration"; - this.textBoxPulseDuration.Size = new System.Drawing.Size(75, 22); + this.textBoxPulseDuration.Size = new System.Drawing.Size(57, 20); this.textBoxPulseDuration.TabIndex = 9; // // labelPulseDuration // this.labelPulseDuration.AutoSize = true; - this.labelPulseDuration.Location = new System.Drawing.Point(6, 149); + this.labelPulseDuration.Location = new System.Drawing.Point(4, 121); + this.labelPulseDuration.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPulseDuration.Name = "labelPulseDuration"; - this.labelPulseDuration.Size = new System.Drawing.Size(123, 16); + this.labelPulseDuration.Size = new System.Drawing.Size(98, 13); this.labelPulseDuration.TabIndex = 8; this.labelPulseDuration.Text = "Pulse Duration [ms]"; // // trackBarChannelTwoPercent // this.trackBarChannelTwoPercent.LargeChange = 125; - this.trackBarChannelTwoPercent.Location = new System.Drawing.Point(219, 83); + this.trackBarChannelTwoPercent.Location = new System.Drawing.Point(164, 67); this.trackBarChannelTwoPercent.Margin = new System.Windows.Forms.Padding(0); this.trackBarChannelTwoPercent.Maximum = 1000; this.trackBarChannelTwoPercent.Name = "trackBarChannelTwoPercent"; - this.trackBarChannelTwoPercent.Size = new System.Drawing.Size(212, 45); + this.trackBarChannelTwoPercent.Size = new System.Drawing.Size(159, 45); this.trackBarChannelTwoPercent.SmallChange = 125; this.trackBarChannelTwoPercent.TabIndex = 7; this.trackBarChannelTwoPercent.TickFrequency = 125; @@ -194,41 +188,45 @@ private void InitializeComponent() // // textBoxChannelTwoPercent // - this.textBoxChannelTwoPercent.Location = new System.Drawing.Point(356, 58); + this.textBoxChannelTwoPercent.Location = new System.Drawing.Point(267, 47); + this.textBoxChannelTwoPercent.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxChannelTwoPercent.Name = "textBoxChannelTwoPercent"; - this.textBoxChannelTwoPercent.Size = new System.Drawing.Size(75, 22); + this.textBoxChannelTwoPercent.Size = new System.Drawing.Size(57, 20); this.textBoxChannelTwoPercent.TabIndex = 5; // // labelChannelTwoPercent // this.labelChannelTwoPercent.AutoSize = true; - this.labelChannelTwoPercent.Location = new System.Drawing.Point(216, 61); + this.labelChannelTwoPercent.Location = new System.Drawing.Point(162, 50); + this.labelChannelTwoPercent.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelChannelTwoPercent.Name = "labelChannelTwoPercent"; - this.labelChannelTwoPercent.Size = new System.Drawing.Size(108, 16); + this.labelChannelTwoPercent.Size = new System.Drawing.Size(87, 13); this.labelChannelTwoPercent.TabIndex = 4; this.labelChannelTwoPercent.Text = "Channel Two [%]"; // // textBoxPulsePeriod // - this.textBoxPulsePeriod.Location = new System.Drawing.Point(356, 146); + this.textBoxPulsePeriod.Location = new System.Drawing.Point(267, 119); + this.textBoxPulsePeriod.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.textBoxPulsePeriod.Name = "textBoxPulsePeriod"; - this.textBoxPulsePeriod.Size = new System.Drawing.Size(75, 22); + this.textBoxPulsePeriod.Size = new System.Drawing.Size(57, 20); this.textBoxPulsePeriod.TabIndex = 11; // // labelPulsePeriod // this.labelPulsePeriod.AutoSize = true; - this.labelPulsePeriod.Location = new System.Drawing.Point(216, 149); + this.labelPulsePeriod.Location = new System.Drawing.Point(162, 121); + this.labelPulsePeriod.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelPulsePeriod.Name = "labelPulsePeriod"; - this.labelPulsePeriod.Size = new System.Drawing.Size(113, 16); + this.labelPulsePeriod.Size = new System.Drawing.Size(88, 13); this.labelPulsePeriod.TabIndex = 10; this.labelPulsePeriod.Text = "Pulse Period [ms]"; // // Headstage64OpticalStimulatorOptions // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(438, 289); + this.ClientSize = new System.Drawing.Size(328, 235); this.Controls.Add(this.textBoxPulsePeriod); this.Controls.Add(this.labelPulsePeriod); this.Controls.Add(this.trackBarChannelTwoPercent); @@ -241,14 +239,13 @@ private void InitializeComponent() this.Controls.Add(this.labelChannelOnePercent); this.Controls.Add(this.textBoxMaxCurrent); this.Controls.Add(this.labelMaxCurrent); - this.Controls.Add(this.textBoxDelay); - this.Controls.Add(this.labelDelay); this.Controls.Add(this.textBoxBurstsPerTrain); this.Controls.Add(this.labelBurstsPerTrain); this.Controls.Add(this.textBoxInterBurstInterval); this.Controls.Add(this.labelInterBurstInterval); this.Controls.Add(this.textBoxPulsesPerBurst); this.Controls.Add(this.labelPulsesPerBurst); + this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.Name = "Headstage64OpticalStimulatorOptions"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Headstage64OpticalStimulatorOptions"; @@ -260,9 +257,6 @@ private void InitializeComponent() } #endregion - - internal System.Windows.Forms.TextBox textBoxDelay; - private System.Windows.Forms.Label labelDelay; internal System.Windows.Forms.TextBox textBoxBurstsPerTrain; private System.Windows.Forms.Label labelBurstsPerTrain; internal System.Windows.Forms.TextBox textBoxInterBurstInterval; diff --git a/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.cs b/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.cs index 83ff20df..ad7367c5 100644 --- a/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.cs +++ b/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorOptions.cs @@ -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; diff --git a/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorSequenceDialog.cs b/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorSequenceDialog.cs index 222d2f0d..35d243e5 100644 --- a/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorSequenceDialog.cs +++ b/OpenEphys.Onix1.Design/Headstage64OpticalStimulatorSequenceDialog.cs @@ -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; @@ -78,11 +77,6 @@ public Headstage64OpticalStimulatorSequenceDialog(ConfigureHeadstage64OpticalSti StimulusSequenceOptions.textBoxInterBurstInterval, value => { OpticalStimulator.InterBurstInterval = value; return OpticalStimulator.InterBurstInterval; }, double.Parse) }, - { StimulusSequenceOptions.textBoxDelay, - new TextBoxBinding( - StimulusSequenceOptions.textBoxDelay, - value => { OpticalStimulator.Delay = value; return OpticalStimulator.Delay; }, - double.Parse) }, { StimulusSequenceOptions.textBoxPulseDuration, new TextBoxBinding( StimulusSequenceOptions.textBoxPulseDuration, @@ -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, diff --git a/OpenEphys.Onix1/ConfigureHeadstage64.cs b/OpenEphys.Onix1/ConfigureHeadstage64.cs index 321ed807..4fa4e8e7 100644 --- a/OpenEphys.Onix1/ConfigureHeadstage64.cs +++ b/OpenEphys.Onix1/ConfigureHeadstage64.cs @@ -88,6 +88,17 @@ public ConfigureHeadstage64() [Editor("OpenEphys.Onix1.Design.Headstage64OpticalStimulatorUITypeEditor, OpenEphys.Onix1.Design", typeof(UITypeEditor))] public ConfigureHeadstage64OpticalStimulator OpticalStimulator { get; set; } = new(); + /// + /// Gets or sets the heartbeat configuration. + /// + /// + /// This heartbeat is always enabled and beats at a minimum of 10 Hz. + /// + [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 }; + /// /// Gets or sets the port. /// @@ -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; } } @@ -148,6 +162,7 @@ internal override IEnumerable GetDevices() yield return TS4231; yield return ElectricalStimulator; yield return OpticalStimulator; + yield return Heartbeat; } class ConfigureHeadstage64PortController : ConfigurePortController diff --git a/OpenEphys.Onix1/ConfigureHeadstage64ElectricalStimulator.cs b/OpenEphys.Onix1/ConfigureHeadstage64ElectricalStimulator.cs index 6f5caae3..e332b8bf 100644 --- a/OpenEphys.Onix1/ConfigureHeadstage64ElectricalStimulator.cs +++ b/OpenEphys.Onix1/ConfigureHeadstage64ElectricalStimulator.cs @@ -19,7 +19,8 @@ namespace OpenEphys.Onix1 [Editor("OpenEphys.Onix1.Design.Headstage64ElectricalStimulatorComponentEditor, OpenEphys.Onix1.Design", typeof(ComponentEditor))] public class ConfigureHeadstage64ElectricalStimulator : SingleDeviceFactory { - readonly BehaviorSubject stimEnable = new(false); + internal uint? PortControllerDeviceAddress { get; set; } + readonly BehaviorSubject phaseOneCurrent = new(0); readonly BehaviorSubject interPhaseCurrent = new(0); readonly BehaviorSubject phaseTwoCurrent = new(0); @@ -30,8 +31,6 @@ public class ConfigureHeadstage64ElectricalStimulator : SingleDeviceFactory readonly BehaviorSubject burstPulseCount = new(0); readonly BehaviorSubject interBurstInterval = new(0); readonly BehaviorSubject trainBurstCount = new(0); - readonly BehaviorSubject triggerDelay = new(0); - readonly BehaviorSubject powerEnable = new(false); /// /// Initializes a new instance of the class. @@ -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; @@ -76,45 +72,6 @@ public ConfigureHeadstage64ElectricalStimulator(ConfigureHeadstage64ElectricalSt [Description("Specifies whether the headstage-64 electrical stimulator will produce stimulus reports.")] public bool Enable { get; set; } - /// - /// Gets or sets the device enable state. - /// - /// - /// If set to true, then the electrical stimulator circuit will respect triggers. If set to false, triggers will be ignored. - /// - [Description("Specifies whether the electrical stimulator will respect triggers.")] - [Category(AcquisitionCategory)] - public bool StimEnable { get; set; } = true; - - /// - /// Gets or sets the electrical stimulator's power state. - /// - /// - /// 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. - /// - [Description("Stimulator power on/off.")] - [Category(AcquisitionCategory)] - public bool PowerEnable - { - get => powerEnable.Value; - set => powerEnable.OnNext(value); - } - - /// - /// Gets or sets a delay from receiving a trigger to the start of stimulus sequence application in μsec. - /// - [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) @@ -271,18 +228,15 @@ public override IObservable Process(IObservable 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)), @@ -290,8 +244,7 @@ public override IObservable Process(IObservable source 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)); }); } } @@ -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) { diff --git a/OpenEphys.Onix1/ConfigureHeadstage64OpticalStimulator.cs b/OpenEphys.Onix1/ConfigureHeadstage64OpticalStimulator.cs index 0bd34413..622fba0c 100644 --- a/OpenEphys.Onix1/ConfigureHeadstage64OpticalStimulator.cs +++ b/OpenEphys.Onix1/ConfigureHeadstage64OpticalStimulator.cs @@ -19,16 +19,17 @@ namespace OpenEphys.Onix1 [Editor("OpenEphys.Onix1.Design.Headstage64OpticalStimulatorComponentEditor, OpenEphys.Onix1.Design", typeof(ComponentEditor))] public class ConfigureHeadstage64OpticalStimulator : SingleDeviceFactory { - readonly BehaviorSubject stimEnable = new(true); - readonly BehaviorSubject maxCurrent = new(100); - readonly BehaviorSubject channelOneCurrent = new(100); + internal uint? PortControllerDeviceAddress { get; set; } + + readonly BehaviorSubject enableIndicationLed = new(false); + readonly BehaviorSubject maxCurrent = new(0); + readonly BehaviorSubject channelOneCurrent = new(0); readonly BehaviorSubject channelTwoCurrent = new(0); - readonly BehaviorSubject pulseDuration = new(5); - readonly BehaviorSubject pulsesPerSecond = new(50); - readonly BehaviorSubject pulsesPerBurst = new(20); + readonly BehaviorSubject pulseDuration = new(0); + readonly BehaviorSubject pulsesPerSecond = new(0); + readonly BehaviorSubject pulsesPerBurst = new(0); readonly BehaviorSubject interBurstInterval = new(0); - readonly BehaviorSubject burstsPerTrain = new(1); - readonly BehaviorSubject delay = new(0); + readonly BehaviorSubject burstsPerTrain = new(0); /// /// Initializes a new instance of the class. @@ -47,8 +48,6 @@ public ConfigureHeadstage64OpticalStimulator(ConfigureHeadstage64OpticalStimulat DeviceName = opticalStimulator.DeviceName; DeviceAddress = opticalStimulator.DeviceAddress; Enable = opticalStimulator.Enable; - StimEnable = opticalStimulator.StimEnable; - Delay = opticalStimulator.Delay; MaxCurrent = opticalStimulator.MaxCurrent; ChannelOneCurrent = opticalStimulator.ChannelOneCurrent; ChannelTwoCurrent = opticalStimulator.ChannelTwoCurrent; @@ -71,31 +70,17 @@ public ConfigureHeadstage64OpticalStimulator(ConfigureHeadstage64OpticalStimulat public bool Enable { get; set; } /// - /// Gets or sets the device enable state. + /// Gets or sets the indication LED enable state. /// /// - /// If set to true, then the optical stimulator circuit will respect triggers. If set to false, triggers will be ignored. + /// If set to true, the headstage's indication LED will turn on. When set to false, it will turn off. /// - [Description("Specifies whether the optical stimulator will respect triggers.")] + [Description("Specifies the state of the headstage indication LED")] [Category(AcquisitionCategory)] - public bool StimEnable + public bool EnableIndicationLed { - get => stimEnable.Value; - set => stimEnable.OnNext(value); - } - - /// - /// Gets or sets a delay from receiving a trigger to the start of stimulus sequence application in msec. - /// - [Description("A delay from receiving a trigger to the start of stimulus sequence application (msec).")] - [Editor(DesignTypes.NumericUpDownEditor, DesignTypes.UITypeEditor)] - [Range(Headstage64OpticalStimulator.MinDelay, Headstage64OpticalStimulator.MaxDelay)] - [Precision(3, 1)] - [Category(AcquisitionCategory)] - public double Delay - { - get => delay.Value; - set => delay.OnNext(Clamp(value, Headstage64OpticalStimulator.MinDelay, Headstage64OpticalStimulator.MaxDelay)); + get => enableIndicationLed.Value; + set => enableIndicationLed.OnNext(value); } /// @@ -272,6 +257,7 @@ public override IObservable Process(IObservable source return source.ConfigureDevice((context, observer) => { var device = context.GetDeviceContext(deviceAddress, DeviceType); + var deviceInfo = new Headstage64StimulatorDeviceInfo(context, DeviceType, deviceAddress, PortControllerDeviceAddress); device.WriteRegister(Headstage64OpticalStimulator.ENABLE, enable ? 1u : 0u); @@ -295,9 +281,17 @@ static uint pulseFrequencyToRegister(double pulseHz, double pulseDuration) return pulsePeriod > pulseDuration ? (uint)(1000 * pulsePeriod) : (uint)(1000 * pulseDuration + 1); } + uint stimEnableValue = 0; + return new CompositeDisposable( - stimEnable.SubscribeSafe(observer, value => - device.WriteRegister(Headstage64OpticalStimulator.STIMENABLE, value ? 1u : 0u)), + enableIndicationLed.SubscribeSafe(observer, value => + { + if (value) + stimEnableValue |= (1u << 8); + else + stimEnableValue &= ~(1u << 8); + device.WriteRegister(Headstage64OpticalStimulator.STIMENABLE, stimEnableValue); + }), maxCurrent.SubscribeSafe(observer, value => device.WriteRegister(Headstage64OpticalStimulator.MAXCURRENT, Headstage64OpticalStimulator.MilliampsToPotSetting(value))), channelOneCurrent.SubscribeSafe(observer, value => @@ -320,9 +314,7 @@ static uint pulseFrequencyToRegister(double pulseHz, double pulseDuration) device.WriteRegister(Headstage64OpticalStimulator.IBI, (uint)(1000 * value))), burstsPerTrain.SubscribeSafe(observer, value => device.WriteRegister(Headstage64OpticalStimulator.TRAINCOUNT, value)), - delay.SubscribeSafe(observer, value => - device.WriteRegister(Headstage64OpticalStimulator.TRAINDELAY, (uint)(1000 * value))), - DeviceManager.RegisterDevice(deviceName, device, DeviceType)); + DeviceManager.RegisterDevice(deviceName, deviceInfo)); }); } } @@ -336,9 +328,6 @@ static class Headstage64OpticalStimulator public const uint MinRheostatResistanceOhms = 590; public const uint PotResistanceOhms = 100_000; - public const double MinDelay = 0.0; - public const double MaxDelay = 1000.0; - public const double MinCurrent = 0.0; public const double MaxCurrent = 300.0; @@ -364,13 +353,10 @@ static class Headstage64OpticalStimulator public const uint BURSTCOUNT = 5; // Number of pulses in burst public const uint IBI = 6; // Inter-burst interval, microseconds public const uint TRAINCOUNT = 7; // Number of bursts in train - public const uint TRAINDELAY = 8; // Stimulus start delay, microseconds - public const uint TRIGGER = 9; // Trigger stimulation (0 = off, 1 = deliver) - public const uint STIMENABLE = 10; // 1: enables the stimulator, 0: stimulator ignores triggers (so that a common trigger can be used) - public const uint RESTMASK = 11; // Bitmask determining the off state of the up to 32 current channels - public const uint RESET = 12; // None If 1, Reset all parameters to default (not implemented) - public const uint MINRHEOR = 13; // The series resistor between the potentiometer (rheostat) and RSET bin on the CAT4016 - public const uint POTRES = 14; // The resistance value of the potentiometer connected in rheostat config to RSET on CAT4016 + public const uint TRIGGER = 8; // Trigger stimulation (0 = off, 1 = deliver) + public const uint STIMENABLE = 9; // 1: enables the stimulator, 0: stimulator ignores triggers (so that a common trigger can be used) + public const uint MINRHEOR = 10; // The series resistor between the potentiometer (rheostat) and RSET bin on the CAT4016 + public const uint POTRES = 11; // The resistance value of the potentiometer connected in rheostat config to RSET on CAT4016 // NB: fit from Fig. 10 of CAT4016 datasheet // x = (y/a)^(1/b) diff --git a/OpenEphys.Onix1/ConfigurePortController.cs b/OpenEphys.Onix1/ConfigurePortController.cs index 0bad98f8..3652709d 100644 --- a/OpenEphys.Onix1/ConfigurePortController.cs +++ b/OpenEphys.Onix1/ConfigurePortController.cs @@ -107,7 +107,7 @@ internal static class PortController public const uint MinimumVersion = 2; public const uint ENABLE = 0; // The LSB is used to enable or disable the device data stream - public const uint GPOSTATE = 1; // GPO output state (bits 31 downto 3: ignore. bits 2 downto 0: ‘1’ = high, ‘0’ = low) + public const uint GPOSTATE = 1; // Controls the GPO output state 32 bits: [X, X, ..., X, GPO 3, GPO 2, GPO 1] public const uint DESPWR = 2; // Set link deserializer PDB state, 0 = deserializer power off else on. Does not affect port voltage. public const uint PORTVOLTAGE = 3; // 10 * link voltage public const uint SAVEVOLTAGE = 4; // Save link voltage to non-volatile EEPROM if greater than 0. This voltage will be applied after POR. @@ -193,4 +193,28 @@ public enum PortName [Description("Port B")] PortB = 2 } + + /// + /// Specifies the state of a port controller's GPIO pins. + /// + /// + /// Pin 0 is inaccessible because it is used for issuing hardware resets. + /// + [Flags] + public enum PortControllerGpioState : byte + { + /// + /// Specifies that pin 1 is high. + /// + Pin1 = 0x1, + /// + /// Specifies that pin 2 is high. + /// + Pin2 = 0x2, + /// + /// Specifies that pin 3 is high. + /// + Pin3 = 0x4, + } + } diff --git a/OpenEphys.Onix1/Headstage64ElectricalStimulatorTrigger.cs b/OpenEphys.Onix1/Headstage64ElectricalStimulatorTrigger.cs index 7cf0f497..aa442fd3 100644 --- a/OpenEphys.Onix1/Headstage64ElectricalStimulatorTrigger.cs +++ b/OpenEphys.Onix1/Headstage64ElectricalStimulatorTrigger.cs @@ -2,7 +2,9 @@ using System.ComponentModel; using System.Linq; using System.Reactive; +using System.Reactive.Disposables; using System.Reactive.Linq; +using System.Reactive.Subjects; using Bonsai; namespace OpenEphys.Onix1 @@ -18,8 +20,11 @@ namespace OpenEphys.Onix1 /// corresponding contact on a compatible electrode interface board. /// [Description("Controls a headstage-64 onboard electrical stimulus sequencer.")] - public class Headstage64ElectricalStimulatorTrigger : Sink + public class Headstage64ElectricalStimulatorTrigger : Sink { + + readonly BehaviorSubject stimEnable = new(false); + /// [TypeConverter(typeof(Headstage64ElectricalStimulator.NameConverter))] [Description(SingleDeviceFactory.DeviceNameDescription)] @@ -27,26 +32,79 @@ public class Headstage64ElectricalStimulatorTrigger : Sink public string DeviceName { get; set; } /// - /// Start an electrical stimulus sequence. + /// Gets or sets the device enable state. + /// + /// + /// 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 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. + /// + [Description("Specifies whether the electrical stimulator will respect triggers.")] + [Category(DeviceFactory.AcquisitionCategory)] + public bool Enable + { + get => stimEnable.Value; + set => stimEnable.OnNext(value); + } + + /// + /// Start an electrical stimulus sequence with an optional hardware delay. /// - /// A sequence of boolean values indicating the start of a stimulus sequence when true. - /// A sequence of boolean values that is identical to - public override IObservable Process(IObservable source) + /// A sequence of doubles that serve as a combined stimulus trigger and + /// delay in microseconds. A value of 0 results in immediate stimulus delivery. A value of 100 results in + /// stimulus delivery following a 100 microsecond delay. Delays are implemented in hardware and are + /// exact. + /// A sequence of doubles that is identical to + public override IObservable Process(IObservable source) { return DeviceManager.GetDevice(DeviceName).SelectMany( - deviceInfo => Observable.Create(observer => + deviceInfo => Observable.Create(observer => { - var device = deviceInfo.GetDeviceContext(typeof(Headstage64ElectricalStimulator)); - var triggerObserver = Observer.Create( - value => - { - device.WriteRegister(Headstage64ElectricalStimulator.TRIGGER, value ? 1u : 0u); + var info = (Headstage64StimulatorDeviceInfo)deviceInfo; + var device = info.GetDeviceContext(typeof(Headstage64ElectricalStimulator)); + IObserver triggerObserver; + + if (info.PortControllerAddress != null) + { + var portController = device.Context.GetDeviceContext((uint)info.PortControllerAddress, typeof(PortController)); + triggerObserver = Observer.Create(value => { + if (stimEnable.Value) + { + if (value == 0) + { + portController.WriteRegister(PortController.GPOSTATE, (byte)PortControllerGpioState.Pin1); + portController.WriteRegister(PortController.GPOSTATE, 0); + } + else + { + device.WriteRegister(Headstage64ElectricalStimulator.TRIGGER, (uint)value << 8 | 0x1); + } + } + observer.OnNext(value); + }, + observer.OnError, + observer.OnCompleted); + } + else + { + triggerObserver = Observer.Create(value => { + if (stimEnable.Value) + { + device.WriteRegister(Headstage64ElectricalStimulator.TRIGGER, (uint)value << 8 | 0x1); + } observer.OnNext(value); }, observer.OnError, observer.OnCompleted); + } - return source.SubscribeSafe(triggerObserver); + return new CompositeDisposable( + stimEnable.SubscribeSafe(observer, value => + device.WriteRegister(Headstage64ElectricalStimulator.STIMENABLE, value ? 3u : 0u)), + source.SubscribeSafe(triggerObserver)); })); } } diff --git a/OpenEphys.Onix1/Headstage64OpticalStimulatorDataFrame.cs b/OpenEphys.Onix1/Headstage64OpticalStimulatorDataFrame.cs index 69b20f3b..2be79667 100644 --- a/OpenEphys.Onix1/Headstage64OpticalStimulatorDataFrame.cs +++ b/OpenEphys.Onix1/Headstage64OpticalStimulatorDataFrame.cs @@ -22,8 +22,6 @@ public unsafe Headstage64OpticalStimulatorDataFrame(oni.Frame frame) HubClock = payload->HubClock; Origin = (Headstage64StimulatorTriggerOrigin)(payload->DelayAndOrigin & 0x000F); Delay = (payload->DelayAndOrigin & 0xFFF0) >> 8; - ChannelOneRestCurrent = CodeToMilliamps(payload->MaxCurrent, (byte)(payload->RestMask & 0x00FF)); - ChannelTwoRestCurrent = CodeToMilliamps(payload->MaxCurrent, (byte)((payload->RestMask & 0xFF00) >> 8)); ChannelOneCurrent = CodeToMilliamps(payload->MaxCurrent, (byte)(payload->PulseMask & 0x00FF)); ChannelTwoCurrent = CodeToMilliamps(payload->MaxCurrent, (byte)((payload->PulseMask & 0xFF00) >> 8)); PulseDuration = payload->PulseDuration / 1e3; @@ -44,16 +42,6 @@ public unsafe Headstage64OpticalStimulatorDataFrame(oni.Frame frame) /// public uint Delay { get; } - /// - /// Gets the channel one rest current in milliamps. - /// - public double ChannelOneRestCurrent { get; } - - /// - /// Gets the channel two rest current in milliamps. - /// - public double ChannelTwoRestCurrent { get; } - /// /// Gets the channel one pulse current in milliamps. /// @@ -114,7 +102,6 @@ unsafe struct Headstage64OpticalStimulatorPayload { public ulong HubClock; public uint DelayAndOrigin; - public uint RestMask; public uint MaxCurrent; public uint PulseMask; public uint PulseDuration; diff --git a/OpenEphys.Onix1/Headstage64OpticalStimulatorTrigger.cs b/OpenEphys.Onix1/Headstage64OpticalStimulatorTrigger.cs index 6af266bb..113b0a25 100644 --- a/OpenEphys.Onix1/Headstage64OpticalStimulatorTrigger.cs +++ b/OpenEphys.Onix1/Headstage64OpticalStimulatorTrigger.cs @@ -2,7 +2,9 @@ using System.ComponentModel; using System.Linq; using System.Reactive; +using System.Reactive.Disposables; using System.Reactive.Linq; +using System.Reactive.Subjects; using Bonsai; namespace OpenEphys.Onix1 @@ -18,34 +20,92 @@ namespace OpenEphys.Onix1 /// contacts on a compatible electrode interface board. /// [Description("Controls a headstage-64 onboard optical stimulus sequencer.")] - public class Headstage64OpticalStimulatorTrigger : Sink + public class Headstage64OpticalStimulatorTrigger : Sink { + readonly BehaviorSubject stimEnable = new(false); + /// [TypeConverter(typeof(Headstage64OpticalStimulator.NameConverter))] [Category(DeviceFactory.ConfigurationCategory)] public string DeviceName { get; set; } /// - /// Start an optical stimulus sequence. + /// Gets or sets the device enable state. + /// + /// + /// If set to true, then the optical stimulator circuit will respect triggers. If set to false, triggers will be ignored. + /// + [Description("Specifies whether the optical stimulator will respect triggers.")] + [Category(DeviceFactory.AcquisitionCategory)] + public bool StimEnable + { + get => stimEnable.Value; + set => stimEnable.OnNext(value); + } + + /// + /// Start an optical stimulus sequence with an optional hardware delay. /// - /// A sequence of boolean values indicating the start of a stimulus sequence when true. - /// A sequence of boolean values that is identical to - public override IObservable Process(IObservable source) + /// A sequence of double values that serve as a combined stimulus trigger and + /// delay in microseconds. For instance, a value of 0 results in immediate stimulus delivery, a value + /// of 100 results in stimulus delivery following a 100 microsecond delay, etc. Delays are implemented in + /// hardware and are exact. + /// A sequence of double values that is identical to + public override IObservable Process(IObservable source) { return DeviceManager.GetDevice(DeviceName).SelectMany( - deviceInfo => Observable.Create(observer => + deviceInfo => Observable.Create(observer => { - var device = deviceInfo.GetDeviceContext(typeof(Headstage64OpticalStimulator)); - var triggerObserver = Observer.Create( - value => + var info = (Headstage64StimulatorDeviceInfo)deviceInfo; + var device = info.GetDeviceContext(typeof(Headstage64OpticalStimulator)); + IObserver triggerObserver; + + if (info.PortControllerAddress != null) + { + var portController = device.Context.GetDeviceContext((uint)info.PortControllerAddress, typeof(PortController)); + triggerObserver = Observer.Create(value => { - device.WriteRegister(Headstage64OpticalStimulator.TRIGGER, value ? 1u : 0u); + if (stimEnable.Value) + { + if (value == 0) + { + portController.WriteRegister(PortController.GPOSTATE, (byte)PortControllerGpioState.Pin1); + portController.WriteRegister(PortController.GPOSTATE, 0); + } + else + { + device.WriteRegister(Headstage64OpticalStimulator.TRIGGER, (uint)value << 8 | 0x1); + } + } + observer.OnNext(value); + }, + observer.OnError, + observer.OnCompleted); + } + else + { + triggerObserver = Observer.Create(value => { + if (stimEnable.Value) + { + device.WriteRegister(Headstage64OpticalStimulator.TRIGGER, (uint)value << 8 | 0x1); + } observer.OnNext(value); }, observer.OnError, observer.OnCompleted); + } + + return new CompositeDisposable(stimEnable.SubscribeSafe(observer, value => + { + var stimEnableValue = device.ReadRegister(Headstage64OpticalStimulator.STIMENABLE); + if (value) + stimEnableValue |= 1u; + else + stimEnableValue &= ~1u; + device.WriteRegister(Headstage64OpticalStimulator.STIMENABLE, stimEnableValue); + }), + source.SubscribeSafe(triggerObserver)); - return source.SubscribeSafe(triggerObserver); })); } } diff --git a/OpenEphys.Onix1/Headstage64StimulatorDeviceInfo.cs b/OpenEphys.Onix1/Headstage64StimulatorDeviceInfo.cs new file mode 100644 index 00000000..5d8a4341 --- /dev/null +++ b/OpenEphys.Onix1/Headstage64StimulatorDeviceInfo.cs @@ -0,0 +1,15 @@ +using System; + +namespace OpenEphys.Onix1 +{ + class Headstage64StimulatorDeviceInfo : DeviceInfo + { + public Headstage64StimulatorDeviceInfo(ContextTask context, Type deviceType, uint deviceAddress, uint? portControllerAddress) + : base(context, deviceType, deviceAddress) + { + PortControllerAddress = portControllerAddress; + } + + public uint? PortControllerAddress {get; } + } +} diff --git a/OpenEphys.Onix1/Rhs2116StimulusTrigger.cs b/OpenEphys.Onix1/Rhs2116StimulusTrigger.cs index 4d7293a9..89d7c4ed 100644 --- a/OpenEphys.Onix1/Rhs2116StimulusTrigger.cs +++ b/OpenEphys.Onix1/Rhs2116StimulusTrigger.cs @@ -23,9 +23,9 @@ public class Rhs2116StimulusTrigger : Sink /// Start an electrical stimulus sequence with an optional hardware delay. /// /// A sequence of double values that serve as a combined stimulus trigger and - /// delay in microseconds. A value of 0 results in immediate stimulus delivery. A value of 100 results in - /// stimulus delivery following a 100 microsecond delay. Delays are implemented in hardware and are - /// exact. + /// delay in microseconds. For instance, a value of 0 results in immediate stimulus delivery, a value + /// of 100 results in stimulus delivery following a 100 microsecond delay, etc. Delays are implemented in + /// hardware and are exact. /// A sequence of double values that is identical to public override IObservable Process(IObservable source) {