-
Notifications
You must be signed in to change notification settings - Fork 5
AnalogIO refactoring and support for buffering and data type conversions #92
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
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
f3bfeb3
Ensure input ranges are assigned for each channel
glopesdev 9e53bfd
Disallow reconfiguration of IO channel direction
glopesdev 7203740
Refactor enum types and constants for consistency
glopesdev 77e93ba
Allow buffered analog input acquisition
glopesdev 149ed38
Add data type conversions for analog input
glopesdev 7f51f5f
Set channel direction with single register write
glopesdev 8f82a9e
Allow creating info instance from device context
glopesdev 618e24a
Add per-channel analog input data type conversions
glopesdev a76b0d9
Ensure property ordering without number prefixes
glopesdev 10eb34c
Prefer 32-bit voltage conversions
glopesdev e4ed157
Add support for buffered output conversions
glopesdev 4c80695
Generalize data conversions to primitive overloads
glopesdev 96aaec0
Ensure correct frame output buffer
glopesdev 94059ce
Allow direct writes of unbuffered raw samples
glopesdev 7cfd334
Transpose analog input data
glopesdev 820fea3
Refactor and remove unused buffer helper methods
glopesdev d983615
Rename copy transpose method for clarity
glopesdev 496951a
Apply fixed output voltage transformation
glopesdev 2602312
Ensure transposed buffer data type
glopesdev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,87 @@ | ||
using System; | ||
using System.ComponentModel; | ||
using System.Linq; | ||
using System.Reactive; | ||
using System.Reactive.Linq; | ||
using System.Runtime.InteropServices; | ||
using Bonsai; | ||
using OpenCV.Net; | ||
|
||
namespace OpenEphys.Onix | ||
{ | ||
public class AnalogInput : Source<ManagedFrame<short>> | ||
public class AnalogInput : Source<AnalogInputDataFrame> | ||
{ | ||
[TypeConverter(typeof(AnalogIO.NameConverter))] | ||
public string DeviceName { get; set; } | ||
|
||
public override IObservable<ManagedFrame<short>> Generate() | ||
public int BufferSize { get; set; } = 100; | ||
|
||
public AnalogIODataType DataType { get; set; } = AnalogIODataType.S16; | ||
|
||
static Mat CreateVoltageScale(int bufferSize, float[] voltsPerDivision) | ||
{ | ||
using var scaleHeader = Mat.CreateMatHeader( | ||
voltsPerDivision, | ||
rows: voltsPerDivision.Length, | ||
cols: 1, | ||
depth: Depth.F32, | ||
channels: 1); | ||
var voltageScale = new Mat(scaleHeader.Rows, bufferSize, scaleHeader.Depth, scaleHeader.Channels); | ||
CV.Repeat(scaleHeader, voltageScale); | ||
return voltageScale; | ||
} | ||
|
||
public unsafe override IObservable<AnalogInputDataFrame> Generate() | ||
{ | ||
var bufferSize = BufferSize; | ||
var dataType = DataType; | ||
return Observable.Using( | ||
() => DeviceManager.ReserveDevice(DeviceName), | ||
disposable => disposable.Subject.SelectMany(deviceInfo => | ||
{ | ||
var device = deviceInfo.GetDeviceContext(typeof(AnalogIO)); | ||
return deviceInfo.Context.FrameReceived | ||
.Where(frame => frame.DeviceAddress == device.Address) | ||
.Select(frame => new ManagedFrame<short>(frame)); | ||
})); | ||
Observable.Create<AnalogInputDataFrame>(observer => | ||
{ | ||
var device = deviceInfo.GetDeviceContext(typeof(AnalogIO)); | ||
var ioDeviceInfo = (AnalogIODeviceInfo)deviceInfo; | ||
|
||
var sampleIndex = 0; | ||
var voltageScale = dataType == AnalogIODataType.Volts | ||
? CreateVoltageScale(bufferSize, ioDeviceInfo.VoltsPerDivision) | ||
: null; | ||
var transposeBuffer = voltageScale != null | ||
? new Mat(AnalogIO.ChannelCount, bufferSize, Depth.S16, 1) | ||
: null; | ||
var analogDataBuffer = new short[AnalogIO.ChannelCount * bufferSize]; | ||
var hubSyncCounterBuffer = new ulong[bufferSize]; | ||
var clockBuffer = new ulong[bufferSize]; | ||
|
||
var frameObserver = Observer.Create<oni.Frame>( | ||
frame => | ||
{ | ||
var payload = (AnalogInputPayload*)frame.Data.ToPointer(); | ||
Marshal.Copy(new IntPtr(payload->AnalogData), analogDataBuffer, sampleIndex * AnalogIO.ChannelCount, AnalogIO.ChannelCount); | ||
hubSyncCounterBuffer[sampleIndex] = payload->HubSyncCounter; | ||
clockBuffer[sampleIndex] = frame.Clock; | ||
if (++sampleIndex >= bufferSize) | ||
{ | ||
var analogData = BufferHelper.CopyTranspose( | ||
analogDataBuffer, | ||
bufferSize, | ||
AnalogIO.ChannelCount, | ||
Depth.S16, | ||
voltageScale, | ||
transposeBuffer); | ||
observer.OnNext(new AnalogInputDataFrame(clockBuffer, hubSyncCounterBuffer, analogData)); | ||
hubSyncCounterBuffer = new ulong[bufferSize]; | ||
clockBuffer = new ulong[bufferSize]; | ||
sampleIndex = 0; | ||
} | ||
}, | ||
observer.OnError, | ||
observer.OnCompleted); | ||
return deviceInfo.Context.FrameReceived | ||
.Where(frame => frame.DeviceAddress == device.Address) | ||
.SubscribeSafe(frameObserver); | ||
}))); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System.Runtime.InteropServices; | ||
using OpenCV.Net; | ||
|
||
namespace OpenEphys.Onix | ||
{ | ||
public class AnalogInputDataFrame | ||
{ | ||
public AnalogInputDataFrame(ulong[] clock, ulong[] hubSyncCounter, Mat analogData) | ||
{ | ||
Clock = clock; | ||
HubSyncCounter = hubSyncCounter; | ||
AnalogData = analogData; | ||
} | ||
|
||
public ulong[] Clock { get; } | ||
|
||
public ulong[] HubSyncCounter { get; } | ||
|
||
public Mat AnalogData { get; } | ||
} | ||
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)] | ||
unsafe struct AnalogInputPayload | ||
{ | ||
public ulong HubSyncCounter; | ||
public fixed short AnalogData[AnalogIO.ChannelCount]; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.