Skip to content

Commit 1fad414

Browse files
committed
Successfully stream data from Neuropixels v1
1 parent cf72e28 commit 1fad414

File tree

5 files changed

+260
-53
lines changed

5 files changed

+260
-53
lines changed

Source/Devices/Neuropixels_1.cpp

Lines changed: 136 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
#include <oni.h>
2525
#include <onix.h>
2626

27-
Neuropixels_1::Neuropixels_1(String name)
28-
: OnixDevice(name, NEUROPIXELS_1)
27+
Neuropixels_1::Neuropixels_1(String name, const oni_dev_idx_t deviceIdx_, const oni_ctx ctx_)
28+
: OnixDevice(name, NEUROPIXELS_1, deviceIdx_, ctx_)
2929
{
3030
StreamInfo apStream;
3131
apStream.name = name + "-AP";
@@ -57,7 +57,140 @@ Neuropixels_1::~Neuropixels_1()
5757
}
5858

5959

60-
void Neuropixels_1::addFrame()
60+
int Neuropixels_1::enableDevice()
6161
{
62+
// Enable device streaming
63+
const oni_reg_addr_t enable_device_stream = 0x8000;
64+
int errorCode = oni_write_reg(ctx, deviceIdx, enable_device_stream, 1);
6265

66+
if (errorCode) { LOGE(oni_error_str(errorCode)); return errorCode; }
67+
68+
// check probe SN
69+
70+
71+
const oni_reg_addr_t probe_sn_msb = 0x8191;
72+
const oni_reg_addr_t probe_sn_lsb = 0x8192;
73+
74+
oni_reg_val_t probe_sn_msb_val;
75+
oni_reg_val_t probe_sn_lsb_val;
76+
77+
errorCode = oni_read_reg(ctx, deviceIdx, probe_sn_msb, &probe_sn_msb_val);
78+
if (errorCode) { LOGE(oni_error_str(errorCode)); return errorCode; }
79+
80+
errorCode = oni_read_reg(ctx, deviceIdx, probe_sn_lsb, &probe_sn_lsb_val);
81+
if (errorCode) { LOGE(oni_error_str(errorCode)); return errorCode; }
82+
83+
uint64_t probe_sn = ((uint64_t)probe_sn_msb_val << 32) | (uint64_t)probe_sn_lsb_val;
84+
85+
LOGC ("******* Probe SN: ", probe_sn);
86+
87+
return 0;
88+
}
89+
90+
91+
void Neuropixels_1::startAcquisition()
92+
{
93+
startThread();
94+
95+
int errorCode = oni_write_reg(ctx, deviceIdx, (uint32_t)NeuropixelsRegisters::REC_MOD , (uint32_t)RecMod::DIG_RESET);
96+
97+
if (errorCode) { LOGE("[", deviceIdx ,"][Register][OP_MODE] ", oni_error_str(errorCode)); }
98+
99+
errorCode = oni_write_reg(ctx, deviceIdx, (uint32_t)NeuropixelsRegisters::REC_MOD , (uint32_t)RecMod::ACTIVE);
100+
101+
if (errorCode) { LOGE("[Neuropixels 1][", deviceIdx ,"] Error starting acquisition: ", oni_error_str(errorCode)); }
102+
}
103+
104+
void Neuropixels_1::stopAcquisition()
105+
{
106+
if (isThreadRunning())
107+
signalThreadShouldExit();
108+
109+
waitForThreadToExit(2000);
110+
111+
int errorCode = oni_write_reg(ctx, deviceIdx, (uint32_t)NeuropixelsRegisters::REC_MOD , (uint32_t)RecMod::RESET_ALL);
112+
if (errorCode) { LOGE("[Neuropixels 1][", deviceIdx ,"] Error stopping acquisition: ", oni_error_str(errorCode)); }
113+
114+
superFrameCount = 0;
115+
ultraFrameCount = 0;
116+
shouldAddToBuffer = false;
117+
sampleNumber = 0;
118+
}
119+
120+
121+
void Neuropixels_1::addFrame(oni_frame_t* frame)
122+
{
123+
124+
uint16_t* dataPtr;
125+
dataPtr = (uint16_t*)frame->data;
126+
127+
auto dataclock = (unsigned char*)frame->data + 936;
128+
uint64 hubClock = ((uint64_t)(*(uint16_t*)dataclock) << 48) |
129+
((uint64_t)(*(uint16_t*)(dataclock + 2)) << 32) |
130+
((uint64_t)(*(uint16_t*)(dataclock + 4)) << 16) |
131+
((uint64_t)(*(uint16_t*)(dataclock + 6)) << 0);
132+
int64_t clockCounter = hubClock * sizeof(hubClock);
133+
apTimestamps[superFrameCount] = clockCounter;
134+
apSampleNumbers[superFrameCount] = sampleNumber++;
135+
136+
for (int i = 0; i < framesPerSuperFrame; i++)
137+
{
138+
if (i == 0) // LFP data
139+
{
140+
int superCountOffset = superFrameCount % superFramesPerUltraFrame;
141+
if (superCountOffset == 0)
142+
{
143+
lfpTimestamps[ultraFrameCount] = apTimestamps[superFrameCount];
144+
lfpSampleNumbers[ultraFrameCount] = apSampleNumbers[superFrameCount];
145+
}
146+
147+
for (int adc = 0; adc < 32; adc++)
148+
{
149+
150+
int chanIndex = adcToChannel[adc] + superCountOffset * 2;
151+
lfpSamples[(chanIndex * numUltraFrames) + ultraFrameCount ] = (*(dataPtr + adcToFrameIndex[adc] + dataOffset) >> 5) * 0.195f;
152+
153+
}
154+
}
155+
else // AP data
156+
{
157+
int chanOffset = 2 * (i - 1);
158+
for (int adc = 0; adc < 32; adc++)
159+
{
160+
int chanIndex = adcToChannel[adc] + chanOffset;
161+
apSamples[(chanIndex * superFramesPerUltraFrame * numUltraFrames) + superFrameCount] = (*(dataPtr + adcToFrameIndex[adc] + dataOffset) >> 5) * 0.195f;
162+
}
163+
}
164+
}
165+
166+
superFrameCount++;
167+
168+
if (superFrameCount % superFramesPerUltraFrame == 0)
169+
{
170+
ultraFrameCount++;
171+
}
172+
173+
if (ultraFrameCount > numUltraFrames)
174+
{
175+
ultraFrameCount = 0;
176+
superFrameCount = 0;
177+
shouldAddToBuffer = true;
178+
}
179+
180+
181+
182+
}
183+
184+
void Neuropixels_1::run()
185+
{
186+
while (!threadShouldExit())
187+
{
188+
if (shouldAddToBuffer)
189+
{
190+
shouldAddToBuffer = false;
191+
lfpBuffer->addToBuffer(lfpSamples, lfpSampleNumbers, lfpTimestamps, lfpEventCodes, numUltraFrames);
192+
apBuffer->addToBuffer(apSamples, apSampleNumbers, apTimestamps, apEventCodes, numUltraFrames * superFramesPerUltraFrame);
193+
}
194+
195+
}
63196
}

Source/Devices/Neuropixels_1.h

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,58 @@ enum NeuropixelsRegisters
3333
{
3434
OP_MODE = 0x00,
3535
REC_MOD = 0x01,
36-
CAL_MOD = 0x02
36+
CAL_MOD = 0x02,
37+
STATUS = 0X08
3738
};
3839

40+
41+
enum OpMode
42+
{
43+
TEST = 1 << 3, // Enable Test mode
44+
DIG_TEST = 1 << 4, // Enable Digital Test mode
45+
CALIBRATE = 1 << 5, // Enable calibration mode
46+
RECORD = 1 << 6, // Enable recording mode
47+
POWER_DOWN = 1 << 7, // Enable power down mode
48+
};
49+
50+
enum RecMod
51+
{
52+
DIG_AND_CH_RESET = 0,
53+
RESET_ALL = 1 << 5, // 1 = Set analog SR chains to default values
54+
DIG_NRESET = 1 << 6, // 0 = Reset the MUX, ADC, and PSB counter, 1 = Disable reset
55+
CH_NRESET = 1 << 7, // 0 = Reset channel pseudo-registers, 1 = Disable reset
56+
57+
// Useful combinations
58+
SR_RESET = RESET_ALL | CH_NRESET | DIG_NRESET,
59+
DIG_RESET = CH_NRESET, // Yes, this is actually correct
60+
CH_RESET = DIG_NRESET, // Yes, this is actually correct
61+
ACTIVE = DIG_NRESET | CH_NRESET
62+
};
63+
64+
// ADC number to frame index mapping
65+
static const int adcToFrameIndex[] = {
66+
0, 7 , 14, 21, 28,
67+
1, 8 , 15, 22, 29,
68+
2, 9 , 16, 23, 30,
69+
3, 10, 17, 24, 31,
70+
4, 11, 18, 25, 32,
71+
5, 12, 19, 26, 33,
72+
6, 13
73+
};
74+
75+
static const int adcToChannel[] = {
76+
0, 1, 24, 25, 48, 49, 72, 73, 96, 97,
77+
120, 121, 144, 145, 168, 169, 192, 193,
78+
216, 217, 240, 241, 264, 265, 288, 289,
79+
312, 313, 336, 337, 360, 361
80+
};
81+
82+
const int superFramesPerUltraFrame = 12;
83+
const int framesPerSuperFrame = 13;
84+
const int framesPerUltraFrame = superFramesPerUltraFrame * framesPerSuperFrame;
85+
const int numUltraFrames = 12;
86+
const int dataOffset = 1;
87+
3988
/**
4089
4190
Streams data from an ONIX device
@@ -46,23 +95,46 @@ class Neuropixels_1 : public OnixDevice
4695
public:
4796

4897
/** Constructor */
49-
Neuropixels_1(String name);
98+
Neuropixels_1(String name, const oni_dev_idx_t, const oni_ctx);
5099

51100
/** Destructor */
52101
~Neuropixels_1();
102+
103+
int enableDevice() override;
104+
105+
/** Starts probe data streaming */
106+
void startAcquisition() override;
107+
108+
/** Stops probe data streaming*/
109+
void stopAcquisition() override;
110+
111+
void addFrame(oni_frame_t*) override;
53112

54113
DataBuffer* apBuffer = deviceBuffer;
55114
DataBuffer* lfpBuffer;
56115

57-
void addFrame() override;
58-
59116
private:
60117

61-
float samples[384 * MAX_SAMPLES_PER_BUFFER];
62-
int64 sampleNumbers[MAX_SAMPLES_PER_BUFFER];
63-
double timestamps[MAX_SAMPLES_PER_BUFFER];
64-
uint64 event_codes[MAX_SAMPLES_PER_BUFFER];
118+
/** Updates buffer during acquisition */
119+
void run() override;
120+
121+
float lfpSamples [384 * numUltraFrames];
122+
float apSamples [384 * numUltraFrames * superFramesPerUltraFrame];
123+
124+
int64 apSampleNumbers[numUltraFrames * superFramesPerUltraFrame];
125+
double apTimestamps[numUltraFrames * superFramesPerUltraFrame];
126+
uint64 apEventCodes[numUltraFrames * superFramesPerUltraFrame];
127+
128+
int64 lfpSampleNumbers[numUltraFrames];
129+
double lfpTimestamps[numUltraFrames];
130+
uint64 lfpEventCodes[numUltraFrames];
131+
132+
133+
bool shouldAddToBuffer = false;
134+
int superFrameCount = 0;
135+
int ultraFrameCount = 0;
65136

137+
int sampleNumber = 0;
66138
};
67139

68140

Source/OnixDevice.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,8 @@
2323

2424
#include "OnixDevice.h"
2525

26-
OnixDevice::OnixDevice(String name, OnixDeviceType type_)
27-
: Thread(name), type(type_)
26+
OnixDevice::OnixDevice(String name, OnixDeviceType type_, const oni_dev_idx_t deviceIdx_, const oni_ctx ctx_)
27+
: Thread(name), type(type_), deviceIdx(deviceIdx_), ctx(ctx_)
2828
{
2929

30-
}
31-
32-
33-
void OnixDevice::run()
34-
{
35-
while (!threadShouldExit())
36-
{
37-
38-
}
3930
}

Source/OnixDevice.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@
3131
#include <chrono>
3232
#include <thread>
3333

34-
#define PI 3.14159f
35-
#define MAX_SAMPLES_PER_BUFFER 300
34+
#include <oni.h>
3635

3736
using namespace std::chrono;
3837

@@ -66,26 +65,39 @@ class OnixDevice : public Thread
6665
public:
6766

6867
/** Constructor */
69-
OnixDevice(String name, OnixDeviceType type);
68+
OnixDevice(String name, OnixDeviceType type, const oni_dev_idx_t, const oni_ctx);
7069

7170
/** Destructor */
7271
~OnixDevice() { }
7372

74-
virtual void addFrame() = 0;
73+
virtual void addFrame(oni_frame_t*) = 0;
7574

7675
const String getName() { return name; }
7776

77+
virtual int enableDevice() = 0;
78+
79+
virtual void startAcquisition() = 0;
80+
81+
virtual void stopAcquisition() = 0;
82+
83+
const oni_dev_idx_t getDeviceIdx() { return deviceIdx; }
84+
7885
OnixDeviceType type;
7986

8087
/** Holds incoming data */
8188
DataBuffer* deviceBuffer;
8289

8390
Array<StreamInfo> streams;
8491

92+
protected:
93+
94+
const oni_dev_idx_t deviceIdx;
95+
const oni_ctx ctx;
96+
8597
private:
8698

8799
/** Updates buffer during acquisition */
88-
void run() override;
100+
// void run() override;
89101

90102
std::vector<float>* data;
91103
int availableSamples;

0 commit comments

Comments
 (0)