Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document breakout board and related #161

Closed
wants to merge 1 commit into from
Closed
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
15 changes: 15 additions & 0 deletions OpenEphys.Onix/OpenEphys.Onix/ConfigureBreakoutBoard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,32 @@

namespace OpenEphys.Onix
{
/// <summary>
/// A class that configures an ONIX breakout board.
/// </summary>
public class ConfigureBreakoutBoard : HubDeviceFactory
{
/// <summary>
/// Gets or sets the heartbeat configuration.
/// </summary>
[TypeConverter(typeof(HubDeviceConverter))]
public ConfigureHeartbeat Heartbeat { get; set; } = new();

/// <summary>
/// Gets or sets the breakout board's analog IO configuration.
/// </summary>
[TypeConverter(typeof(HubDeviceConverter))]
public ConfigureAnalogIO AnalogIO { get; set; } = new();

/// <summary>
/// Gets or sets the breakout board's digital IO configuration.
/// </summary>
[TypeConverter(typeof(HubDeviceConverter))]
public ConfigureDigitalIO DigitalIO { get; set; } = new();

/// <summary>
/// Gets or sets the hardware memory monitor configuration.
/// </summary>
[TypeConverter(typeof(HubDeviceConverter))]
public ConfigureMemoryMonitor MemoryMonitor { get; set; } = new();

Expand Down
88 changes: 87 additions & 1 deletion OpenEphys.Onix/OpenEphys.Onix/ConfigureDigitalIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,38 @@

namespace OpenEphys.Onix
{
/// <summary>
/// A class for configuring the ONIX breakout board's digital inputs and outputs.
/// </summary>
public class ConfigureDigitalIO : SingleDeviceFactory
{
/// <summary>
/// Initialize a new instance of <see cref="ConfigureDigitalIO"/>.
/// </summary>
public ConfigureDigitalIO()
: base(typeof(DigitalIO))
{
DeviceAddress = 7;
}

/// <summary>
/// Get or set the device enable state.
/// </summary>
/// <remarks>
/// If set to true, <see cref="DigitalInput"/> will produce data. If set to false, <see cref="DigitalInput"/> will not produce data.
/// </remarks>
[Category(ConfigurationCategory)]
[Description("Specifies whether the digital IO device is enabled.")]
public bool Enable { get; set; } = true;

/// <summary>
/// Configure an ONIX breakout board's digital inputs and outputs within an ONI context.
/// </summary>
/// <remarks>
/// This will schedule digital IO hardware configuration actions that can be applied by a <see cref="StartAcquisition"/> object prior to data collection.
/// </remarks>
/// <param name="source">A sequence of <see cref="ContextTask"/> instances that holds configuration actions.</param>
/// <returns>The original sequence modified by adding additional configuration actions required to configure a digital IO device./></returns>
public override IObservable<ContextTask> Process(IObservable<ContextTask> source)
{
var deviceName = DeviceName;
Expand Down Expand Up @@ -44,33 +64,99 @@ public NameConverter()
}
}

/// <summary>
/// Specifies the state of the ONIX breakout board's digital input pins.
/// </summary>
[Flags]
public enum DigitalPortState : ushort
public enum BreakoutDigitalPortState : ushort
{
/// <summary>
/// Specifies that pin 0 is high.
/// </summary>
Pin0 = 0x1,
/// <summary>
/// Specifies that pin 1 is high.
/// </summary>
Pin1 = 0x2,
/// <summary>
/// Specifies that pin 2 is high.
/// </summary>
Pin2 = 0x4,
/// <summary>
/// Specifies that pin 3 is high.
/// </summary>
Pin3 = 0x8,
/// <summary>
/// Specifies that pin 4 is high.
/// </summary>
Pin4 = 0x10,
/// <summary>
/// Specifies that pin 5 is high.
/// </summary>
Pin5 = 0x20,
/// <summary>
/// Specifies that pin 6 is high.
/// </summary>
Pin6 = 0x40,
/// <summary>
/// Specifies that pin 7 is high.
/// </summary>
Pin7 = 0x80,
}

/// <summary>
/// Specifies the state of the ONIX breakout board's switches and buttons.
/// </summary>
[Flags]
public enum BreakoutButtonState : ushort
{
/// <summary>
/// Specifies that the ☾ key is depressed.
/// </summary>
Moon = 0x1,
/// <summary>
/// Specifies that the △ key is depressed.
/// </summary>
Triangle = 0x2,
/// <summary>
/// Specifies that the × key is depressed.
/// </summary>
X = 0x4,
/// <summary>
/// Specifies that the ✓ key is depressed.
/// </summary>
Check = 0x8,
/// <summary>
/// Specifies that the ◯ key is depressed.
/// </summary>
Circle = 0x10,
/// <summary>
/// Specifies that the □ key is depressed.
/// </summary>
Square = 0x20,
/// <summary>
/// Specifies that reserved bit 0 is high.
/// </summary>
Reserved0 = 0x40,
/// <summary>
/// Specifies that reserved bit 1 is high.
/// </summary>
Reserved1 = 0x80,
/// <summary>
/// Specifies that port D power switch is set to on.
/// </summary>
PortDOn = 0x100,
/// <summary>
/// Specifies that port C power switch is set to on.
/// </summary>
PortCOn = 0x200,
/// <summary>
/// Specifies that port B power switch is set to on.
/// </summary>
PortBOn = 0x400,
/// <summary>
/// Specifies that port A power switch is set to on.
/// </summary>
PortAOn = 0x800,
}
}
37 changes: 34 additions & 3 deletions OpenEphys.Onix/OpenEphys.Onix/ConfigureHeartbeat.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,65 @@
using System;
using System.ComponentModel;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Bonsai;

namespace OpenEphys.Onix
{
/// <summary>
/// A class for configuring a heartbeat device.
/// <remarks>
/// This configuration class can be linked to a <see cref="HeartbeatData"/> instance to stream
/// heartbeats from the acquisition system.
/// </remarks>
/// </summary>
public class ConfigureHeartbeat : SingleDeviceFactory
{
readonly BehaviorSubject<uint> beatsPerSecond = new(10);

/// <summary>
/// Initializes and new instance of the <see cref="ConfigureHeartbeat"/> class.
/// </summary>
public ConfigureHeartbeat()
: base(typeof(Heartbeat))
{
}

/// <summary>
/// Get or set the device enable state.
/// </summary>
/// <remarks>
/// If set to true, a <see cref="HeartbeatData"/> instance that is linked to this configuration will produce data.
/// If set to false, it will not produce data.
/// </remarks>
[Category(ConfigurationCategory)]
[Description("Specifies whether the heartbeat device is enabled.")]
public bool Enable { get; set; } = true;

/// <summary>
/// Get or set the rate at which beats are produced in Hz.
/// </summary>
/// <remarks>
/// If set to true, a <see cref="HeartbeatData"/> instance that is linked to this configuration will produce data.
/// If set to false, it will not produce data.
[Range(1, 10e6)]
[Category(ConfigurationCategory)]
[Description("Rate at which beats are produced.")]
[Category(AcquisitionCategory)]
[Description("Rate at which beats are produced (Hz).")]
public uint BeatsPerSecond
{
get => beatsPerSecond.Value;
set => beatsPerSecond.OnNext(value);
}

/// <summary>
/// Configure a heartbeat device.
/// </summary>
/// <remarks>
/// This will schedule configuration actions to be applied by a <see cref="StartAcquisition"/> instance
/// prior to data acquisition.
/// </remarks>
/// <param name="source">A sequence of <see cref="ContextTask"/> instances that holds configuration actions.</param>
/// <returns>The original sequence modified by adding additional configuration actions required to configure a heartbeat device./></returns>
public override IObservable<ContextTask> Process(IObservable<ContextTask> source)
{
var deviceName = DeviceName;
Expand Down
41 changes: 39 additions & 2 deletions OpenEphys.Onix/OpenEphys.Onix/ConfigureMemoryMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,60 @@

namespace OpenEphys.Onix
{
/// <summary>
/// A class for configuring a hardware memory monitor.
/// </summary>
/// <remarks>
/// The memory monitor produces periodic snapshots of the system's first in, first out (FIFO) data buffer.
/// This can be useful for:
/// <list type="bullet">
/// <item><description>Ensuring that data is being read by the host PC quickly enough to prevent real-time delays or overflows.
/// In the case that the PC is not keeping up with data collection, FIFO memory use will increase monotonically.</description></item>
/// <item><description>Tuning the value of <see cref="StartAcquisition.ReadSize"/> to optimize real-time performance.
/// For optimal real-time performance, <see cref="StartAcquisition.ReadSize"/> should be as small as possible and the FIFO should be bypassed
/// (memory usage should remain at 0). However, these requirements are in conflict. The memory monitor provides a way to find the minimal value of
/// value of <see cref="StartAcquisition.ReadSize"/> that does not result in excessive FIFO data buffering. This tradeoff will depend on the
/// bandwidth of data being acquired, the performance of the host PC, and downstream real-time processing.</description></item>
/// </list>
/// </remarks>
public class ConfigureMemoryMonitor : SingleDeviceFactory
{
/// <summary>
/// Initialize a new instance of <see cref="ConfigureMemoryMonitor"/>.
/// </summary>
public ConfigureMemoryMonitor()
: base(typeof(MemoryMonitor))
{
DeviceAddress = 10;
}

/// <summary>
/// Get or set the device enable state.
/// </summary>
/// <remarks>
/// If set to true, <see cref="MemoryMonitorData"/> will produce data. If set to false, <see cref="MemoryMonitorData"/> will not produce data.
/// </remarks>
[Category(ConfigurationCategory)]
[Description("Specifies whether the monitor device is enabled.")]
[Description("Specifies whether the memory monitor device is enabled.")]
public bool Enable { get; set; } = false;

/// <summary>
/// Get or set the frequency at which memory use is recorded in Hz.
/// </summary>
[Range(1, 1000)]
[Category(ConfigurationCategory)]
[Description("Frequency at which hardware memory use is recorded (Hz).")]
[Description("Frequency at which memory use is recorded (Hz).")]
public uint SamplesPerSecond { get; set; } = 10;

/// <summary>
/// Configure a memory monitor device.
/// </summary>
/// <remarks>
/// This will schedule configuration actions to be applied by a <see cref="StartAcquisition"/> instance
/// prior to data acquisition.
/// </remarks>
/// <param name="source">A sequence of <see cref="ContextTask"/> instances that holds configuration actions.</param>
/// <returns>The original sequence modified by adding additional configuration actions required to configure a memory monitor device./></returns>
public override IObservable<ContextTask> Process(IObservable<ContextTask> source)
{
var deviceName = DeviceName;
Expand Down
35 changes: 35 additions & 0 deletions OpenEphys.Onix/OpenEphys.Onix/DataFrame.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
namespace OpenEphys.Onix
{
/// <summary>
/// An abstract class for representing <see cref="oni.Frame"/> objects in way that suits their use in this library.
/// </summary>
public abstract class DataFrame
{
/// <summary>
/// Initializes and new instance of the <see cref="DataFrame"/> class.
/// </summary>
/// <param name="clock">System clock count. Generally provided by the underlying <see cref="oni.Frame.Clock"/> value.</param>
internal DataFrame(ulong clock)
{
Clock = clock;
Expand All @@ -13,11 +20,33 @@ internal DataFrame(ulong clock, ulong hubClock)
HubClock = hubClock;
}

/// <summary>
/// Gets the acquisition clock count.
/// </summary>
/// <remarks>
/// Acquisition clock count that is synchronous for all frames collected within With an ONI context created using <see cref="CreateContext"/>.
/// The acquisition clock rate is given by <see cref="ContextTask.AcquisitionClockHz"/>. This clock value provides a common, synchronized
/// time base for all data collected with an single ONI context.
/// </remarks>
public ulong Clock { get; }

/// <summary>
/// Gets the hub clock count.
/// </summary>
/// <remarks>
/// Local, potentially asynchronous, clock count. Aside from the synchronous <see cref="Clock"/> value, data frames also contain a local clock
/// count produced within the <see cref="oni.Hub"/> that the data was actually produced within. For instance, a headstage may contain an onboard controller
/// for controlling devices and arbitrating data stream that runs asynchronously from the <see cref="ContextTask.AcquisitionClockHz"/>. This value
/// is therefore the most precise way to compare the sample time of data collected within a given <see cref="oni.Hub"/>. However, the delay between time of
/// data collection and synchronous time stamping by <see cref="Clock"/> is very small (sub-microsecond) and this value can therefore
/// be disregarded in most scenarios in favor of <see cref="Clock"/>.
/// </remarks>
public ulong HubClock { get; internal set; }
}

/// <summary>
/// An abstract class for representing buffered groups <see cref="oni.Frame"/> objects in way that suits their use in this library.
/// </summary>
public abstract class BufferedDataFrame
{
internal BufferedDataFrame(ulong[] clock, ulong[] hubClock)
Expand All @@ -26,8 +55,14 @@ internal BufferedDataFrame(ulong[] clock, ulong[] hubClock)
HubClock = hubClock;
}

/// <summary>
/// Gets the buffered array of <see cref="DataFrame.Clock"/> values.
/// </summary>
public ulong[] Clock { get; }

/// <summary>
/// Gets the buffered array of <see cref="DataFrame.HubClock"/> values.
/// </summary>
public ulong[] HubClock { get; }
}
}
17 changes: 17 additions & 0 deletions OpenEphys.Onix/OpenEphys.Onix/DigitalInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,28 @@

namespace OpenEphys.Onix
{
/// <summary>
/// A class that produces a sequence of digital input data frames.
/// </summary>
/// <remarks>
/// This data stream class must be linked to an appropriate configuration, such as a <see cref="ConfigureDigitalIO"/>,
/// in order to stream data.
/// </remarks>
public class DigitalInput : Source<DigitalInputDataFrame>
{
/// <inheritdoc cref = "SingleDeviceFactory.DeviceName"/>
[TypeConverter(typeof(DigitalIO.NameConverter))]
public string DeviceName { get; set; }

/// <summary>
/// Generates a sequence of <see cref="DigitalInputDataFrame"/> objects, which contains information about breakout
/// board's digital input state.
/// </summary>
/// <remarks>
/// Digital inputs are not regularly sampled. Instead, a new <see cref="DigitalInputDataFrame"/> is produced each
/// whenever any digital state (i.e. a digital input pin, button, or switch state) changes.
/// </remarks>
/// <returns>A sequence of <see cref="DigitalInputDataFrame"/> objects.</returns>
public unsafe override IObservable<DigitalInputDataFrame> Generate()
{
return DeviceManager.GetDevice(DeviceName).SelectMany(deviceInfo =>
Expand Down
Loading