diff --git a/OpenEphys.Onix1.Design/NeuropixelsV1eDialog.cs b/OpenEphys.Onix1.Design/NeuropixelsV1eDialog.cs
index e831865..72ac286 100644
--- a/OpenEphys.Onix1.Design/NeuropixelsV1eDialog.cs
+++ b/OpenEphys.Onix1.Design/NeuropixelsV1eDialog.cs
@@ -269,7 +269,8 @@ private void CheckStatus()
{
gainCorrection = NeuropixelsV1Helper.TryParseGainCalibrationFile(ConfigureNode.GainCalibrationFile,
ConfigureNode.ProbeConfiguration.SpikeAmplifierGain,
- ConfigureNode.ProbeConfiguration.LfpAmplifierGain);
+ ConfigureNode.ProbeConfiguration.LfpAmplifierGain,
+ 960);
}
catch (IOException ex)
{
diff --git a/OpenEphys.Onix1/ConfigureNric1384.cs b/OpenEphys.Onix1/ConfigureNric1384.cs
index c37d7cc..6b195a1 100644
--- a/OpenEphys.Onix1/ConfigureNric1384.cs
+++ b/OpenEphys.Onix1/ConfigureNric1384.cs
@@ -5,7 +5,7 @@
namespace OpenEphys.Onix1
{
///
- /// Configures a Nric184 bioacquisition device.
+ /// Configures a Nric184 bioacquisition chip.
///
public class ConfigureNric1384 : SingleDeviceFactory
{
@@ -141,6 +141,8 @@ static class Nric1384
public const int ID = 33;
public const int I2cAddress = 0x70;
+ public const int ChannelCount = 384;
+ public const int ElectrodeCount = 384;
// managed registers
public const uint ENABLE = 0x8000; // Enable or disable the data output stream
diff --git a/OpenEphys.Onix1/NeuropixelsV1Helper.cs b/OpenEphys.Onix1/NeuropixelsV1Helper.cs
index 7344e2d..7da1bf6 100644
--- a/OpenEphys.Onix1/NeuropixelsV1Helper.cs
+++ b/OpenEphys.Onix1/NeuropixelsV1Helper.cs
@@ -63,7 +63,7 @@ public static class NeuropixelsV1Helper
.Where(l => l.Ok)
.Select(l => l.Param);
- return calibrationValues.Count() == NumberOfAdcParameters
+ return calibrationValues.Count() != NumberOfAdcParameters
? null
: new NeuropixelsV1eAdc {
CompP = calibrationValues.ElementAt(0),
@@ -99,13 +99,13 @@ public static class NeuropixelsV1Helper
/// Current for the AP data.
/// Current for the LFP data.
/// object that contains the AP and LFP gain correction values. This object is null if the file was not successfully parsed.
- public static NeuropixelsV1eGainCorrection? TryParseGainCalibrationFile(string gainCalibrationFile, NeuropixelsV1Gain apGain, NeuropixelsV1Gain lfpGain)
+ public static NeuropixelsV1eGainCorrection? TryParseGainCalibrationFile(string gainCalibrationFile, NeuropixelsV1Gain apGain, NeuropixelsV1Gain lfpGain, int electrodeCount)
{
if (!File.Exists(gainCalibrationFile)) return null;
var lines = File.ReadLines(gainCalibrationFile);
- if (lines.Count() != NeuropixelsV1e.ElectrodeCount + 1) return null;
+ if (lines.Count() != electrodeCount + 1) return null;
if (!ulong.TryParse(lines.ElementAt(0), out var serialNumber)) return null;
if (!lines
@@ -117,7 +117,7 @@ public static class NeuropixelsV1Helper
})
.Where(l => l.Ok)
.Select(l => l.Channel)
- .SequenceEqual(Enumerable.Range(0, NeuropixelsV1e.ElectrodeCount))) return null;
+ .SequenceEqual(Enumerable.Range(0, electrodeCount))) return null;
var apIndex = Array.IndexOf(Enum.GetValues(typeof(NeuropixelsV1Gain)), apGain);
var apGainCorrections = lines
diff --git a/OpenEphys.Onix1/NeuropixelsV1eRegisterContext.cs b/OpenEphys.Onix1/NeuropixelsV1eRegisterContext.cs
index d44d51f..f51b490 100644
--- a/OpenEphys.Onix1/NeuropixelsV1eRegisterContext.cs
+++ b/OpenEphys.Onix1/NeuropixelsV1eRegisterContext.cs
@@ -51,7 +51,8 @@ public NeuropixelsV1eRegisterContext(DeviceContext deviceContext, uint i2cAddres
$"match the ADC calibration file serial number: {adcCalibration.Value.SerialNumber}.");
}
- var gainCorrection = NeuropixelsV1Helper.TryParseGainCalibrationFile(gainCalibrationFile, probeConfiguration.SpikeAmplifierGain, probeConfiguration.LfpAmplifierGain);
+ var gainCorrection = NeuropixelsV1Helper.TryParseGainCalibrationFile(gainCalibrationFile,
+ probeConfiguration.SpikeAmplifierGain, probeConfiguration.LfpAmplifierGain, NeuropixelsV1e.ElectrodeCount);
if (!gainCorrection.HasValue)
{
diff --git a/OpenEphys.Onix1/Nric1384RegisterContext.cs b/OpenEphys.Onix1/Nric1384RegisterContext.cs
index fe9c8d4..b04eba7 100644
--- a/OpenEphys.Onix1/Nric1384RegisterContext.cs
+++ b/OpenEphys.Onix1/Nric1384RegisterContext.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections;
-using System.Linq;
+using System.IO;
namespace OpenEphys.Onix1
{
@@ -13,7 +13,6 @@ class Nric1384RegisterContext : I2CRegisterContext
const byte ReferenceSource = 0b001; // All, hardcoded
const int BaseConfigurationBitCount = 2448;
const int BaseConfigurationConfigOffset = 576;
- const int NumberOfGains = 8;
const uint ShiftRegisterSuccess = 1 << 7;
readonly DeviceContext device;
@@ -24,51 +23,42 @@ class Nric1384RegisterContext : I2CRegisterContext
public Nric1384RegisterContext(DeviceContext deviceContext, NeuropixelsV1Gain apGain, NeuropixelsV1Gain lfpGain, bool apFilter, string gainCalibrationFile, string adcCalibrationFile)
: base(deviceContext, Nric1384.I2cAddress)
{
+
device = deviceContext;
- if (gainCalibrationFile == null || adcCalibrationFile == null)
+ if (!File.Exists(gainCalibrationFile))
{
- throw new ArgumentException("Calibration files must be specified.");
+ throw new ArgumentException("A gain calibration file must be specified for the Nric1384 chip.");
}
- System.IO.StreamReader gainFile = new(gainCalibrationFile);
- var sn = UInt64.Parse(gainFile.ReadLine());
-
- System.IO.StreamReader adcFile = new(adcCalibrationFile);
- if (sn != UInt64.Parse(adcFile.ReadLine()))
- throw new ArgumentException("Calibration file serial numbers do not match.");
+ if (!File.Exists(adcCalibrationFile))
+ {
+ throw new ArgumentException("An ADC calibration file must be specified for the Nric1384 chip.");
+ }
- // parse gain correction file
- var gainCorrections = gainFile.ReadLine().Split(',').Skip(1);
+ var adcCalibration = NeuropixelsV1Helper.TryParseAdcCalibrationFile(adcCalibrationFile);
- if (gainCorrections.Count() != 2 * NumberOfGains)
- throw new ArgumentException("Incorrectly formatted gain correction calibration file.");
+ if (!adcCalibration.HasValue)
+ {
+ throw new ArgumentException($"The calibration file \"{adcCalibrationFile}\" is invalid.");
+ }
- ApGainCorrection = double.Parse(gainCorrections.ElementAt(Array.IndexOf(Enum.GetValues(typeof(NeuropixelsV1Gain)), apGain)));
- LfpGainCorrection = double.Parse(gainCorrections.ElementAt(Array.IndexOf(Enum.GetValues(typeof(NeuropixelsV1Gain)), lfpGain) + 8));
+ var gainCorrection = NeuropixelsV1Helper.TryParseGainCalibrationFile(gainCalibrationFile,apGain, lfpGain, Nric1384.ElectrodeCount);
- // parse ADC calibration file
- for (var i = 0; i < NeuropixelsV1e.AdcCount; i++)
+ if (!gainCorrection.HasValue)
{
- var adcCal = adcFile.ReadLine().Split(',').Skip(1);
- if (adcCal.Count() != NumberOfGains)
- {
- throw new ArgumentException("Incorrectly formatted ADC calibration file.");
- }
+ throw new ArgumentException($"The calibration file \"{gainCalibrationFile}\" is invalid.");
+ }
- Adcs[i] = new NeuropixelsV1eAdc
- {
- CompP = int.Parse(adcCal.ElementAt(0)),
- CompN = int.Parse(adcCal.ElementAt(1)),
- Slope = int.Parse(adcCal.ElementAt(2)),
- Coarse = int.Parse(adcCal.ElementAt(3)),
- Fine = int.Parse(adcCal.ElementAt(4)),
- Cfix = int.Parse(adcCal.ElementAt(5)),
- Offset = int.Parse(adcCal.ElementAt(6)),
- Threshold = int.Parse(adcCal.ElementAt(7))
- };
+ if (adcCalibration.Value.SerialNumber != gainCorrection.Value.SerialNumber)
+ {
+ throw new ArgumentException($"The ADC calibration file's serial number ({adcCalibration.Value.SerialNumber}) " +
+ $"does not match the gain calibration file's serial number ({gainCorrection.Value.SerialNumber}).");
}
+ ApGainCorrection = gainCorrection.Value.ApGainCorrectionFactor;
+ LfpGainCorrection = gainCorrection.Value.LfpGainCorrectionFactor;
+
// create shift-register bit arrays
for (int i = 0; i < NeuropixelsV1e.ChannelCount; i++)
{
@@ -100,6 +90,8 @@ public Nric1384RegisterContext(DeviceContext deviceContext, NeuropixelsV1Gain ap
}
+ Adcs = adcCalibration.Value.Adcs;
+
int k = 0;
foreach (var adc in Adcs)
{
@@ -172,7 +164,6 @@ public Nric1384RegisterContext(DeviceContext deviceContext, NeuropixelsV1Gain ap
BaseConfigs[configIdx][slopeOffset + 8] = cfix[1];
BaseConfigs[configIdx][slopeOffset + 9] = cfix[2];
BaseConfigs[configIdx][slopeOffset + 10] = cfix[3];
-
}
}
@@ -201,7 +192,7 @@ public void WriteShiftRegisters()
for (int j = 0; j < 2; j++)
{
- var baseBytes = BitArrayToBytes(BaseConfigs[i]);
+ var baseBytes = BitHelper.ToBitReversedBytes(BaseConfigs[i]);
WriteByte(Nric1384.SR_LENGTH1, (uint)baseBytes.Length % 0x100);
WriteByte(Nric1384.SR_LENGTH2, (uint)baseBytes.Length / 0x100);
@@ -218,30 +209,17 @@ public void WriteShiftRegisters()
}
}
- // gain corrections
- device.WriteRegister(Nric1384.LFP_GAIN, (uint)(LfpGainCorrection * (1 << 14)));
- device.WriteRegister(Nric1384.AP_GAIN, (uint)(ApGainCorrection * (1 << 14)));
- }
-
- // Bits go into the shift registers MSB first
- // This creates a *bit-reversed* byte array from a bit array
- private static byte[] BitArrayToBytes(BitArray bits)
- {
- if (bits.Length == 0)
+ // write adc thresholds and offsets
+ for (uint i = 0; i < Adcs.Length; i++)
{
- throw new ArgumentException("Shift register data is empty", nameof(bits));
+ var thresh = (uint)Adcs[i].Threshold;
+ var offset = (uint)Adcs[i].Offset;
+ device.WriteRegister(Nric1384.ADC00_OFF_THRESH + i, offset << 10 | thresh);
}
- var bytes = new byte[(bits.Length - 1) / 8 + 1];
- bits.CopyTo(bytes, 0);
-
- for (int i = 0; i < bytes.Length; i++)
- {
- // NB: http://graphics.stanford.edu/~seander/bithacks.html
- bytes[i] = (byte)((bytes[i] * 0x0202020202ul & 0x010884422010ul) % 1023);
- }
-
- return bytes;
+ // gain corrections
+ device.WriteRegister(Nric1384.LFP_GAIN, (uint)(LfpGainCorrection * (1 << 14)));
+ device.WriteRegister(Nric1384.AP_GAIN, (uint)(ApGainCorrection * (1 << 14)));
}
}
}