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

Neuropix configuration #1

Merged
merged 32 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
aaabe8a
Add BNO055 functionality
bparks13 Sep 17, 2024
8b9fbe0
Fixed streaming of BNO055 data
bparks13 Sep 30, 2024
f37e144
WIP:
bparks13 Oct 1, 2024
a8c862c
Finalized calibration file parsing
bparks13 Oct 2, 2024
29cc8ea
WIP fpga-less EEPROM access
aacuevas Oct 2, 2024
84bcc93
Merge branch 'bno-addition' of github.com:open-ephys-plugins/onix-sou…
aacuevas Oct 2, 2024
1561ed7
Working FPGA-less headstage EEPROM reading
bparks13 Oct 2, 2024
d9e0395
WIP: NPX 2.0 flex is working
bparks13 Oct 2, 2024
7d3ec06
Skip setting port voltage with uninitialized context
bparks13 Oct 11, 2024
63a9469
Replace deprecated `ScopedPointer` with unique pointers
bparks13 Oct 11, 2024
fb9c4e4
Add Canvas support to view Neuropixels probes
bparks13 Nov 22, 2024
2a2ab81
Update compiled liboni files to v4.3.12
bparks13 Nov 26, 2024
31ce556
Refactor code to simplify saving settings
bparks13 Jan 6, 2025
5365063
Correct UI to correctly save and use probe settings
bparks13 Jan 22, 2025
e22e759
Updates to Neuropixels 1.0e
bparks13 Jan 23, 2025
b8fc04b
Ignore .vscode folder
bparks13 Jan 23, 2025
47fa2bf
Add Bno055 Interface
bparks13 Jan 23, 2025
dfdf989
Use Parameters
bparks13 Jan 27, 2025
49942a9
Refactor header dependencies
bparks13 Jan 28, 2025
22dab16
Use enum class
bparks13 Jan 28, 2025
69bbee9
Use progress window when updating Neuropixels probes
bparks13 Jan 28, 2025
12c4f72
Correctly remove source buffers when devices are disabled
bparks13 Jan 29, 2025
364f4b3
Add FrameReader
bparks13 Jan 29, 2025
f8d65b2
Remove Thread inheritance from OnixDevice
bparks13 Jan 30, 2025
964b28d
Remove automatic scan when first opened
bparks13 Jan 30, 2025
a0d200e
Add button to connect/disconnect hardware
bparks13 Jan 30, 2025
e1844ff
Updated editor
bparks13 Jan 30, 2025
60ffb2d
Fixed parameter name
bparks13 Jan 31, 2025
e8fec31
Add PortController, for both Port A and B, and add automatic port vol…
bparks13 Jan 31, 2025
4e9ab70
Check if link state is active before starting acquisition
bparks13 Jan 31, 2025
b5f9037
Merge branch 'main' into neuropix-configuration
bparks13 Feb 3, 2025
66e01d3
Address review comments
bparks13 Feb 27, 2025
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
build/
build/

.vscode
12 changes: 6 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,17 @@ set(LIBONI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libONI)
target_include_directories(${PLUGIN_NAME} PRIVATE ${LIBONI_DIR}/include)

if (MSVC)
set(LIBONI_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libONI/win64)
set(LIBONI_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libONI/win64)
target_link_libraries(${PLUGIN_NAME} "${LIBONI_LIB_DIR}/liboni.lib")
target_link_libraries(${PLUGIN_NAME} "${LIBONI_LIB_DIR}/riffa.lib")
target_link_libraries(${PLUGIN_NAME} "${LIBONI_LIB_DIR}/onidriver_riffa.lib")
install(DIRECTORY ${LIBONI_LIB_DIR}/ DESTINATION ${GUI_BIN_DIR}/shared FILES_MATCHING PATTERN "*.dll")
elseif(LINUX)
find_library(LIBONI_LIBRARIES oni liboni PATHS ${CMAKE_CURRENT_SOURCE_DIR}/libONI/linux)
find_library(LIBONI_LIBRARIES oni liboni PATHS ${CMAKE_CURRENT_SOURCE_DIR}/libONI/linux)
target_link_libraries(${PLUGIN_NAME} ${LIBONI_LIBRARIES})
install(DIRECTORY ${LIBONI_DIR}/linux/ DESTINATION ${GUI_BIN_DIR}/shared FILES_MATCHING PATTERN "*.so")
install(DIRECTORY ${LIBONI_DIR}/linux/ DESTINATION ${GUI_BIN_DIR}/shared FILES_MATCHING PATTERN "*.so")
elseif(APPLE)
set(LIBONI_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libONI/osx)
target_link_libraries(${PLUGIN_NAME} "${LIBONI_LIB_DIR}/liboni.dylib")
install(FILES ${LIBONI_LIB_DIR}/liboni.dylib DESTINATION $ENV{HOME}/Library/Application\ Support/open-ephys/shared-api8)
set(LIBONI_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libONI/osx)
target_link_libraries(${PLUGIN_NAME} "${LIBONI_LIB_DIR}/liboni.dylib")
install(FILES ${LIBONI_LIB_DIR}/liboni.dylib DESTINATION $ENV{HOME}/Library/Application\ Support/open-ephys/shared-api8)
endif()
213 changes: 213 additions & 0 deletions Source/Devices/Bno055.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/*
------------------------------------------------------------------

This file is part of the Open Ephys GUI
Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys

------------------------------------------------------------------

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

*/

#include "Bno055.h"

Bno055::Bno055(String name, const oni_dev_idx_t deviceIdx_, const oni_ctx ctx_)
: OnixDevice(name, OnixDeviceType::BNO, deviceIdx_, ctx_)
{
const float bitVolts = 1.0;

StreamInfo eulerAngleStream;
eulerAngleStream.name = name + "-Euler";
eulerAngleStream.description = "Bosch Bno055 9-axis inertial measurement unit (IMU) Euler angle";
eulerAngleStream.identifier = "onix-bno055.data.euler";
eulerAngleStream.numChannels = 3;
eulerAngleStream.sampleRate = 100.0f;
eulerAngleStream.channelPrefix = "Euler";
eulerAngleStream.bitVolts = bitVolts;
eulerAngleStream.channelType = ContinuousChannel::Type::AUX;
streams.add(eulerAngleStream);

StreamInfo quaternionStream;
quaternionStream.name = name + "-Quaternion";
quaternionStream.description = "Bosch Bno055 9-axis inertial measurement unit (IMU) Quaternion";
quaternionStream.identifier = "onix-bno055.data.quat";
quaternionStream.numChannels = 4;
quaternionStream.sampleRate = 100.0f;
quaternionStream.channelPrefix = "Quaternion";
quaternionStream.bitVolts = bitVolts;
quaternionStream.channelType = ContinuousChannel::Type::AUX;
streams.add(quaternionStream);

StreamInfo accelerationStream;
accelerationStream.name = name + "-Acceleration";
accelerationStream.description = "Bosch Bno055 9-axis inertial measurement unit (IMU) Acceleration";
accelerationStream.identifier = "onix-bno055.data.acc";
accelerationStream.numChannels = 3;
accelerationStream.sampleRate = 100.0f;
accelerationStream.channelPrefix = "Acceleration";
accelerationStream.bitVolts = bitVolts;
accelerationStream.channelType = ContinuousChannel::Type::AUX;
streams.add(accelerationStream);

StreamInfo gravityStream;
gravityStream.name = name + "-Gravity";
gravityStream.description = "Bosch Bno055 9-axis inertial measurement unit (IMU) Gravity";
gravityStream.identifier = "onix-bno055.data.grav";
gravityStream.numChannels = 3;
gravityStream.sampleRate = 100.0f;
gravityStream.channelPrefix = "Gravity";
gravityStream.bitVolts = bitVolts;
gravityStream.channelType = ContinuousChannel::Type::AUX;
streams.add(gravityStream);

StreamInfo temperatureStream;
temperatureStream.name = name + "-Temperature";
temperatureStream.description = "Bosch Bno055 9-axis inertial measurement unit (IMU) Temperature";
temperatureStream.identifier = "onix-bno055.data.temp";
temperatureStream.numChannels = 1;
temperatureStream.sampleRate = 100.0f;
temperatureStream.channelPrefix = "Temperature";
temperatureStream.bitVolts = bitVolts;
temperatureStream.channelType = ContinuousChannel::Type::AUX;
streams.add(temperatureStream);

for (int i = 0; i < numFrames; i++)
eventCodes[i] = 0;
}

Bno055::~Bno055()
{
}

int Bno055::enableDevice()
{
oni_write_reg(ctx, deviceIdx, (uint32_t)Bno055Registers::ENABLE, (uint32_t)1);

return 0;
}

int Bno055::updateSettings()
{
return 0;
}

void Bno055::startAcquisition()
{
}

void Bno055::stopAcquisition()
{
while (!frameArray.isEmpty())
{
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
oni_destroy_frame(frameArray.removeAndReturn(0));
}

currentFrame = 0;
sampleNumber = 0;
}

void Bno055::addFrame(oni_frame_t* frame)
{
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
frameArray.add(frame);
}

void Bno055::addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers)
{
for (StreamInfo streamInfo : streams)
{
sourceBuffers.add(new DataBuffer(streamInfo.numChannels, (int)streamInfo.sampleRate * bufferSizeInSeconds));

if (streamInfo.channelPrefix.equalsIgnoreCase("Euler"))
eulerBuffer = sourceBuffers.getLast();
else if (streamInfo.channelPrefix.equalsIgnoreCase("Quaternion"))
quaternionBuffer = sourceBuffers.getLast();
else if (streamInfo.channelPrefix.equalsIgnoreCase("Acceleration"))
accelerationBuffer = sourceBuffers.getLast();
else if (streamInfo.channelPrefix.equalsIgnoreCase("Gravity"))
gravityBuffer = sourceBuffers.getLast();
else if (streamInfo.channelPrefix.equalsIgnoreCase("Temperature"))
temperatureBuffer = sourceBuffers.getLast();
}
}

void Bno055::processFrames()
{
while (!frameArray.isEmpty())
{
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
oni_frame_t* frame = frameArray.removeAndReturn(0);

int16_t* dataPtr = (int16_t*)frame->data;

bnoTimestamps[currentFrame] = *(uint64_t*)frame->data;

int dataOffset = 4;

const float eulerAngleScale = 1.0f / 16; // 1 degree = 16 LSB
const float quaternionScale = 1.0f / (1 << 14); // 1 = 2^14 LSB
const float accelerationScale = 1.0f / 100; // 1m / s^2 = 100 LSB

for (int i = 0; i < 3; i++)
{
eulerSamples[currentFrame + i * numFrames] = float(*(dataPtr + dataOffset)) * eulerAngleScale;
dataOffset++;
}

for (int i = 0; i < 4; i++)
{
quaternionSamples[currentFrame + i * numFrames] = float(*(dataPtr + dataOffset)) * quaternionScale;
dataOffset++;
}

for (int i = 0; i < 3; i++)
{
accelerationSamples[currentFrame + i * numFrames] = float(*(dataPtr + dataOffset)) * accelerationScale;
dataOffset++;
}

for (int i = 0; i < 3; i++)
{
gravitySamples[currentFrame + i * numFrames] = float(*(dataPtr + dataOffset)) * accelerationScale;
dataOffset++;
}

temperatureSamples[currentFrame] = float(*((uint8_t*)(dataPtr + dataOffset)));

oni_destroy_frame(frame);

sampleNumbers[currentFrame] = sampleNumber++;

currentFrame++;

if (currentFrame >= numFrames)
{
shouldAddToBuffer = true;
currentFrame = 0;
sampleNumber = 0;
}

if (shouldAddToBuffer)
{
shouldAddToBuffer = false;
eulerBuffer->addToBuffer(eulerSamples, sampleNumbers, bnoTimestamps, eventCodes, numFrames);
quaternionBuffer->addToBuffer(quaternionSamples, sampleNumbers, bnoTimestamps, eventCodes, numFrames);
accelerationBuffer->addToBuffer(accelerationSamples, sampleNumbers, bnoTimestamps, eventCodes, numFrames);
gravityBuffer->addToBuffer(gravitySamples, sampleNumbers, bnoTimestamps, eventCodes, numFrames);
temperatureBuffer->addToBuffer(temperatureSamples, sampleNumbers, bnoTimestamps, eventCodes, numFrames);
}
}
}
89 changes: 89 additions & 0 deletions Source/Devices/Bno055.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
------------------------------------------------------------------

This file is part of the Open Ephys GUI
Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys

------------------------------------------------------------------

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef BNO055_H_DEFINED
#define BNO055_H_DEFINED

#include "../OnixDevice.h"

enum class Bno055Registers
{
ENABLE = 0x00
};

class Bno055 : public OnixDevice
{
public:

/** Constructor */
Bno055(String name, const oni_dev_idx_t, const oni_ctx);

/** Destructor */
~Bno055();

int enableDevice() override;

/** Update the settings of the device */
int updateSettings() override;

/** Starts probe data streaming */
void startAcquisition() override;

/** Stops probe data streaming*/
void stopAcquisition() override;

void addFrame(oni_frame_t*) override;

void processFrames() override;

void addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers) override;

DataBuffer* eulerBuffer = deviceBuffer;
DataBuffer* quaternionBuffer;
DataBuffer* accelerationBuffer;
DataBuffer* gravityBuffer;
DataBuffer* temperatureBuffer;

private:

static const int numFrames = 2;

Array<oni_frame_t*, CriticalSection, numFrames> frameArray;

bool shouldAddToBuffer = false;

float eulerSamples[3 * numFrames];
float quaternionSamples[4 * numFrames];
float accelerationSamples[3 * numFrames];
float gravitySamples[3 * numFrames];
float temperatureSamples[numFrames];

double bnoTimestamps[numFrames];
int64 sampleNumbers[numFrames];
uint64 eventCodes[numFrames];

unsigned short currentFrame = 0;
int sampleNumber = 0;
};

#endif
Loading