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

Expose headstage port status data stream #216

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
36 changes: 36 additions & 0 deletions OpenEphys.Onix1/ConfigureFmcLinkController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,47 @@ internal static class FmcLinkController

public const uint LINKSTATE_PP = 0x2; // parity check pass bit
public const uint LINKSTATE_SL = 0x1; // SERDES lock bit

internal class NameConverter : DeviceNameConverter
{
public NameConverter()
: base(typeof(FmcLinkController))
{
}
}
}

internal enum HubConfiguration
{
Standard,
Passthrough
}

/// <summary>
/// Specifies the headstage port status codes.
/// </summary>
[Flags]
public enum PortStatusCode : byte
{
/// <summary>
/// Specifies nominal communication status.
/// </summary>
Nominal = 0x0,
/// <summary>
/// Specifies a cyclic redundancy check failure.
/// </summary>
CrcError = 0x1,
/// <summary>
/// Specifies too many devices were indicated in the hub device table.
/// </summary>
TooManyDevices = 0x2,
/// <summary>
/// Specifies a hub initialization error.
/// </summary>
InitializationError = 0x4,
/// <summary>
/// Specifies the receipt of a badly formed data packet.
/// </summary>
BadPacketFormat = 0x8,
}
}
2 changes: 1 addition & 1 deletion OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

void SetVoltage(DeviceContext device, double voltage)
{
device.WriteRegister(FmcLinkController.PORTVOLTAGE, 0);
device.WriteRegister(PortController.PORTVOLTAGE, 0);

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (debug, ubuntu-latest)

The name 'PortController' does not exist in the current context

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (debug, ubuntu-latest)

The name 'PortController' does not exist in the current context

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (debug, windows-latest)

The name 'PortController' does not exist in the current context

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (debug, windows-latest)

The name 'PortController' does not exist in the current context

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (release, ubuntu-latest)

The name 'PortController' does not exist in the current context

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (release, ubuntu-latest)

The name 'PortController' does not exist in the current context

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (release, windows-latest)

The name 'PortController' does not exist in the current context

Check failure on line 32 in OpenEphys.Onix1/ConfigureNeuropixelsV2eLinkController.cs

View workflow job for this annotation

GitHub Actions / build (release, windows-latest)

The name 'PortController' does not exist in the current context
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a mistake. I tried to leave this change for the discussion and instead broke the code.

Thread.Sleep(200);
device.WriteRegister(FmcLinkController.PORTVOLTAGE, (uint)(10 * voltage));
Thread.Sleep(200);
Expand Down
40 changes: 40 additions & 0 deletions OpenEphys.Onix1/PortStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using Bonsai;

namespace OpenEphys.Onix1
{
/// <summary>
/// A class that produces a sequence of port status information.
/// </summary>
/// <remarks>
/// This data stream class must be linked to an appropriate headstage, miniscope, or similar configuration.
/// </remarks>
[Description("Produces a sequence of port status information.")]
public class PortStatus : Source<PortStatusFrame>
{
/// <inheritdoc cref = "SingleDeviceFactory.DeviceName"/>
[TypeConverter(typeof(FmcLinkController.NameConverter))]
[Description(SingleDeviceFactory.DeviceNameDescription)]
public string DeviceName { get; set; }

/// <summary>
/// Generates a sequence of <see cref="MemoryMonitorDataFrame"/> objects, which contains information
/// about the system's low-level first-in, first-out (FIFO) data buffer.
/// </summary>
/// <returns>A sequence of <see cref="MemoryMonitorDataFrame"/> objects.</returns>
public override IObservable<PortStatusFrame> Generate()
{
return DeviceManager.GetDevice(DeviceName).SelectMany(deviceInfo =>
{
var device = deviceInfo.GetDeviceContext(typeof(FmcLinkController));

return deviceInfo.Context
.GetDeviceFrames(device.Address)
.Select(frame => new PortStatusFrame(frame));
});
}
}
}
56 changes: 56 additions & 0 deletions OpenEphys.Onix1/PortStatusFrame.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Runtime.InteropServices;

namespace OpenEphys.Onix1
{
/// <summary>
/// A class that contains hardware memory use information.
/// </summary>
public class PortStatusFrame : DataFrame
{
/// <summary>
/// Initializes a new instance of the <see cref="MemoryMonitorDataFrame"/> class.
/// </summary>
/// <param name="frame">A data frame produced by a memory monitor device.</param>
/// <param name="totalMemory">
/// The total amount of memory, in 32-bit words, on the hardware that is available for data buffering.
/// </param>
public unsafe PortStatusFrame(oni.Frame frame)
: base(frame.Clock)
{
var payload = (PortStatusPayload*)frame.Data.ToPointer();
HubClock = payload->HubClock;
StatusCode = payload->Code;
StatusCodeValid = (payload->DeserializerStatus & 0x0004) == 4;
SerdesLocked = (payload->DeserializerStatus & 0x0001) == 1;
SerdesPass = (payload->DeserializerStatus & 0x0002) == 2;
}

/// <summary>
/// Gets the
/// </summary>
public PortStatusCode StatusCode { get; }

/// <summary>
/// Gets the
/// </summary>
public bool StatusCodeValid { get; }

/// <summary>
/// Gets the
/// </summary>
public bool SerdesLocked { get; }

/// <summary>
/// Gets the
/// </summary>
public bool SerdesPass { get; }
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct PortStatusPayload
{
public ulong HubClock;
public PortStatusCode Code;
public byte DeserializerStatus;
}
}
Loading