diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..bd1691e --- /dev/null +++ b/.clang-format @@ -0,0 +1,64 @@ +--- +Language: Cpp +# BasedOnStyle: JUCE (Custom) +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BreakAfterJavaFieldAnnotations: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList : BeforeColon +BreakStringLiterals: false +ColumnLimit: 0 +# ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: Inner +PackConstructorInitializers: CurrentLine +PointerAlignment: Left +ReflowComments: false +SortIncludes: true +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeParens: NonEmptyParentheses +SpaceInEmptyParentheses: false +SpaceBeforeInheritanceColon: true +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: "c++17" +TabWidth: 4 +UseTab: Never +--- + diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9cc1a11..4491555 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,19 +10,16 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [windows-2019] + os: [windows-latest] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: setup - env: - repo: open-ephys-gui - package: "open-ephys-lib" run: | cd ../.. git clone https://github.com/open-ephys/plugin-GUI.git --branch main cd plugin-GUI/Build - cmake -G "Visual Studio 16 2019" -A x64 .. + cmake -G "Visual Studio 17 2022" -A x64 .. mkdir Release && cd Release curl -L https://openephysgui.jfrog.io/artifactory/Libraries/open-ephys-lib-v0.6.0.zip --output open-ephys-lib.zip unzip open-ephys-lib.zip @@ -30,7 +27,7 @@ jobs: - name: configure run: | cd Build - cmake -G "Visual Studio 16 2019" -A x64 .. + cmake -G "Visual Studio 17 2022" -A x64 .. shell: bash - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v2 diff --git a/.gitignore b/.gitignore index 54b8e15..e94756d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ Builds/*/* # 3. OS-specific files .DS_Store + +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt index 95dc0fe..f36c031 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,14 +51,8 @@ target_include_directories(${PLUGIN_NAME} PUBLIC ${GUI_BASE_DIR}/JuceLibraryCode set(GUI_BIN_DIR ${GUI_BASE_DIR}/Build/${CONFIGURATION_FOLDER}) if (NOT CMAKE_LIBRARY_ARCHITECTURE) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(CMAKE_LIBRARY_ARCHITECTURE "x64") - set(NEUROPIX_LINK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/API/v1/lib64/NeuropixAPI_x64_1_20.lib) - set(NEUROPIX2_LINK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/API/v3/lib64/NeuropixAPI_x64_3_62_1.lib) - else() - set(CMAKE_LIBRARY_ARCHITECTURE "x86") - set(NEUROPIX_LINK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/neuropix-api/lib32/NeuropixAPI_x86_1_20.lib) - endif() + set(CMAKE_LIBRARY_ARCHITECTURE "x64") + set(NEUROPIX_LINK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/API/lib64/NeuropixAPI_x64_3_70_2.lib) endif() #Libraries and compiler options @@ -67,6 +61,7 @@ if(MSVC) target_compile_options(${PLUGIN_NAME} PRIVATE /sdl- /W0) install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION ${GUI_BIN_DIR}/plugins CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES}) + install(FILES $ DESTINATION ${GUI_BIN_DIR}/plugins OPTIONAL) set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../libs) elseif(LINUX) @@ -99,16 +94,7 @@ if (MSVC) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Resources/ DESTINATION ${GUI_BIN_DIR}/shared FILES_MATCHING PATTERN "*.dll") endif() -set(NEUROPIX_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/neuropix-api) +set(NEUROPIX_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/API) target_include_directories(${PLUGIN_NAME} PRIVATE ${NEUROPIX_INCLUDE_DIR}) target_link_libraries(${PLUGIN_NAME} ${NEUROPIX_LINK_DIR}) -target_link_libraries(${PLUGIN_NAME} ${NEUROPIX2_LINK_DIR}) - -#additional libraries, if needed -#find_package(LIBNAME) -#or -#find_library(LIBNAME_LIBRARIES NAMES libname) -#find_path(LIBNAME_INCLUDE_DIRS includefile.h) -# -#target_link_libraries(${PLUGIN_NAME} ${LIBNAME_LIBRARIES}) -#target_include_directories(${PLUGIN_NAME} PRIVATE ${LIBNAME_INCLUDE_DIRS}) + diff --git a/Resources/FTD3XX.dll b/Resources/FTD3XX.dll index f3b21ce..d5e6061 100644 Binary files a/Resources/FTD3XX.dll and b/Resources/FTD3XX.dll differ diff --git a/Resources/FpgaManager.dll b/Resources/FpgaManager.dll index 6f57f9e..8df20fa 100644 Binary files a/Resources/FpgaManager.dll and b/Resources/FpgaManager.dll differ diff --git a/Resources/NeuropixAPI_x64_1_20.dll b/Resources/NeuropixAPI_x64_1_20.dll deleted file mode 100644 index 40eba23..0000000 Binary files a/Resources/NeuropixAPI_x64_1_20.dll and /dev/null differ diff --git a/Resources/NeuropixAPI_x64_3_62_1.dll b/Resources/NeuropixAPI_x64_3_70_2.dll similarity index 55% rename from Resources/NeuropixAPI_x64_3_62_1.dll rename to Resources/NeuropixAPI_x64_3_70_2.dll index 456fe25..1e21adc 100644 Binary files a/Resources/NeuropixAPI_x64_3_62_1.dll and b/Resources/NeuropixAPI_x64_3_70_2.dll differ diff --git a/Resources/imec-firmware-for-plugin-0.7.x.zip b/Resources/imec-firmware-for-plugin-0.7.x.zip new file mode 100644 index 0000000..da806a3 Binary files /dev/null and b/Resources/imec-firmware-for-plugin-0.7.x.zip differ diff --git a/Resources/imec-firmware-for-plugin-0.7.x/BS_FPGA_B169.bin b/Resources/imec-firmware-for-plugin-0.7.x/BS_FPGA_B169.bin new file mode 100644 index 0000000..b0e6e20 Binary files /dev/null and b/Resources/imec-firmware-for-plugin-0.7.x/BS_FPGA_B169.bin differ diff --git a/Resources/imec-firmware-for-plugin-0.7.x/QBSC_FPGA_B191.bin b/Resources/imec-firmware-for-plugin-0.7.x/QBSC_FPGA_B191.bin new file mode 100644 index 0000000..20188fb Binary files /dev/null and b/Resources/imec-firmware-for-plugin-0.7.x/QBSC_FPGA_B191.bin differ diff --git a/Source/API/v3/NeuropixAPI.h b/Source/API/NeuropixAPI.h similarity index 80% rename from Source/API/v3/NeuropixAPI.h rename to Source/API/NeuropixAPI.h index 87892a0..ded774b 100644 --- a/Source/API/v3/NeuropixAPI.h +++ b/Source/API/NeuropixAPI.h @@ -1,13 +1,13 @@ /******************************** - * Copyright (C) Imec 2023 * + * Copyright (C) Imec 2024 * * * * Neuropixels C/C++ API header * ********************************/ - /** - * @file NeuropixAPI.h - * @brief Neuropixels c/c++ API header - */ +/** + * @file NeuropixAPI.h + * @brief Neuropixels c/c++ API header + */ #pragma once @@ -18,18 +18,18 @@ #define NP_EXPORT __declspec(dllexport) #define NP_CALLBACK __stdcall - /** - * @brief Main Neuropixels API namespace. All external functions are included in this namespace. - * - */ +/** + * @brief Main Neuropixels API namespace. All external functions are included in this namespace. + * + */ namespace Neuropixels { /** Flag set of hardware basestation selection. */ typedef enum { /** Do not select any, or none are selected */ - NPPlatform_None = 0, - /** PXI (PCIe) neuropixels basestation */ + NPPlatform_None = 0, + /** PXI (PCIe) neuropixels basestation */ NPPlatform_PXI = 0x1, /** USB (Onebox) neuropixels basestation */ NPPlatform_USB = 0x2, @@ -37,9 +37,9 @@ namespace Neuropixels { NPPlatform_ALL = NPPlatform_PXI | NPPlatform_USB, }NPPlatformID_t; - /** Unique basestation identification. - * - * This struct is a return value only + /** Unique basestation identification. + * + * This struct is a return value only * The combination of \c platformid and \c ID form a unique tuple to identify a base station */ struct basestationID @@ -83,9 +83,9 @@ namespace Neuropixels { }np_packet_t; #pragma pack(pop) - + typedef void(NP_CALLBACK* np_packetcallbackfn_t)(const np_packet_t& packet, const void* userdata); - + typedef enum { None = 0, @@ -111,7 +111,9 @@ namespace Neuropixels { typedef enum { SourceDefault = 0, /**< default stream source */ SourceAP = 0, - SourceLFP = 1 + SourceLFP = 1, + SourceSt2 = 2, + SourceSt3 = 3 }streamsource_t; struct PacketInfo { @@ -216,7 +218,7 @@ namespace Neuropixels { { INNER = 0, OUTER = 1, - ALL = 2 + ALL = 2 } columnpattern_t; #define enumspace_SM_Input 0x01 @@ -238,21 +240,18 @@ namespace Neuropixels { swcap_invert = (1 << 1) }swcapflags_t; - typedef enum { - SyncSource_None = SM_SyncSource_(0), - SyncSource_SMA = SM_SyncSource_(1), - SyncSource_Clock = SM_SyncSource_(2), - }syncsource_t; - typedef enum { SM_Input_None = SM_Input_(0), SM_Input_SWTrigger1 = SM_Input_(1), SM_Input_SWTrigger2 = SM_Input_(2), - SM_Input_SMA = SM_Input_(5), /* PXI system SMA input */ + SM_Input_SMA = SM_Input_(5), /* PXI system SMA input */ SM_Input_SMA1 = SM_Input_(6), /* OneBox backpanel SMA (SMA1) */ + SM_Input_SMATrigger = SM_Input_(7), /* PXI system pulse-stretched SMA */ + SM_Input_SMASYNC = SM_Input_(8), /* PXI system unprocessed input */ + SM_Input_PXI0 = SM_Input_(0x10), SM_Input_PXI1 = SM_Input_(0x11), SM_Input_PXI2 = SM_Input_(0x12), @@ -262,23 +261,23 @@ namespace Neuropixels { SM_Input_PXI6 = SM_Input_(0x16), SM_Input_PXISYNC = SM_Input_(0x17), - SM_Input_ADC0 = SM_Input_(0x20), - SM_Input_ADC1 = SM_Input_(0x21), - SM_Input_ADC2 = SM_Input_(0x22), - SM_Input_ADC3 = SM_Input_(0x23), - SM_Input_ADC4 = SM_Input_(0x24), - SM_Input_ADC5 = SM_Input_(0x25), - SM_Input_ADC6 = SM_Input_(0x26), - SM_Input_ADC7 = SM_Input_(0x27), - SM_Input_ADC8 = SM_Input_(0x28), - SM_Input_ADC9 = SM_Input_(0x29), + SM_Input_ADC0 = SM_Input_(0x20), + SM_Input_ADC1 = SM_Input_(0x21), + SM_Input_ADC2 = SM_Input_(0x22), + SM_Input_ADC3 = SM_Input_(0x23), + SM_Input_ADC4 = SM_Input_(0x24), + SM_Input_ADC5 = SM_Input_(0x25), + SM_Input_ADC6 = SM_Input_(0x26), + SM_Input_ADC7 = SM_Input_(0x27), + SM_Input_ADC8 = SM_Input_(0x28), + SM_Input_ADC9 = SM_Input_(0x29), SM_Input_ADC10 = SM_Input_(0x3A), SM_Input_ADC11 = SM_Input_(0x3B), SM_Input_ADC12 = SM_Input_(0x3C), SM_Input_ADC13 = SM_Input_(0x3D), SM_Input_ADC14 = SM_Input_(0x3E), SM_Input_ADC15 = SM_Input_(0x3F), - + SM_Input_SyncClk = SM_Input_(0x40), SM_Input_TimeStampClk = SM_Input_(0x41), SM_Input_ADCClk = SM_Input_(0x42), @@ -318,7 +317,7 @@ namespace Neuropixels { }switchmatrixoutput_t; typedef enum { - triggeredge_rising = 1, + triggeredge_rising = 1, triggeredge_falling = 2, }triggeredge_t; @@ -343,6 +342,11 @@ namespace Neuropixels { */ NP_EXPORT size_t getAPIVersionFull(char* buffer, size_t size); + /* + * \brief Returns the minimum required FTDI Driver version number that is expected by the API library + */ + NP_EXPORT void getMinimumFtdiDriverVersion(int* version_major, int* version_minor, int* version_build); + /** * Read the last error message * @@ -352,12 +356,12 @@ namespace Neuropixels { */ NP_EXPORT size_t getLastErrorMessage(char* buffer, size_t buffersize); - /** - * Get an error message for a given error code. - * - * @param code Error code - * @returns const pointer to string containing error message - */ + /** + * Get an error message for a given error code. + * + * @param code Error code + * @returns const pointer to string containing error message + */ NP_EXPORT const char* getErrorMessage(NP_ErrorCode code); /* @@ -377,11 +381,11 @@ namespace Neuropixels { /* * \brief try to get the associated slotID * @param bsid: basestation ID (use getDeviceList to retrieve list of known devices) - * @param slotID: output value associated slot ID + * @param slotID: output value associated slot ID * @returns true if the bsid is found and mapped to a slot, false otherwise */ NP_EXPORT bool tryGetSlotID(const basestationID* bsid, int* slotID); - + /* * \brief Scan the system for available devices. This function updates the cached device list. (See getDeviceList) */ @@ -389,9 +393,9 @@ namespace Neuropixels { /* * \brief Maps a specific basestation device to a slot. - * If a device with the specified platform and serial number is discovered (using 'scanBS'), it will be automatically - * mapped to the specified slot. - * Note: A PXI basestation device is automatically mapped to a slot corresponding to its PXI geographic location + * If a device with the specified platform and serial number is discovered (using 'scanBS'), it will be automatically + * mapped to the specified slot. + * Note: A PXI basestation device is automatically mapped to a slot corresponding to its PXI geographic location */ NP_EXPORT NP_ErrorCode mapBS(int serialnr, int slot); @@ -412,15 +416,10 @@ namespace Neuropixels { typedef enum { NP_PARAM_BUFFERSIZE = 1, NP_PARAM_BUFFERCOUNT = 2, - NP_PARAM_SYNCMASTER = 3, - NP_PARAM_SYNCFREQUENCY_HZ = 4, - NP_PARAM_SYNCPERIOD_MS = 5, - NP_PARAM_SYNCSOURCE = 6, NP_PARAM_SIGNALINVERT = 7, // internal use only - NP_PARAM_IGNOREPROBESN = 0x1000, - NP_PARAM_ALLOWMANUALPXISYNCCONFIG = 0x1001 + NP_PARAM_IGNOREPROBESN = 0x1000 }np_parameter_t; /* * \brief Set the value of a system-wide parameter @@ -440,7 +439,7 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode getParameter_double(np_parameter_t paramid, double* value); /* Base station board/Slot Functions **************************************************/ - + NP_EXPORT NP_ErrorCode detectBS(int slotID, bool* detected); /* * \brief Open a basestation at the specified slot. @@ -463,15 +462,10 @@ namespace Neuropixels { /* * \brief Force software triggers on multiple software trigger channels. Onebox supports 2 trigger channels, PXI only 1 - * @param triggerflags: A mask of software triggers to set. + * @param triggerflags: A mask of software triggers to set. */ NP_EXPORT NP_ErrorCode setSWTriggerEx(int slotID, swtriggerflags_t triggerflags); - /* - * \brief Configures the input/output trigger signal edge as rising/falling sensitive - */ - NP_EXPORT NP_ErrorCode setTriggerEdge(int slotID, bool rising); - /* * \brief Connect/disconnect a switch matrix input to/from an output signal */ @@ -491,20 +485,58 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode switchmatrix_setOutputTriggerEdge(int slotID, switchmatrixoutput_t output, triggeredge_t edge); NP_EXPORT NP_ErrorCode switchmatrix_getOutputTriggerEdge(int slotID, switchmatrixoutput_t output, triggeredge_t* edge); + /** + * Set the frequency of the internal sync clock. + * + * This function will attempt to set the frequency of the internal sync clock to + * the target frequency. Because of rounding and conversion of the frequency to + * a half period in milliseconds, the actual frequency may differ slightly from + * the target frequency. The actual frequency can always be checked by using + * `getSyncClockFrequency`. + * + * @param slotID Target slot + * @param frequency Target frequency in Hz + * @returns PARAMETER_INVALID if the target frequency is out-of-bounds or otherwise illegal + */ + NP_EXPORT NP_ErrorCode setSyncClockFrequency(int slotID, double frequency); + /** + * Get the frequency of the internal sync clock. + * + * @param slotID Target slot + * @param frequency Pointer to result + */ + NP_EXPORT NP_ErrorCode getSyncClockFrequency(int slotID, double* frequency); + + /** + * Set the period of the internal sync clock. + * + * @param slotID Target slot + * @param period_ms Target period in milliseconds + * @returns PARAMETER_INVALID if period is out-of-bounds or otherwise illegal + */ + NP_EXPORT NP_ErrorCode setSyncClockPeriod(int slotID, int period_ms); + + /** + * Get the period of the internal sync clock. + * + * @param slotID Target slot + * @param period_ms Pointer to result + */ + NP_EXPORT NP_ErrorCode getSyncClockPeriod(int slotID, int* period_ms); typedef enum { NP_DATAMODE_OFF = 0, NP_DATAMODE_ELECTRODE = 1, NP_DATAMODE_ADC = 2 }np_datamode_t; - + NP_EXPORT NP_ErrorCode setDataMode(int slotID, int portID, np_datamode_t mode); NP_EXPORT NP_ErrorCode getDataMode(int slotID, int portID, np_datamode_t* mode); /* - * \brief Get the basestation temperature (in degrees Celsius) + * \brief Get the basestation temperature (in degrees Celsius) */ NP_EXPORT NP_ErrorCode bs_getTemperature(int slotID, double* temperature_degC); /* @@ -525,7 +557,7 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode bs_updateFirmware(int slotID, const char* filename, int(*callback)(size_t byteswritten)); /* - * \brief (Only on PXI platform) Get the basestation connect board temperature (in degrees Celsius) + * \brief (Only on PXI platform) Get the basestation connect board temperature (in degrees Celsius) */ NP_EXPORT NP_ErrorCode bsc_getTemperature(int slotID, double* temperature_degC); /* @@ -545,17 +577,6 @@ namespace Neuropixels { */ NP_EXPORT NP_ErrorCode bsc_updateFirmware(int slotID, const char* filename, int(*callback)(size_t byteswritten)); - - /* File stream API *****************************************************************************************/ - /* - * \brief Associate a raw packet file dump stream with a mapped basestation - */ - NP_EXPORT NP_ErrorCode setFileStream(int slotID, const char* filename); - /* - * \brief Enable writing to the file stream (See setFileStream) - */ - NP_EXPORT NP_ErrorCode enableFileStream(int slotID, bool enable); - /** * @brief Get the amount of ports on the base station connect board * @param slotID: slot ID @@ -572,62 +593,34 @@ namespace Neuropixels { */ NP_EXPORT NP_ErrorCode getHSSupportedProbeCount(int slotID, int portID, int* count); - NP_EXPORT NP_ErrorCode openPort(int slotID, int portID); - NP_EXPORT NP_ErrorCode closePort(int slotID, int portID); - NP_EXPORT NP_ErrorCode detectHeadStage(int slotID, int portID, bool* detected); - NP_EXPORT NP_ErrorCode detectFlex(int slotID, int portID, int dockID, bool* detected); - NP_EXPORT NP_ErrorCode setHSLed(int slotID, int portID, bool enable); - - NP_EXPORT NP_ErrorCode getFlexVersion(int slotID, int portID, int dockID, int* version_major, int* version_minor); - NP_EXPORT NP_ErrorCode readFlexPN(int slotID, int portID, int dockID, char* pn, size_t maxlen); - - NP_EXPORT NP_ErrorCode getHSVersion(int slotID, int portID, int* version_major, int* version_minor); - NP_EXPORT NP_ErrorCode readHSPN(int slotID, int portID, char* pn, size_t maxlen); - NP_EXPORT NP_ErrorCode readHSSN(int slotID, int portID, uint64_t* sn); - NP_EXPORT NP_ErrorCode readProbeSN(int slotID, int portID, int dockID, uint64_t* id); - NP_EXPORT NP_ErrorCode readProbePN(int slotID, int portID, int dockID, char* pn, size_t maxlen); - - NP_EXPORT NP_ErrorCode readBSCPN(int slotID, char* pn, size_t len); - NP_EXPORT NP_ErrorCode readBSCSN(int slotID, uint64_t* sn); - NP_EXPORT NP_ErrorCode getBSCVersion(int slotID, int* version_major, int* version_minor); - - /** - * Configures the sync pattern on the FPGA (NPM2b/c specific) - * - * Using this procedure the sync pattern can be configured on the FPGA. - * This sync pattern is used to detect sync errors by comparing the pattern - * with the pattern sent by the probe ASIC. - * - * @param slotID slot ID - * @param portID port ID - * @param sync_pattern Pointer to the 12 bytes to be used as sync pattern - */ - NP_EXPORT NP_ErrorCode setPortSyncPattern(int slotID, int portID, uint8_t* sync_pattern); - NP_EXPORT NP_ErrorCode getPortSyncPattern(int slotID, int portID, uint8_t* sync_pattern); - + NP_EXPORT NP_ErrorCode openPort (int slotID, int portID); + NP_EXPORT NP_ErrorCode closePort (int slotID, int portID); + NP_EXPORT NP_ErrorCode detectHeadStage (int slotID, int portID, bool* detected); + NP_EXPORT NP_ErrorCode detectFlex (int slotID, int portID, int dockID, bool* detected); + NP_EXPORT NP_ErrorCode setHSLed (int slotID, int portID, bool enable); + + NP_EXPORT NP_ErrorCode getFlexVersion (int slotID, int portID, int dockID, int* version_major, int* version_minor); + NP_EXPORT NP_ErrorCode readFlexPN (int slotID, int portID, int dockID, char* pn, size_t maxlen); + + NP_EXPORT NP_ErrorCode getHSVersion (int slotID, int portID, int* version_major, int* version_minor); + NP_EXPORT NP_ErrorCode readHSPN (int slotID, int portID, char* pn, size_t maxlen); + NP_EXPORT NP_ErrorCode readHSSN (int slotID, int portID, uint64_t* sn); + NP_EXPORT NP_ErrorCode readProbeSN (int slotID, int portID, int dockID, uint64_t* id); + NP_EXPORT NP_ErrorCode readProbePN (int slotID, int portID, int dockID, char* pn, size_t maxlen); + + NP_EXPORT NP_ErrorCode readBSCPN (int slotID, char* pn, size_t len); + NP_EXPORT NP_ErrorCode readBSCSN (int slotID, uint64_t* sn); + NP_EXPORT NP_ErrorCode getBSCVersion (int slotID, int* version_major, int* version_minor); + /* Probe functions *******************************************************************/ - NP_EXPORT NP_ErrorCode openProbe(int slotID, int portID, int dockID); - NP_EXPORT NP_ErrorCode closeProbe(int slotID, int portID, int dockID); - NP_EXPORT NP_ErrorCode init(int slotID, int portID, int dockID); - NP_EXPORT NP_ErrorCode writeProbeConfiguration(int slotID, int portID, int dockID, bool readCheck); - NP_EXPORT NP_ErrorCode setADCCalibration(int slotID, int portID, const char* filename); - NP_EXPORT NP_ErrorCode setGainCalibration(int slotID, int portID, int dockID, const char* filename); - - /** - * Configures the sync pattern on the probe ASIC (NPM2b/c specific) - * - * Using this procedure the sync pattern can be configured on the probe ASIC. - * This sync pattern is sent as sync word in the PSB frames. - * - * @param slotID slot ID - * @param portID port ID - * @param dockID dock ID - * @param sync_pattern Pointer to buffer for 12 sync bytes - */ - NP_EXPORT NP_ErrorCode setProbeSyncPattern(int slotID, int portID, int dockID, uint8_t* sync_pattern); - NP_EXPORT NP_ErrorCode getProbeSyncPattern(int slotID, int portID, int dockID, uint8_t* sync_pattern); - - // + NP_EXPORT NP_ErrorCode openProbe (int slotID, int portID, int dockID); + NP_EXPORT NP_ErrorCode closeProbe (int slotID, int portID, int dockID); + NP_EXPORT NP_ErrorCode init (int slotID, int portID, int dockID); + NP_EXPORT NP_ErrorCode writeProbeConfiguration (int slotID, int portID, int dockID, bool readCheck); + NP_EXPORT NP_ErrorCode setADCCalibration (int slotID, int portID, const char* filename); + NP_EXPORT NP_ErrorCode setGainCalibration (int slotID, int portID, int dockID, const char* filename); + +// #define NP1_PROBE_CHANNEL_COUNT 384 #define NP1_PROBE_SUPERFRAMESIZE 12 #define NP1_PROBE_ADC_COUNT 32 @@ -648,14 +641,14 @@ namespace Neuropixels { int16_t lfpData[NP1_PROBE_CHANNEL_COUNT]; uint16_t Status[NP1_PROBE_SUPERFRAMESIZE]; }; - NP_EXPORT NP_ErrorCode readElectrodeData(int slotID, int portID, int dockID, struct electrodePacket* packets, int* actualAmount, int requestedAmount); - NP_EXPORT NP_ErrorCode getElectrodeDataFifoState(int slotID, int portID, int dockID, int* packetsavailable, int* headroom); - // + NP_EXPORT NP_ErrorCode readElectrodeData (int slotID, int portID, int dockID, struct electrodePacket* packets, int* actualAmount, int requestedAmount); + NP_EXPORT NP_ErrorCode getElectrodeDataFifoState (int slotID, int portID, int dockID, int* packetsavailable, int* headroom); +// - NP_EXPORT NP_ErrorCode setTestSignal(int slotID, int portID, int dockID, bool enable); - NP_EXPORT NP_ErrorCode setOPMODE(int slotID, int portID, int dockID, probe_opmode_t mode); - NP_EXPORT NP_ErrorCode setCALMODE(int slotID, int portID, int dockID, testinputmode_t mode); - NP_EXPORT NP_ErrorCode setREC_NRESET(int slotID, int portID, bool state); + NP_EXPORT NP_ErrorCode setTestSignal (int slotID, int portID, int dockID, bool enable); + NP_EXPORT NP_ErrorCode setOPMODE (int slotID, int portID, int dockID, probe_opmode_t mode); + NP_EXPORT NP_ErrorCode setCALMODE (int slotID, int portID, int dockID, testinputmode_t mode); + NP_EXPORT NP_ErrorCode setREC_NRESET (int slotID, int portID, bool state); /** * @brief Read a single packet data from the specified fifo. @@ -720,7 +713,7 @@ namespace Neuropixels { * @returns SUCCESS if successful */ NP_EXPORT NP_ErrorCode createProbePacketCallback(int slotID, int portID, int dockID, streamsource_t source, npcallbackhandle_t* handle, np_packetcallbackfn_t callback, const void* userdata); - + /** * @brief Unpacks samples from a raw data packet frame. @@ -769,8 +762,8 @@ namespace Neuropixels { */ NP_EXPORT NP_ErrorCode selectElectrodeGroup(int slotID, int portID, int dockID, int channelgroup, int bank); /** - * Connect a maximum of two banks to channel group. - * + * Connect a maximum of two banks to channel group. + * * In the case the EN_A or EN_B bit in the shank register is set low, * it is allowed to connect a channel group to maximum two banks. * @@ -918,7 +911,7 @@ namespace Neuropixels { * Set the ADC Voltage range. * * This voltage range is used for all ADC channels. - * + * * @param slotID The slot number of the device * @param range Programmed range will be -range .. +range. * @return SUCCESS if successful. @@ -937,7 +930,7 @@ namespace Neuropixels { */ NP_EXPORT NP_ErrorCode ADC_getVoltageRange(int slotID, ADCrange_t* range); - /** + /** * Set a DAC channel to a fixed voltage. * * @param slotID The slot number of the device @@ -1020,7 +1013,7 @@ namespace Neuropixels { /** * @brief Head Stage heartbeat test - * + * * The heartbeat signal generated by the PSB_SYNC signal of the probe. The PSB_SYNC signal starts when the probe is powered on, the OP_MODE register in the probes' memory map set to 1, and the REC_NRESET signal set high. * The heartbeat signal is visible on the headstage (can be disabled by API functions) and on the BSC. This is in the first place a visual check. * In order to facilitate a software check of the BSC heartbeat signal, the PSB_SYNC signal is also routed to the BS FPGA. A function is provided to check whether the PSB_SYNC signal contains a 0.5Hz clock. @@ -1079,15 +1072,23 @@ namespace Neuropixels { */ NP_EXPORT NP_ErrorCode bistEEPROM(int slotID, int portID); - /** - * @brief Test the shift registers - * This test verifies the functionality of the shank and base shift registers (SR_CHAIN 1 to 3). The function configures the shift register two times with the same code. After the 2nd write cycle the SR_OUT_OK bit in the STATUS register is read. If OK, the shift register configuration was successful. The test is done for all 3 registers. The configuration code used for the test is a dedicated code (to make sure the bits are not all 0 or 1). - * - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @param port: for which HS (valid range 1 to 4) - * @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered, ERROR_SR_CHAIN_1 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_1, ERROR_SR_CHAIN_2 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_2, ERROR_SR_CHAIN_3 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_3. - */ + * Test the shift registers + * + * This test verifies the functionality of the shank and base shift registers. + * The function configures the shift register two or more times with the same code. + * After the 2nd write cycle the SR_OUT_OK bit in the STATUS register is read. + * If OK, the shift register configuration was successful. + * The test is done for all applicable SR chain registers. + * The configuration code used for the test is a dedicated code (to make sure the bits are not all 0 or 1). + * + * Note that this test overwrites and does not restore the data stored in the SR chains before the test. + * Use writeProbeConfiguration to restore the configuration. + * + * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) + * @param port: for which HS (valid range 1 to 4) + * @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered, ERROR_SR_CHAIN_1 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_1, ERROR_SR_CHAIN_2 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_2, ERROR_SR_CHAIN_3 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_3. + */ NP_EXPORT NP_ErrorCode bistSR(int slotID, int portID, int dockID); /** @@ -1124,70 +1125,7 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode HSTestNRST(int slotID, int portID); NP_EXPORT NP_ErrorCode HSTestREC_NRESET(int slotID, int portID); - - /********************* Raw Stream file API functions ****************************/ - - /** - * @brief Open an acquisition stream from an existing file. - * @param filename Specifies an existing file with probe acquisition data. - * @param port specifies the target port (1..4) - * @param dockID 1..2 (depending on type of probe. default=1) - * @param source data type (AP or LFP) if supported (default = AP) - * @param psh stream a pointer to the stream pointer that will receive the handle to the opened stream - * @returns FILE_OPEN_ERROR if unable to open file - */ - NP_EXPORT NP_ErrorCode streamOpenFile(const char* filename, int portID, int dockID, streamsource_t source, np_streamhandle_t* pstream); - - /** - * @brief Closes an acquisition stream. - * Closes the stream along with the optional recording file. - */ - NP_EXPORT NP_ErrorCode streamClose(np_streamhandle_t sh); - - /** - * @brief Moves the stream pointer to given timestamp. - * Stream seek is only supported on streams that are backed by a recording file store. - * @param stream: the acquisition stream handle - * @param filepos: The file position to navigate to. - * @param actualtimestamp: returns the timestamp at the stream pointer (NULL allowed) - * @returns TIMESTAMPNOTFOUND if no valid data packet is found beyond the specified file position - */ - NP_EXPORT NP_ErrorCode streamSeek(np_streamhandle_t sh, uint64_t filepos, uint32_t* actualtimestamp); - - NP_EXPORT NP_ErrorCode streamSetPos(np_streamhandle_t sh, uint64_t filepos); - - /** - * @brief Report the current file position in the filestream. - * @param stream: the acquisition stream handle - * @returns the current file position at the stream cursor position. - */ - NP_EXPORT uint64_t streamTell(np_streamhandle_t sh); - - /** - * @brief read probe data from a recorded file stream. - * Example: - * #define SAMPLECOUNT 128 - * uint16_t interleaveddata[SAMPLECOUNT * 384]; - * uint32_t timestamps[SAMPLECOUNT]; - * - * np_streamhandle_t sh; - * streamOpenFile("myrecording.bin",1, false, &sh); - * int actualread; - * streamRead(sh, timestamps, interleaveddata, SAMPLECOUNT, &actualread); - * - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @param timestamps: Optional timestamps buffer (NULL if not used). size should be 'samplecount' - * @param data: buffer of size samplecount*384. The buffer will be populated with channel interleaved, 16 bit per sample data. - * @param samplestoread: amount of timestamps to read. - * @param actualread: output parameter: amount of 16 timestamps actually read from the stream. - * @returns SUCCESS if succesfully read any sample from the stream - */ - NP_EXPORT NP_ErrorCode streamRead(np_streamhandle_t sh, uint32_t* timestamps, int16_t* data, int samplestoread, int* actualread); - - NP_EXPORT NP_ErrorCode streamReadPacket(np_streamhandle_t sh, pckhdr_t* header, int16_t* data, int samplestoread, int* actualread); - - - // Configuration +// Configuration const int HARDWAREID_PN_LEN = 40; #pragma pack(push, 1) @@ -1205,18 +1143,13 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode getProbeDriverID(int slotID, int portID, int dockID, char* name, size_t len); NP_EXPORT NP_ErrorCode getBSCHardwareID(int slotID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode setBSCHardwareID(int slotID, const struct HardwareID* pHwid); NP_EXPORT NP_ErrorCode getHeadstageHardwareID(int slotID, int portID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode setHeadstageHardwareID(int slotID, int portID, const struct HardwareID* pHwid); NP_EXPORT NP_ErrorCode getFlexHardwareID(int slotID, int portID, int dockID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode setFlexHardwareID(int slotID, int portID, int dockID, const struct HardwareID* pHwid); NP_EXPORT NP_ErrorCode getProbeHardwareID(int slotID, int portID, int dockID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode setProbeHardwareID(int slotID, int portID, int dockID, const struct HardwareID* pHwid); - - // Debug +// Debug - // A fatal error occurred, the system must be reset completely to proceed +// A fatal error occurred, the system must be reset completely to proceed #define DBG_FATAL 0 // An error occurred, the function could not complete its operation #define DBG_ERROR 1 @@ -1251,30 +1184,6 @@ namespace Neuropixels { uint32_t fifooverflow; /**< last recorded sample counter */ }; - typedef enum { - NPSlotEmulatorMode_Off = 0, /**< No emulation data is generated */ - NPSlotEmulatorMode_Static = 1, /**< static data per channel: value = channel number */ - NPSlotEmulatorMode_Linear = 2, /**< a linear ramp is generated per channel (1 sample shift between channels) */ - } slotemulatormode_t; - - typedef enum - { - NPSlotEmulatorType_NP2, - NPSlotEmulatorType_NPM, - NPSlotEmulatorType_NPM2, - NPSlotEmulatorType_Colibri - } slotemulatortype_t; - - typedef enum { - NPPortEmulatorMode_Off = 0, - NPPortEmulatorMode_NP1_0 = 1, - NPPortEmulatorMode_NHP = 2, - NPPortEmulatorMode_NPM = 3, - NPPortEmulatorMode_NPM2b = 4, - NPPortEmulatorMode_NPM2c = 5, - NPPortEmulatorMode_Colibri = 6 - } portemulatormode_t; - typedef enum { // A new device was found @@ -1293,15 +1202,6 @@ namespace Neuropixels { */ NP_EXPORT NP_ErrorCode createSystemEventCallback(npcallbackhandle_t* handle, np_systemeventcallbackfn_t callback, const void* userdata); - NP_EXPORT NP_ErrorCode writeBSCMM(int slotID, uint32_t address, uint32_t data); - NP_EXPORT NP_ErrorCode readBSCMM(int slotID, uint32_t address, uint32_t* data); - NP_EXPORT NP_ErrorCode writeI2C(int slotID, int portID, uint8_t device, uint8_t address, uint8_t data); - NP_EXPORT NP_ErrorCode readI2C(int slotID, int portID, uint8_t device, uint8_t address, uint8_t* data); - NP_EXPORT NP_ErrorCode writeI2Cex(int slotID, int portID, uint8_t device, uint8_t address, const void* data, size_t len); - NP_EXPORT NP_ErrorCode readI2Cex(int slotID, int portID, uint8_t device, uint8_t address, void* data, size_t len); - NP_EXPORT NP_ErrorCode writeI2Cflex(int slotID, int portID, int dockID, uint8_t device, uint8_t address, uint8_t data); - NP_EXPORT NP_ErrorCode readI2Cflex(int slotID, int portID, int dockID, uint8_t device, uint8_t address, uint8_t* data); - /* Neuropixels OPTO specific **********************************************************************************************************************/ typedef enum { @@ -1313,7 +1213,7 @@ namespace Neuropixels { * \brief Program the optical switch calibration using a calibration file * A OPTO headstage must be attached to SlotID/PortID * dockID is ignored - * + * * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) * @param portID: specifies the target port (valid range depends on slot type) * @param dockID: ignored @@ -1321,14 +1221,14 @@ namespace Neuropixels { * first line : probe serial number * next lines: , , , * wavelengthindex : 0 = blue(450nm), 1 = red(638nm) - * thermalswitchindex : + * thermalswitchindex : * 0 : 1_1 * 1..2 : 2_1, 2_2 * 3..8 : 3_1, 3_2, 3_3, 3_4 * 9..14: 4_1, 4_2, 4_3, 4_4, 4_5, 4_6, 4_7, 4_8 * off_mA/on_mA : on/off current setting - * - * example csv file content: + * + * example csv file content: * 21050005 * 0, 0, 0.0, 4.0 * 0, 1, 0.0, 4.0 @@ -1422,7 +1322,7 @@ namespace Neuropixels { */ NP_EXPORT NP_ErrorCode getEmissionSiteAttenuation(int slotID, int portID, int dockID, wavelength_t wavelength, int site, double* attenuation); /* - * \brief Disable an optical emission path. + * \brief Disable an optical emission path. * Note: only the current to the optical thermal switches is disabled. Laser power is not affected * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) * @param portID: specifies the target port (valid range depends on slot type) @@ -1491,55 +1391,19 @@ namespace Neuropixels { NP_EXPORT int dbg_getlevel(void); NP_EXPORT void dbg_setlogcallback(int minlevel, void(*callback)(int level, time_t ts, const char* module, const char* msg)); NP_EXPORT void dbg_getversion_datetime(char* dst, size_t maxlen); - NP_EXPORT NP_ErrorCode dbg_setSlotEmulatorMode(int slotID, slotemulatormode_t mode); - NP_EXPORT NP_ErrorCode dbg_getSlotEmulatorMode(int slotID, slotemulatormode_t* mode); - /** Sets the emulation type of the slot. - * - * To avoid conflicts between slot and port emulator types, - * the following actions will be executed when calling this function: - * - All open ports will be closed - * - The emulator mode of the port will be set to "Off" - * - * @param slotID slot ID - * @param type emulation type - */ - NP_EXPORT NP_ErrorCode dbg_setSlotEmulatorType(int slotID, slotemulatortype_t type); - NP_EXPORT NP_ErrorCode dbg_getSlotEmulatorType(int slotID, slotemulatortype_t* type); - - /** - * Set the sync pattern for the NPM 2b/c emulator. - * - * @param slotID slot ID - * @param sync_pattern Pointer to buffer containing 12 sync bytes. - */ - NP_EXPORT NP_ErrorCode dbg_setSlotEmulatorSyncPattern(int slotID, uint8_t* sync_pattern); - - /** - * Get the current sync pattern for the NPM 2b/c emulator. - * - * @param slotID slot ID - * @param sync_pattern Pointer to buffer for 12 sync bytes. - */ - NP_EXPORT NP_ErrorCode dbg_getSlotEmulatorSyncPattern(int slotID, uint8_t* sync_pattern); - NP_EXPORT NP_ErrorCode dbg_setPortEmulatorMode(int slotID, int portID, portemulatormode_t emulationmode); - NP_EXPORT NP_ErrorCode dbg_getPortEmulatorMode(int slotID, int portID, portemulatormode_t* emulationmode); NP_EXPORT NP_ErrorCode dbg_stats_reset(int slotID); NP_EXPORT NP_ErrorCode dbg_diagstats_read(int slotID, struct np_diagstats* stats); NP_EXPORT NP_ErrorCode dbg_sourcestats_read(int slotID, uint8_t sourceID, struct np_sourcestats* stats); - NP_EXPORT NP_ErrorCode dbg_read_srchain(int slotID, int portID, int dockID, uint8_t SRChain_registeraddress, uint8_t* dst, size_t len, size_t* actualread); - NP_EXPORT NP_ErrorCode setVirtualHeadstage(int slotID, int portID); - - - #define NP_APIC __stdcall extern "C" { //NeuropixAPI.h NP_EXPORT void NP_APIC np_getAPIVersion(int* version_major, int* version_minor); NP_EXPORT size_t NP_APIC np_getAPIVersionFull(char* buffer, size_t size); + NP_EXPORT void NP_APIC np_getMinimumFtdiDriverVersion(int* version_major, int* version_minor, int* version_build); NP_EXPORT size_t NP_APIC np_getLastErrorMessage(char* buffer, size_t buffersize); - NP_EXPORT const char* NP_APIC np_getErrorMessage(NP_ErrorCode code); + NP_EXPORT const char* NP_APIC np_getErrorMessage(NP_ErrorCode code); NP_EXPORT int NP_APIC np_getDeviceList(struct basestationID* list, int count); NP_EXPORT NP_ErrorCode NP_APIC np_getDeviceInfo(int slotID, struct basestationID* info); NP_EXPORT bool NP_APIC np_tryGetSlotID(const basestationID* bsid, int* slotID); @@ -1557,7 +1421,6 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode NP_APIC np_arm(int slotID); NP_EXPORT NP_ErrorCode NP_APIC np_setSWTrigger(int slotID); NP_EXPORT NP_ErrorCode NP_APIC np_setSWTriggerEx(int slotID, swtriggerflags_t triggerflags); - NP_EXPORT NP_ErrorCode NP_APIC np_setTriggerEdge(int slotID, bool rising); NP_EXPORT NP_ErrorCode NP_APIC np_switchmatrix_set(int slotID, switchmatrixoutput_t output, switchmatrixinput_t inputline, bool connect); NP_EXPORT NP_ErrorCode NP_APIC np_switchmatrix_get(int slotID, switchmatrixoutput_t output, switchmatrixinput_t inputline, bool* isconnected); NP_EXPORT NP_ErrorCode NP_APIC np_switchmatrix_clear(int slotID, switchmatrixoutput_t output); @@ -1567,7 +1430,11 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode NP_APIC np_switchmatrix_getOutputInversion(int slotID, switchmatrixoutput_t output, bool* invert); NP_EXPORT NP_ErrorCode NP_APIC np_switchmatrix_setOutputTriggerEdge(int slotID, switchmatrixoutput_t output, triggeredge_t edge); NP_EXPORT NP_ErrorCode NP_APIC np_switchmatrix_getOutputTriggerEdge(int slotID, switchmatrixoutput_t output, triggeredge_t* edge); - NP_EXPORT NP_ErrorCode NP_APIC np_setDataMode(int slotID, int portID, np_datamode_t mode); + NP_EXPORT NP_ErrorCode NP_APIC np_setSyncClockFrequency(int slotID, double frequency); + NP_EXPORT NP_ErrorCode NP_APIC np_getSyncClockFrequency(int slotID, double* frequency); + NP_EXPORT NP_ErrorCode NP_APIC np_setSyncClockPeriod(int slotID, int period_ms); + NP_EXPORT NP_ErrorCode NP_APIC np_getSyncClockPeriod(int slotID, int* period_ms); + NP_EXPORT NP_ErrorCode NP_APIC np_setDataMode(int slotID, int portID, np_datamode_t mode); NP_EXPORT NP_ErrorCode NP_APIC np_getDataMode(int slotID, int portID, np_datamode_t* mode); NP_EXPORT NP_ErrorCode NP_APIC np_bs_getTemperature(int slotID, double* temperature_degC); NP_EXPORT NP_ErrorCode NP_APIC np_bs_getFirmwareInfo(int slotID, struct firmware_Info* info); @@ -1575,8 +1442,6 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode NP_APIC np_bsc_getTemperature(int slotID, double* temperature_degC); NP_EXPORT NP_ErrorCode NP_APIC np_bsc_getFirmwareInfo(int slotID, struct firmware_Info* info); NP_EXPORT NP_ErrorCode NP_APIC np_bsc_updateFirmware(int slotID, const char* filename, int(*callback)(size_t byteswritten)); - NP_EXPORT NP_ErrorCode NP_APIC np_setFileStream(int slotID, const char* filename); - NP_EXPORT NP_ErrorCode NP_APIC np_enableFileStream(int slotID, bool enable); NP_EXPORT NP_ErrorCode NP_APIC np_getBSCSupportedPortCount(int slotID, int* count); NP_EXPORT NP_ErrorCode NP_APIC np_getHSSupportedProbeCount(int slotID, int portID, int* count); NP_EXPORT NP_ErrorCode NP_APIC np_openPort(int slotID, int portID); @@ -1594,16 +1459,12 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode NP_APIC np_readBSCPN(int slotID, char* pn, size_t len); NP_EXPORT NP_ErrorCode NP_APIC np_readBSCSN(int slotID, uint64_t* sn); NP_EXPORT NP_ErrorCode NP_APIC np_getBSCVersion(int slotID, int* version_major, int* version_minor); - NP_EXPORT NP_ErrorCode NP_APIC np_setPortSyncPattern(int slotID, int portID, uint8_t* sync_pattern); - NP_EXPORT NP_ErrorCode NP_APIC np_getPortSyncPattern(int slotID, int portID, uint8_t* sync_pattern); NP_EXPORT NP_ErrorCode NP_APIC np_openProbe(int slotID, int portID, int dockID); NP_EXPORT NP_ErrorCode NP_APIC np_closeProbe(int slotID, int portID, int dockID); NP_EXPORT NP_ErrorCode NP_APIC np_init(int slotID, int portID, int dockID); NP_EXPORT NP_ErrorCode NP_APIC np_writeProbeConfiguration(int slotID, int portID, int dockID, bool readCheck); NP_EXPORT NP_ErrorCode NP_APIC np_setADCCalibration(int slotID, int portID, const char* filename); NP_EXPORT NP_ErrorCode NP_APIC np_setGainCalibration(int slotID, int portID, int dockID, const char* filename); - NP_EXPORT NP_ErrorCode NP_APIC np_setProbeSyncPattern(int slotID, int portID, int dockID, uint8_t* sync_pattern); - NP_EXPORT NP_ErrorCode NP_APIC np_getProbeSyncPattern(int slotID, int portID, int dockID, uint8_t* sync_pattern); NP_EXPORT NP_ErrorCode NP_APIC np_readElectrodeData(int slotID, int portID, int dockID, struct electrodePacket* packets, int* actualAmount, int requestedAmount); NP_EXPORT NP_ErrorCode NP_APIC np_getElectrodeDataFifoState(int slotID, int portID, int dockID, int* packetsavailable, int* headroom); NP_EXPORT NP_ErrorCode NP_APIC np_setTestSignal(int slotID, int portID, int dockID, bool enable); @@ -1670,53 +1531,25 @@ namespace Neuropixels { NP_EXPORT NP_ErrorCode NP_APIC np_HSTestNRST(int slotID, int portID); NP_EXPORT NP_ErrorCode NP_APIC np_HSTestREC_NRESET(int slotID, int portID); - NP_EXPORT NP_ErrorCode NP_APIC np_streamOpenFile(const char* filename, int portID, int dockID, streamsource_t source, np_streamhandle_t* pstream); - NP_EXPORT NP_ErrorCode NP_APIC np_streamClose(np_streamhandle_t sh); - NP_EXPORT NP_ErrorCode NP_APIC np_streamSeek(np_streamhandle_t sh, uint64_t filepos, uint32_t* actualtimestamp); - NP_EXPORT NP_ErrorCode NP_APIC np_streamSetPos(np_streamhandle_t sh, uint64_t filepos); - NP_EXPORT uint64_t NP_APIC np_streamTell(np_streamhandle_t sh); - NP_EXPORT NP_ErrorCode NP_APIC np_streamRead(np_streamhandle_t sh, uint32_t* timestamps, int16_t* data, int samplestoread, int* actualread); - NP_EXPORT NP_ErrorCode NP_APIC np_streamReadPacket(np_streamhandle_t sh, pckhdr_t* header, int16_t* data, int samplestoread, int* actualread); - //NeuropixAPI_configuration.h NP_EXPORT NP_ErrorCode NP_APIC np_getBasestationDriverID(int slotID, char* name, size_t len); NP_EXPORT NP_ErrorCode NP_APIC np_getHeadstageDriverID(int slotID, int portID, char* name, size_t len); NP_EXPORT NP_ErrorCode NP_APIC np_getFlexDriverID(int slotID, int portID, int dockID, char* name, size_t len); NP_EXPORT NP_ErrorCode NP_APIC np_getProbeDriverID(int slotID, int portID, int dockID, char* name, size_t len); - NP_EXPORT NP_ErrorCode NP_APIC np_getBSCHardwareID(int slotID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode NP_APIC np_setBSCHardwareID(int slotID, const struct HardwareID* pHwid); + NP_EXPORT NP_ErrorCode NP_APIC np_getBSCHardwareID(int slotID, struct HardwareID* pHwid);\ NP_EXPORT NP_ErrorCode NP_APIC np_getHeadstageHardwareID(int slotID, int portID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode NP_APIC np_setHeadstageHardwareID(int slotID, int portID, const struct HardwareID* pHwid); NP_EXPORT NP_ErrorCode NP_APIC np_getFlexHardwareID(int slotID, int portID, int dockID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode NP_APIC np_setFlexHardwareID(int slotID, int portID, int dockID, const struct HardwareID* pHwid); NP_EXPORT NP_ErrorCode NP_APIC np_getProbeHardwareID(int slotID, int portID, int dockID, struct HardwareID* pHwid); - NP_EXPORT NP_ErrorCode NP_APIC np_setProbeHardwareID(int slotID, int portID, int dockID, const struct HardwareID* pHwid); //NeuropixAPI_debug.h NP_EXPORT NP_ErrorCode NP_APIC np_createSystemEventCallback(npcallbackhandle_t* handle, np_systemeventcallbackfn_t callback, const void* userdata); - NP_EXPORT NP_ErrorCode NP_APIC np_writeBSCMM(int slotID, uint32_t address, uint32_t data); - NP_EXPORT NP_ErrorCode NP_APIC np_readBSCMM(int slotID, uint32_t address, uint32_t* data); - NP_EXPORT NP_ErrorCode NP_APIC np_writeI2C(int slotID, int portID, uint8_t device, uint8_t address, uint8_t data); - NP_EXPORT NP_ErrorCode NP_APIC np_readI2C(int slotID, int portID, uint8_t device, uint8_t address, uint8_t* data); - NP_EXPORT NP_ErrorCode NP_APIC np_writeI2Cflex(int slotID, int portID, int dockID, uint8_t device, uint8_t address, uint8_t data); - NP_EXPORT NP_ErrorCode NP_APIC np_readI2Cflex(int slotID, int portID, int dockID, uint8_t device, uint8_t address, uint8_t* data); NP_EXPORT void NP_APIC np_dbg_setlevel(int level); NP_EXPORT int NP_APIC np_dbg_getlevel(void); NP_EXPORT void NP_APIC np_dbg_setlogcallback(int minlevel, void(*callback)(int level, time_t ts, const char* module, const char* msg)); NP_EXPORT void NP_APIC np_dbg_getversion_datetime(char* dst, size_t maxlen); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_setSlotEmulatorMode(int slotID, slotemulatormode_t mode); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_getSlotEmulatorMode(int slotID, slotemulatormode_t* mode); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_setSlotEmulatorType(int slotID, slotemulatortype_t type); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_getSlotEmulatorType(int slotID, slotemulatortype_t* type); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_setSlotEmulatorSyncPattern(int slotID, uint8_t* sync_pattern); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_getSlotEmulatorSyncPattern(int slotID, uint8_t* sync_pattern); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_setPortEmulatorMode(int slotID, int portID, portemulatormode_t emulationmode); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_getPortEmulatorMode(int slotID, int portID, portemulatormode_t* emulationmode); NP_EXPORT NP_ErrorCode NP_APIC np_dbg_stats_reset(int slotID); NP_EXPORT NP_ErrorCode NP_APIC np_dbg_diagstats_read(int slotID, struct np_diagstats* stats); NP_EXPORT NP_ErrorCode NP_APIC np_dbg_sourcestats_read(int slotID, uint8_t sourceID, struct np_sourcestats* stats); - NP_EXPORT NP_ErrorCode NP_APIC np_dbg_read_srchain(int slotID, int portID, int dockID, uint8_t SRChain_registeraddress, uint8_t* dst, size_t len, size_t* actualread); - NP_EXPORT NP_ErrorCode NP_APIC np_setVirtualHeadstage(int slotID, int portID); // Opto specific NP_EXPORT NP_ErrorCode NP_APIC np_setOpticalCalibration(int slotID, int portID, int dockID, const char* filename); diff --git a/Source/API/lib64/NeuropixAPI_x64_3_70_2.lib b/Source/API/lib64/NeuropixAPI_x64_3_70_2.lib new file mode 100644 index 0000000..141354a Binary files /dev/null and b/Source/API/lib64/NeuropixAPI_x64_3_70_2.lib differ diff --git a/Source/API/v1/NeuropixAPI.h b/Source/API/v1/NeuropixAPI.h deleted file mode 100644 index 6bba0a0..0000000 --- a/Source/API/v1/NeuropixAPI.h +++ /dev/null @@ -1,1053 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -#define NP_EXPORT __declspec(dllexport) -#define NP_APIC __stdcall - -#define PROBE_ELECTRODE_COUNT 960 -#define PROBE_CHANNEL_COUNT 384 -#define PROBE_SUPERFRAMESIZE 12 - - -#define ELECTRODEPACKET_STATUS_TRIGGER (1<<0) -#define ELECTRODEPACKET_STATUS_SYNC (1<<6) - -#define ELECTRODEPACKET_STATUS_LFP (1<<1) -#define ELECTRODEPACKET_STATUS_ERR_COUNT (1<<2) -#define ELECTRODEPACKET_STATUS_ERR_SERDES (1<<3) -#define ELECTRODEPACKET_STATUS_ERR_LOCK (1<<4) -#define ELECTRODEPACKET_STATUS_ERR_POP (1<<5) -#define ELECTRODEPACKET_STATUS_ERR_SYNC (1<<7) - -/* - Debug std_err output levels - These values can be set using dbg_setlevel() -*/ -/* output errors only */ -#define DBG_ERROR 4 -/* output warnings */ -#define DBG_WARNING 3 -/* output messages (such as BIST information) */ -#define DBG_MESSAGE 2 -/* output more detailed background information */ -#define DBG_VERBOSE 1 -/* output register transactions */ -#define DBG_PARANOID 0 - -namespace np { - -struct electrodePacket { - uint32_t timestamp[PROBE_SUPERFRAMESIZE]; - int16_t apData[PROBE_SUPERFRAMESIZE][PROBE_CHANNEL_COUNT]; - int16_t lfpData[PROBE_CHANNEL_COUNT]; - uint16_t Status[PROBE_SUPERFRAMESIZE]; - //uint16_t SYNC[PROBE_SUPERFRAMESIZE]; -}; - -struct ADC_Calib { - int ADCnr; - int CompP; - int CompN; - int Slope; - int Coarse; - int Fine; - int Cfix; - int offset; - int threshold; -}; - -/** -* Neuropix API error codes -*/ -typedef enum { - - SUCCESS = 0,/**< The function returned sucessfully */ - FAILED = 1, /**< Unspecified failure */ - ALREADY_OPEN = 2,/**< A board was already open */ - NOT_OPEN = 3,/**< The function cannot execute, because the board or port is not open */ - IIC_ERROR = 4,/**< An error occurred while accessing devices on the BS i2c bus */ - VERSION_MISMATCH = 5,/**< FPGA firmware version mismatch */ - PARAMETER_INVALID = 6,/**< A parameter had an illegal value or out of range */ - UART_ACK_ERROR = 7,/**< uart communication on the serdes link failed to receive an acknowledgement */ - TIMEOUT = 8,/**< the function did not complete within a restricted period of time */ - WRONG_CHANNEL = 9,/**< illegal channel number */ - WRONG_BANK = 10,/**< illegal electrode bank number */ - WRONG_REF = 11,/**< a reference number outside the valid range was specified */ - WRONG_INTREF = 12,/**< an internal reference number outside the valid range was specified */ - CSV_READ_ERROR = 13,/**< an parsing error occurred while reading a malformed CSV file. */ - BIST_ERROR = 14,/**< a BIST operation has failed */ - FILE_OPEN_ERROR = 15,/**< The file could not be opened */ - READBACK_ERROR = 16,/**< a BIST readback verification failed */ - READBACK_ERROR_FLEX = 17,/**< a BIST Flex EEPROM readback verification failed */ - READBACK_ERROR_HS = 18,/**< a BIST HS EEPROM readback verification failed */ - READBACK_ERROR_BSC = 19,/**< a BIST HS EEPROM readback verification failed */ - TIMESTAMPNOTFOUND = 20,/**< the specified timestamp could not be found in the stream */ - FILE_IO_ERR = 21,/**< a file IO operation failed */ - OUTOFMEMORY = 22,/**< the operation could not complete due to insufficient process memory */ - LINK_IO_ERROR = 23,/**< serdes link IO error */ - NO_LOCK = 24,/**< missing serializer clock. Probably bad cable or connection */ - WRONG_AP = 25,/**< AP gain number out of range */ - WRONG_LFP = 26,/**< LFP gain number out of range */ - ERROR_SR_CHAIN_1 = 27,/**< Validation of SRChain1 data upload failed */ - ERROR_SR_CHAIN_2 = 28,/**< Validation of SRChain2 data upload failed */ - ERROR_SR_CHAIN_3 = 29,/**< Validation of SRChain3 data upload failed */ - PCIE_IO_ERROR = 30,/**< a PCIe data stream IO error occurred. */ - NO_SLOT = 31,/**< no Neuropix board found at the specified slot number */ - WRONG_SLOT = 32,/**< the specified slot is out of bound */ - WRONG_PORT = 33,/**< the specified port is out of bound */ - STREAM_EOF = 34, - HDRERR_MAGIC = 35, - HDRERR_CRC = 36, - WRONG_PROBESN = 37, - WRONG_TRIGGERLINE = 38, - PROGRAMMINGABORTED = 39, /**< the flash programming was aborted */ - VALUE_INVALID = 40, /**< The parameter value is invalid */ - NOTSUPPORTED = 0xFE,/**< the function is not supported */ - NOTIMPLEMENTED = 0xFF/**< the function is not implemented */ -}NP_ErrorCode; - -/** -* Operating mode of the probe -*/ -typedef enum { - RECORDING = 0, /**< Recording mode: (default) pixels connected to channels */ - CALIBRATION = 1, /**< Calibration mode: test signal input connected to pixel, channel or ADC input */ - DIGITAL_TEST = 2, /**< Digital test mode: data transmitted over the PSB bus is a fixed data pattern */ -}probe_opmode_t; - -/** -* Test input mode -*/ -typedef enum { - PIXEL_MODE = 0, /**< HS test signal is connected to the pixel inputs */ - CHANNEL_MODE = 1, /**< HS test signal is connected to channel inputs */ - NO_TEST_MODE = 2, /**< no test mode */ - ADC_MODE = 3, /**< HS test signal is connected to the ADC inputs */ -}testinputmode_t; - -typedef enum { - EXT_REF = 0, /**< External electrode */ - TIP_REF = 1, /**< Tip electrode */ - INT_REF = 2 /**< Internal electrode */ -}channelreference_t; - -typedef enum { - EMUL_OFF = 0, /**< No emulation data is generated */ - EMUL_STATIC = 1, /**< static data per channel: value = channel number */ - EMUL_LINEAR = 2, /**< a linear ramp is generated per channel (1 sample shift between channels) */ -}emulatormode_t; - -typedef enum { - SIGNALLINE_NONE = 0, - SIGNALLINE_PXI0 = (1 << 0), - SIGNALLINE_PXI1 = (1 << 1), - SIGNALLINE_PXI2 = (1 << 2), - SIGNALLINE_PXI3 = (1 << 3), - SIGNALLINE_PXI4 = (1 << 4), - SIGNALLINE_PXI5 = (1 << 5), - SIGNALLINE_PXI6 = (1 << 6), - SIGNALLINE_SHAREDSYNC = (1 << 7), - SIGNALLINE_LOCALTRIGGER = (1 << 8), - SIGNALLINE_LOCALSYNC = (1 << 9), - SIGNALLINE_SMA = (1 << 10), - SIGNALLINE_SW = (1 << 11), - SIGNALLINE_LOCALSYNCCLOCK = (1 << 12) - -}signalline_t; - -typedef enum { - TRIGOUT_NONE = 0, - TRIGOUT_SMA = 1, /**< PXI SMA trigger output */ - TRIGOUT_PXI0 = 2, /**< PXI signal line 0 */ - TRIGOUT_PXI1 = 3, /**< PXI signal line 1 */ - TRIGOUT_PXI2 = 4, /**< PXI signal line 2 */ - TRIGOUT_PXI3 = 5, /**< PXI signal line 3 */ - TRIGOUT_PXI4 = 6, /**< PXI signal line 4 */ - TRIGOUT_PXI5 = 7, /**< PXI signal line 5 */ - TRIGOUT_PXI6 = 8, /**< PXI signal line 6 */ -}triggerOutputline_t; - -typedef enum { - TRIGIN_SW = 0, /**< Software trigger selected as input */ - TRIGIN_SMA = 1, /**< PXI SMA line selected as input */ - - TRIGIN_PXI0 = 2, /**< PXI signal line 0 selected as input */ - TRIGIN_PXI1 = 3, /**< PXI signal line 1 selected as input */ - TRIGIN_PXI2 = 4, /**< PXI signal line 2 selected as input */ - TRIGIN_PXI3 = 5, /**< PXI signal line 3 selected as input */ - TRIGIN_PXI4 = 6, /**< PXI signal line 4 selected as input */ - TRIGIN_PXI5 = 7, /**< PXI signal line 5 selected as input */ - TRIGIN_PXI6 = 8, /**< PXI signal line 6 selected as input */ - TRIGIN_SHAREDSYNC = 9, /**< shared sync line selected as input */ - - TRIGIN_SYNCCLOCK = 10, /**< Internal SYNC clock */ - - TRIGIN_USER1 = 11, /**< User trigger 1 (FUTURE) */ - TRIGIN_USER2 = 12, /**< User trigger 2 (FUTURE) */ - TRIGIN_USER3 = 13, /**< User trigger 3 (FUTURE) */ - TRIGIN_USER4 = 14, /**< User trigger 4 (FUTURE) */ - TRIGIN_USER5 = 15, /**< User trigger 5 (FUTURE) */ - TRIGIN_USER6 = 16, /**< User trigger 6 (FUTURE) */ - TRIGIN_USER7 = 17, /**< User trigger 7 (FUTURE) */ - TRIGIN_USER8 = 18, /**< User trigger 8 (FUTURE) */ - TRIGIN_USER9 = 19, /**< User trigger 9 (FUTURE) */ - - TRIGIN_NONE = -1 /**< No trigger input selected */ -}triggerInputline_t; - - -typedef void* np_streamhandle_t; - -struct np_sourcestats { - uint32_t timestamp; - uint32_t packetcount; - uint32_t samplecount; - uint32_t fifooverflow; -}; - -struct np_diagstats { - uint64_t totalbytes; /**< total amount of bytes received */ - uint32_t packetcount; /**< Amount of packets received */ - uint32_t triggers; /**< Amount of triggers received */ - uint32_t err_badmagic; /**< amount of packet header bad MAGIC markers */ - uint32_t err_badcrc; /**< amount of packet header CRC errors */ - uint32_t err_droppedframes; /**< amount of dropped frames in the stream */ - uint32_t err_count; /**< Every psb frame has an incrementing count index. If the received frame count value is not as expected possible data loss has occured and this flag is raised. */ - uint32_t err_serdes; /**< incremented if a deserializer error (hardware pin) occured during receiption of this frame this flag is raised */ - uint32_t err_lock; /**< incremented if a deserializer loss of lock (hardware pin) occured during receiption of this frame this flag is raised */ - uint32_t err_pop; /**< incremented whenever the ‘next blocknummer’ round-robin FiFo is flagged empty during request of the next value (for debug purpose only, irrelevant for end-user software) */ - uint32_t err_sync; /**< Front-end receivers are out of sync. => frame is invalid. */ -}; - -typedef struct { - uint32_t MAGIC; // includes 'Type' field as lower 4 bits - - uint16_t samplecount; - uint8_t seqnr; - uint8_t format; - - uint32_t timestamp; - - uint8_t status; - uint8_t sourceid; - uint16_t crc; - -}pckhdr_t; - - -/********************* Parameter configuration functions ****************************/ -#define MINSTREAMBUFFERSIZE (1024*32) -#define MAXSTREAMBUFFERSIZE (1024*1024*32) -#define MINSTREAMBUFFERCOUNT (2) -#define MAXSTREAMBUFFERCOUNT (1024) -typedef enum { - NP_PARAM_BUFFERSIZE = 1, - NP_PARAM_BUFFERCOUNT = 2, - NP_PARAM_SYNCMASTER = 3, - NP_PARAM_SYNCFREQUENCY_HZ = 4, - NP_PARAM_SYNCPERIOD_MS = 5, - NP_PARAM_SYNCSOURCE = 6, - NP_PARAM_SIGNALINVERT = 7, -}np_parameter_t; - -NP_EXPORT NP_ErrorCode NP_APIC setParameter(np_parameter_t paramid, int value); -NP_EXPORT NP_ErrorCode NP_APIC getParameter(np_parameter_t paramid, int* value); -NP_EXPORT NP_ErrorCode NP_APIC setParameter_double(np_parameter_t paramid, double value); -NP_EXPORT NP_ErrorCode NP_APIC getParameter_double(np_parameter_t paramid, double* value); - -/********************* Opening and initialization functions ****************************/ - -/** -* @brief returns get a mask of available PXI slots. -* @return SUCCESS if the scan completed successfully. -*/ -NP_EXPORT NP_ErrorCode NP_APIC scanPXI(uint32_t* availableslotmask); - -/** -* @brief The ‘openBS’ function initializes the BS FPGA and BSC FPGA and opens the communication channel -* -* - BS FPGA reset -* - Check hardware and software versions : BSC FPGA, BS FPGA, API -* -* @param slotID : which slot in the PXI chassis (valid range depends on the chassis) -* -* @return SUCCESS if successful, NO_SLOT if no Neuropix BS card is plugged in the selected PXI chassis slot, WRONG_SLOT if the slot number is out of range for the chassis, VERSION_MISMATCH if API and BS FPGA version are not compatible, IIC_ERROR in case of error on the I2C bus on the BS card, ALREADY_OPEN if function called twice. -*/ -NP_EXPORT NP_ErrorCode NP_APIC openBS(unsigned char slotID); - -/** -* @brief The ‘closeBS’ function closes the BS connection -* Close access and teardown communication with BS -* -* @param slotID : which slot in the PXI chassis (valid range depends on the chassis) -* -* @return SUCCESS if successful, NOT_OPEN if no Neuropix BS card was open on this slot. WRONG_SLOT if the slot number is out of range for the chassis. -*/ -NP_EXPORT NP_ErrorCode NP_APIC closeBS(unsigned char slotID); - -/** -* @brief The ‘openProbe’ function enables the power supply to the cable to the HS. The function initializes the serdes link and HS, but not the probe itself. The argument selects which of the 4 headstage ports on the BSC to enable. -* Calling the ‘openProbe’ function with a certain port number does not close any previously opened ports. The ‘openProbe’ function initializes the serdes and HS: -* - Enable the power supply on the cable to the HS, via the EN_HSx signal from the BSC FPGA (ref. [BSC]). -* - Configure the deserializer registers as described in [BSC]. -* - Configure the serializer registers as described in [HS]. -* - Set the DIG_NRESET bit in the REC_MOD register of the probe memory map to 0. Wait 1ms. Set the DIG_NRESET bit in the REC_MOD register to 1. -* - Set the REC bit in the OP_MODE register of the probe memory map to 1 (required to enable the PSB_SYNC signal). -* - Set the REC_NRST_IN signal of the BSC FPGA high via the AXI chip2chip interface [BSC]. This signal is transmitted via the GPI/GPO channel of the serdes to the probe, and will enable the PSB bus. The PSB_SYNC line is visualized as a heartbeat signal on the BSC. -* - Set the GPIO1 signal from the serializer high [HS]. This makes the heartbeat signal visible on the HS. -* - Set BS FPGA for this port in electrode mode. -* - Enable data zeroing on BS FPGA, enable Lock checking. -* The ‘openProbe’ function should execute fast (<500ms), such that the user can use the ‘openProbe’ function to quickly query if a port has hardware connected. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: which HS/probe (valid range 1 to 4) -* @return SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe, ALREADY_OPEN if function called twice.). -*/ -NP_EXPORT NP_ErrorCode NP_APIC openProbe(unsigned char slotID, signed char port); - -/* - Similar as openProbe, but opens the port/probe only for Headstage Tester operation -*/ -NP_EXPORT NP_ErrorCode NP_APIC openProbeHSTest(unsigned char slotID, signed char port); - - -/** -* @brief Initialize -* The function resets the connected probe to the default settings: load the default settings for configuration registers and memory map; and subsequently initialize the probe in recording mode -* Set the memory map to the default values (ref. 3.1.3). -* - Set the test configuration register map to the default values (ref. 3.1.3). -* - Set the GPIO1 signal from the serializer low ((serializer register 0x0E and 0x0F, ref. [HS]). This makes the heartbeat signal no longer visible on the HS. -* - Set the shank configuration register map to the default values indicated in [Shank configuration]. -* - Set the base configuration register map to the default values indicated in [Base configuration], excluding the ADC comparator values (ADCxxSlope, ADCxxFine, ADCxxCoarse, ADCxxCfix, ADCxxCompP, ADCxxCompN). -* - Set the REC bit in the OP_MODE register in the memory map to high (ref. 3.1.3). All other bits in the OP_MODE register are set low. -* - Set the PSB_F bit in the REC_MOD register in the memory map to high (ref. 3.1.3). -* -* @param slotID which slot in the PXI chassis (valid range depends on the chassis) -* @param port which HS/probe (valid range 1 to 4) -* @return SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC init(unsigned char slotID, signed char port); - -/* -* @brief Load calibration data -* The probe calibration is programmed via the probes’ base configuration register. The probe calibration data is stored in a .csv file. -* The following function reads the .csv file containing the calibration data, updates the base configuration register variable in the API and subsequently writes the base configuration register to the probe. The function also checks if the selected calibration file is for the connected probe, by checking the S/N of the connected probe with the S/N in the calibration csv file. -* This function sets the ADC calibration values (compP and compN, Slope, Coarse, Fine and Cfix): -* The first row of the ADC calibration csv file contains the probes’ serial number. Below the first row are 7 columns of data: -* - First column: ADC number (1-32) -* - Second column: CompP calibration factor in hex format -* - Third column: CompN calibration factor in hex format -* - Fourth column: Cfix calibration factor in hex format -* - Fifth column: Slope calibration factor in hex format -* - Sixth column: Coarse calibration factor in hex format -* - Seventh column: Fine calibration factor in hex format -* The name of the file is: [ASIC’s serial number]_ADC_Calibration.csv -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param filename: the filename to read from (.csv) -* @returns: SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). WRONG_PROBESN is the Probe serial number does not match -*/ -NP_EXPORT NP_ErrorCode NP_APIC setADCCalibration(unsigned char slotID, signed char port, const char* filename); - -/* @brief Set the gain correction data -* The probe gain correction data is stored in a csv file. There is a gain correction factor for each electrode, both for AP and LFP, and for each gain setting. The gain correction parameter is loaded to the basestation FPGA, where it is applied in the scale module (ref. chapter 4.2). -* The following function reads the gain correction parameters from the specified .csv file and writes these to the BS FPGA. The function also checks if the selected gain correction file is for the connected probe, by checking the S/N of the connected probe with the S/N in the gain correction csv file. -* The first row of the gain correction csv file contains the probes’ serial number. Below the first row are 3 columns of data: -* - first column: electrode number (1 – 960), -* - 2nd to 9th column: AP gain correction factors for AP gain x50 to 3000 (ref. chapter 5.7.6: ‘ap_gain’ parameter values 0 to 7). -* - 10th to 17th column: LFP gain correction factors for LFP gains x50 to 3000 (ref. chapter 5.7.6: ‘lfp_gain’ parameter values 0 to 7). -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns: SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC setGainCalibration(unsigned char slotID, signed char port, const char* filename); - -/* @brief Close -* The ‘close’ function shuts down the power supply to the cable on the selected port, via the EN_HSx signal from the BSC FPGA (ref. [BSC]). In case the ‘port’ argument is set to -1, all ports on the BSC are shut down PXIe link is released. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range -1 to 3) -* @returns SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC close(unsigned char slotID, signed char port); - -/* @brief Log file -* The system can log commands an status information to a text file (api_log.txt). This functionality is default disabled, after calling the ‘open’ function. -* The log is saved in separate text files per serdes port and per PXI slot. The log file name contains the serdes port number and PXI slot number. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param enable: enable (true) or disable (false) the logging -* @returns SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setLog(unsigned char slotID, signed char port, bool enable); - - -/********************* Interface to Base station FPGA memory map ****************************/ -/* @brief Write to base station memory map -* This function allows the user to write 1 data byte to a specified address on the BSC FPGA memory map -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param register: the register address to write to -* @param data: the data word to write -* @returns SUCCESS correct acknowledgment byte returned by the slave, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC writeBSCMM(unsigned char slotID, uint32_t address, uint32_t data); - -/* @brief Read from base station memory map -* this functions reads 1 data byte from a specified address on the BSC FPGA memory map -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param register: the register address to read from -* @param data: the data word read -* @returns SUCCESS correct acknowledgment byte returned by the slave, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC readBSCMM(unsigned char slotID, uint32_t address, uint32_t* data); - -/********************* UART/I2C interface to serdes ports ****************************/ - -/* @brief Write to I2C bus -* this function allows the user to write N data bytes to a specified address on a slave device. -* Writing more than 1 byte to the probes’ memory map is only applicable for register addresses related to the shift registers. For all other register addresses only 1 byte should be written. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param device: the device address (slave) to write to -* @param register: the register address to write to -* @param data: the date to write -* @param size: amoutn of bytes to write -* @returns SUCCESS correct acknowledgment byte returned by the slave, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC writeI2C(unsigned char slotID, signed char port, unsigned char device, unsigned char address, unsigned char data); - -/* @brief Read from I2C bus -* This functions reads N data bytes from a specified address on a slave device -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param device: the device address (slave) to read from -* @param register: the register address to read from -* @param data: vector containing the data read over the I2C bus -* @param size: the number of bytes to read -* @returns SUCCESS correct acknowledgment byte returned by the slave, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC readI2C(unsigned char slotID, signed char port, unsigned char device, unsigned char address, unsigned char* data); - -/********************* Hardware/software versions ****************************/ - -/* @brief Read the Head Stage version from EEPROM memory -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param version_major: the HS board version number -* @param version_build: the HS board build number (NULL allowed) -* @returns SUCCESS correct acknowledgment byte returned by the slave, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC getHSVersion(unsigned char slotID, signed char port, unsigned char* version_major, unsigned char* version_minor); - - -/* -* @brief Get the API software version -* -* @param version_major: the API version number -* @param version_minor: the API revision number -*/ -NP_EXPORT void NP_APIC getAPIVersion(unsigned char* version_major, unsigned char* version_minor); - -/** -* @brief Get the BSC FPGA boot code version -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param version_major: the BSC FPGA boot code version number -* @param version_minor: the BSC FPGA boot code revision number -* @param version_build: the BSC FPGA boot code build number -* @returns SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, -*/ -NP_EXPORT NP_ErrorCode NP_APIC getBSCBootVersion(unsigned char slotID, unsigned char* version_major, unsigned char* version_minor, uint16_t* version_build); - -/** -* @brief Get the BS FPGA boot code version -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param version_major: the BS FPGA boot code version number -* @param version_minor: the BS FPGA boot code revision number -* @param version_build: the BS FPGA boot code build number (NULL allowed) -* @returns SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, -*/ -NP_EXPORT NP_ErrorCode NP_APIC getBSBootVersion(unsigned char slotID, unsigned char* version_major, unsigned char* version_minor, uint16_t* version_build); - -/** -* \brief Read the BSC hardware version from the EEPROM memory -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param version_major: the BSC FPGA boot code version number -* @param version_minor: the BSC FPGA boot code revision number -* @param version_build: the BSC FPGA boot code build number (NULL allowed) -* @returns NO_LINK if no datalink, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered -*/ -NP_EXPORT NP_ErrorCode NP_APIC getBSCVersion(unsigned char slotID, unsigned char* version_major, unsigned char* version_minor); - - - -/* -* \brief Read the last error message -* -* @param bufStart: destination buffer -* @param bufsize: size of the destination buffer -* @returns amount of characters written to the destination buffer -*/ -NP_EXPORT size_t NP_APIC getLastErrorMessage(char* bufStart, size_t bufsize); -/********************* Serial Numbers ****************************/ - -/** -* @brief Read the probe ID -* The probe ID is stored on the EEPROM memory on the flex. The probe ID is a 16 digit number. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param id: the probe ID code to return -* @returns NO_LINK if no datalink, TIMEOUT if no I2C acknowledgement is received, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC readId(unsigned char slotID, signed char port, uint64_t* id); - - - -NP_EXPORT NP_ErrorCode NP_APIC readProbePN(unsigned char slotID, signed char port, char* pn,size_t len); -NP_EXPORT NP_ErrorCode NP_APIC getFlexVersion(unsigned char slotID, signed char port, unsigned char* version_major, unsigned char* version_minor); -NP_EXPORT NP_ErrorCode NP_APIC readFlexPN(unsigned char slotID, signed char port, char* pn, size_t len); - - -/** -* @brief Get the headstage serial number -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param id: the probe ID code to return -* @returns NO_LINK if no datalink, TIMEOUT if no I2C acknowledgement is received, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC readHSSN(unsigned char slotID, signed char port, uint64_t* sn); - - - - -NP_EXPORT NP_ErrorCode NP_APIC readHSPN(unsigned char slotID, signed char port, char* pn,size_t maxlen); - - -/** -* @brief Read the BSC serial number from EEPROM -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param sn: the BSC S/N to return -* @returns NO_LINK if no datalink, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC readBSCSN(unsigned char slotID, uint64_t* sn); - -/** -* @brief Write the BSC serial number to EEPROM -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param sn: the BSC S/N to return -* @returns NO_LINK if no datalink, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC writeBSCSN(unsigned char slotID, uint64_t sn); - -NP_EXPORT NP_ErrorCode NP_APIC readBSCPN(unsigned char slotID, char* pn, size_t len); -NP_EXPORT NP_ErrorCode NP_APIC writeBSCPN(unsigned char slotID, const char* pn); - -/********************* System Configuration ****************************/ - -/** -* @brief Enable or disable the head stage heartbeat LED -* The HS LED heartbeat blinking is enabled/disabled by the GPIO1 signal which is controlled through serializer registers. -* The default blinking status of the HS LED after calling the ‘open’ function is enabled. The default status after calling the ‘init’ function is disabled. -* The function sets the GPIO1 signal from the serializer (serializer register 0x0E and 0x0F, ref. [HS]). This makes the heartbeat signal visible on the HS. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param enable: enable (true) or disable (false) HS heartbeat LED -* @returns SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). -*/ -NP_EXPORT NP_ErrorCode NP_APIC setHSLed(unsigned char slotID, signed char port, bool enable); - -/** -* @brief Set the ADC operating mode -* The function sets the system in ADC mode or electrode mode. This mode defines how data is demuxed on the BS FPGA and transmitted in packets to the PC. The default status after calling the ‘open’ function is electrode mode. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param mode: electrode (true) or ADC (false) mode -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setDataMode(unsigned char slotID, bool mode); -NP_EXPORT NP_ErrorCode NP_APIC getDataMode(unsigned char slotID, bool* mode); - -/** -* @brief Read the temperator of the BS FPGA -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param temperature: the BS temperature, in degrees Celsius. -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC getTemperature(unsigned char slotID, float* temperature); - -/** -* @brief Enable or disable the HS test signal -* The HS contains a test signal generator which can be used for probe integrity checks. The output of the test signal generator is connected to the CAL_SIGNAL input of the probe. -* The test signal on the HS is enabled by a gate signal coming from the probe which is controlled via a register in the probes’ memory map. The test signal is default off after calling the ‘init’ function. -* The function sets the OSC_STDB bit in the CAL_MOD register of the probe memory map. Asserting the bit enables the test signal. -* -@param slotID: which slot in the PXI chassis (valid range depends on the chassis) -@param port: for which HS (valid range 1 to 4) -@param enable: enable (true) or disable (false) the test signal. -@returns SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setTestSignal(unsigned char slotID, signed char port, bool enable); - -/********************* Probe Configuration ****************************/ - -/** -* @brief set the probe operating mode -* The function supports the following modes: -* - Recording: the default operation mode. The pixels are connected to the channels. The recorded signal is digitized and output on the PSB bus. Set the REC bit in the OP_MODE register high. All the other bits in the OP_MODE register are set low. -* - Calibration: the test signal input (CAL_SIGNAL) is connected to either the pixel, channel or ADC input (selected via the CAL_MOD register). The recorded signal is digitized and output on the PSB bus. Set the CAL and REC bit in the OP_MODE register high. All the other bits in the OP_MODE register are set low. -* - Digital test: the data transmitted over the PSB bus is a fixed data pattern. Set the DIG_TEST and REC bit in the OPMODE register to activate this mode. All the other bits in the OP_MODE register are set low. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param mode: the selected probe operation mode. -* @returns SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received , NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setOPMODE(unsigned char slotID, signed char port, probe_opmode_t mode); - -/** -* @brief set the test signal input mode -* The CAL_SIGNAL input of the probe, which is connected to the HS test signal via the HS and flex, can be connected to either the probes’ pixel inputs, channel inputs, or ADC inputs. The following function configures the CAL_MOD register of the probes’ memory map. -* The function supports the following modes: -* - Pixel: the HS test signal is connected to the pixel inputs. Set the PIX_CAL bit in the CAL_MOD register to activate this mode. All other bits in the CAL_MOD register are set low. -* - Channel: the HS test signal is connected to the channel inputs. Set the CH_CAL bit in the CAL_MOD register to activate this mode. All other bits in the CAL_MOD register are set low. -* - None: All bits in the CAL_MOD register are set low. -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param mode: the selected test signal mode -* @returns SUCCESS if successful, TIMEOUT if no I2C acknowledgement is received , NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setCALMODE(unsigned char slotID, signed char port, testinputmode_t mode); - -/** -* @brief Recording reset -* The following function sets/resets the REC_NRESET signal to the probe. The REC_NRESET is controlled via the serdes link by the REC_NRST output pin of the BSC FPGA (ref [BSC]). -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param value: logic high (true) or logic low (false) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setREC_NRESET(unsigned char slotID, signed char port, bool value); - -/** -* @brief Set which electrode is connected to a channel. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param channel: the channel number (valid range: 0 to 383, excluding 191) -* @param electrode_bank: the electrode bank number to connect to (valid range: 0 to 2 or 0xFF to disconnect) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, WRONG_CHANNEL in case a channel number outside the range is entered, WRONG_BANK in case an electrode bank number outside the range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC selectElectrode(unsigned char slotID, signed char port, uint32_t channel, uint8_t electrode_bank); - -/** -* @brief Set the channel reference of the given channel. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param channel: the channel number (valid range: 0 to 383) -* @param reference: the sleected reference input (valid range: 0 to 2) -* @param intRefElectrodeBank: the selected internal reference electrode (valid range: 0 to 2) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, WRONG_CHANNEL in case a channel number outside the valid range is entered, WRONG_REF in case a reference number outside the valid range is entered, WRONG_INTREF in case a internal reference electrode number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setReference(unsigned char slotID, signed char port, unsigned int channel, channelreference_t reference, uint8_t intRefElectrodeBank); - -/** -* @brief Set the AP and LFP gain of the given channel. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param channel: the channel number (valid range: 0 to 383) -* @param ap_gain: the AP gain value (valid range: 0 to 7) -* @param lfp_gain: the LFP gain value (valid range: 0 to 7) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, WRONG_CHANNEL in case a channel number outside the valid range is entered, WRONG_AP in case an AP gain number outside the valid range is entered, WRONG_LFP in case an LFP gain number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setGain(unsigned char slotID, signed char port, unsigned int channel, unsigned char ap_gain, unsigned char lfp_gain); - -/** -* @brief Get the AP and LFP gain of the given channel. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param channel: the channel number (valid range: 0 to 383) -* @param ap_gain: the AP gain value (valid range: 0 to 7) -* @param lfp_gain: the LFP gain value (valid range: 0 to 7) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, WRONG_CHANNEL in case a channel number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC getGain(uint8_t slotID, int8_t port, int channel, int* APgainselect, int* LFPgainselect); - -/** -* @brief Set the high-pass corner frequency for the given AP channel. -* The function checks whether the input parameters ‘slotID’ and ‘port’ are valid and updates the base configuration register variable in the API. The function does not transmit the base configuration shift register to the memory map of the probe. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param channel: the channel number (valid range: 0 to 383) -* @param disableHighPass: the highpass cut-off frequency of the AP channels -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, WRONG_CHANNEL in case a channel number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setAPCornerFrequency(unsigned char slotID, signed char port, unsigned int channel, bool disableHighPass); - -/** -* @brief Set the given channel in stand-by mode. -* The function checks whether the input parameters ‘slotID’ and ‘port’ are valid and updates the base configuration register variable in the API. The function does not transmit the base configuration shift register to the memory map of the probe. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param channel: the channel number (valid range: 0 to 383) -* @param standby: the standby value to write -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, WRONG_CHANNEL in case a channel number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setStdb(unsigned char slotID, signed char port, unsigned int channel, bool standby); - -/** -* @brief Write probe configuration settings to the probe. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param readCheck : if enabled, read the configuration shift registers back to check -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, WRONG_CHANNEL in case a channel number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC writeProbeConfiguration(unsigned char slotID, signed char port, bool readCheck); - -/********************* Trigger Configuration ****************************/ -/** -* \brief Re-arm the data capture trigger -* In anticipation of receiving a start trigger, the system is set in ‘arm’ mode. In ‘arm’ mode, neural data packets from the probe are not buffered in the FIFO on the basestation, and the time stamp is fixed at 0. Upon receiving the start trigger, the system starts to buffer the incoming neural data in the basestation FIFO buffer and start the timestamp generator. -* After the system has received a start trigger and is buffering incoming neural data, calling the API ‘arm’ function again stops the buffering of neural data packets, clears the basestation FIFO, stops the time stamp generator and resets the timestamp to 0. -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC arm(unsigned char slotID); - - -NP_EXPORT NP_ErrorCode NP_APIC setTriggerBinding(uint8_t slotID, signalline_t outputline, signalline_t inputlines); -NP_EXPORT NP_ErrorCode NP_APIC getTriggerBinding(uint8_t slotID, signalline_t outputline, signalline_t* inputlines); -/** -* \brief Select the source of the trigger -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param source: the trigger source as a selection mask -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_TRIGGER in case a source number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setTriggerInput(uint8_t slotID, triggerInputline_t inputline); -NP_EXPORT NP_ErrorCode NP_APIC getTriggerInput(uint8_t slotID, triggerInputline_t* input); - -NP_EXPORT NP_ErrorCode NP_APIC setTriggerOutput(uint8_t slotID, triggerOutputline_t line, triggerInputline_t inputline); -NP_EXPORT NP_ErrorCode NP_APIC getTriggerOutput(uint8_t slotID, triggerOutputline_t* output, triggerInputline_t* source); -//NP_EXPORT NP_ErrorCode NP_APIC getTriggerOutput(uint8_t slotID, triggerOutputline_t line, triggerInputline_t* inputline); - -NP_EXPORT NP_ErrorCode NP_APIC setTriggerEdge(unsigned char slotID, bool rising); -/** -* \brief Generate a software trigger -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC setSWTrigger(unsigned char slotID); - - -/********************* Built In Self Test ****************************/ - -/** -* @brief Basestation platform BIST -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistBS(unsigned char slotID); - -/** -* @brief Head Stage heartbeat test -* The heartbeat signal generated by the PSB_SYNC signal of the probe. The PSB_SYNC signal starts when the probe is powered on, the OP_MODE register in the probes’ memory map set to 1, and the REC_NRESET signal set high. -* The heartbeat signal is visible on the headstage (can be disabled by API functions) and on the BSC. This is in the first place a visual check. -* In order to facilitate a software check of the BSC heartbeat signal, the PSB_SYNC signal is also routed to the BS FPGA. A function is provided to check whether the PSB_SYNC signal contains a 0.5Hz clock. -* The presence of a heartbeat signal acknowledges the functionality of the power supplies on the headstage for serializer and probe, the POR signal, the presence of the master clock signal on the probe, the functionality of the clock divider on the probe, an basic communication over the serdes link. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistHB(unsigned char slotID, signed char port); - -/** -* @brief Start Serdes PRBS test -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistStartPRBS(unsigned char slotID, signed char port); - -/** -* @brief Stop Serdes PRBS test -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param prbs_err: the number of prbs errors -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistStopPRBS(unsigned char slotID, signed char port, unsigned char* prbs_err); - -/** -* @brief Test I2C memory map access -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered, NO_ACK in case no acknowledgment is received, READBACK_ERROR in case the written and readback word are not the same. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistI2CMM(unsigned char slotID, signed char port); - -/** -* @brief Test all EEPROMs (Flex, headstage, BSC). by verifying a write/readback cycle on an unused memory location -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered, NO_ACK_FLEX in case no acknowledgment is received from the flex eeprom, READBACK_ERROR_FLEX in case the written and readback word are not the same from the flex eeprom, NO_ACK_HS in case no acknowledgment is received from the HS eeprom, READBACK_ERROR_HS in case the written and readback word are not the same from the HS eeprom, NO_ACK_BSC in case no acknowledgment is received from the BSC eeprom, READBACK_ERROR_BSC in case the written and readback word are not the same from the BSC eeprom. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistEEPROM(unsigned char slotID, signed char port); - - -/** -* @brief Test the shift registers -* This test verifies the functionality of the shank and base shift registers (SR_CHAIN 1 to 3). The function configures the shift register two times with the same code. After the 2nd write cycle the SR_OUT_OK bit in the STATUS register is read. If OK, the shift register configuration was successful. The test is done for all 3 registers. The configuration code used for the test is a dedicated code (to make sure the bits are not all 0 or 1). -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered, ERROR_SR_CHAIN_1 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_1, ERROR_SR_CHAIN_2 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_2, ERROR_SR_CHAIN_3 in case the SR_OUT_OK bit is not ok when writing SR_CHAIN_3. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistSR(unsigned char slotID, signed char port); - -/** -* @brief Test the PSB bus on the headstage -* A test mode is implemented on the probe which enables the transmission of a known data pattern over the PSB bus. The following function sets the probe in this test mode, records a small data set, and verifies whether the acquired data matches the known data pattern. -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistPSB(unsigned char slotID, signed char port); - -/** -* @brief The probe is configured for noise analysis. Via the shank and base configuration registers and the memory map, the electrode inputs are shorted to ground. The data signal is recorded and the noise level is calculated. The function analyses if the probe performance falls inside a specified tolerance range (go/no-go test). -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @returns SUCCESS if successful, BIST_ERROR of test failed. NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered. -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistNoise(unsigned char slotID, signed char port); - -struct bistElectrodeStats { - double peakfreq_Hz; - double min; - double max; - double avg; -}; - -/** -* @brief The probe is configured for recording of a test signal which is generated on the headstage. This configuration is done via the shank and base configuration registers and the memory map. The data signal is recorded and the frequency and amplitude of the recorded signal are extracted for each electrode. The function analyses if the probe performance falls inside specified a tolerance range (go/no-go test). -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param pass: true if >=90% of the electrodes passed the test sucessfully -* @param stats: Optionally output argument (NULL if not used). If used, input is an array of size 960, which gets populated by electrode signal statistics in mV -* -* @returns SUCCESS if successful, BIST_ERROR of test failed. NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the valid range is entered, WRONG_PORT in case a port number outside the valid range is entered. -* -*/ -NP_EXPORT NP_ErrorCode NP_APIC bistSignal(uint8_t slotID, int8_t port, bool* pass, struct bistElectrodeStats* stats); -/********************* Data Acquisition ****************************/ - - -/** -* @brief Open an acquisition stream from an existing file. -* @param filename Specifies an existing file with probe acquisition data. -* @param port specifies the target port -* @param lfp if true, specifies that LFP data will be extracted. otherwise AP data only -* @param stream a pointer to the stream pointer that will receive the handle to the opened stream -* @param filename Specifies an existing file with probe acquisition data. -* @returns FILE_OPEN_ERROR if unable to open file -*/ -NP_EXPORT NP_ErrorCode NP_APIC streamOpenFile(const char* filename, int8_t port, bool lfp, np_streamhandle_t* pstream); - -/** -* @brief Closes an acquisition stream. -* Closes the stream along with the optional recording file. -* @returns (TBD) -*/ -NP_EXPORT NP_ErrorCode NP_APIC streamClose(np_streamhandle_t stream); - -/** -* @brief Moves the stream pointer to given timestamp. -* Stream seek is only supported on streams that are backed by a recording file store. -* @param stream: the acquisition stream handle -* @param filepos: The file position to navigate to. -* @param actualtimestamp: returns the timestamp at the stream pointer (NULL allowed) -* @returns TIMESTAMPNOTFOUND if no valid data packet is found beyond the specified file position -*/ -NP_EXPORT NP_ErrorCode NP_APIC streamSeek(np_streamhandle_t stream, uint64_t filepos, uint32_t* actualtimestamp); - -NP_EXPORT NP_ErrorCode NP_APIC streamSetPos(np_streamhandle_t sh, uint64_t filepos); - -/** -* @brief Report the current file position in the filestream. -* @param stream: the acquisition stream handle -* @returns the current file position at the stream cursor position. -*/ -NP_EXPORT uint64_t NP_APIC streamTell(np_streamhandle_t stream); - -/** -* @brief read probe data from a recorded file stream. -* Example: -* #define SAMPLECOUNT 128 -* uint16_t interleaveddata[SAMPLECOUNT * 384]; -* uint32_t timestamps[SAMPLECOUNT]; -* -* np_streamhandle_t sh; -* streamOpenFile("myrecording.bin",1, false, &sh); -* streamRead(sh, timestamps, interleaveddata, SAMPLECOUNT); -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param timestamps: Optional timestamps buffer (NULL if not used). size should be 'samplecount' -* @param data: buffer of size samplecount*384. The buffer will be populated with channel interleaved, 16 bit per sample data. -* @returns amount of actual time stamps read. -*/ -NP_EXPORT int NP_APIC streamRead( - np_streamhandle_t sh, - uint32_t* timestamps, - int16_t* data, - int samplecount); - -NP_EXPORT NP_ErrorCode NP_APIC streamReadPacket( - np_streamhandle_t sh, - pckhdr_t* header, - int16_t* data, - size_t elementstoread, - size_t* elementread); - -/** -* @brief Blocking live read from the AP Fifo. -* Example: - -* #define SAMPLECOUNT 128 -* uint16_t interleaveddata[SAMPLECOUNT * 384]; -* uint32_t timestamps[SAMPLECOUNT]; -* -* readAPFifo(0,0, timestamps, interleaveddata, SAMPLECOUNT); -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param timestamps: Optional timestamps buffer (NULL if not used). size should be 'samplecount' -* @param data: buffer of size samplecount*384. The buffer will be populated with channel interleaved, 16 bit per sample data. -* @returns amount of actual time stamps read. -*/ -NP_EXPORT size_t NP_APIC readAPFifo(uint8_t slotid, uint8_t port, uint32_t* timestamps, int16_t* data, int samplecount); - -/** -* @brief Blocking live read from the LFP Fifo. -* Example: - -* #define SAMPLECOUNT 128 -* uint16_t interleaveddata[SAMPLECOUNT * 384]; -* uint32_t timestamps[SAMPLECOUNT]; -* -* readAPFifo(0,0, timestamps, interleaveddata, SAMPLECOUNT); -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param timestamps: Optional timestamps buffer (NULL if not used). size should be 'samplecount' -* @param data: buffer of size samplecount*384. The buffer will be populated with channel interleaved, 16 bit per sample data. -* @returns amount of actual time stamps read. -*/ -NP_EXPORT size_t NP_APIC readLFPFifo(unsigned char slotid, signed char port, uint32_t* timestamps, int16_t* data, int samplecount); - -NP_EXPORT size_t NP_APIC readADCFifo(unsigned char slotid, signed char port, uint32_t* timestamps, int16_t* data, int samplecount); - -/** -* @brief Blocking live read from the electrode data Fifo. -* Example: - -* #define SAMPLECOUNT 128 -* struct electrodePacket[SAMPLECOUNT]; -* size_t count = SAMPLECOUNT; -* readElectrodeData(1,1, &electrodePacket[0], &count, count); -* -* @param slotID: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param packets: read buffer to copy the packets from the fifo to. -* @param actualAmount: actual amount of packets read from the fifo. -* @param requestedAmount: amount of packets to try to read from the fifo. -*/ -NP_EXPORT NP_ErrorCode NP_APIC readElectrodeData( - unsigned char slotid, - signed char port, - struct electrodePacket* packets, - size_t* actualAmount, - size_t requestedAmount); - -/** -* @brief Get the filling state of the ElectrodeDataFifo. -* -* @param slotid: which slot in the PXI chassis (valid range depends on the chassis) -* @param port: for which HS (valid range 1 to 4) -* @param packetsavailable: returns the amount unread of packets in the fifo. NULL allowed for no return. -* @param headroom: returns the amount of space left in the fifo. NULL allowed for no return. -*/ -NP_EXPORT NP_ErrorCode NP_APIC getElectrodeDataFifoState( - unsigned char slotid, - signed char port, - size_t* packetsavailable, - size_t* headroom); - -/*** TEST MODULE FUNCTIONS *****/ -NP_EXPORT NP_ErrorCode NP_APIC HSTestVDDA1V2(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestVDDD1V2(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestVDDA1V8(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestVDDD1V8(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestOscillator(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestMCLK(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestPCLK(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestPSB(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestI2C(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestNRST(uint8_t slotID, int8_t port); -NP_EXPORT NP_ErrorCode NP_APIC HSTestREC_NRESET(uint8_t slotID, int8_t port); - -/********************* debug output control ****************************/ -NP_EXPORT void NP_APIC dbg_setlevel(int level); -NP_EXPORT int NP_APIC dbg_getlevel(void); - -/********************* Firmware update functions ****************************/ -NP_EXPORT NP_ErrorCode NP_APIC qbsc_update(unsigned char slotID, const char* filename, int(*callback)(size_t byteswritten)); -NP_EXPORT NP_ErrorCode NP_APIC bs_update(unsigned char slotID, const char* filename, int(*callback)(size_t byteswritten)); - -/********************* Stream API ****************************/ -NP_EXPORT NP_ErrorCode NP_APIC setFileStream(unsigned char slotID, const char* filename); -NP_EXPORT NP_ErrorCode NP_APIC enableFileStream(unsigned char slotID, bool enable); - -NP_EXPORT NP_ErrorCode NP_APIC getADCparams(unsigned char slotID, signed char port, int adcnr, struct ADC_Calib* data); -NP_EXPORT NP_ErrorCode NP_APIC setADCparams(unsigned char slotID, signed char port, const struct ADC_Calib* data); - -NP_EXPORT const char* np_GetErrorMessage(NP_ErrorCode code); - -} - -#ifdef __cplusplus -} -#endif diff --git a/Source/API/v1/NeuropixAPI_private.h b/Source/API/v1/NeuropixAPI_private.h deleted file mode 100644 index 1a997a3..0000000 --- a/Source/API/v1/NeuropixAPI_private.h +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once - -#include "NeuropixAPI.h" - -#ifdef __cplusplus -extern "C" { -#endif - - typedef enum - { - ChannelType_None = 0, - ChannelType_LFP = (1 << 0), - ChannelType_AP = (1 << 1), - ChannelType_ADC = (1 << 2) - }channeltype_t; - - struct probechannelstatistics { - uint32_t channelnr; - uint32_t samplecount; - double min; - double max; - double avg; - double stddev; - }; - - /********************* Non volatile memory write functions ****************************/ - /** - * \brief Write the BSC version data to the EEPROM memory - * - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @param version_major: the BSC FPGA boot code version number - * @param version_minor: the BSC FPGA boot code revision number - * @returns NO_LINK if no datalink, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered - */ - NP_EXPORT NP_ErrorCode NP_APIC setBSCVersion(unsigned char slotID, unsigned char version_major, unsigned char version_minor); - /* @brief Write the Head Stage version to EEPROM memory - * - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @param port: for which HS (valid range 0 to 3) - * @param version_major: the HS board version number - * @param version_minor: the HS board revision number - * @param version_build: the HS board build number (NULL allowed) - * @returns SUCCESS correct acknowledgment byte returned by the slave, TIMEOUT if no I2C acknowledgement is received, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). - */ - NP_EXPORT NP_ErrorCode NP_APIC setHSVersion(unsigned char slotID, signed char port, unsigned char version_major, unsigned char version_minor); - - /** - * @brief Write probe ID - * The probe ID is stored on the EEPROM memory on the flex. The probe ID is a 16 digit number. - * - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @param port: for which HS (valid range 0 to 3) - * @param id: the probe ID code to return - * @returns NO_LINK if no datalink, TIMEOUT if no I2C acknowledgement is received, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). - */ - NP_EXPORT NP_ErrorCode NP_APIC writeId(unsigned char slotID, signed char port, uint64_t id); - NP_EXPORT NP_ErrorCode NP_APIC writeProbePN(unsigned char slotID, signed char port, const char* pn); - NP_EXPORT NP_ErrorCode NP_APIC setFlexVersion(unsigned char slotID, signed char port, unsigned char version_major, unsigned char version_minor); - NP_EXPORT NP_ErrorCode NP_APIC writeFlexPN(unsigned char slotID, signed char port, const char* pn); - /** - * @brief Write the headstage serial number to EEPROM - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @param port: for which HS (valid range 0 to 3) - * @param id: the probe ID code to return - * @returns NO_LINK if no datalink, TIMEOUT if no I2C acknowledgement is received, SUCCESS if successful, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered, WRONG_PORT in case a port number outside the range is entered, NO_LOCK if no clock signal arrives at the deserializer (=missing or malfunctioning cable, HS or probe). - */ - NP_EXPORT NP_ErrorCode NP_APIC writeHSSN(unsigned char slotID, signed char port, uint64_t sn); - NP_EXPORT NP_ErrorCode NP_APIC writeHSPN(unsigned char slotID, signed char port, const char* pn); - - - /********************* Debug functions ****************************/ - NP_EXPORT void NP_APIC dbg_getversion_datetime(char* dst, size_t maxlen); - NP_EXPORT NP_ErrorCode NP_APIC dbg_setQBSCSWTrigger(uint8_t slotID); - NP_EXPORT NP_ErrorCode NP_APIC openEmulationProbe(uint8_t slotID, int8_t port); - NP_EXPORT NP_ErrorCode NP_APIC dbg_setEmulatorMode(uint8_t slotID, emulatormode_t mode); - NP_EXPORT NP_ErrorCode NP_APIC dbg_getEmulatorMode(uint8_t slotID, emulatormode_t* mode); - NP_EXPORT NP_ErrorCode NP_APIC dbg_setProbeEmulationMode(uint8_t slotID, int8_t port, bool state); - NP_EXPORT NP_ErrorCode NP_APIC dbg_getProbeEmulationMode(uint8_t slotID, int8_t port, bool* state); - NP_EXPORT NP_ErrorCode NP_APIC dbg_read_SRCHAIN1(uint8_t slotID, int8_t port, void* dst, size_t len); - NP_EXPORT NP_ErrorCode NP_APIC dbg_read_SRCHAIN2(uint8_t slotID, int8_t port, void* dst, size_t len); - NP_EXPORT NP_ErrorCode NP_APIC dbg_read_SRCHAIN3(uint8_t slotID, int8_t port, void* dst, size_t len); - NP_EXPORT NP_ErrorCode NP_APIC dbg_diagstats_reset(uint8_t slotID); - NP_EXPORT NP_ErrorCode NP_APIC dbg_diagstats_read(uint8_t slotID, struct np_diagstats* diag); - NP_EXPORT NP_ErrorCode NP_APIC dbg_disablescale(uint8_t slotID, bool disable); - NP_EXPORT NP_ErrorCode NP_APIC dbg_headstageReadRegister(uint8_t slotID, int8_t port, uint8_t address, uint8_t* value); - NP_EXPORT NP_ErrorCode NP_APIC dbg_headstageWriteRegister(uint8_t slotID, int8_t port, uint8_t address, uint8_t value); - NP_EXPORT NP_ErrorCode NP_APIC dbg_setchannelgain(uint8_t slotID, int8_t port, int channel, double gainAP, double gainLFP); - NP_EXPORT NP_ErrorCode NP_APIC dbg_getchannelgain(uint8_t slotID, int8_t port, int channel, double* gainAP, double* gainLFP); - - /* @brief Set the offset correction data - * ADC offset correction can be programmed per channel. - * - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @param port: for which HS (valid range 0 to 3) - * @param adcchannel nr: 0..31 - * @param offset: 6 bit offset to be subtraced from the ADC value when the raw ADC data crosses the threshold value - * @param threshold: 10 bit threshold value. if the raw ADC value crosses this threshold, - * @returns SUCCESS if succesful, error code otherwise. - */ - NP_EXPORT NP_ErrorCode NP_APIC setOffsetCorrection(unsigned char slotID, signed char port, int adcchannel, uint16_t offset, uint16_t threshold); - - /** - * @brief Starts a continuous stream of data from the BS FPGA - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered. - */ - NP_EXPORT NP_ErrorCode NP_APIC startInfiniteStream(uint8_t slotID); - - /** - * @brief Stops a continuous stream of data from the BS FPGA - * @param slotID: which slot in the PXI chassis (valid range depends on the chassis) - * @returns SUCCESS if successful, NO_LINK if no datalink, NO_SLOT if no Neuropix card is plugged in the selected PXI chassis slot, WRONG_SLOT in case a slot number outside the chassis range is entered. - */ - NP_EXPORT NP_ErrorCode NP_APIC stopInfiniteStream(uint8_t slotID); - - - - NP_EXPORT NP_ErrorCode NP_APIC probeChannelStatistics_Reset(uint8_t slotID, int8_t portID, channeltype_t channels); - NP_EXPORT NP_ErrorCode NP_APIC probeChannelStatistics_Start(uint8_t slotID, int8_t portID, channeltype_t channels, int maxsamplecount); - NP_EXPORT NP_ErrorCode NP_APIC probeChannelStatistics_Stop(uint8_t slotID, int8_t portID, channeltype_t channels); - NP_EXPORT NP_ErrorCode NP_APIC probeChannelStatistics_ReadLFP(uint8_t slotID, int8_t portID, struct probechannelstatistics* stats, int firstchannel, int count); - NP_EXPORT NP_ErrorCode NP_APIC probeChannelStatistics_ReadAP(uint8_t slotID, int8_t portID, struct probechannelstatistics* stats, int firstchannel, int count); - NP_EXPORT NP_ErrorCode NP_APIC probeChannelStatistics_ReadADC(uint8_t slotID, int8_t portID, struct probechannelstatistics* stats, int firstchannel, int count); - - - NP_EXPORT NP_ErrorCode NP_APIC bist_fft(double* real, size_t samplecount, size_t channelcount); - NP_EXPORT NP_ErrorCode NP_APIC bist_fftpeakdetect(uint8_t slotID, int8_t port, double* peakfreq, double* peakampl, size_t samplecount, size_t channelcount); - - /* - Set the state to prevents the QBSC to reboot into normal image when openBS is called. - */ - NP_EXPORT NP_ErrorCode NP_APIC dbg_preventQBSCnormalboot(int state); - -#ifdef __cplusplus -} -#endif diff --git a/Source/API/v1/lib64/NeuropixAPI_x64_1_20.lib b/Source/API/v1/lib64/NeuropixAPI_x64_1_20.lib deleted file mode 100644 index 7782726..0000000 Binary files a/Source/API/v1/lib64/NeuropixAPI_x64_1_20.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_31.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_31.lib deleted file mode 100644 index 611f947..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_31.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_34.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_34.lib deleted file mode 100644 index 4981990..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_34.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_40.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_40.lib deleted file mode 100644 index 3534b49..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_40.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_41.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_41.lib deleted file mode 100644 index c27bfc7..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_41.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_42.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_42.lib deleted file mode 100644 index 34f57e7..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_42.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_52.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_52.lib deleted file mode 100644 index 4fff368..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_52.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_57.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_57.lib deleted file mode 100644 index 6727f70..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_57.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_59.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_59.lib deleted file mode 100644 index 47caade..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_59.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_60.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_60.lib deleted file mode 100644 index 14218a3..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_60.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_62.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_62.lib deleted file mode 100644 index d8e763d..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_62.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_62_1.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_62_1.lib deleted file mode 100644 index 578e152..0000000 Binary files a/Source/API/v3/lib64/NeuropixAPI_x64_3_62_1.lib and /dev/null differ diff --git a/Source/API/v3/lib64/NeuropixAPI_x64_3_67.lib b/Source/API/v3/lib64/NeuropixAPI_x64_3_67.lib new file mode 100644 index 0000000..e83d286 Binary files /dev/null and b/Source/API/v3/lib64/NeuropixAPI_x64_3_67.lib differ diff --git a/Source/Basestations/Basestation_v1.cpp b/Source/Basestations/Basestation_v1.cpp deleted file mode 100644 index 695de14..0000000 --- a/Source/Basestations/Basestation_v1.cpp +++ /dev/null @@ -1,322 +0,0 @@ -/* ------------------------------------------------------------------- - -This file is part of the Open Ephys GUI -Copyright (C) 2018 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 . - -*/ - -#ifdef _WIN32 -#include -#else -#include -#endif - -#include "Basestation_v1.h" -#include "../Probes/Neuropixels1_v1.h" -#include "../Headstages/Headstage1_v1.h" - -#define MAXLEN 50 - - -void Basestation_v1::getInfo() -{ - - unsigned char version_major; - unsigned char version_minor; - uint16_t version_build; - - errorCode = np::getBSBootVersion(slot, &version_major, &version_minor, &version_build); - - info.boot_version = String(version_major) + "." + String(version_minor); - - if (version_build != NULL) - info.boot_version += "."; - info.boot_version += String(version_build); - -} - - -void BasestationConnectBoard_v1::getInfo() -{ - - unsigned char version_major; - unsigned char version_minor; - uint16_t version_build; - - errorCode = np::getBSCBootVersion(basestation->slot, &version_major, &version_minor, &version_build); - - info.boot_version = String(version_major) + "." + String(version_minor); - - if (version_build != NULL) - info.boot_version += "."; - info.boot_version += String(version_build); - - errorCode = np::getBSCVersion(basestation->slot, &version_major, &version_minor); - - info.version = String(version_major) + "." + String(version_minor); - - errorCode = np::readBSCSN(basestation->slot, &info.serial_number); - - char pn[MAXLEN]; - np::readBSCPN(basestation->slot, pn, MAXLEN); - - info.part_number = String(pn); - -} - -BasestationConnectBoard_v1::BasestationConnectBoard_v1(Basestation* bs) : BasestationConnectBoard(bs) -{ - getInfo(); -} - -Basestation_v1::Basestation_v1(NeuropixThread* neuropixThread, int slot_number) : Basestation(neuropixThread, slot_number) -{ - type = BasestationType::V1; - - armBasestation = std::make_unique(slot_c); - - getInfo(); -} - -bool Basestation_v1::open() -{ - - errorCode = np::openBS(slot_c); - - if (errorCode == np::VERSION_MISMATCH) - { - return false; - } - - if (errorCode == np::SUCCESS) - { - - LOGD(" Opened BSv1 on slot ", slot_c); - - basestationConnectBoard = new BasestationConnectBoard_v1(this); - - savingDirectory = File(); - - for (signed char port = 1; port <= 4; port++) - { - - errorCode = np::openProbe(slot_c, port); // check for probe on slot - - LOGD("openProbe: Port: ", port, " errorCode: ", errorCode); - - if (errorCode == np::NO_LOCK) - { //likely no cable connected - headstages.add(nullptr); - LOGD("Check if cable is connected properly!") - } - else if (errorCode == np::TIMEOUT) - { //either headstage test module detected or broken connection to real probe - Headstage* headstage = new Headstage1_v1(this, port); - if (headstage->hasTestModule()) - { - headstage->runTestModule(); - } - else - { - //TODO: Run other calls to help narrow down error - } - delete headstage; - headstages.add(nullptr); - } - else if (errorCode == np::SUCCESS) - { - Headstage* headstage = new Headstage1_v1(this, port); - headstages.add(headstage); - probes.add(headstage->probes[0]); - } - - } - - LOGD("Found ", probes.size(), probes.size() == 1 ? " probe." : " probes."); - } - - syncFrequencies.add(1); - syncFrequencies.add(10); - - return true; -} - -void Basestation_v1::initialize(bool signalChainIsLoading) -{ - - if (!probesInitialized) - { - errorCode = np::setTriggerInput(slot, np::TRIGIN_SW); - - for (auto probe : probes) - { - probe->initialize(signalChainIsLoading); - } - - probesInitialized = true; - } - - errorCode = np::arm(slot_c); -} - -Basestation_v1::~Basestation_v1() -{ - close(); - -} - -void Basestation_v1::close() -{ - for (int i = 0; i < probes.size(); i++) - { - errorCode = np::close(slot_c, probes[i]->headstage->port_c); - } - - errorCode = np::closeBS(slot_c); -} - -bool Basestation_v1::isBusy() -{ - return armBasestation->isThreadRunning(); -} - -void Basestation_v1::waitForThreadToExit() -{ - armBasestation->waitForThreadToExit(10000); -} - -void Basestation_v1::setSyncAsInput() -{ - - /* - errorCode = np::setTriggerInput(slot_c, np::TRIGIN_SW); - if (errorCode != np::SUCCESS) - { - printf("Failed to set slot %d trigger as input!\n"); - return; - } - */ - - errorCode = setParameter(np::NP_PARAM_SYNCMASTER, slot_c); - if (errorCode != np::SUCCESS) - { - LOGD("Failed to set slot ", slot, " as sync master!"); - return; - } - - errorCode = setParameter(np::NP_PARAM_SYNCSOURCE, np::TRIGIN_SMA); - if (errorCode != np::SUCCESS) - LOGD("Failed to set slot ", slot, " SMA as sync input!"); - - /* - errorCode = setTriggerOutput(slot, np::TRIGOUT_PXI1, np::TRIGIN_SW); - if (errorCode != np::SUCCESS) - { - printf("Failed to reset sync on SMA output on slot: %d\n", slot_c); - } - */ - -} - -Array Basestation_v1::getSyncFrequencies() -{ - return syncFrequencies; -} - -void Basestation_v1::setSyncAsOutput(int freqIndex) -{ - - errorCode = setParameter(np::NP_PARAM_SYNCMASTER, slot_c); - if (errorCode != np::SUCCESS) - { - LOGD("Failed to set slot ", slot, " as sync master!"); - return; - } - - errorCode = setParameter(np::NP_PARAM_SYNCSOURCE, np::TRIGIN_SYNCCLOCK); - if (errorCode != np::SUCCESS) - { - LOGD("Failed to set slot ", slot, " internal clock as sync source!"); - return; - } - - int freq = syncFrequencies[freqIndex]; - - LOGD("Setting slot ", slot_c, " sync frequency to ", freq, " Hz..."); - errorCode = setParameter(np::NP_PARAM_SYNCFREQUENCY_HZ, freq); - if (errorCode != np::SUCCESS) - { - LOGD("Failed to set slot ", slot_c, " sync frequency to ", freq, " Hz"); - return; - } - - errorCode = setTriggerOutput(slot_c, np::TRIGOUT_SMA, np::TRIGIN_SHAREDSYNC); - if (errorCode != np::SUCCESS) - { - printf("Failed to set sync on SMA output on slot: %d\n", slot); - } - - -} - -int Basestation_v1::getProbeCount() -{ - return probes.size(); -} - -float Basestation_v1::getFillPercentage() -{ - float perc = 0.0; - - for (int i = 0; i < getProbeCount(); i++) - { - if (probes[i]->fifoFillPercentage > perc) - perc = probes[i]->fifoFillPercentage; - } - - return perc; -} - -void Basestation_v1::startAcquisition() -{ - - if (armBasestation->isThreadRunning()) - armBasestation->waitForThreadToExit(5000); - - for (auto probe : probes) - { - probe->startAcquisition(); - } - - errorCode = np::setSWTrigger(slot_c); - -} - -void Basestation_v1::stopAcquisition() -{ - - LOGC("Basestation stopping acquisition."); - - for (auto probe : probes) - { - probe->stopAcquisition(); - } - - armBasestation->startThread(); -} \ No newline at end of file diff --git a/Source/Basestations/Basestation_v1.h b/Source/Basestations/Basestation_v1.h deleted file mode 100644 index 066ef17..0000000 --- a/Source/Basestations/Basestation_v1.h +++ /dev/null @@ -1,138 +0,0 @@ -/* ------------------------------------------------------------------- - -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 . - -*/ - -#ifndef __NEUROPIXBASESTATIONV1_H_2C4C2D67__ -#define __NEUROPIXBASESTATIONV1_H_2C4C2D67__ - -#include "../API/v1/NeuropixAPI.h" -#include "../NeuropixComponents.h" - -# define SAMPLECOUNT 64 - -/* -* - Thread for arming basestation immediately after acquisition - ends. This takes a few seconds, so we should do it in a thread - so acquisition stops promptly. - -*/ -class ArmBasestationV1 : public Thread -{ -public: - ArmBasestationV1(unsigned char slot_) : - Thread("Arm Basestation in Slot " + String(int(slot))) - , slot(slot_) { } - - ~ArmBasestationV1() { } - - void run() - { - LOGC("Arming PXI slot ", int(slot), "..."); - np::arm(slot); - LOGC("Arming complete."); - } - -private: - - unsigned char slot; -}; - -/* - - Standard Neuropixels PXI basestation - running v1 firmware. - -*/ -class Basestation_v1 : public Basestation -{ -public: - /** Constructor */ - Basestation_v1(NeuropixThread*, int slot); - - /** Destructor */ - ~Basestation_v1(); - - /** Opens connection to the basestation */ - bool open() override; - - /** Closes connection to the basestation */ - void close() override; - - /** Initializes probes in a background thread */ - void initialize(bool signalChainIsLoading) override; - - /** Returns the total number of probes connected to this basestation*/ - int getProbeCount() override; - - /** Gets part number, firmware version, etc.*/ - void getInfo() override; - - /** Set basestation SMA connector as input*/ - void setSyncAsInput() override; - - /** Set basestation SMA connector as output (and set frequency)*/ - void setSyncAsOutput(int freqIndex) override; - - /** Returns an array of available frequencies when SMA is in "output" mode */ - Array getSyncFrequencies() override; - - /** Starts probe data streaming */ - void startAcquisition() override; - - /** Stops probe data streaming*/ - void stopAcquisition() override; - - /** Returns the fraction of the basestation FIFO that is filled */ - float getFillPercentage() override; - - bool isBusy() override; - - void waitForThreadToExit() override; - -private: - np::bistElectrodeStats stats[960]; - - np::NP_ErrorCode errorCode; - - std::unique_ptr armBasestation; - -}; - -class BasestationConnectBoard_v1 : public BasestationConnectBoard -{ -public: - - /** Constructor */ - BasestationConnectBoard_v1(Basestation*); - - /** Returns part number, firmware version, etc.*/ - void getInfo() override; - -private: - np::NP_ErrorCode errorCode; -}; - - - - -#endif // __NEUROPIXBASESTATIONV1_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Basestations/Basestation_v3.cpp b/Source/Basestations/Basestation_v3.cpp deleted file mode 100644 index d0be582..0000000 --- a/Source/Basestations/Basestation_v3.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* ------------------------------------------------------------------- - -This file is part of the Open Ephys GUI -Copyright (C) 2018 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 . - -*/ - -#ifdef _WIN32 -#include -#else -#include -#endif - -#include "Basestation_v3.h" -#include "../Probes/Neuropixels1_v3.h" -#include "../Headstages/Headstage1_v3.h" -#include "../Headstages/Headstage2.h" -#include "../Headstages/Headstage_Analog128.h" -#include "../Headstages/Headstage_Custom384.h" - -#define MAXLEN 50 - - - -void Basestation_v3::getInfo() -{ - Neuropixels::firmware_Info firmwareInfo; - - Neuropixels::bs_getFirmwareInfo(slot, &firmwareInfo); - - info.boot_version = String(firmwareInfo.major) + "." + String(firmwareInfo.minor) + String(firmwareInfo.build); - - info.part_number = String(firmwareInfo.name); - -} - - -void BasestationConnectBoard_v3::getInfo() -{ - - int version_major; - int version_minor; - - errorCode = Neuropixels::getBSCVersion(basestation->slot, &version_major, &version_minor); - - info.version = String(version_major) + "." + String(version_minor); - - errorCode = Neuropixels::readBSCSN(basestation->slot, &info.serial_number); - - char pn[MAXLEN]; - Neuropixels::readBSCPN(basestation->slot, pn, MAXLEN); - - info.part_number = String(pn); - - Neuropixels::firmware_Info firmwareInfo; - Neuropixels::bsc_getFirmwareInfo(basestation->slot, &firmwareInfo); - info.boot_version = String(firmwareInfo.major) + "." + String(firmwareInfo.minor) + String(firmwareInfo.build); -} - -BasestationConnectBoard_v3::BasestationConnectBoard_v3(Basestation* bs) : BasestationConnectBoard(bs) -{ - getInfo(); -} - -Basestation_v3::Basestation_v3(NeuropixThread* neuropixThread, int slot_number) : Basestation(neuropixThread, slot_number) -{ - type = BasestationType::V3; - - armBasestation = std::make_unique(slot_number); - - getInfo(); -} - -ThreadPoolJob::JobStatus PortChecker::runJob() -{ - - bool detected = false; - - Neuropixels::NP_ErrorCode errorCode = Neuropixels::openPort(slot, port); - - errorCode = Neuropixels::detectHeadStage(slot, port, &detected); // check for headstage on port - - if (detected && errorCode == Neuropixels::SUCCESS) - { - char pn[MAXLEN]; - Neuropixels::readHSPN(slot, port, pn, MAXLEN); - - String hsPartNumber = String(pn); - - LOGC("Got HS part #: ", hsPartNumber); - - if (hsPartNumber == "NP2_HS_30" || hsPartNumber == "OPTO_HS_00") // 1.0 headstage, only one dock - { - LOGC(" Found 1.0 single-dock headstage on port: ", port); - headstage = new Headstage1_v3(basestation, port); - if (headstage->testModule != nullptr || !headstage->probes.size()) - { - headstage = nullptr; - } - } - else if (hsPartNumber == "NPNH_HS_30" || hsPartNumber == "NPNH_HS_31") // 128-ch analog headstage - { - LOGC(" Found 128-ch analog headstage on port: ", port); - headstage = new Headstage_Analog128(basestation, port); - } - else if (hsPartNumber == "NPNH_HS_00") // custom 384-ch headstage - { - LOGC(" Found 384-ch custom headstage on port: ", port); - headstage = new Headstage_Custom384(basestation, port); - } - else if (hsPartNumber == "NPM_HS_30" || hsPartNumber == "NPM_HS_31" || hsPartNumber == "NPM_HS_01") // 2.0 headstage, 2 docks - { - LOGC(" Found 2.0 dual-dock headstage on port: ", port); - headstage = new Headstage2(basestation, port); - } - else - { - headstage = nullptr; - } - - } - else - { - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("***detectHeadstage failed w/ error code: ", errorCode); - } - else - { - LOGC(" No headstage detected on port: ", port); - } - - errorCode = Neuropixels::closePort(slot, port); // close port - - headstage = nullptr; - } - - return jobHasFinished; -} - -bool Basestation_v3::open() -{ - - errorCode = Neuropixels::openBS(slot); - - if (errorCode == Neuropixels::VERSION_MISMATCH) - { - LOGC("Basestation at slot: ", slot, " API VERSION MISMATCH!"); - return false; - } - - if (errorCode == Neuropixels::SUCCESS) - { - - LOGC(" Opened BS on slot ", slot); - - basestationConnectBoard = new BasestationConnectBoard_v3(this); - - //Confirm v3 basestation by BS version 2.0 or greater. - LOGC(" BS firmware: ", info.boot_version); - if (std::stod((info.boot_version.toStdString())) < 2.0) - return false; - - invertOutput = false; - - if (info.boot_version.equalsIgnoreCase("2.0137")) - { - LOGC("Found basestation firmware version ", info.boot_version, "; setting invertOutput to true."); - - // show popup notification window - String message = "The basestation on slot " + String(slot) + " has firmware version 2.0137, but version 2.0169 is required for this plugin. "; - message += "This is contained in the file named BS_FPGA_B169.bin. "; - message += "Please see the Neuropixels PXI page on the Open Ephys GUI documentation site for information on how to perform a firmware update. "; - - AlertWindow::showMessageBox(AlertWindow::AlertIconType::WarningIcon, "Outdated basestation firmware on slot " + String(slot), message, "OK"); - - invertOutput = true; - } - - if (basestationConnectBoard->info.boot_version.equalsIgnoreCase("3.2176")) - { - LOGC("Found basestation connect board firmware version ", basestationConnectBoard->info.boot_version); - - // show popup notification window - String message = "The basestation on slot " + String(slot) + " has basestation firmware version 3.2176, but version 3.2189 is required for this plugin. "; - message += "This is contained in the file named QBSC_FPGA_B189.bin. "; - message += "Please see the Neuropixels PXI page on the Open Ephys GUI documentation site for information on how to perform a firmware update."; - - AlertWindow::showMessageBox(AlertWindow::AlertIconType::WarningIcon, "Outdated basestation connect board firmware on slot " + String(slot), message, "OK"); - } - - if (basestationConnectBoard->info.boot_version.equalsIgnoreCase("3.2186")) - { - LOGC("Found basestation connect board firmware version ", basestationConnectBoard->info.boot_version); - - // show popup notification window - String message = "The basestation on slot " + String(slot) + " has basestation firmware version 3.2186, but version 3.2189 is required for this plugin. "; - message += "This is contained in the file named QBSC_FPGA_B189.bin. "; - message += "Please see the Neuropixels PXI page on the Open Ephys GUI documentation site for information on how to perform a firmware update."; - - AlertWindow::showMessageBox(AlertWindow::AlertIconType::WarningIcon, "Outdated basestation connect board firmware on slot " + String(slot), message, "OK"); - } - - LOGC(" Searching for probes..."); - - ThreadPool threadPool; - OwnedArray portCheckers; - - for (int port = 1; port <= 4; port++) - { - - if (type == BasestationType::OPTO && port > 2) - break; - - bool detected = false; - - portCheckers.add(new PortChecker(slot, port, this)); - threadPool.addJob(portCheckers.getLast(), false); - } - - //LOGC(" Waiting for jobs to finish..."); - while (threadPool.getNumJobs() > 0) - Sleep(100); - //LOGC(" Jobs finished."); - - int portIndex = 0; - - for (auto portChecker : portCheckers) - { - - headstages.add(portChecker->headstage); - - if (portChecker->headstage != nullptr) - { - - for (auto probe : portChecker->headstage->probes) - { - if (probe != nullptr) - { - probes.add(probe); - - if (probe->info.part_number.equalsIgnoreCase("NP1300")) - type = BasestationType::OPTO; - } - } - } - } - - LOGC(" Found ", probes.size(), probes.size() == 1 ? " probe." : " probes."); - - } - - syncFrequencies.add(1); - syncFrequencies.add(10); - - return true; -} - -void Basestation_v3::initialize(bool signalChainIsLoading) -{ - - if (!probesInitialized) - { - //errorCode = Neuropixels::setTriggerInput(slot, Neuropixels::TRIGIN_SW); - - for (auto probe : probes) - { - probe->initialize(signalChainIsLoading); - } - - probesInitialized = true; - } - - LOGC("Arming basestation"); - Neuropixels::arm(slot); //armBasestation->startThread(); - LOGC("Arming complete"); -} - -Basestation_v3::~Basestation_v3() -{ - /* As of API 3.31, closing a v3 basestation does not turn off the SMA output */ - setSyncAsInput(); - close(); - -} - -void Basestation_v3::close() -{ - for (auto probe : probes) - { - errorCode = Neuropixels::closeProbe(slot, probe->headstage->port, probe->dock); - } - - errorCode = Neuropixels::closeBS(slot); - LOGD("Closed basestation on slot: ", slot, " w/ error code: ", errorCode); -} - -bool Basestation_v3::isBusy() -{ - return armBasestation->isThreadRunning(); -} - -void Basestation_v3::waitForThreadToExit() -{ - armBasestation->waitForThreadToExit(25000); -} - -void Basestation_v3::setSyncAsInput() -{ - - LOGD("Setting sync as input..."); - - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SyncClk, false); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set sync on SMA output on slot: ", slot); - } - - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SyncClk, false); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set sync on SMA input on slot: ", slot); - } - - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCMASTER, slot); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot", slot, "as sync master!"); - return; - } - - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCSOURCE, Neuropixels::SyncSource_SMA); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, "SMA as sync source!"); - } - - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_PXISYNC, true); - if (errorCode != Neuropixels::SUCCESS) - { - LOGD("Failed to set sync on SMA input on slot: ", slot); - } - - if (invertOutput) - { - - LOGD("Sync as input: don't invert sync line."); - - for (auto probe : probes) - { - probe->invertSyncLine = false; - } - } - - -} - - -Array Basestation_v3::getSyncFrequencies() -{ - return syncFrequencies; -} - -void Basestation_v3::setSyncAsOutput(int freqIndex) -{ - - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCMASTER, slot); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, " as sync master!"); - return; - } - - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCSOURCE, Neuropixels::SyncSource_Clock); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, " internal clock as sync source!"); - return; - } - - int freq = syncFrequencies[freqIndex]; - - LOGD("Setting slot ", slot, " sync frequency to ", freq, " Hz..."); - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCFREQUENCY_HZ, freq); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, " sync frequency to ", freq, " Hz!"); - return; - } - - LOGD("Setting sync as output..."); - - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SyncClk, true); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set sync on SMA output on slot: ", slot); - } - - - - - if (invertOutput) - { - LOGD("Sync as output: do invert sync line."); - - for (auto probe : probes) - { - probe->invertSyncLine = true; - } - } - -} - -int Basestation_v3::getProbeCount() -{ - return probes.size(); -} - -float Basestation_v3::getFillPercentage() -{ - float perc = 0.0; - - for (int i = 0; i < getProbeCount(); i++) - { - //LOGDD("Percentage for probe ", i, ": ", probes[i]->fifoFillPercentage); - - if (probes[i]->fifoFillPercentage > perc) - perc = probes[i]->fifoFillPercentage; - } - - return perc; -} - -void Basestation_v3::startAcquisition() -{ - - if (armBasestation->isThreadRunning()) - armBasestation->waitForThreadToExit(25000); - - for (auto probe : probes) - { - probe->startAcquisition(); - } - - errorCode = Neuropixels::setSWTrigger(slot); - -} - -void Basestation_v3::stopAcquisition() -{ - - LOGC("Basestation stopping acquisition."); - - for (auto probe : probes) - { - probe->stopAcquisition(); - } - - armBasestation->startThread(); -} - - - - -void Basestation_v3::selectEmissionSite(int port, int dock, String wavelength, int site) -{ - - if (type == BasestationType::OPTO) - { - LOGD("Opto basestation on slot ", slot, " selecting emission site on port ", port, ", dock ", dock); - - Neuropixels::wavelength_t wv; - - if (wavelength.equalsIgnoreCase("red")) - { - wv = Neuropixels::wavelength_red; - } - else if (wavelength.equalsIgnoreCase("blue")) - { - wv = Neuropixels::wavelength_blue; - } - else { - LOGD("Wavelength not recognized. No emission site selected."); - return; - } - - if (site < -1 || site > 13) - { - LOGD(site, ": invalid site number."); - return; - } - - errorCode = Neuropixels::setEmissionSite(slot, port, dock, wv, site); - - LOGD(wavelength, " site ", site, " selected with error code ", errorCode); - - errorCode = Neuropixels::getEmissionSite(slot, port, dock, wv, &site); - - LOGD(wavelength, " actual site: ", site, " selected with error code ", errorCode); - } -} - - diff --git a/Source/Basestations/Basestation_v3.h b/Source/Basestations/Basestation_v3.h deleted file mode 100644 index 2e68c33..0000000 --- a/Source/Basestations/Basestation_v3.h +++ /dev/null @@ -1,170 +0,0 @@ -/* ------------------------------------------------------------------- - -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 . - -*/ - -#ifndef __NEUROPIXBASESTATIONV3_H_2C4C2D67__ -#define __NEUROPIXBASESTATIONV3_H_2C4C2D67__ - -#include "../API/v3/NeuropixAPI.h" -#include "../NeuropixComponents.h" - -# define SAMPLECOUNT 64 - -/* -* - Thread for arming basestation immediately after acquisition - ends. This takes a few seconds, so we should do it in a thread - so acquisition stops promptly. - -*/ - -class Basestation_v3; - -class PortChecker : public ThreadPoolJob -{ -public: - - PortChecker(int slot_, int port_, Basestation_v3* basestation_) : - ThreadPoolJob("Port checker for " + String(slot_) + ":" + String(port_)) - , slot(slot_), port(port_), basestation(basestation_), headstage(nullptr) { } - - ~PortChecker() { - signalJobShouldExit(); - } - - JobStatus runJob(); - - Headstage* headstage; - -private: - - int slot; - int port; - Basestation_v3* basestation; -}; - -class ArmBasestation : public Thread -{ -public: - ArmBasestation(int slot_) : - Thread("Arm Basestation in Slot " + String(slot)) - , slot(slot_) { } - - ~ArmBasestation() { - stopThread(2000); - } - - void run() - { - LOGC("Arming PXI slot ", slot, "..."); - Neuropixels::arm(slot); - LOGC("Arming complete."); - } - -private: - - int slot; -}; - -/* - - Standard Neuropixels PXI basestation - running v3 firmware. - -*/ -class Basestation_v3 : public Basestation - -{ -public: - /** Constructor */ - Basestation_v3(NeuropixThread*, int slot); - - /** Destructor */ - ~Basestation_v3(); - - /** Opens connection to the basestation */ - bool open() override; - - /** Closes connection to the basestation */ - void close() override; - - /** Initializes probes in a background thread */ - void initialize(bool signalChainIsLoading) override; - - /** Returns the total number of probes connected to this basestation*/ - int getProbeCount() override; - - /** Gets part number, firmware version, etc.*/ - void getInfo() override; - - /** Set basestation SMA connector as input*/ - void setSyncAsInput() override; - - /** Set basestation SMA connector as output (and set frequency)*/ - void setSyncAsOutput(int freqIndex) override; - - /** Returns an array of available frequencies when SMA is in "output" mode */ - Array getSyncFrequencies() override; - - /** Starts probe data streaming */ - void startAcquisition() override; - - /** Stops probe data streaming*/ - void stopAcquisition() override; - - /** Returns the fraction of the basestation FIFO that is filled */ - float getFillPercentage() override; - - /** Activates a probe emission site (only works for Opto probes) */ - void selectEmissionSite(int port, int dock, String wavelength, int site); - - /** Returns true if the arm basestation thread is running */ - bool isBusy() override; - - /** Waits for the arm basestation thread to exit */ - void waitForThreadToExit() override; - -private: - std::unique_ptr armBasestation; - - Neuropixels::NP_ErrorCode errorCode; - - bool invertOutput; - -}; - -class BasestationConnectBoard_v3 : public BasestationConnectBoard -{ -public: - - /** Constructor */ - BasestationConnectBoard_v3(Basestation*); - - /** Returns part number, firmware version, etc.*/ - void getInfo() override; - -private: - Neuropixels::NP_ErrorCode errorCode; -}; - - -#endif // __NEUROPIXBASESTATIONV3_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Basestations/OneBox.cpp b/Source/Basestations/OneBox.cpp index 92150f0..214065e 100644 --- a/Source/Basestations/OneBox.cpp +++ b/Source/Basestations/OneBox.cpp @@ -1,38 +1,33 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2021 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ -#ifdef _WIN32 -#include -#else -#include -#endif - #include "OneBox.h" -#include "../Probes/Neuropixels1_v3.h" -#include "../Headstages/Headstage1_v3.h" +#include "../Headstages/Headstage1.h" #include "../Headstages/Headstage2.h" #include "../Headstages/Headstage_Analog128.h" #include "../Headstages/Headstage_Custom384.h" +#include "../Headstages/Headstage_QuadBase.h" +#include "../Probes/Neuropixels1.h" #include "../Probes/OneBoxADC.h" #include "../Probes/OneBoxDAC.h" @@ -42,375 +37,409 @@ Array OneBox::existing_oneboxes = Array(); void OneBox::getInfo() { - Neuropixels::firmware_Info firmwareInfo; + Neuropixels::firmware_Info firmwareInfo; - errorCode = Neuropixels::bs_getFirmwareInfo(slot, &firmwareInfo); + errorCode = Neuropixels::bs_getFirmwareInfo (slot, &firmwareInfo); - info.boot_version = String(firmwareInfo.major) + "." + String(firmwareInfo.minor) + String(firmwareInfo.build); - - info.part_number = String(firmwareInfo.name); + info.boot_version = String (firmwareInfo.major) + "." + String (firmwareInfo.minor) + String (firmwareInfo.build); + info.part_number = String (firmwareInfo.name); } -OneBox::OneBox(NeuropixThread* neuropixThread, int slot_number) : Basestation(neuropixThread, slot_number) +OneBox::OneBox (NeuropixThread* neuropixThread, int serial_number_) : Basestation (neuropixThread, serial_number) { + type = BasestationType::ONEBOX; + + serial_number = serial_number_; + + if (! existing_oneboxes.contains (serial_number)) + { + existing_oneboxes.add (serial_number); + LOGC ("Stored OneBox serial number ", serial_number); + } + else + { + LOGC ("OneBox with serial number ", serial_number, " already connected!"); + return; + } + + int next_slot = first_available_slot + existing_oneboxes.size() - 1; + + LOGD ("Mapping OneBox with serial number ", serial_number, " to slot ", next_slot); + + errorCode = Neuropixels::mapBS (serial_number, next_slot); // assign to slot ID + errorCode = Neuropixels::openBS (next_slot); + + if (errorCode == Neuropixels::NO_SLOT) + { + LOGD ("NO_SLOT error"); + return; + } + else if (errorCode == Neuropixels::IO_ERROR) + { + LOGD ("IO_ERROR"); + return; + } + else if (errorCode == Neuropixels::WRONG_SLOT) + { + LOGD ("WRONG_SLOT error"); + return; + } + + LOGD ("Successfully mapped OneBox with serial number ", serial_number, " to slot ", next_slot, ", error code: ", errorCode); + + slot = next_slot; + slot_c = next_slot; + + customPortNames.clear(); + + for (int p = 0; p < 4; p++) + { + for (int d = 0; d < 2; d++) + { + customPortNames.add ("slot" + String (slot) + "-port" + String (p + 1) + "-" + String (d + 1)); + } + } +} - type = BasestationType::ONEBOX; +OneBox::~OneBox() +{ + /* As of API 3.31, closing a v3 basestation does not turn off the SMA output */ + setSyncAsInput(); + close(); - int next_slot = first_available_slot + existing_oneboxes.size(); + existing_oneboxes.removeFirstMatchingValue (serial_number); +} - errorCode = Neuropixels::mapBS(slot_number, next_slot); // assign to slot ID +bool OneBox::open() +{ + if (serial_number == -1) + return false; - if (errorCode == Neuropixels::NO_SLOT || errorCode == Neuropixels::IO_ERROR) - { - LOGD("NO_SLOT error"); - return; - } - - LOGD("Mapped basestation ", slot_number, " to slot ", next_slot, ", error code: ", errorCode); + errorCode = Neuropixels::openBS (slot); - LOGD("Stored slot number: ", slot); - slot = next_slot; - slot_c = next_slot; + if (errorCode == Neuropixels::VERSION_MISMATCH) + { + LOGC ("Basestation at slot: ", slot, " API VERSION MISMATCH!"); + return false; + } + else if (errorCode == Neuropixels::NO_SLOT) + { + LOGC ("No OneBox found at slot ", slot); + return false; + } + else if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Opening OneBox, error code: ", errorCode); + return false; + } - customPortNames.clear(); - for (int p = 0; p < 4; p++) - { - for (int d = 0; d < 2; d++) - { - customPortNames.add("slot" + String(slot) + "-port" + String(p + 1) + "-" + String(d + 1)); - } - } + if (errorCode == Neuropixels::SUCCESS) + { + getInfo(); - LOGD("Stored slot number: ", slot); + LOGC (" Opened OneBox on slot ", slot); - if (!existing_oneboxes.contains(slot_number)) - { - existing_oneboxes.add(slot_number); - original_slot_number = slot_number; - } - else - { - original_slot_number = -1; - } + LOGD (" Searching for probes..."); -} + searchForProbes(); -OneBox::~OneBox() -{ - /* As of API 3.31, closing a v3 basestation does not turn off the SMA output */ - setSyncAsInput(); - close(); + LOGD (" Found ", probes.size(), probes.size() == 1 ? " probe." : " probes."); - existing_oneboxes.removeFirstMatchingValue(original_slot_number); + dacSource = std::make_unique (this); + adcSource = std::make_unique (this, dacSource.get()); + } -} + setSyncAsInput(); -bool OneBox::open() -{ - - if (original_slot_number == -1) - return false; - - errorCode = Neuropixels::openBS(slot); - - if (errorCode == Neuropixels::VERSION_MISMATCH) - { - LOGD("Basestation at slot: ", slot, " API VERSION MISMATCH!"); - return false; - } - else if (errorCode != Neuropixels::SUCCESS) - { - LOGD("Opening OneBox, error code: ", errorCode); - return false; - } + syncFrequencies.clear(); + syncFrequencies.add (1); - if (errorCode == Neuropixels::SUCCESS) - { - getInfo(); - - LOGC(" Opened OneBox on slot ", slot); - - LOGD(" Searching for probes..."); - - for (int port = 1; port <= 2; port++) - { - bool detected = false; - - errorCode = Neuropixels::detectHeadStage(slot, port, &detected); // check for headstage on port - - if (detected && errorCode == Neuropixels::SUCCESS) - { - - char pn[MAXLEN]; - Neuropixels::readHSPN(slot, port, pn, MAXLEN); - - String hsPartNumber = String(pn); - - LOGDD("Got part #: ", hsPartNumber); - - Headstage* headstage; - - if (hsPartNumber == "NP2_HS_30") // 1.0 headstage, only one dock - { - LOGD(" Found 1.0 single-dock headstage on port: ", port); - headstage = new Headstage1_v3(this, port); - if (headstage->testModule != nullptr) - { - headstage = nullptr; - } - } - else if (hsPartNumber == "NPNH_HS_30" || hsPartNumber == "NPNH_HS_31") // 128-ch analog headstage - { - LOGD(" Found 128-ch analog headstage on port: ", port); - headstage = new Headstage_Analog128(this, port); - } - else if (hsPartNumber == "NPNH_HS_00") // custom 384-ch headstage - { - LOGC(" Found 384-ch custom headstage on port: ", port); - headstage = new Headstage_Custom384(this, port); - } - else if (hsPartNumber == "NPM_HS_30" || hsPartNumber == "NPM_HS_31" || hsPartNumber == "NPM_HS_01") // 2.0 headstage, 2 docks - { - LOGD(" Found 2.0 dual-dock headstage on port: ", port); - headstage = new Headstage2(this, port); - } - else - { - headstage = nullptr; - } - - headstages.add(headstage); - - if (headstage != nullptr) - { - for (auto probe : headstage->probes) - { - if (probe != nullptr) - probes.add(probe); - } - } - - continue; - } - else - { - if (errorCode != Neuropixels::SUCCESS) - { - LOGD("***detectHeadstage failed w/ error code: ", errorCode); - } - else if (!detected) - { - LOGDD(" No headstage detected on port: ", port); - } - - errorCode = Neuropixels::closePort(slot, port); // close port - - headstages.add(nullptr); - } - - - } - - LOGD(" Found ", probes.size(), probes.size() == 1 ? " probe." : " probes."); - - adcSource = new OneBoxADC(this); - dacSource = new OneBoxDAC(this); - - adcSource->dac = dacSource; - dacSource->adc = adcSource; - } + return true; +} - syncFrequencies.add(1); - syncFrequencies.add(10); +void OneBox::searchForProbes() { + + probes.clear(); + headstages.clear(); + + for (int port = 1; port <= 2; port++) + { + bool detected = false; + + errorCode = Neuropixels::detectHeadStage (slot, port, &detected); // check for headstage on port + + if (detected && errorCode == Neuropixels::SUCCESS) + { + char pn[MAXLEN]; + Neuropixels::readHSPN (slot, port, pn, MAXLEN); + + String hsPartNumber = String (pn); + + LOGDD ("Got part #: ", hsPartNumber); + + Headstage* headstage; + + if (hsPartNumber == "NP2_HS_30") // 1.0 headstage, only one dock + { + LOGD (" Found 1.0 single-dock headstage on port: ", port); + headstage = new Headstage1 (this, port); + if (headstage->testModule != nullptr) + { + headstage = nullptr; + } + } + else if (hsPartNumber == "NPNH_HS_30" || hsPartNumber == "NPNH_HS_31") // 128-ch analog headstage + { + LOGD (" Found 128-ch analog headstage on port: ", port); + headstage = new Headstage_Analog128 (this, port); + } + else if (hsPartNumber == "NPNH_HS_00") // custom 384-ch headstage + { + LOGC (" Found 384-ch custom headstage on port: ", port); + headstage = new Headstage_Custom384 (this, port); + } + else if (hsPartNumber == "NPM_HS_30" || hsPartNumber == "NPM_HS_31" || hsPartNumber == "NPM_HS_01") // 2.0 headstage, 2 docks + { + LOGD (" Found 2.0 dual-dock headstage on port: ", port); + headstage = new Headstage2 (this, port); + } + else if (hsPartNumber == "NPM_HS_32") //QuadBase headstage + { + LOGC (" Found 2.0 Phase 2C dual-dock headstage on port: ", port); + headstage = new Headstage_QuadBase (this, port); + } + else + { + headstage = nullptr; + } + + headstages.add (headstage); + + if (headstage != nullptr) + { + for (auto probe : headstage->probes) + { + if (probe != nullptr) + probes.add (probe); + } + } + + continue; + } + else + { + if (errorCode != Neuropixels::SUCCESS) + { + LOGD ("***detectHeadstage failed w/ error code: ", errorCode); + } + else if (! detected) + { + LOGDD (" No headstage detected on port: ", port); + } + + errorCode = Neuropixels::closePort (slot, port); // close port + + headstages.add (nullptr); + } + } - return true; } Array OneBox::getAdditionalDataSources() { - Array sources; - sources.add((DataSource*) adcSource); - //sources.add((DataSource*) dacSource); + Array sources; + sources.add ((DataSource*) adcSource.get()); - return sources; + return sources; } -void OneBox::initialize(bool signalChainIsLoading) +void OneBox::initialize (bool signalChainIsLoading) { - Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_AcquisitionTrigger, Neuropixels::SM_Input_SWTrigger1, true); + LOGD ("Initializing OneBox on slot ", slot); + Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_AcquisitionTrigger, Neuropixels::SM_Input_SWTrigger1, true); - if (!probesInitialized) - { + LOGD ("Initializing probes on slot ", slot); + if (! probesInitialized) + { + for (auto probe : probes) + { + probe->initialize (signalChainIsLoading); + } - for (auto probe : probes) - { - probe->initialize(signalChainIsLoading); - } + probesInitialized = true; + } - probesInitialized = true; - } + LOGD ("Initializing ADC source on slot ", slot); + adcSource->initialize (signalChainIsLoading); - adcSource->initialize(signalChainIsLoading); - - errorCode = Neuropixels::arm(slot); - LOGD("OneBox is armed"); -} + errorCode = checkError(Neuropixels::arm (slot), "arm slot " + String(slot)); + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to arm OneBox on slot ", slot, ", error code = ", errorCode); + } + else + { + LOGC ("OneBox initialized on slot ", slot); + } +} void OneBox::close() { - for (auto probe : probes) - { - errorCode = Neuropixels::closeProbe(slot, probe->headstage->port, probe->dock); - } + LOGD ("Closing OneBox on slot: ", slot); + for (auto probe : probes) + { + checkError (Neuropixels::closeProbe (slot, probe->headstage->port, probe->dock), "closeProbe"); + } + + checkError(Neuropixels::closeBS (slot), "closeBS slot " + String(slot)); - errorCode = Neuropixels::closeBS(slot); - LOGD("Closed basestation on slot: ", slot, " w/ error code: ", errorCode); } void OneBox::setSyncAsInput() { + LOGC ("Setting slot ", slot, " sync as input."); - LOGD("Setting sync as input..."); + errorCode = Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_StatusBit); - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SyncClk, false); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set sync on SMA output on slot: ", slot); - } + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to clear SM_Output_StatusBit on slot ", slot, ", error code = ", errorCode); + } - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SyncClk, false); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set sync on SMA input on slot: ", slot); - } + errorCode = Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_SMA1); - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCMASTER, slot); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot", slot, "as sync master!"); - return; - } + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to clear SM_Output_SMA1 on slot ", slot, ", error code = ", errorCode); + } - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCSOURCE, Neuropixels::SyncSource_SMA); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, "SMA as sync source!"); - } - - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SMA1, true); - if (errorCode != Neuropixels::SUCCESS) - { - LOGD("Failed to set sync on SMA input on slot: ", slot); - } + errorCode = Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SMA1, true); + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to connect SM_Output_StatusBit and SM_Input_SMA1 on slot ", slot, ", error code = ", errorCode); + } } Array OneBox::getSyncFrequencies() { - return syncFrequencies; + return syncFrequencies; } -void OneBox::setSyncAsOutput(int freqIndex) +void OneBox::setSyncAsOutput (int freqIndex) { + LOGC ("Setting slot ", slot, " sync as output."); + + errorCode = Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_StatusBit); + + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to clear SM_Output_StatusBit on slot ", slot, ", error code = ", errorCode); + } + + errorCode = Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_SMA1); + + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to clear SM_Output_SMA1 on slot ", slot, ", error code = ", errorCode); + } + + errorCode = Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SyncClk, true); + + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to connect SM_Output_StatusBit and SM_Input_SyncClk on slot ", slot, ", error code = ", errorCode); + } + + errorCode = Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_SMA1, Neuropixels::SM_Input_SyncClk, true); + + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to connect SM_Output_SMA1 and SM_Input_SyncClk on slot ", slot, ", error code = ", errorCode); + } + + errorCode = Neuropixels::setSyncClockFrequency (slot, syncFrequencies[freqIndex]); + + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to set SyncClockFrequency slot ", slot, ", error code = ", errorCode); + } +} - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCMASTER, slot); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, " as sync master!"); - return; - } - - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCSOURCE, Neuropixels::SyncSource_Clock); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, " internal clock as sync source!"); - return; - } - - int freq = syncFrequencies[freqIndex]; - - LOGD("Setting slot ", slot, " sync frequency to ", freq, " Hz..."); - errorCode = Neuropixels::setParameter(Neuropixels::NP_PARAM_SYNCFREQUENCY_HZ, freq); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set slot ", slot, " sync frequency to ", freq, " Hz!"); - return; - } - - LOGD("Setting sync as output..."); - - errorCode = Neuropixels::switchmatrix_set(slot, Neuropixels::SM_Output_SMA1, Neuropixels::SM_Input_SyncClk, true); - if (errorCode != Neuropixels::SUCCESS) - { - LOGC("Failed to set sync on SMA output on slot: ", slot); - } - +void OneBox::setSyncAsPassive() +{ } int OneBox::getProbeCount() { - return probes.size(); + return probes.size(); } float OneBox::getFillPercentage() { - float perc = 0.0; + float perc = 0.0; - for (int i = 0; i < getProbeCount(); i++) - { - LOGDD("Percentage for probe ", i, ": ", probes[i]->fifoFillPercentage); + for (int i = 0; i < getProbeCount(); i++) + { - if (probes[i]->fifoFillPercentage > perc) - perc = probes[i]->fifoFillPercentage; - } + if (probes[i]->fifoFillPercentage > perc) + perc = probes[i]->fifoFillPercentage; + } - return perc; + return perc; } -void OneBox::triggerWaveplayer(bool shouldStart) +void OneBox::triggerWaveplayer (bool shouldStart) { - - if (shouldStart) - { - LOGD("OneBox starting waveplayer."); - dacSource->playWaveform(); - } - else - { - LOGD("OneBox stopping waveplayer."); - dacSource->stopWaveform(); - } - + if (shouldStart) + { + LOGD ("OneBox starting waveplayer."); + dacSource->playWaveform(); + } + else + { + LOGD ("OneBox stopping waveplayer."); + dacSource->stopWaveform(); + } } void OneBox::startAcquisition() { - for (auto probe : probes) - { - probe->startAcquisition(); - } + for (auto probe : probes) + { + if (probe->isEnabled) + probe->startAcquisition(); + } - adcSource->startAcquisition(); + adcSource->startAcquisition(); - LOGD("OneBox software trigger"); - errorCode = Neuropixels::setSWTrigger(slot); + errorCode = Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_AcquisitionTrigger, Neuropixels::SM_Input_SWTrigger1, true); + LOGD ("OneBox software trigger"); + checkError (Neuropixels::setSWTrigger (slot), "setSWTrigger slot " + String (slot)); + checkError (Neuropixels::arm (slot), "arm slot " + String (slot)); + checkError(Neuropixels::setSWTrigger (slot)); + + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to set SWTrigger slot ", slot, ", error code = ", errorCode); + } } void OneBox::stopAcquisition() { - for (auto probe : probes) - { - probe->stopAcquisition(); - } + for (auto probe : probes) + { + if (probe->isEnabled) + probe->stopAcquisition(); + } - adcSource->stopAcquisition(); + adcSource->stopAcquisition(); - errorCode = Neuropixels::arm(slot); + errorCode = Neuropixels::arm (slot); } - diff --git a/Source/Basestations/OneBox.h b/Source/Basestations/OneBox.h index 5e42b39..dcc60de 100644 --- a/Source/Basestations/OneBox.h +++ b/Source/Basestations/OneBox.h @@ -1,33 +1,32 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2021 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #ifndef __ONEBOX_H_2C4C2D67__ #define __ONEBOX_H_2C4C2D67__ -#include "../API/v3/NeuropixAPI.h" #include "../NeuropixComponents.h" -# define SAMPLECOUNT 64 +#define SAMPLECOUNT 64 class OneBoxADC; class OneBoxDAC; @@ -39,63 +38,64 @@ class OneBox : public Basestation { public: + /** Constructor */ + OneBox (NeuropixThread*, int serial_number); - /** Constructor */ - OneBox(NeuropixThread*, int ID); + /** Destructor */ + ~OneBox(); - /** Destructor */ - ~OneBox(); + /** Opens connection to OneBox */ + bool open() override; - /** Opens connection to OneBox */ - bool open() override; + /** Closes connection to OneBox */ + void close() override; - /** Closes connection to OneBox */ - void close() override; + /** Initializes in a separate thread*/ + void initialize (bool signalChainIsLoading) override; - /** Initializes in a separate thread*/ - void initialize(bool signalChainIsLoading) override; + /** Search for probes connected to OneBox */ + void searchForProbes() override; - /** Returns the total number of connected probes */ - int getProbeCount() override; + /** Returns the total number of connected probes */ + int getProbeCount() override; - /** Gets info about this device */ - void getInfo() override; + /** Gets info about this device */ + void getInfo() override; - /** Sets the SMA port to input mode */ - void setSyncAsInput() override; + /** Sets the SMA port to input mode */ + void setSyncAsInput() override; - /** Sets the SMA port to output mode */ - void setSyncAsOutput(int freqIndex) override; + /** Sets the SMA port to output mode */ + void setSyncAsOutput (int freqIndex) override; - /** Returns the available sync frequencies*/ - Array getSyncFrequencies() override; + /** Sets the OneBox as passive input (does nothing) */ + void setSyncAsPassive() override; - /** Starts acquisition on all probes */ - void startAcquisition() override; + /** Returns the available sync frequencies*/ + Array getSyncFrequencies() override; - /** Stops acquisition on all probes */ - void stopAcquisition() override; + /** Starts acquisition on all probes */ + void startAcquisition() override; - /** Gets fill percentage of OneBox FIFO buffer */ - float getFillPercentage() override; + /** Stops acquisition on all probes */ + void stopAcquisition() override; - /** Returns any non-probe data sources (e.g. ADCs)*/ - Array getAdditionalDataSources() override; + /** Gets fill percentage of OneBox FIFO buffer */ + float getFillPercentage() override; - /** Triggers the Waveplayer output */ - void triggerWaveplayer(bool shouldStart); + /** Returns any non-probe data sources (e.g. ADCs)*/ + Array getAdditionalDataSources() override; - Neuropixels::NP_ErrorCode errorCode; + /** Triggers the Waveplayer output */ + void triggerWaveplayer (bool shouldStart); - static Array existing_oneboxes; - int original_slot_number; + static Array existing_oneboxes; + int serial_number = -1; - const int first_available_slot = 16; - - ScopedPointer adcSource; - ScopedPointer dacSource; + const int first_available_slot = 16; + std::unique_ptr adcSource; + std::unique_ptr dacSource; }; - -#endif // __ONEBOX_H_2C4C2D67__ \ No newline at end of file +#endif // __ONEBOX_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Basestations/PxiBasestation.cpp b/Source/Basestations/PxiBasestation.cpp new file mode 100644 index 0000000..04fc9fb --- /dev/null +++ b/Source/Basestations/PxiBasestation.cpp @@ -0,0 +1,549 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + +#include "PxiBasestation.h" +#include "../Headstages/Headstage1.h" +#include "../Headstages/Headstage2.h" +#include "../Headstages/Headstage_Analog128.h" +#include "../Headstages/Headstage_Custom384.h" +#include "../Headstages/Headstage_QuadBase.h" +#include "../Probes/Neuropixels1.h" + +#define MAXLEN 50 + +Array PxiBasestation::connected_slots = Array(); + +void PxiBasestation::getInfo() +{ + Neuropixels::firmware_Info firmwareInfo; + + Neuropixels::bs_getFirmwareInfo (slot, &firmwareInfo); + + info.boot_version = String (firmwareInfo.major) + "." + String (firmwareInfo.minor) + String (firmwareInfo.build); + + info.part_number = String (firmwareInfo.name); +} + +void BasestationConnectBoard_v3::getInfo() +{ + int version_major; + int version_minor; + + errorCode = Neuropixels::getBSCVersion (basestation->slot, &version_major, &version_minor); + + info.version = String (version_major) + "." + String (version_minor); + + errorCode = Neuropixels::readBSCSN (basestation->slot, &info.serial_number); + + char pn[MAXLEN]; + Neuropixels::readBSCPN (basestation->slot, pn, MAXLEN); + + info.part_number = String (pn); + + Neuropixels::firmware_Info firmwareInfo; + Neuropixels::bsc_getFirmwareInfo (basestation->slot, &firmwareInfo); + info.boot_version = String (firmwareInfo.major) + "." + String (firmwareInfo.minor) + String (firmwareInfo.build); +} + +BasestationConnectBoard_v3::BasestationConnectBoard_v3 (Basestation* bs) : BasestationConnectBoard (bs) +{ + getInfo(); +} + +PxiBasestation::PxiBasestation (NeuropixThread* neuropixThread, int slot_number) : Basestation (neuropixThread, slot_number) +{ + type = BasestationType::PXI; + + armBasestation = std::make_unique (slot_number); + + getInfo(); +} + +ThreadPoolJob::JobStatus PortChecker::runJob() +{ + bool detected = false; + + Neuropixels::NP_ErrorCode errorCode = Neuropixels::openPort (slot, port); + + errorCode = Neuropixels::detectHeadStage (slot, port, &detected); // check for headstage on port + + if (detected && errorCode == Neuropixels::SUCCESS) + { + char pn[MAXLEN]; + Neuropixels::readHSPN (slot, port, pn, MAXLEN); + + String hsPartNumber = String (pn); + + LOGC ("Port ", port, " HS part #: ", hsPartNumber); + + if (hsPartNumber == "NP2_HS_30" || hsPartNumber == "OPTO_HS_00") // 1.0 headstage, only one dock + { + LOGC (" Found 1.0 single-dock headstage on port: ", port); + headstage = new Headstage1 (basestation, port); + if (headstage->testModule != nullptr || ! headstage->probes.size()) + { + headstage = nullptr; + } + } + else if (hsPartNumber == "NPNH_HS_30" || hsPartNumber == "NPNH_HS_31") // 128-ch analog headstage + { + LOGC (" Found 128-ch analog headstage on port: ", port); + headstage = new Headstage_Analog128 (basestation, port); + } + else if (hsPartNumber == "NPNH_HS_00") // custom 384-ch headstage + { + LOGC (" Found 384-ch custom headstage on port: ", port); + headstage = new Headstage_Custom384 (basestation, port); + } + else if (hsPartNumber == "NPM_HS_30" || hsPartNumber == "NPM_HS_31" || hsPartNumber == "NPM_HS_01") // 2.0 headstage, 2 docks + { + LOGC (" Found 2.0 dual-dock headstage on port: ", port); + headstage = new Headstage2 (basestation, port); + } + else if (hsPartNumber == "NPM_HS_32") //QuadBase headstage + { + LOGC (" Found 2.0 Phase 2C dual-dock headstage on port: ", port); + headstage = new Headstage_QuadBase (basestation, port); + } + else + { + headstage = nullptr; + } + } + else + { + if (errorCode != Neuropixels::SUCCESS) + { + LOGC (" Error opening port ", port, ": ", errorCode); + } + else + { + LOGC (" No headstage detected on port: ", port); + } + + errorCode = Neuropixels::closePort (slot, port); // close port + + headstage = nullptr; + } + + return jobHasFinished; +} + +bool PxiBasestation::open() +{ + syncFrequencies.clear(); + syncFrequencies.add (1); + + if (connected_slots.contains(slot)) + { + LOGC ("Slot ", slot, " already connected."); + return false; + } + + errorCode = Neuropixels::openBS (slot); + + if (errorCode == Neuropixels::VERSION_MISMATCH) + { + LOGC ("Basestation at slot: ", slot, " API VERSION MISMATCH!"); + return false; + } + + if (errorCode == Neuropixels::SUCCESS) + { + LOGC (" Opened BS on slot ", slot); + + connected_slots.add (slot); + + basestationConnectBoard = std::make_unique (this); + + //Confirm v3 basestation by BS version 2.0 or greater. + LOGC (" BS firmware: ", info.boot_version); + if (std::stod ((info.boot_version.toStdString())) < 2.0) + return false; + + invertOutput = false; + + if (! info.boot_version.equalsIgnoreCase (BS_FIRMWARE_VERSION)) + { + LOGC ("Found basestation firmware version ", info.boot_version); + LOGC ("Required version is ", BS_FIRMWARE_VERSION); + + return true; + } + + if (! basestationConnectBoard->info.boot_version.equalsIgnoreCase (BSC_FIRMWARE_VERSION)) + { + LOGC ("Found basestation connect board firmware version ", basestationConnectBoard->info.boot_version); + LOGC ("Required version is ", BSC_FIRMWARE_VERSION); + + return true; + } + + LOGC (" Searching for probes..."); + + probes.clear(); + searchForProbes(); + + LOGC (" Found ", probes.size(), probes.size() == 1 ? " probe " : " probes on slot ", slot); + } + + //LOGC("Initial switchmatrix status:"); + //print_switchmatrix(); + + return true; +} + +void PxiBasestation::searchForProbes() +{ + ThreadPool threadPool; + OwnedArray portCheckers; + + for (int port = 1; port <= 4; port++) + { + if (type == BasestationType::OPTO && port > 2) + break; + + bool detected = false; + + portCheckers.add (new PortChecker (slot, port, this)); + threadPool.addJob (portCheckers.getLast(), false); + } + + while (threadPool.getNumJobs() > 0) + std::this_thread::sleep_for (std::chrono::milliseconds (100)); + + int portIndex = 0; + + headstages.clear(); + + for (auto portChecker : portCheckers) + { + headstages.add (portChecker->headstage); + + if (portChecker->headstage != nullptr) + { + for (auto probe : portChecker->headstage->probes) + { + if (probe != nullptr) + { + //check if probe serial number already exists + probes.add (probe); + + if (probe->info.part_number.equalsIgnoreCase ("NP1300")) + type = BasestationType::OPTO; + } + } + } + } +} + +void PxiBasestation::initialize (bool signalChainIsLoading) +{ + if (! probesInitialized) + { + for (auto probe : probes) + { + probe->initialize (signalChainIsLoading); + } + + probesInitialized = true; + } + + LOGD ("Arming basestation"); + Neuropixels::arm (slot); + LOGD ("Arming complete"); + +} + +void PxiBasestation::print_switchmatrix() +{ + bool isConnected; + + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_PXISYNC, &isConnected); + LOGC ("Slot ", slot, " connection between StatusBit and PXISYNC: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SMA, &isConnected); + LOGC ("Slot ", slot, " connection between StatusBit and SMA: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SyncClk, &isConnected); + LOGC ("Slot ", slot, " connection between StatusBit and SyncClk: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_None, &isConnected); + LOGC ("Slot ", slot, " connection between StatusBit and None: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_TimeStampClk, &isConnected); + LOGC ("Slot ", slot, " connection between StatusBit and TimestampClk: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SMA1, &isConnected); + LOGC ("Slot ", slot, " connection between StatusBit and SMA1: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SWTrigger1, &isConnected); + LOGC ("Slot ", slot, " connection between StatusBit and SWTrigger1: ", isConnected); + + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_PXISYNC, &isConnected); + LOGC ("Slot ", slot, " connection between PXISYNC and PXISYNC: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_SMA, &isConnected); + LOGC ("Slot ", slot, " connection between PXISYNC and SMA: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_SyncClk, &isConnected); + LOGC ("Slot ", slot, " connection between PXISYNC and SyncClk: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_None, &isConnected); + LOGC ("Slot ", slot, " connection between PXISYNC and None: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_TimeStampClk, &isConnected); + LOGC ("Slot ", slot, " connection between PXISYNC and TimestampClk: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_SMA1, &isConnected); + LOGC ("Slot ", slot, " connection between PXISYNC and SMA1: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_SWTrigger1, &isConnected); + LOGC ("Slot ", slot, " connection between PXISYNC and SWTrigger1: ", isConnected); + + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_PXISYNC, &isConnected); + LOGC ("Slot ", slot, " connection between SMA and PXISYNC: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SMA, &isConnected); + LOGC ("Slot ", slot, " connection between SMA and SMA: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SyncClk, &isConnected); + LOGC ("Slot ", slot, " connection between SMA and SyncClk: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_None, &isConnected); + LOGC ("Slot ", slot, " connection between SMA and None: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_TimeStampClk, &isConnected); + LOGC ("Slot ", slot, " connection between SMA and TimestampClk: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SMA1, &isConnected); + LOGC ("Slot ", slot, " connection between SMA and SMA1: ", isConnected); + Neuropixels::switchmatrix_get (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SWTrigger1, &isConnected); + LOGC ("Slot ", slot, " connection between SMA and SWTrigger1: ", isConnected); +} + +PxiBasestation::~PxiBasestation() +{ + /* As of API 3.31, closing a v3 basestation does not turn off the SMA output */ + setSyncAsPassive(); + + close(); + +} + +void PxiBasestation::close() +{ + for (auto probe : probes) + { + try + { + errorCode = Neuropixels::closeBS (slot); + LOGC (" Closing probe ", probe->info.serial_number, " on slot ", slot, " w/ error code: ", errorCode); + } + catch (std::exception& e) + { + LOGC ("Error closing probe: ", e.what()); + } + } + probes.clear(); + headstages.clear(); + + errorCode = Neuropixels::closeBS (slot); + + connected_slots.removeFirstMatchingValue (slot); + + LOGC ("Closed basestation on slot: ", slot, " w/ error code: ", errorCode); +} + +void PxiBasestation::checkFirmwareVersion() +{ + if (! info.boot_version.equalsIgnoreCase (BS_FIRMWARE_VERSION)) + { + LOGC ("Found basestation firmware version ", info.boot_version); + + // show popup notification window + String message = "The basestation on slot " + String (slot) + " has firmware version " + info.boot_version; + message += ", but version " + String (BS_FIRMWARE_VERSION) + " is required for this plugin. "; + message += "This is contained in the file named " + String (BS_FIRMWARE_FILENAME) + ". "; + message += "Please see the Neuropixels PXI page on the Open Ephys GUI documentation site for information on how to perform a firmware update. "; + + AlertWindow::showMessageBox (AlertWindow::AlertIconType::WarningIcon, "Outdated basestation firmware on slot " + String (slot), message, "OK"); + } + + if (! basestationConnectBoard->info.boot_version.equalsIgnoreCase (BSC_FIRMWARE_VERSION)) + { + LOGC ("Found basestation connect board firmware version ", basestationConnectBoard->info.boot_version); + + // show popup notification window + String message = "The basestation on slot " + String (slot) + " has basestation firmware version " + basestationConnectBoard->info.boot_version; + message += ", but version " + String (BSC_FIRMWARE_VERSION) + " is required for this plugin. "; + message += "This is contained in the file named " + String (BSC_FIRMWARE_FILENAME) + ". "; + message += "Please see the Neuropixels PXI page on the Open Ephys GUI documentation site for information on how to perform a firmware update."; + + AlertWindow::showMessageBox (AlertWindow::AlertIconType::WarningIcon, "Outdated basestation connect board firmware on slot " + String (slot), message, "OK"); + } +} + +bool PxiBasestation::isBusy() +{ + return armBasestation->isThreadRunning(); +} + +void PxiBasestation::waitForThreadToExit() +{ + armBasestation->waitForThreadToExit (25000); +} + +void PxiBasestation::setSyncAsPassive() +{ + LOGC ("Setting slot ", slot, " sync as passive."); + + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_StatusBit), "switchmatrix_clear SM_Output_StatusBit"); + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_SMA), "switchmatrix_clear SM_Output_SMA"); + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_PXISYNC), "switchmatrix_clear SM_Output_PXISYNC"); + + checkError (Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_PXISYNC, true), "switchmatrix_set SM_Input_PXISYNC --> SM_Output_StatusBit"); + checkError (Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_PXISYNC, true), "switchmatrix_set SM_Input_PXISYNC --> SM_Output_SMA"); + + if (invertOutput) + { + for (auto probe : probes) + { + probe->invertSyncLine = true; + } + } + + //print_switchmatrix(); +} + +void PxiBasestation::setSyncAsInput() +{ + LOGC ("Setting slot ", slot, " sync as input."); + + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_StatusBit), "switchmatrix_clear SM_Output_StatusBit"); + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_SMA), "switchmatrix_clear SM_Output_SMA"); + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_PXISYNC), "switchmatrix_clear SM_Output_PXISYNC"); + + checkError (Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SMASYNC, true), "switchmatrix_set SM_Input_SMA --> SM_Output_StatusBit"); + checkError (Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_SMASYNC, true), "switchmatrix_set SM_Input_SMA --> SM_Output_PXISYNC"); + + //print_switchmatrix(); +} + +Array PxiBasestation::getSyncFrequencies() +{ + return syncFrequencies; +} + +void PxiBasestation::setSyncAsOutput (int freqIndex) +{ + LOGC ("Setting slot ", slot, " sync as output."); + + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_StatusBit), "switchmatrix_clear SM_Output_StatusBit"); + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_SMA), "switchmatrix_clear SM_Output_SMA"); + checkError (Neuropixels::switchmatrix_clear (slot, Neuropixels::SM_Output_PXISYNC), "switchmatrix_clear SM_Output_PXISYNC"); + + checkError (Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_StatusBit, Neuropixels::SM_Input_SyncClk, true), "switchmatrix_set SM_Input_SyncClk --> SM_Output_StatusBit"); + checkError (Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_PXISYNC, Neuropixels::SM_Input_SyncClk, true), "switchmatrix_set SM_Input_SyncClk --> SM_Output_PXISYNC"); + checkError (Neuropixels::switchmatrix_set (slot, Neuropixels::SM_Output_SMA, Neuropixels::SM_Input_SyncClk, true), "switchmatrix_set SM_Input_SyncClk --> SM_Output_SMA"); + + errorCode = checkError(Neuropixels::setSyncClockFrequency (slot, syncFrequencies[freqIndex]), "setSyncClockFrequency"); + + if (errorCode != Neuropixels::SUCCESS) + { + LOGC ("Failed to set sync on SMA output on slot: ", slot); + } + + //print_switchmatrix(); +} + +int PxiBasestation::getProbeCount() +{ + return probes.size(); +} + +float PxiBasestation::getFillPercentage() +{ + if (neuropixThread->isRefreshing) + return 0.0; + + float perc = 0.0; + + for (int i = 0; i < getProbeCount(); i++) + { + //LOGDD("Percentage for probe ", i, ": ", probes[i]->fifoFillPercentage); + + if (probes[i]->fifoFillPercentage > perc) + perc = probes[i]->fifoFillPercentage; + } + + return perc; +} + +void PxiBasestation::startAcquisition() +{ + if (armBasestation->isThreadRunning()) + armBasestation->waitForThreadToExit (25000); + + for (auto probe : probes) + { + if (probe->isEnabled) + probe->startAcquisition(); + } + + errorCode = Neuropixels::setSWTrigger (slot); +} + +void PxiBasestation::stopAcquisition() +{ + LOGC ("Basestation stopping acquisition."); + + for (auto probe : probes) + { + if (probe->isEnabled) + probe->stopAcquisition(); + } + + armBasestation->startThread(); +} + +void PxiBasestation::selectEmissionSite (int port, int dock, String wavelength, int site) +{ + if (type == BasestationType::OPTO) + { + LOGD ("Opto basestation on slot ", slot, " selecting emission site on port ", port, ", dock ", dock); + + Neuropixels::wavelength_t wv; + + if (wavelength.equalsIgnoreCase ("red")) + { + wv = Neuropixels::wavelength_red; + } + else if (wavelength.equalsIgnoreCase ("blue")) + { + wv = Neuropixels::wavelength_blue; + } + else + { + LOGD ("Wavelength not recognized. No emission site selected."); + return; + } + + if (site < -1 || site > 13) + { + LOGD (site, ": invalid site number."); + return; + } + + errorCode = Neuropixels::setEmissionSite (slot, port, dock, wv, site); + + LOGD (wavelength, " site ", site, " selected with error code ", errorCode); + + errorCode = Neuropixels::getEmissionSite (slot, port, dock, wv, &site); + + LOGD (wavelength, " actual site: ", site, " selected with error code ", errorCode); + } +} diff --git a/Source/Basestations/PxiBasestation.h b/Source/Basestations/PxiBasestation.h new file mode 100644 index 0000000..4977a93 --- /dev/null +++ b/Source/Basestations/PxiBasestation.h @@ -0,0 +1,184 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + +#ifndef __NEUROPIXBASESTATIONV3_H_2C4C2D67__ +#define __NEUROPIXBASESTATIONV3_H_2C4C2D67__ + +#include "../NeuropixComponents.h" +#include "../NeuropixThread.h" + +#define SAMPLECOUNT 64 + +#define BS_FIRMWARE_VERSION "2.0169" +#define BSC_FIRMWARE_VERSION "3.2191" +#define BS_FIRMWARE_FILENAME "BS_FPGA_B169.bin" +#define BSC_FIRMWARE_FILENAME "QBSC_FPGA_B191.bin" + +/* +* + Thread for arming basestation immediately after acquisition + ends. This takes a few seconds, so we should do it in a thread + so acquisition stops promptly. + +*/ + +class PxiBasestation; + +class PortChecker : public ThreadPoolJob +{ +public: + PortChecker (int slot_, int port_, Basestation* basestation_) : ThreadPoolJob ("Port checker for " + String (slot_) + ":" + String (port_)), + slot (slot_), + port (port_), + basestation (basestation_), + headstage (nullptr) {} + + ~PortChecker() + { + signalJobShouldExit(); + } + + JobStatus runJob(); + + Headstage* headstage; + +private: + int slot; + int port; + Basestation* basestation; +}; + +class ArmBasestation : public Thread +{ +public: + ArmBasestation (int slot_) : Thread ("Arm Basestation in Slot " + String (slot)), + slot (slot_) {} + + ~ArmBasestation() + { + stopThread (2000); + } + + void run() + { + LOGC ("Arming PXI slot ", slot, "..."); + Neuropixels::arm (slot); + LOGC ("Arming complete."); + } + +private: + int slot; +}; + +/* + + Standard Neuropixels PXI basestation + running v3 firmware. + +*/ +class PxiBasestation : public Basestation + +{ +public: + /** Constructor */ + PxiBasestation (NeuropixThread*, int slot); + + /** Destructor */ + ~PxiBasestation(); + + /** Opens connection to the basestation */ + bool open() override; + + /** Closes connection to the basestation */ + void close() override; + + /** Initializes probes in a background thread */ + void initialize (bool signalChainIsLoading) override; + + /** Searches for probes connected to this basestation */ + void searchForProbes() override; + + /** Returns the total number of probes connected to this basestation*/ + int getProbeCount() override; + + /** Gets part number, firmware version, etc.*/ + void getInfo() override; + + /** Set basestation SMA connector as input*/ + void setSyncAsInput() override; + + /** Set basestation SMA connector as output (and set frequency)*/ + void setSyncAsOutput (int freqIndex) override; + + /** Set basestation SMA connector to inherit signal from PXI backplane */ + void setSyncAsPassive() override; + + /** Returns an array of available frequencies when SMA is in "output" mode */ + Array getSyncFrequencies() override; + + /** Starts probe data streaming */ + void startAcquisition() override; + + /** Stops probe data streaming*/ + void stopAcquisition() override; + + /** Returns the fraction of the basestation FIFO that is filled */ + float getFillPercentage() override; + + /** Activates a probe emission site (only works for Opto probes) */ + void selectEmissionSite (int port, int dock, String wavelength, int site); + + /** Returns true if the arm basestation thread is running */ + bool isBusy() override; + + /** Waits for the arm basestation thread to exit */ + void waitForThreadToExit() override; + + /** Checks for firmware compatibility with API version */ + void checkFirmwareVersion() override; + + /** Holds list of connected PXI slots */ + static Array connected_slots; + +private: + void print_switchmatrix(); + + std::unique_ptr armBasestation; + + bool invertOutput; +}; + +class BasestationConnectBoard_v3 : public BasestationConnectBoard +{ +public: + /** Constructor */ + BasestationConnectBoard_v3 (Basestation*); + + /** Returns part number, firmware version, etc.*/ + void getInfo() override; + +private: + Neuropixels::NP_ErrorCode errorCode; +}; + +#endif // __NEUROPIXBASESTATIONV3_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Basestations/SimulatedBasestation.cpp b/Source/Basestations/SimulatedBasestation.cpp index 2bad7d1..0e7e017 100644 --- a/Source/Basestations/SimulatedBasestation.cpp +++ b/Source/Basestations/SimulatedBasestation.cpp @@ -1,260 +1,255 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "SimulatedBasestation.h" -#include "../Probes/SimulatedProbe.h" #include "../Headstages/SimulatedHeadstage.h" +#include "../Probes/SimulatedProbe.h" -SimulatedBasestationConfigWindow::SimulatedBasestationConfigWindow(SimulatedBasestation* bs_) - : bs(bs_) +SimulatedBasestationConfigWindow::SimulatedBasestationConfigWindow (SimulatedBasestation* bs_) + : bs (bs_) { - - for (int i = 0; i < bs->headstage_count; i++) - { - ComboBox* comboBox = new ComboBox("Port " + String(i) + " Combo Box"); - - comboBox->addItem("Empty", (int) ProbeType::NONE); - comboBox->addItem("Neuropixels 1.0", (int) ProbeType::NP1); - comboBox->addItem("Neuropixels NHP (45 mm)", (int)ProbeType::NHP45); - comboBox->addItem("Neuropixels UHD - Active", (int)ProbeType::UHD2); - comboBox->addItem("Neuropixels 2.0 1-shank", (int)ProbeType::NP2_1); - comboBox->addItem("Neuropixels 2.0 4-shank", (int)ProbeType::NP2_4); - comboBox->addItem("Neuropixels Opto", (int) ProbeType::OPTO); - - if (i == 0) - comboBox->setSelectedId((int)ProbeType::NP1, dontSendNotification); - else - comboBox->setSelectedId((int)ProbeType::NONE, dontSendNotification); - - portComboBoxes.add(comboBox); - addAndMakeVisible(comboBox); - comboBox->setBounds(65, 50 + 35 * i, 200, 20); - } - - acceptButton = std::make_unique("LAUNCH", Font("Small Text", 13, Font::plain)); - acceptButton->setBounds(120, 200, 80, 20); - acceptButton->addListener(this); - addAndMakeVisible(acceptButton.get()); + for (int i = 0; i < bs->headstage_count; i++) + { + ComboBox* comboBox = new ComboBox ("Port " + String (i) + " Combo Box"); + + comboBox->addItem ("Empty", (int) ProbeType::NONE); + comboBox->addItem ("Neuropixels 1.0", (int) ProbeType::NP1); + comboBox->addItem ("Neuropixels NHP (45 mm)", (int) ProbeType::NHP45); + comboBox->addItem ("Neuropixels UHD - Active", (int) ProbeType::UHD2); + comboBox->addItem ("Neuropixels 2.0 1-shank", (int) ProbeType::NP2_1); + comboBox->addItem ("Neuropixels 2.0 4-shank", (int) ProbeType::NP2_4); + comboBox->addItem ("Neuropixels Opto", (int) ProbeType::OPTO); + + comboBox->setSelectedId ((int) bs->simulatedProbeTypes[i], dontSendNotification); + + portComboBoxes.add (comboBox); + addAndMakeVisible (comboBox); + comboBox->setBounds (65, 50 + 35 * i, 200, 20); + } + + acceptButton = std::make_unique ("LAUNCH", Font ("Small Text", 13, Font::plain)); + acceptButton->setBounds (120, 200, 80, 20); + acceptButton->addListener (this); + addAndMakeVisible (acceptButton.get()); } -void SimulatedBasestationConfigWindow::paint(Graphics& g) +void SimulatedBasestationConfigWindow::paint (Graphics& g) { - g.setColour(Colours::lightgrey); + g.setColour (Colours::lightgrey); - g.drawText("PORT", 22, 22, 50, 25, Justification::centred); - g.drawText("PROBE TYPE", 62, 22, 200, 20, Justification::centred); + g.drawText ("PORT", 22, 22, 50, 25, Justification::centred); + g.drawText ("PROBE TYPE", 62, 22, 200, 20, Justification::centred); - for (int port_index = 0; port_index < bs->headstage_count; port_index++) - { - g.drawText(String(port_index + 1), 25, 50 + 35 * port_index, 25, 20, Justification::right); - } + for (int port_index = 0; port_index < bs->headstage_count; port_index++) + { + g.drawText (String (port_index + 1), 25, 50 + 35 * port_index, 25, 20, Justification::right); + } } -void SimulatedBasestationConfigWindow::buttonClicked(Button* button) +void SimulatedBasestationConfigWindow::buttonClicked (Button* button) { + for (int i = 0; i < bs->headstage_count; i++) + bs->simulatedProbeTypes[i] = (ProbeType) portComboBoxes[i]->getSelectedId(); - for (int i = 0; i < bs->headstage_count; i++) - bs->simulatedProbeTypes[i] = (ProbeType)portComboBoxes[i]->getSelectedId(); - - if (DialogWindow* dw = findParentComponentOfClass()) - dw->exitModalState(0); + if (DialogWindow* dw = findParentComponentOfClass()) + dw->exitModalState (0); } void SimulatedBasestationConnectBoard::getInfo() { - info.boot_version = "SIM 0.0"; - info.version = "SIM 0.0"; - info.part_number = "Simulated BSC"; + info.boot_version = "SIM 0.0"; + info.version = "SIM 0.0"; + info.part_number = "Simulated BSC"; } - void SimulatedBasestation::getInfo() { - info.boot_version = "SIM 0.0"; - info.version = "SIM 0.0"; - info.part_number = "Simulated BS"; + info.boot_version = "SIM 0.0"; + info.version = "SIM 0.0"; + info.part_number = "Simulated BS"; } /// ########################################### -SimulatedBasestation::SimulatedBasestation(NeuropixThread* neuropixThread, - DeviceType deviceType, - int slot_number) : Basestation(neuropixThread, slot_number) +SimulatedBasestation::SimulatedBasestation (NeuropixThread* neuropixThread, + DeviceType deviceType, + int slot_number) : Basestation (neuropixThread, slot_number) { - - type = BasestationType::SIMULATED; - - if (deviceType == PXI) - headstage_count = 4; - else - headstage_count = 2; - - simulatedProbeTypes[0] = ProbeType::NP1; - simulatedProbeTypes[1] = ProbeType::NONE; - simulatedProbeTypes[2] = ProbeType::NONE; - simulatedProbeTypes[3] = ProbeType::NONE; - - DialogWindow::LaunchOptions options; - - configComponent = std::make_unique(this); - options.content.setOwned(configComponent.get()); - configComponent.release(); - - options.content->setSize(320, 250); + type = BasestationType::SIMULATED; - options.dialogTitle = "Configure basestation"; - options.dialogBackgroundColour = Colours::darkgrey; - options.escapeKeyTriggersCloseButton = true; - options.useNativeTitleBar = false; - options.resizable = false; + if (deviceType == PXI) + headstage_count = 4; + else + headstage_count = 2; - int result = options.runModal(); + simulatedProbeTypes[0] = ProbeType::NP1; + simulatedProbeTypes[1] = ProbeType::NONE; + simulatedProbeTypes[2] = ProbeType::NONE; + simulatedProbeTypes[3] = ProbeType::NONE; - getInfo(); + getInfo(); } bool SimulatedBasestation::open() { - savingDirectory = File(); - - basestationConnectBoard = new SimulatedBasestationConnectBoard(this); - basestationConnectBoard->getInfo(); - - for (int i = 0; i < headstage_count; i++) - { - switch (simulatedProbeTypes[i]) - { - case ProbeType::NONE: - headstages.add(nullptr); - break; - case ProbeType::NP1: - headstages.add(new SimulatedHeadstage(this, i + 1, "PRB_1_4_0480_1", 28948291 + i)); - break; - case ProbeType::NHP45: - headstages.add(new SimulatedHeadstage(this, i + 1, "NP1031", 38948291 + i)); - break; - case ProbeType::UHD1: - headstages.add(new SimulatedHeadstage(this, i + 1, "NP1100", 48948291 + i)); - break; - case ProbeType::UHD2: - headstages.add(new SimulatedHeadstage(this, i + 1, "NP1110", 48948211 + i)); - break; - case ProbeType::NP2_1: - headstages.add(new SimulatedHeadstage(this, i + 1, "NP2000", 58948291 + i)); - break; - case ProbeType::NP2_4: - headstages.add(new SimulatedHeadstage(this, i + 1, "NP2010", 68948291 + i)); - break; - case ProbeType::OPTO: - headstages.add(new SimulatedHeadstage(this, i + 1, "NP1300", 78948291 + i)); - break; - default: - headstages.add(new SimulatedHeadstage(this, i + 1, "PRB_1_4_0480_1", 28948291 + i)); - } - } - - for (auto headstage : headstages) - { - if (headstage != nullptr) - { - probes.add(headstage->getProbes()[0]); - } - } - - LOGD(probes.size(), " total probes "); - - syncFrequencies.add(1); - syncFrequencies.add(10); - - return true; + DialogWindow::LaunchOptions options; + + configComponent = std::make_unique (this); + options.content.setOwned (configComponent.get()); + configComponent.release(); + + options.content->setSize (320, 250); + + options.dialogTitle = "Configure basestation"; + options.dialogBackgroundColour = Colours::darkgrey; + options.escapeKeyTriggersCloseButton = true; + options.useNativeTitleBar = false; + options.resizable = false; + + int result = options.runModal(); + + headstages.clear(); + probes.clear(); + + savingDirectory = File(); + + basestationConnectBoard = std::make_unique (this); + basestationConnectBoard->getInfo(); + + for (int i = 0; i < headstage_count; i++) + { + switch (simulatedProbeTypes[i]) + { + case ProbeType::NONE: + headstages.add (nullptr); + break; + case ProbeType::NP1: + headstages.add (new SimulatedHeadstage (this, i + 1, "PRB_1_4_0480_1", 28948291 + i)); + break; + case ProbeType::NHP45: + headstages.add (new SimulatedHeadstage (this, i + 1, "NP1031", 38948291 + i)); + break; + case ProbeType::UHD1: + headstages.add (new SimulatedHeadstage (this, i + 1, "NP1100", 48948291 + i)); + break; + case ProbeType::UHD2: + headstages.add (new SimulatedHeadstage (this, i + 1, "NP1110", 48948211 + i)); + break; + case ProbeType::NP2_1: + headstages.add (new SimulatedHeadstage (this, i + 1, "NP2003", 58948291 + i)); + break; + case ProbeType::NP2_4: + headstages.add (new SimulatedHeadstage (this, i + 1, "NP2013", 68948291 + i)); + break; + case ProbeType::OPTO: + headstages.add (new SimulatedHeadstage (this, i + 1, "NP1300", 78948291 + i)); + break; + default: + headstages.add (new SimulatedHeadstage (this, i + 1, "PRB_1_4_0480_1", 28948291 + i)); + } + } + + for (auto headstage : headstages) + { + if (headstage != nullptr) + { + probes.add (headstage->getProbes()[0]); + } + } + + LOGD (probes.size(), " total probes "); + + syncFrequencies.add (1); + + return true; } void SimulatedBasestation::close() { - } - void SimulatedBasestation::setSyncAsInput() { - } - -void SimulatedBasestation::setSyncAsOutput(int freqIndex) +void SimulatedBasestation::setSyncAsOutput (int freqIndex) { +} +void SimulatedBasestation::setSyncAsPassive() +{ } int SimulatedBasestation::getProbeCount() { - return probes.size(); + return probes.size(); } - -void SimulatedBasestation::initialize(bool signalChainIsLoading) +void SimulatedBasestation::initialize (bool signalChainIsLoading) { - if (!probesInitialized) - { - LOGD("Basestation initializing probes..."); - - for (auto probe: probes) - { - probe->initialize(signalChainIsLoading); - - } - - probesInitialized = true; - } + if (! probesInitialized) + { + LOGD ("Basestation initializing probes..."); + + for (auto probe : probes) + { + probe->initialize (signalChainIsLoading); + } + + probesInitialized = true; + } } +void SimulatedBasestation::searchForProbes() +{ +} Array SimulatedBasestation::getSyncFrequencies() { - return syncFrequencies; + return syncFrequencies; } float SimulatedBasestation::getFillPercentage() { - return 0.0f; + return 0.0f; } void SimulatedBasestation::startAcquisition() { - for (int i = 0; i < probes.size(); i++) - { - probes[i]->startAcquisition(); - } - + for (int i = 0; i < probes.size(); i++) + { + if (probes[i]->isEnabled) + probes[i]->startAcquisition(); + } } void SimulatedBasestation::stopAcquisition() { - for (int i = 0; i < probes.size(); i++) - { - probes[i]->stopAcquisition(); - } - + for (int i = 0; i < probes.size(); i++) + { + if (probes[i]->isEnabled) + probes[i]->stopAcquisition(); + } } diff --git a/Source/Basestations/SimulatedBasestation.h b/Source/Basestations/SimulatedBasestation.h index be08137..56c659b 100644 --- a/Source/Basestations/SimulatedBasestation.h +++ b/Source/Basestations/SimulatedBasestation.h @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -35,31 +35,28 @@ class SimulatedBasestation; */ -class SimulatedBasestationConfigWindow : - public Component, - public Button::Listener +class SimulatedBasestationConfigWindow : public Component, + public Button::Listener { public: - /** Constructor */ - SimulatedBasestationConfigWindow(SimulatedBasestation* bs); + /** Constructor */ + SimulatedBasestationConfigWindow (SimulatedBasestation* bs); - /** Destructor */ - ~SimulatedBasestationConfigWindow() { } + /** Destructor */ + ~SimulatedBasestationConfigWindow() {} - /** Render the component */ - void paint(Graphics& g) override; + /** Render the component */ + void paint (Graphics& g) override; - /** Accepts the configuration and closes the window */ - void buttonClicked(Button* button); + /** Accepts the configuration and closes the window */ + void buttonClicked (Button* button); private: + OwnedArray portComboBoxes; - OwnedArray portComboBoxes; - - std::unique_ptr acceptButton; - - SimulatedBasestation* bs; + std::unique_ptr acceptButton; + SimulatedBasestation* bs; }; /** @@ -70,70 +67,69 @@ class SimulatedBasestationConfigWindow : class SimulatedBasestation : public Basestation { public: + /** Constructor */ + SimulatedBasestation (NeuropixThread*, DeviceType type, int slot); - /** Constructor */ - SimulatedBasestation(NeuropixThread*, DeviceType type, int slot); + /** Destructor */ + ~SimulatedBasestation() {} - /** Destructor */ - ~SimulatedBasestation() { } + /** Gets part number, firmware version, etc.*/ + void getInfo() override; - /** Gets part number, firmware version, etc.*/ - void getInfo() override; + /** Opens connection to the basestation */ + bool open() override; - /** Opens connection to the basestation */ - bool open() override; + /** Closes connection to the basestation */ + void close() override; - /** Closes connection to the basestation */ - void close() override; + /** Initializes probes in a background thread */ + void initialize (bool signalChainIsLoading) override; - /** Initializes probes in a background thread */ - void initialize(bool signalChainIsLoading) override; + /** Searches for probes connected to this basestation */ + void searchForProbes() override; - /** Returns the total number of probes connected to this basestation*/ - int getProbeCount() override; + /** Returns the total number of probes connected to this basestation*/ + int getProbeCount() override; - /** Set basestation SMA connector as input*/ - void setSyncAsInput() override; + /** Set basestation SMA connector as input*/ + void setSyncAsInput() override; - /** Set basestation SMA connector as output (and set frequency)*/ - void setSyncAsOutput(int freqIndex) override; + /** Set basestation SMA connector as output (and set frequency)*/ + void setSyncAsOutput (int freqIndex) override; - /** Starts probe data streaming */ - void startAcquisition() override; + /** Set basestation SMA connector to passively inherit signal from backplane */ + void setSyncAsPassive() override; - /** Stops probe data streaming*/ - void stopAcquisition() override; + /** Starts probe data streaming */ + void startAcquisition() override; - /** Returns an array of available frequencies when SMA is in "output" mode */ - Array getSyncFrequencies() override; + /** Stops probe data streaming*/ + void stopAcquisition() override; - /** Returns the fraction of the basestation FIFO that is filled */ - float getFillPercentage() override; + /** Returns an array of available frequencies when SMA is in "output" mode */ + Array getSyncFrequencies() override; - /** Probes for each slot */ - ProbeType simulatedProbeTypes[4]; + /** Returns the fraction of the basestation FIFO that is filled */ + float getFillPercentage() override; - /** Number of headstages that can be connected */ - int headstage_count; + /** Probes for each slot */ + ProbeType simulatedProbeTypes[4]; -private: - - std::unique_ptr configComponent; + /** Number of headstages that can be connected */ + int headstage_count; +private: + std::unique_ptr configComponent; }; class SimulatedBasestationConnectBoard : public BasestationConnectBoard { public: + /** Constructor */ + SimulatedBasestationConnectBoard (Basestation* bs) : BasestationConnectBoard (bs) { getInfo(); } - /** Constructor */ - SimulatedBasestationConnectBoard(Basestation* bs) : BasestationConnectBoard(bs) { getInfo(); } - - /** Returns part number, firmware version, etc.*/ - void getInfo() override; + /** Returns part number, firmware version, etc.*/ + void getInfo() override; }; - - - -#endif // __SIMULATEDBASESTATION_H_2C4C2D67__ \ No newline at end of file +#endif // __SIMULATEDBASESTATION_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Formats/IMRO.h b/Source/Formats/IMRO.h index 063ce00..60293af 100644 --- a/Source/Formats/IMRO.h +++ b/Source/Formats/IMRO.h @@ -1,3 +1,26 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + #ifndef __IMRO_H__ #define __IMRO_H_ @@ -6,220 +29,286 @@ class IMRO { public: - - static bool writeSettingsToImro(File& file, ProbeSettings& settings) - { - + static bool writeSettingsToImro (File& file, ProbeSettings& settings) + { if (file.existsAsFile()) { - file.deleteFile(); - } + file.deleteFile(); + } const Result result = file.create(); - if (!result.wasOk()) + if (! result.wasOk()) { - LOGC("Could not create file: ", file.getFullPathName()); + LOGC ("Could not create file: ", file.getFullPathName()); } - if (settings.probeType == ProbeType::NP1 || - settings.probeType == ProbeType::NHP10 || - settings.probeType == ProbeType::NHP25 || - settings.probeType == ProbeType::NHP45 || - settings.probeType == ProbeType::UHD1) + String imroPartId; + String partNumber = settings.probe->info.part_number; + + if (partNumber.startsWith ("NP")) { - file.appendText("(0,384)"); + imroPartId = partNumber.substring (2); } - else if (settings.probeType == ProbeType::NP2_1) + else { - file.appendText("(21,384)"); + if (partNumber.equalsIgnoreCase ("PRB2_1_2_0640_0") || partNumber.equalsIgnoreCase ("PRB2_1_4_0480_1")) + imroPartId = "21"; + else if (partNumber.equalsIgnoreCase ("PRB2_4_2_0640_0")) + imroPartId = "24"; + else if (partNumber.equalsIgnoreCase ("PRB_1_4_0480_1") || partNumber.equalsIgnoreCase ("PRB_1_4_0480_1_C") || partNumber.equalsIgnoreCase ("PRB_1_2_0480_2")) + { + imroPartId = "0"; + } + else + { + LOGC ("Unknown part number: ", partNumber); + return false; + } + } + + String imroChannelCount; + + if (settings.probeType == ProbeType::NHP1) + { + imroChannelCount = "128"; } - else if (settings.probeType == ProbeType::NP2_4) + else if (settings.probeType == ProbeType::QUAD_BASE) { - file.appendText("(24,384)"); + imroChannelCount = "1536"; } - else if (settings.probeType == ProbeType::NHP1) + else { - file.appendText("(0,128)"); + imroChannelCount = "384"; } - - else { - return false; + + if (settings.probeType == ProbeType::UHD2) + { + // not yet implemented + writeUHDFile (file, settings); + return true; } + else + file.appendText ("(" + imroPartId + "," + imroChannelCount + ")"); for (int i = 0; i < settings.selectedChannel.size(); i++) { - String channelInfo = "(" + String(settings.selectedChannel[i]); // channel + String channelInfo = "(" + String (settings.selectedChannel[i]); // channel - if (settings.probeType == ProbeType::NP2_4) - channelInfo += " " + String(settings.selectedShank[i]); // shank + if (settings.probeType == ProbeType::NP2_4 || settings.probeType == ProbeType::QUAD_BASE) + channelInfo += " " + String (settings.selectedShank[i]); // shank if (settings.probeType == ProbeType::NP2_1) - channelInfo += " " + String(pow(2,int(settings.selectedBank[i]))); // bank + channelInfo += " " + String (pow (2, int (settings.selectedBank[i]))); // bank else - channelInfo += " " + String(int(settings.selectedBank[i])); + channelInfo += " " + String (int (settings.selectedBank[i])); - channelInfo += " " + String(settings.referenceIndex); // reference + channelInfo += " " + String (settings.referenceIndex); // reference - if (settings.probeType == ProbeType::NP2_1 || - settings.probeType == ProbeType::NP2_4) + if (settings.probeType == ProbeType::QUAD_BASE + || settings.probeType == ProbeType::NP2_4) + { + channelInfo += " " + String (settings.selectedElectrode[i] - 1280 * settings.selectedShank[i]); // electrode + } + else if (settings.probeType == ProbeType::NP2_1) { - channelInfo += " " + String(settings.selectedElectrode[i]); // electrode + channelInfo += " " + String (settings.selectedElectrode[i]); // electrode } - - else { - channelInfo += " " + String(int(settings.availableApGains[settings.apGainIndex])); - channelInfo += " " + String(int(settings.availableLfpGains[settings.lfpGainIndex])); - channelInfo += " " + String(int(settings.apFilterState)); + + else + { + channelInfo += " " + String (int (settings.availableApGains[settings.apGainIndex])); + channelInfo += " " + String (int (settings.availableLfpGains[settings.lfpGainIndex])); + channelInfo += " " + String (int (settings.apFilterState)); } channelInfo += ")"; - - file.appendText(channelInfo); + + file.appendText (channelInfo); } return true; - - - } - - static bool readSettingsFromImro(File& file, ProbeSettings& settings) - { + } + static bool readSettingsFromImro (File& file, ProbeSettings& settings) + { String imro = file.loadFileAsString(); bool foundHeader = false; int lastOpeningParen = 0; - LOGD("Length: ", imro.length()); + LOGD ("IMRO length: ", imro.length()); for (int i = 0; i < imro.length(); i++) { - if (imro.substring(i, i + 1) == "(") + if (imro.substring (i, i + 1) == "(") { lastOpeningParen = i; } - else if (imro.substring(i, i + 1) == ")") + else if (imro.substring (i, i + 1) == ")") { //std::cout << imro.substring(lastOpeningParen + 1, i) << std::endl; - if (!foundHeader) + if (! foundHeader) { - String substring = imro.substring(lastOpeningParen + 1, i); - int commaLoc = substring.indexOf(","); - - int value = substring.substring(0, commaLoc).getIntValue(); + String substring = imro.substring (lastOpeningParen + 1, i); + int commaLoc = substring.indexOf (","); - std::cout << value << std::endl; + int value = substring.substring (0, commaLoc).getIntValue(); if (value == 0) { - if (!(settings.probeType == ProbeType::NP1) && !(settings.probeType == ProbeType::NHP10)) - settings.probeType == ProbeType::NP1; + LOGC ("Neuropixels 1.0 probe detected."); + settings.probeType = ProbeType::NP1; + } + else if (value >= 1010 && value <= 1016) + { + LOGC ("Neuropixels NHP probe 10 mm probe detected."); + settings.probeType = ProbeType::NHP10; + } + else if (value >= 1020 && value <= 1022) + { + LOGC ("Neuropixels NHP probe 25 mm probe detected."); + settings.probeType = ProbeType::NHP25; } - else if (value == 21) + else if (value >= 1030 && value <= 1032) + { + LOGC ("Neuropixels NHP probe 45 mm probe detected."); + settings.probeType = ProbeType::NHP45; + } + else if (value == 1200 || value == 1210) + { + LOGC ("Neuropixels NHP passive probe detected."); + settings.probeType = ProbeType::NHP1; + } + else if (value == 21 || value == 2000 || value == 2003 || value == 2004) + { + LOGC ("Neuropixels 2.0 single shank probe detected."); settings.probeType = ProbeType::NP2_1; - else if (value == 24) + } + else if (value == 24 || value == 2010 || value == 2013 || value == 2014) + { + LOGC ("Neuropixels 2.0 multi-shank probe detected."); settings.probeType = ProbeType::NP2_4; + } + else if (value == 2020 || value == 2021) + { + LOGC ("Neuropixels 2.0 quad base probe detected."); + settings.probeType = ProbeType::QUAD_BASE; + } + else if (value == 1100 || value == 1120 || value == 1121 || value == 1122 || value == 1123) + { + LOGC ("Neuropixels UHD passive probe detected."); + settings.probeType = ProbeType::UHD1; + } + else if (value == 1110) + { + LOGC ("Neuropixels UHD active probe detected."); + settings.probeType = ProbeType::UHD2; + } else - return false; + { + LOGC ("Could not load IMRO, unknown probe part number: ", value); + return false; + } foundHeader = true; } - else { - StringArray strvals = StringArray::fromTokens(imro.substring(lastOpeningParen+1, i), " "); + else + { + StringArray strvals = StringArray::fromTokens (imro.substring (lastOpeningParen + 1, i), " "); Array values; for (int j = 0; j < strvals.size(); j++) { // std::cout << strvals[j] << " "; - values.add(strvals[j].getIntValue()); + values.add (strvals[j].getIntValue()); } // std::cout << std::endl; - parseValues(values, settings.probeType, settings); + parseValues (values, settings.probeType, settings); } } - } return true; + } - } - - - static void parseValues(Array values, ProbeType probeType, ProbeSettings& settings) + static void parseValues (Array values, ProbeType probeType, ProbeSettings& settings) { - if (probeType == ProbeType::NP1 || probeType == ProbeType::NHP10 || probeType == ProbeType::NHP45) + if (probeType == ProbeType::NP1 + || probeType == ProbeType::NHP10 + || probeType == ProbeType::NHP25 + || probeType == ProbeType::NHP45) { // 0 = 1.0 probe - // channel ID - // bank number - // reference ID (0=ext, 1=tip, [2..4] = on-shank-ref) - // AP band gain (e.g. 500) - // LFP band gain (e.g. 250) - // AP highpass applied (1 = on) + // channel ID + // bank number + // reference ID (0=ext, 1=tip, [2..4] = on-shank-ref) + // AP band gain (e.g. 500) + // LFP band gain (e.g. 250) + // AP highpass applied (1 = on) Bank bank; switch (values[1]) { - case 0: - bank = Bank::A; - break; - case 1: - bank = Bank::B; - break; - case 2: - bank = Bank::C; - break; - case 3: - bank = Bank::D; - break; - case 4: - bank = Bank::E; - break; - case 5: - bank = Bank::F; - break; - case 6: - bank = Bank::G; - break; - case 7: - bank = Bank::H; - break; - case 8: - bank = Bank::I; - break; - case 9: - bank = Bank::J; - break; - case 10: - bank = Bank::K; - break; - case 11: - bank = Bank::L; - break; - default: - bank = Bank::A; + case 0: + bank = Bank::A; + break; + case 1: + bank = Bank::B; + break; + case 2: + bank = Bank::C; + break; + case 3: + bank = Bank::D; + break; + case 4: + bank = Bank::E; + break; + case 5: + bank = Bank::F; + break; + case 6: + bank = Bank::G; + break; + case 7: + bank = Bank::H; + break; + case 8: + bank = Bank::I; + break; + case 9: + bank = Bank::J; + break; + case 10: + bank = Bank::K; + break; + case 11: + bank = Bank::L; + break; + default: + bank = Bank::A; } - settings.selectedChannel.add(values[0]); - settings.selectedBank.add(bank); + settings.selectedChannel.add (values[0]); + settings.selectedBank.add (bank); settings.referenceIndex = values[2]; - settings.apGainIndex = getIndexFromGain(values[3]); - settings.lfpGainIndex = getIndexFromGain(values[4]); - settings.apFilterState = bool(values[5]); + settings.apGainIndex = getIndexFromGain (values[3]); + settings.lfpGainIndex = getIndexFromGain (values[4]); + settings.apFilterState = bool (values[5]); - // std::cout << values[0] << " " - // << values[1] << " " + // std::cout << values[0] << " " + // << values[1] << " " // << values[2] << " " // << values[3] << " " // << values[4] << " " - // << values[5] << std::endl; + // << values[5] << std::endl; } else if (probeType == ProbeType::NP2_1) { @@ -229,36 +318,34 @@ class IMRO // reference ID (0=ext, 1=tip, [2..5] = on-shank ref) // electrode ID [0,1279] - settings.selectedChannel.add(values[0]); + settings.selectedChannel.add (values[0]); Bank bank; switch (values[1]) { - case 1: - bank = Bank::A; - break; - case 2: - bank = Bank::B; - break; - case 4: - bank = Bank::C; - break; - case 8: - bank = Bank::D; - break; - default: - bank = Bank::A; + case 1: + bank = Bank::A; + break; + case 2: + bank = Bank::B; + break; + case 4: + bank = Bank::C; + break; + case 8: + bank = Bank::D; + break; + default: + bank = Bank::A; } - settings.selectedBank.add(bank); + settings.selectedBank.add (bank); settings.referenceIndex = values[2]; - settings.selectedElectrode.add(values[3]); - + settings.selectedElectrode.add (values[3]); } - else if (probeType == ProbeType::NP2_4) + else if (probeType == ProbeType::NP2_4 || probeType == ProbeType::QUAD_BASE) { - - // 24 = 4-shank 2.0 + // 4-shank 2.0 // channel ID // shank ID // bank ID @@ -269,66 +356,81 @@ class IMRO switch (values[2]) { - case 0: - bank = Bank::A; - break; - case 1: - bank = Bank::B; - break; - case 2: - bank = Bank::C; - break; - case 3: - bank = Bank::D; - break; - default: - bank = Bank::A; + case 0: + bank = Bank::A; + break; + case 1: + bank = Bank::B; + break; + case 2: + bank = Bank::C; + break; + case 3: + bank = Bank::D; + break; + default: + bank = Bank::A; } - settings.selectedChannel.add(values[0]); - settings.selectedShank.add(values[1]); - settings.selectedBank.add(bank); + settings.selectedChannel.add (values[0]); + settings.selectedShank.add (values[1]); + settings.selectedBank.add (bank); settings.referenceIndex = values[3]; - settings.selectedElectrode.add(values[4]); - - + settings.selectedElectrode.add (values[4]); } } - static int getIndexFromGain(int value) + static int getIndexFromGain (int value) { switch (value) { - case 50: - return 0; - break; - case 125: - return 1; - break; - case 250: - return 2; - break; - case 500: - return 3; - break; - case 1000: - return 4; - break; - case 1500: - return 5; - break; - case 2000: - return 6; - break; - case 30000: - return 7; - break; - default: - return 3; + case 50: + return 0; + break; + case 125: + return 1; + break; + case 250: + return 2; + break; + case 500: + return 3; + break; + case 1000: + return 4; + break; + case 1500: + return 5; + break; + case 2000: + return 6; + break; + case 30000: + return 7; + break; + default: + return 3; } } + static void writeUHDFile (File file, ProbeSettings settings) + { + String configuration = settings.availableElectrodeConfigurations[settings.electrodeConfigurationIndex]; + + int columnMode = 2; // ALL + if (configuration.startsWith ("1 x 384")) + columnMode = 1; // OUTER + + file.appendText ("(1110," + + String (columnMode) + "," + + String (settings.referenceIndex) + "," + + String ((int) settings.availableApGains[settings.apGainIndex]) + "," + + String ((int) settings.availableLfpGains[settings.lfpGainIndex]) + "," + + String ((int) settings.apFilterState) + ")"); + + // TODO -- write the rest of the file + } }; #endif \ No newline at end of file diff --git a/Source/Formats/ProbeInterfaceJson.h b/Source/Formats/ProbeInterfaceJson.h index a9af5ee..9779dca 100644 --- a/Source/Formats/ProbeInterfaceJson.h +++ b/Source/Formats/ProbeInterfaceJson.h @@ -1,3 +1,26 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + #ifndef __PROBEINTERFACEJSON_H__ #define __PROBEINTERFACEJSON_H__ @@ -6,18 +29,16 @@ class ProbeInterfaceJson { public: - - static bool writeProbeSettingsToJson(File& file, ProbeSettings settings) + static bool writeProbeSettingsToJson (File& file, ProbeSettings settings) { - //std::cout << "Writing JSON file." << std::endl; DynamicObject output; - output.setProperty(Identifier("specification"), - var("probeinterface")); - output.setProperty(Identifier("version"), - var("0.2.2dev0")); + output.setProperty (Identifier ("specification"), + var ("probeinterface")); + output.setProperty (Identifier ("version"), + var ("0.2.23")); Array contact_positions; Array shank_ids; @@ -30,123 +51,118 @@ class ProbeInterfaceJson Array ax2 = { 0.0f, 1.0f }; Array contact_plane_axis = { ax1, ax2 }; - Array xpositions = { 27, 59, 11, 43 }; - - for (int ch = 0; ch < settings.selectedElectrode.size(); ch++) + for (int elec = 0; elec < settings.probe->electrodeMetadata.size(); elec++) { - - int elec = settings.selectedElectrode[ch]; + ElectrodeMetadata& em = settings.probe->electrodeMetadata.getReference (elec); + int channelIndex = settings.selectedElectrode.indexOf (elec); + int channel = -1; + if(channelIndex > -1) + channel = settings.selectedChannel[channelIndex]; Array contact_position; - contact_position.add(settings.probe->electrodeMetadata.getReference(elec).xpos + 250 * settings.selectedShank[ch]); - contact_position.add(settings.probe->electrodeMetadata.getReference(elec).ypos); + contact_position.add (em.xpos + 250 * em.shank); + contact_position.add (em.ypos); DynamicObject::Ptr contact_shape_param = new DynamicObject; - contact_shape_param->setProperty(Identifier("width"), settings.probe->electrodeMetadata.getReference(elec).site_width); - - contact_positions.add(contact_position); - shank_ids.add(String(settings.selectedShank[ch])); - device_channel_indices.add(settings.selectedChannel[ch]); - contact_plane_axes.add(contact_plane_axis); - contact_shapes.add("square"); - contact_shape_params.add(contact_shape_param.get()); - + contact_shape_param->setProperty (Identifier ("width"), settings.probe->electrodeMetadata.getReference (elec).site_width); + + contact_positions.add (contact_position); + shank_ids.add (String (em.shank)); + device_channel_indices.add (channel); + contact_plane_axes.add (contact_plane_axis); + contact_shapes.add ("square"); + contact_shape_params.add (contact_shape_param.get()); } DynamicObject::Ptr probe = new DynamicObject(); DynamicObject::Ptr annotations = new DynamicObject(); - annotations->setProperty(Identifier("name"), var("")); - - probe->setProperty(Identifier("ndim"), 2); - probe->setProperty(Identifier("si_units"), "um"); - probe->setProperty(Identifier("annotations"), var(annotations)); - probe->setProperty(Identifier("contact_positions"), contact_positions); - probe->setProperty(Identifier("contact_plane_axes"), contact_plane_axes); - probe->setProperty(Identifier("contact_shapes"), contact_shapes); - probe->setProperty(Identifier("contact_shape_params"), contact_shape_params); - probe->setProperty(Identifier("device_channel_indices"), device_channel_indices); - probe->setProperty(Identifier("shank_ids"), shank_ids); - probe->setProperty(Identifier("num_adcs"), settings.probe->probeMetadata.num_adcs); + annotations->setProperty (Identifier ("name"), settings.probe->name); + annotations->setProperty (Identifier ("manufacturer"), "imec"); + + probe->setProperty (Identifier ("ndim"), 2); + probe->setProperty (Identifier ("si_units"), "um"); + probe->setProperty (Identifier ("annotations"), var (annotations)); + probe->setProperty (Identifier ("contact_positions"), contact_positions); + probe->setProperty (Identifier ("contact_plane_axes"), contact_plane_axes); + probe->setProperty (Identifier ("contact_shapes"), contact_shapes); + probe->setProperty (Identifier ("contact_shape_params"), contact_shape_params); + probe->setProperty (Identifier ("device_channel_indices"), device_channel_indices); + probe->setProperty (Identifier ("shank_ids"), shank_ids); Array probes; - probes.add(probe.get()); + probes.add (probe.get()); - output.setProperty(Identifier("probes"), probes); + output.setProperty (Identifier ("probes"), probes); if (file.exists()) file.deleteFile(); - FileOutputStream f(file); + FileOutputStream f (file); - output.writeAsJSON(f, 4, false, 4); + output.writeAsJSON (f, 4, false, 4); return true; - } - static bool readProbeSettingsFromJson(File& file, ProbeSettings& settings) + static bool readProbeSettingsFromJson (File& file, ProbeSettings& settings) { - - // std::cout << "Reading JSON file." << std::endl; + // std::cout << "Reading JSON file." << std::endl; var result; - static Result r = JSON::parse(file.loadFileAsString(), result); + static Result r = JSON::parse (file.loadFileAsString(), result); DynamicObject::Ptr obj = result.getDynamicObject(); // check that specification == 'probeinterface' - if (obj->hasProperty(Identifier("specification"))) + if (obj->hasProperty (Identifier ("specification"))) { - String specification = obj->getProperty(Identifier("specification")).toString(); + String specification = obj->getProperty (Identifier ("specification")).toString(); - if (specification.compare("probeinterface") != 0) + if (specification.compare ("probeinterface") != 0) return false; } - if (obj->hasProperty(Identifier("probes"))) + if (obj->hasProperty (Identifier ("probes"))) { - Array* probes = obj->getProperty(Identifier("probes")).getArray(); + Array* probes = obj->getProperty (Identifier ("probes")).getArray(); // check that this file contains only one probe if (probes->size() != 1) return false; - DynamicObject::Ptr probe = probes->getReference(0).getDynamicObject(); + DynamicObject::Ptr probe = probes->getReference (0).getDynamicObject(); - if (probe->hasProperty(Identifier("device_channel_indices"))) + if (probe->hasProperty (Identifier ("device_channel_indices"))) { - - Array* device_channel_indices = probe->getProperty(Identifier("device_channel_indices")).getArray(); + Array* device_channel_indices = probe->getProperty (Identifier ("device_channel_indices")).getArray(); for (int ch = 0; ch < device_channel_indices->size(); ch++) { - int index = int(device_channel_indices->getReference(ch)); + int index = int (device_channel_indices->getReference (ch)); } } - if (probe->hasProperty(Identifier("shank_ids"))) + if (probe->hasProperty (Identifier ("shank_ids"))) { - - Array* shank_ids = probe->getProperty(Identifier("shank_ids")).getArray(); + Array* shank_ids = probe->getProperty (Identifier ("shank_ids")).getArray(); for (int ch = 0; ch < shank_ids->size(); ch++) { - int shank_id = int(shank_ids->getReference(ch)); + int shank_id = int (shank_ids->getReference (ch)); } } - if (probe->hasProperty(Identifier("contact_positions"))) + if (probe->hasProperty (Identifier ("contact_positions"))) { - - Array* contact_positions = probe->getProperty(Identifier("contact_positions")).getArray(); + Array* contact_positions = probe->getProperty (Identifier ("contact_positions")).getArray(); for (int ch = 0; ch < contact_positions->size(); ch++) { - Array* contact_position = contact_positions->getReference(ch).getArray(); + Array* contact_position = contact_positions->getReference (ch).getArray(); - int xpos = int(contact_position->getReference(0)); - int ypos = int(contact_position->getReference(1)); + int xpos = int (contact_position->getReference (0)); + int ypos = int (contact_position->getReference (1)); //std::cout << " Position: " << xpos << ", " << ypos << std::endl; } diff --git a/Source/Headstages/Headstage1.cpp b/Source/Headstages/Headstage1.cpp new file mode 100644 index 0000000..1fc0e3f --- /dev/null +++ b/Source/Headstages/Headstage1.cpp @@ -0,0 +1,269 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + +#include "Headstage1.h" +#include "../Probes/Neuropixels1.h" +#include "../Probes/NeuropixelsOpto.h" +#include "../Probes/Neuropixels_NHP_Active.h" +#include "../Probes/Neuropixels_UHD.h" + +#define MAXLEN 50 + +void Headstage1::getInfo() +{ + int version_major; + int version_minor; + + errorCode = Neuropixels::getHSVersion (basestation->slot, port, &version_major, &version_minor); + + info.version = String (version_major) + "." + String (version_minor); + + errorCode = Neuropixels::readHSSN (basestation->slot, port, &info.serial_number); + + char pn[MAXLEN]; + errorCode = Neuropixels::readHSPN (basestation->slot, port, pn, MAXLEN); + + info.part_number = String (pn); +} + +void Flex1::getInfo() +{ + int version_major; + int version_minor; + + errorCode = Neuropixels::getFlexVersion (headstage->basestation->slot, + headstage->port, + dock, + &version_major, + &version_minor); + + info.version = String (version_major) + "." + String (version_minor); + + char pn[MAXLEN]; + errorCode = Neuropixels::readFlexPN (headstage->basestation->slot, + headstage->port, + dock, + pn, + MAXLEN); + + info.part_number = String (pn); +} + +Headstage1::Headstage1 (Basestation* bs_, int port) : Headstage (bs_, port) +{ + getInfo(); + + testModule = nullptr; + + if (hasTestModule()) + { + LOGD ("Test module detected"); + testModule = new HeadstageTestModule_v3 (basestation, this); + testModule->runAll(); + testModule->showResults(); + } + else + { + flexCables.add (new Flex1 (this)); + + char partNumber[MAXLEN]; + + errorCode = Neuropixels::readProbePN (basestation->slot, port, 1, partNumber, MAXLEN); + + LOGC (" Found probe part number: ", partNumber); + + if (! CharPointer_ASCII::isValidString (partNumber, MAXLEN)) + { + // invalid probe part number + LOGC ("Headstage has no valid probes connected."); + return; + } + + if (String (partNumber).equalsIgnoreCase ("NP1300")) + probes.add (new NeuropixelsOpto (basestation, this, flexCables[0])); + else if (String (partNumber).equalsIgnoreCase ("NP1110")) + { + probes.add (new Neuropixels_UHD (basestation, this, flexCables[0])); + } + else if (String (partNumber).equalsIgnoreCase ("NP1010") || String (partNumber).equalsIgnoreCase ("NP1011") || String (partNumber).equalsIgnoreCase ("NP1012") || String (partNumber).equalsIgnoreCase ("NP1013") || String (partNumber).equalsIgnoreCase ("NP1015") || String (partNumber).equalsIgnoreCase ("NP1016") || String (partNumber).equalsIgnoreCase ("NP1020") || String (partNumber).equalsIgnoreCase ("NP1022") || String (partNumber).equalsIgnoreCase ("NP1030") || String (partNumber).equalsIgnoreCase ("NP1032")) + { + probes.add (new Neuropixels_NHP_Active (basestation, this, flexCables[0])); + } + else + { + probes.add (new Neuropixels1 (basestation, this, flexCables[0])); + } + + if (probes[0]->isValid) + probes[0]->setStatus (SourceStatus::CONNECTING); + else + probes.remove (0, true); + + if (probes.size() != 1) + { + LOGC ("Headstage has ", probes.size(), " valid probes connected."); + } + else + LOGC ("Headstage has 1 valid probe connected."); + } +} + +bool Headstage1::hasTestModule() +{ + int vmajor; + int vminor; + return Neuropixels::HST_GetVersion (basestation->slot, port, &vmajor, &vminor) == Neuropixels::SUCCESS; +} + +void Headstage1::runTestModule() +{ + testModule->runAll(); + testModule->showResults(); +} + +Flex1::Flex1 (Headstage* hs_) : Flex (hs_, 1) +{ + getInfo(); + + errorCode = Neuropixels::SUCCESS; +} + +/****************Headstage Test Module**************************/ + +HeadstageTestModule_v3::HeadstageTestModule_v3 (Basestation* bs, Headstage* hs) : HeadstageTestModule (bs, hs) +{ + tests = { + "VDDA1V2", + "VDDA1V8", + "VDDD1V2", + "VDDD1V8", + "MCLK", + "PCLK", + "PSB", + "I2C", + "NRST", + "REC_NRESET", + "SIGNAL" + }; + + basestation = bs; + headstage = hs; +} + +void HeadstageTestModule_v3::getInfo() +{ + //TODO? +} + +void HeadstageTestModule_v3::runAll() +{ + status = std::make_unique(); + + status->VDD_A1V2 = test_VDD_A1V2(); + status->VDD_A1V8 = test_VDD_A1V8(); + status->VDD_D1V2 = test_VDD_D1V2(); + status->VDD_D1V8 = test_VDD_D1V8(); + status->MCLK = test_MCLK(); + status->PCLK = test_PCLK(); + status->PSB = test_PSB(); + status->I2C = test_I2C(); + status->NRST = test_NRST(); + status->REC_NRESET = test_REC_NRESET(); + status->SIGNAL = test_SIGNAL(); +} + +void HeadstageTestModule_v3::showResults() +{ + int numTests = sizeof (struct HST_Status) / sizeof (Neuropixels::NP_ErrorCode); + int resultLineTextLength = 30; + String message = "Test results from HST module on slot: " + String (basestation->slot) + " port: " + String (headstage->port) + "\n\n"; + + Neuropixels::NP_ErrorCode* results = (Neuropixels::NP_ErrorCode*) (&status->VDD_A1V2); + + for (int i = 0; i < numTests; i++) + { + message += String (tests[i]); + for (int ii = 0; ii < resultLineTextLength - tests[i].length(); ii++) + message += "-"; + message += results[i] == Neuropixels::SUCCESS ? "PASSED" : "FAILED w/ error code: " + String (results[i]); + message += "\n"; + } + + //AlertWindow::showMessageBox(AlertWindow::AlertIconType::InfoIcon, "HST Module Detected!", message, "OK"); + LOGC ("Headstage Module Test Results: ", message); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_A1V2() +{ + return Neuropixels::HSTestVDDA1V2 (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_A1V8() +{ + return Neuropixels::HSTestVDDA1V8 (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_D1V2() +{ + return Neuropixels::HSTestVDDD1V2 (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_D1V8() +{ + return Neuropixels::HSTestVDDD1V8 (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_MCLK() +{ + return Neuropixels::HSTestMCLK (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_PCLK() +{ + return Neuropixels::HSTestPCLK (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_PSB() +{ + return Neuropixels::HSTestPSB (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_I2C() +{ + return Neuropixels::HSTestI2C (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_NRST() +{ + return Neuropixels::HSTestNRST (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_REC_NRESET() +{ + return Neuropixels::HSTestREC_NRESET (basestation->slot, headstage->port); +} + +Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_SIGNAL() +{ + return Neuropixels::HSTestOscillator (basestation->slot, headstage->port); +} \ No newline at end of file diff --git a/Source/Headstages/Headstage1.h b/Source/Headstages/Headstage1.h new file mode 100644 index 0000000..9697d9c --- /dev/null +++ b/Source/Headstages/Headstage1.h @@ -0,0 +1,124 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + +#ifndef __NEUROPIXHS1V3_H_2C4C2D67__ +#define __NEUROPIXHS1V3_H_2C4C2D67__ + +#include "../NeuropixComponents.h" + +/** + + Connects to a Neuropixels 1.0 probe + +*/ +class Headstage1 : public Headstage +{ +public: + /** Constructor */ + Headstage1::Headstage1 (Basestation*, int port); + + /** Reads headstage part number and serial number */ + void getInfo() override; + + /** Returns true if headstage tester is connected */ + bool hasTestModule() override; + + /** Runs the headstage tests */ + void runTestModule() override; +}; + +/** + + Represents a Neuropixels 1.0 flex cable + +*/ +class Flex1 : public Flex +{ +public: + /** Constructor */ + Flex1::Flex1 (Headstage*); + + /** Reads flex part number */ + void getInfo() override; +}; + +/** Test module status codes */ +typedef struct HST_Status +{ + Neuropixels::NP_ErrorCode VDD_A1V2; + Neuropixels::NP_ErrorCode VDD_A1V8; + Neuropixels::NP_ErrorCode VDD_D1V2; + Neuropixels::NP_ErrorCode VDD_D1V8; + Neuropixels::NP_ErrorCode MCLK; + Neuropixels::NP_ErrorCode PCLK; + Neuropixels::NP_ErrorCode PSB; + Neuropixels::NP_ErrorCode I2C; + Neuropixels::NP_ErrorCode NRST; + Neuropixels::NP_ErrorCode REC_NRESET; + Neuropixels::NP_ErrorCode SIGNAL; +}; + +/** + + Interface to headstage test module + +*/ +class HeadstageTestModule_v3 : public HeadstageTestModule +{ +public: + + /** Constructor */ + HeadstageTestModule_v3::HeadstageTestModule_v3 (Basestation* bs, Headstage* hs); + + /** Gets part info */ + void getInfo() override; + + /** Runs all tests */ + void runAll() override; + + /** Shows test results */ + void showResults() override; + +private: + Neuropixels::NP_ErrorCode test_VDD_A1V2(); + Neuropixels::NP_ErrorCode test_VDD_A1V8(); + Neuropixels::NP_ErrorCode test_VDD_D1V2(); + Neuropixels::NP_ErrorCode test_VDD_D1V8(); + Neuropixels::NP_ErrorCode test_MCLK(); + Neuropixels::NP_ErrorCode test_PCLK(); + Neuropixels::NP_ErrorCode test_PSB(); + Neuropixels::NP_ErrorCode test_I2C(); + Neuropixels::NP_ErrorCode test_NRST(); + Neuropixels::NP_ErrorCode test_REC_NRESET(); + Neuropixels::NP_ErrorCode test_SIGNAL(); + + Basestation* basestation; + Headstage* headstage; + HeadstageTestModule* testModule; + + std::vector tests; + + std::unique_ptr status; +}; + +#endif // __NEUROPIXHS1V3_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Headstages/Headstage1_v1.cpp b/Source/Headstages/Headstage1_v1.cpp deleted file mode 100644 index bd360e2..0000000 --- a/Source/Headstages/Headstage1_v1.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* ------------------------------------------------------------------- - -This file is part of the Open Ephys GUI -Copyright (C) 2018 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 . - -*/ - -#include "Headstage1_v1.h" -#include "../Probes/Neuropixels1_v1.h" -#include "../Probes/Neuropixels_UHD.h" - -#define MAXLEN 50 - -void Headstage1_v1::getInfo() -{ - - unsigned char version_major; - unsigned char version_minor; - - errorCode = np::getHSVersion(basestation->slot_c, port_c, &version_major, &version_minor); - - info.version = String(version_major) + "." + String(version_minor); - - errorCode = np::readHSSN(basestation->slot_c, port_c, &info.serial_number); - - char pn[MAXLEN]; - errorCode = np::readHSPN(basestation->slot_c, port_c, pn, MAXLEN); - - info.part_number = String(pn); - -} - - -void Flex1_v1::getInfo() -{ - - unsigned char version_major; - unsigned char version_minor; - - errorCode = np::getFlexVersion(headstage->basestation->slot_c, - headstage->port_c, - &version_major, - &version_minor); - - info.version = String(version_major) + "." + String(version_minor); - - char pn[MAXLEN]; - errorCode = np::readFlexPN(headstage->basestation->slot_c, - headstage->port_c, - pn, - MAXLEN); - - info.part_number = String(pn); - -} - - -Headstage1_v1::Headstage1_v1(Basestation* bs_, int port) : Headstage(bs_, port) -{ - - getInfo(); - - if (hasTestModule()) - { - testModule = new HeadstageTestModule_v1(basestation, this); - testModule->runAll(); - testModule->showResults(); - } - else - { - testModule = nullptr; - flexCables.add(new Flex1_v1(this)); - - char partNumber[MAXLEN]; - errorCode = np::readProbePN(basestation->slot, port, partNumber, MAXLEN); - - if (!CharPointer_ASCII::isValidString(partNumber, MAXLEN)) - { - // invalid probe part number - LOGC("Headstage has no valid probes connected."); - return; - } - - if (String(partNumber).equalsIgnoreCase("NP1110")) - { - probes.add(new Neuropixels_UHD(basestation, this, flexCables[0])); - } - else { - probes.add(new Neuropixels1_v1(basestation, this, flexCables[0])); - } - - if (probes[0]->isValid) - probes[0]->setStatus(SourceStatus::CONNECTING); - else - probes.remove(0, true); - - if (probes.size() != 1) - { - LOGC("Headstage has ", probes.size(), " valid probes connected."); - } - else - LOGC("Headstage has 1 valid probe connected."); - } - -} - -bool Headstage1_v1::hasTestModule() -{ - return np::openProbeHSTest(basestation->slot_c, port) == np::SUCCESS; -} - -void Headstage1_v1::runTestModule() -{ - testModule->runAll(); - testModule->showResults(); -} - -Flex1_v1::Flex1_v1(Headstage* hs_) : Flex(hs_, 1) -{ - getInfo(); - - errorCode = np::SUCCESS; -} - - -/****************Headstage Test Module**************************/ - -HeadstageTestModule_v1::HeadstageTestModule_v1(Basestation* bs, Headstage* hs) : HeadstageTestModule(bs, hs) -{ - - tests = { - "VDDA1V2", - "VDDA1V8", - "VDDD1V2", - "VDDD1V8", - "MCLK", - "PCLK", - "PSB", - "I2C", - "NRST", - "REC_NRESET", - "SIGNAL" - }; - - basestation = bs; - headstage = hs; - -} - -void HeadstageTestModule_v1::getInfo() -{ - //TODO? -} - -void HeadstageTestModule_v1::runAll() -{ - - status = new HST_Status(); - - status->VDD_A1V2 = test_VDD_A1V2(); - status->VDD_A1V8 = test_VDD_A1V8(); - status->VDD_D1V2 = test_VDD_D1V2(); - status->VDD_D1V8 = test_VDD_D1V8(); - status->MCLK = test_MCLK(); - status->PCLK = test_PCLK(); - status->PSB = test_PSB(); - status->I2C = test_I2C(); - status->NRST = test_NRST(); - status->REC_NRESET = test_REC_NRESET(); - status->SIGNAL = test_SIGNAL(); - -} - -void HeadstageTestModule_v1::showResults() -{ - - int numTests = sizeof(struct HST_Status)/sizeof(np::NP_ErrorCode); - int resultLineTextLength = 30; - String message = "Test results from HST module on slot: " + String(basestation->slot) + " port: " + String(headstage->port) + "\n\n"; - - np::NP_ErrorCode *results = (np::NP_ErrorCode*)(&status->VDD_A1V2); - - for (int i = 0; i < numTests; i++) - { - message+=String(tests[i]); - for (int ii = 0; ii < resultLineTextLength - tests[i].length(); ii++) message+="-"; - message+=results[i] == np::SUCCESS ? "PASSED" : "FAILED w/ error code: " + String(results[i]); - message+= "\n"; - } - - AlertWindow::showMessageBox(AlertWindow::AlertIconType::InfoIcon, "HST Module Detected!", message, "OK"); - -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_VDD_A1V2() -{ - return np::HSTestVDDA1V2(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_VDD_A1V8() -{ - return np::HSTestVDDA1V8(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_VDD_D1V2() -{ - return np::HSTestVDDD1V2(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_VDD_D1V8() -{ - return np::HSTestVDDD1V8(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_MCLK() -{ - return np::HSTestMCLK(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_PCLK() -{ - return np::HSTestPCLK(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_PSB() -{ - return np::HSTestPSB(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_I2C() -{ - return np::HSTestI2C(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_NRST() -{ - return np::HSTestNRST(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_REC_NRESET() -{ - return np::HSTestREC_NRESET(basestation->slot_c, headstage->port_c); -} - -np::NP_ErrorCode HeadstageTestModule_v1::test_SIGNAL() -{ - return np::HSTestOscillator(basestation->slot_c, headstage->port_c); -} \ No newline at end of file diff --git a/Source/Headstages/Headstage1_v1.h b/Source/Headstages/Headstage1_v1.h deleted file mode 100644 index dc88415..0000000 --- a/Source/Headstages/Headstage1_v1.h +++ /dev/null @@ -1,102 +0,0 @@ -/* ------------------------------------------------------------------- - -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 . - -*/ - -#ifndef __NEUROPIXHSNP1V1_H_2C4C2D67__ -#define __NEUROPIXHSNP1V1_H_2C4C2D67__ - - -#include "../API/v1/NeuropixAPI.h" -#include "../NeuropixComponents.h" - - -class Headstage1_v1 : public Headstage -{ -public: - Headstage1_v1::Headstage1_v1(Basestation*, int port); - void getInfo() override; - bool hasTestModule() override; - void runTestModule() override; - - np::NP_ErrorCode errorCode; -}; - -class Flex1_v1 : public Flex -{ -public: - Flex1_v1::Flex1_v1(Headstage*); - void getInfo() override; - - np::NP_ErrorCode errorCode; -}; - -typedef struct HST_Status { - np::NP_ErrorCode VDD_A1V2; - np::NP_ErrorCode VDD_A1V8; - np::NP_ErrorCode VDD_D1V2; - np::NP_ErrorCode VDD_D1V8; - np::NP_ErrorCode MCLK; - np::NP_ErrorCode PCLK; - np::NP_ErrorCode PSB; - np::NP_ErrorCode I2C; - np::NP_ErrorCode NRST; - np::NP_ErrorCode REC_NRESET; - np::NP_ErrorCode SIGNAL; -}; - -class HeadstageTestModule_v1 : public HeadstageTestModule -{ -public: - - HeadstageTestModule_v1::HeadstageTestModule_v1(Basestation* bs, Headstage* hs); - - void getInfo() override; - - void runAll() override; - void showResults() override; - -private: - - np::NP_ErrorCode test_VDD_A1V2(); - np::NP_ErrorCode test_VDD_A1V8(); - np::NP_ErrorCode test_VDD_D1V2(); - np::NP_ErrorCode test_VDD_D1V8(); - np::NP_ErrorCode test_MCLK(); - np::NP_ErrorCode test_PCLK(); - np::NP_ErrorCode test_PSB(); - np::NP_ErrorCode test_I2C(); - np::NP_ErrorCode test_NRST(); - np::NP_ErrorCode test_REC_NRESET(); - np::NP_ErrorCode test_SIGNAL(); - - Basestation* basestation; - Headstage* headstage; - - std::vector tests; - - np::NP_ErrorCode errorCode; - - ScopedPointer status; - -}; - -#endif // __NEUROPIXHSNP1V1_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Headstages/Headstage1_v3.cpp b/Source/Headstages/Headstage1_v3.cpp deleted file mode 100644 index f680f24..0000000 --- a/Source/Headstages/Headstage1_v3.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* ------------------------------------------------------------------- - -This file is part of the Open Ephys GUI -Copyright (C) 2018 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 . - -*/ - -#include "Headstage1_v3.h" -#include "../Probes/Neuropixels1_v3.h" -#include "../Probes/NeuropixelsOpto.h" -#include "../Probes/Neuropixels_UHD.h" -#include "../Probes/Neuropixels_NHP_Active.h" - -#define MAXLEN 50 - -void Headstage1_v3::getInfo() -{ - - int version_major; - int version_minor; - - errorCode = Neuropixels::getHSVersion(basestation->slot, port, &version_major, &version_minor); - - info.version = String(version_major) + "." + String(version_minor); - - errorCode = Neuropixels::readHSSN(basestation->slot, port, &info.serial_number); - - char pn[MAXLEN]; - errorCode = Neuropixels::readHSPN(basestation->slot, port, pn, MAXLEN); - - info.part_number = String(pn); - -} - - -void Flex1_v3::getInfo() -{ - - int version_major; - int version_minor; - - errorCode = Neuropixels::getFlexVersion(headstage->basestation->slot, - headstage->port, - dock, - &version_major, - &version_minor); - - info.version = String(version_major) + "." + String(version_minor); - - char pn[MAXLEN]; - errorCode = Neuropixels::readFlexPN(headstage->basestation->slot, - headstage->port, - dock, - pn, - MAXLEN); - - info.part_number = String(pn); - -} - - -Headstage1_v3::Headstage1_v3(Basestation* bs_, int port) : Headstage(bs_, port) -{ - - getInfo(); - - testModule = nullptr; - - if (hasTestModule()) - { - LOGD("Test module detected"); - testModule = new HeadstageTestModule_v3(basestation, this); - testModule->runAll(); - testModule->showResults(); - } - else - { - flexCables.add(new Flex1_v3(this)); - - char partNumber[MAXLEN]; - - errorCode = Neuropixels::readProbePN(basestation->slot, port, 1, partNumber, MAXLEN); - - LOGC(" Found probe part number: ", partNumber); - - if (!CharPointer_ASCII::isValidString(partNumber, MAXLEN)) - { - // invalid probe part number - LOGC("Headstage has no valid probes connected."); - return; - } - - if (String(partNumber).equalsIgnoreCase("NP1300")) - probes.add(new NeuropixelsOpto(basestation, this, flexCables[0])); - else if (String(partNumber).equalsIgnoreCase("NP1110")) - { - probes.add(new Neuropixels_UHD(basestation, this, flexCables[0])); - } - else if (String(partNumber).equalsIgnoreCase("NP1010") || - String(partNumber).equalsIgnoreCase("NP1011") || - String(partNumber).equalsIgnoreCase("NP1012") || - String(partNumber).equalsIgnoreCase("NP1013") || - String(partNumber).equalsIgnoreCase("NP1015") || - String(partNumber).equalsIgnoreCase("NP1016") || - String(partNumber).equalsIgnoreCase("NP1020") || - String(partNumber).equalsIgnoreCase("NP1022") || - String(partNumber).equalsIgnoreCase("NP1030") || - String(partNumber).equalsIgnoreCase("NP1032")) - { - probes.add(new Neuropixels_NHP_Active(basestation, this, flexCables[0])); - } - else { - probes.add(new Neuropixels1_v3(basestation, this, flexCables[0])); - } - - if (probes[0]->isValid) - probes[0]->setStatus(SourceStatus::CONNECTING); - else - probes.remove(0, true); - - if (probes.size() != 1) - { - LOGC("Headstage has ", probes.size(), " valid probes connected."); - } - else - LOGC("Headstage has 1 valid probe connected."); - } - -} - -bool Headstage1_v3::hasTestModule() -{ - int vmajor; - int vminor; - return Neuropixels::HST_GetVersion(basestation->slot, port, &vmajor, &vminor) == Neuropixels::SUCCESS; -} - -void Headstage1_v3::runTestModule() -{ - testModule->runAll(); - testModule->showResults(); -} - -Flex1_v3::Flex1_v3(Headstage* hs_) : Flex(hs_, 1) -{ - getInfo(); - - errorCode = Neuropixels::SUCCESS; -} - - -/****************Headstage Test Module**************************/ - -HeadstageTestModule_v3::HeadstageTestModule_v3(Basestation* bs, Headstage* hs) : HeadstageTestModule(bs, hs) -{ - - tests = { - "VDDA1V2", - "VDDA1V8", - "VDDD1V2", - "VDDD1V8", - "MCLK", - "PCLK", - "PSB", - "I2C", - "NRST", - "REC_NRESET", - "SIGNAL" - }; - - basestation = bs; - headstage = hs; - -} - -void HeadstageTestModule_v3::getInfo() -{ - //TODO? -} - -void HeadstageTestModule_v3::runAll() -{ - - status = new HST_Status(); - - status->VDD_A1V2 = test_VDD_A1V2(); - status->VDD_A1V8 = test_VDD_A1V8(); - status->VDD_D1V2 = test_VDD_D1V2(); - status->VDD_D1V8 = test_VDD_D1V8(); - status->MCLK = test_MCLK(); - status->PCLK = test_PCLK(); - status->PSB = test_PSB(); - status->I2C = test_I2C(); - status->NRST = test_NRST(); - status->REC_NRESET = test_REC_NRESET(); - status->SIGNAL = test_SIGNAL(); - -} - -void HeadstageTestModule_v3::showResults() -{ - - int numTests = sizeof(struct HST_Status)/sizeof(Neuropixels::NP_ErrorCode); - int resultLineTextLength = 30; - String message = "Test results from HST module on slot: " + String(basestation->slot) + " port: " + String(headstage->port) + "\n\n"; - - Neuropixels::NP_ErrorCode *results = (Neuropixels::NP_ErrorCode*)(&status->VDD_A1V2); - - for (int i = 0; i < numTests; i++) - { - message+=String(tests[i]); - for (int ii = 0; ii < resultLineTextLength - tests[i].length(); ii++) message+="-"; - message+=results[i] == Neuropixels::SUCCESS ? "PASSED" : "FAILED w/ error code: " + String(results[i]); - message+= "\n"; - } - - //AlertWindow::showMessageBox(AlertWindow::AlertIconType::InfoIcon, "HST Module Detected!", message, "OK"); - LOGC("Headstage Module Test Results: ", message); - -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_A1V2() -{ - return Neuropixels::HSTestVDDA1V2(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_A1V8() -{ - return Neuropixels::HSTestVDDA1V8(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_D1V2() -{ - return Neuropixels::HSTestVDDD1V2(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_VDD_D1V8() -{ - return Neuropixels::HSTestVDDD1V8(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_MCLK() -{ - return Neuropixels::HSTestMCLK(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_PCLK() -{ - return Neuropixels::HSTestPCLK(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_PSB() -{ - return Neuropixels::HSTestPSB(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_I2C() -{ - return Neuropixels::HSTestI2C(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_NRST() -{ - return Neuropixels::HSTestNRST(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_REC_NRESET() -{ - return Neuropixels::HSTestREC_NRESET(basestation->slot, headstage->port); -} - -Neuropixels::NP_ErrorCode HeadstageTestModule_v3::test_SIGNAL() -{ - return Neuropixels::HSTestOscillator(basestation->slot, headstage->port); -} \ No newline at end of file diff --git a/Source/Headstages/Headstage1_v3.h b/Source/Headstages/Headstage1_v3.h deleted file mode 100644 index 3d91c88..0000000 --- a/Source/Headstages/Headstage1_v3.h +++ /dev/null @@ -1,103 +0,0 @@ -/* ------------------------------------------------------------------- - -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 . - -*/ - -#ifndef __NEUROPIXHS1V3_H_2C4C2D67__ -#define __NEUROPIXHS1V3_H_2C4C2D67__ - - -#include "../API/v3/NeuropixAPI.h" -#include "../NeuropixComponents.h" - - -class Headstage1_v3 : public Headstage -{ -public: - Headstage1_v3::Headstage1_v3(Basestation*, int port); - void getInfo() override; - bool hasTestModule() override; - void runTestModule() override; - - Neuropixels::NP_ErrorCode errorCode; -}; - -class Flex1_v3 : public Flex -{ -public: - Flex1_v3::Flex1_v3(Headstage*); - void getInfo() override; - - Neuropixels::NP_ErrorCode errorCode; -}; - -typedef struct HST_Status { - Neuropixels::NP_ErrorCode VDD_A1V2; - Neuropixels::NP_ErrorCode VDD_A1V8; - Neuropixels::NP_ErrorCode VDD_D1V2; - Neuropixels::NP_ErrorCode VDD_D1V8; - Neuropixels::NP_ErrorCode MCLK; - Neuropixels::NP_ErrorCode PCLK; - Neuropixels::NP_ErrorCode PSB; - Neuropixels::NP_ErrorCode I2C; - Neuropixels::NP_ErrorCode NRST; - Neuropixels::NP_ErrorCode REC_NRESET; - Neuropixels::NP_ErrorCode SIGNAL; -}; - -class HeadstageTestModule_v3 : public HeadstageTestModule -{ -public: - - HeadstageTestModule_v3::HeadstageTestModule_v3(Basestation* bs, Headstage* hs); - - void getInfo() override; - - void runAll() override; - void showResults() override; - -private: - - Neuropixels::NP_ErrorCode test_VDD_A1V2(); - Neuropixels::NP_ErrorCode test_VDD_A1V8(); - Neuropixels::NP_ErrorCode test_VDD_D1V2(); - Neuropixels::NP_ErrorCode test_VDD_D1V8(); - Neuropixels::NP_ErrorCode test_MCLK(); - Neuropixels::NP_ErrorCode test_PCLK(); - Neuropixels::NP_ErrorCode test_PSB(); - Neuropixels::NP_ErrorCode test_I2C(); - Neuropixels::NP_ErrorCode test_NRST(); - Neuropixels::NP_ErrorCode test_REC_NRESET(); - Neuropixels::NP_ErrorCode test_SIGNAL(); - - Basestation* basestation; - Headstage* headstage; - HeadstageTestModule* testModule; - - std::vector tests; - - Neuropixels::NP_ErrorCode errorCode; - - ScopedPointer status; - -}; - -#endif // __NEUROPIXHS1V3_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Headstages/Headstage2.cpp b/Source/Headstages/Headstage2.cpp index 3f0e53c..09fe915 100644 --- a/Source/Headstages/Headstage2.cpp +++ b/Source/Headstages/Headstage2.cpp @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2018 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -28,92 +28,88 @@ along with this program. If not, see . void Headstage2::getInfo() { + int version_major; + int version_minor; - int version_major; - int version_minor; + errorCode = Neuropixels::getHSVersion (basestation->slot, port, &version_major, &version_minor); - errorCode = Neuropixels::getHSVersion(basestation->slot, port, &version_major, &version_minor); + info.version = String (version_major) + "." + String (version_minor); - info.version = String(version_major) + "." + String(version_minor); + errorCode = Neuropixels::readHSSN (basestation->slot, port, &info.serial_number); - errorCode = Neuropixels::readHSSN(basestation->slot, port, &info.serial_number); - - char pn[MAXLEN]; - errorCode = Neuropixels::readHSPN(basestation->slot, port, pn, MAXLEN); - - info.part_number = String(pn); + char pn[MAXLEN]; + errorCode = Neuropixels::readHSPN (basestation->slot, port, pn, MAXLEN); + info.part_number = String (pn); } - void Flex2::getInfo() { + int version_major; + int version_minor; - int version_major; - int version_minor; + errorCode = Neuropixels::getFlexVersion (headstage->basestation->slot, + headstage->port, + dock, + &version_major, + &version_minor); - errorCode = Neuropixels::getFlexVersion(headstage->basestation->slot, - headstage->port, - dock, - &version_major, - &version_minor); + LOGD("### Flex2::getFlexVersion() errorCode: ", errorCode); - info.version = String(version_major) + "." + String(version_minor); + info.version = String (version_major) + "." + String (version_minor); - char pn[MAXLEN]; - errorCode = Neuropixels::readFlexPN(headstage->basestation->slot, - headstage->port, - dock, - pn, - MAXLEN); + char pn[MAXLEN]; + errorCode = Neuropixels::readFlexPN (headstage->basestation->slot, + headstage->port, + dock, + pn, + MAXLEN); - info.part_number = String(pn); + LOGD("### Flex2::readFlexPN() errorCode: ", errorCode); + info.part_number = String (pn); } - -Headstage2::Headstage2(Basestation* bs_, int port) : Headstage(bs_, port) +Headstage2::Headstage2 (Basestation* bs_, int port) : Headstage (bs_, port) { - getInfo(); - - int count; - - Neuropixels::getHSSupportedProbeCount(basestation->slot, port, &count); - - for (int dock = 1; dock <= count; dock++) - { - bool flexDetected; - - Neuropixels::detectFlex(basestation->slot, port, dock, &flexDetected); - - if (flexDetected) - { - flexCables.add(new Flex2(this, dock)); - Neuropixels2* probe = new Neuropixels2(basestation, this, flexCables.getLast(), dock); - - if (probe->isValid) - { - probe->setStatus(SourceStatus::CONNECTING); - probes.add(probe); - } - else - { - delete probe; - probes.add(nullptr); - } - - } - else { - probes.add(nullptr); - } - - } - + getInfo(); + + int count; + + Neuropixels::getHSSupportedProbeCount (basestation->slot, port, &count); + + for (int dock = 1; dock <= count; dock++) + { + bool flexDetected; + + Neuropixels::detectFlex (basestation->slot, port, dock, &flexDetected); + + if (flexDetected) + { + flexCables.add (new Flex2 (this, dock)); + Neuropixels2* probe = new Neuropixels2 (basestation, this, flexCables.getLast(), dock); + + if (probe->isValid) + { + probe->setStatus (SourceStatus::CONNECTING); + probes.add (probe); + } + else + { + delete probe; + probes.add (nullptr); + } + } + else + { + probes.add (nullptr); + } + } } -Flex2::Flex2(Headstage* hs_, int dock) : Flex(hs_, dock) +Flex2::Flex2 (Headstage* hs_, int dock) : Flex (hs_, dock) { - getInfo(); + getInfo(); - errorCode = Neuropixels::SUCCESS; + errorCode = Neuropixels::SUCCESS; } diff --git a/Source/Headstages/Headstage2.h b/Source/Headstages/Headstage2.h index e7355d8..8fa3a87 100644 --- a/Source/Headstages/Headstage2.h +++ b/Source/Headstages/Headstage2.h @@ -6,47 +6,70 @@ 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 file is part of the Open Ephys GUI + Copyright (C) 2024 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #ifndef __NEUROPIXHS2_H_2C4C2D67__ #define __NEUROPIXHS2_H_2C4C2D67__ - -#include "../API/v3/NeuropixAPI.h" #include "../NeuropixComponents.h" +/** + + Connects to a Neuropixels 2.0 probe +*/ class Headstage2 : public Headstage { public: - Headstage2::Headstage2(Basestation*, int port); - void getInfo() override; - bool hasTestModule() override { return false; } - void runTestModule() override {} - Neuropixels::NP_ErrorCode errorCode; + /** Constructor */ + Headstage2::Headstage2 (Basestation*, int port); + + /** Gets headstage info */ + void getInfo() override; + + /** No test module available for 2.0 probes, so this is always false */ + bool hasTestModule() override { return false; } + + /** No tests can be run */ + void runTestModule() override {} }; +/** + + Represents a Neuropixels 2.0 probe flex cable + +*/ class Flex2 : public Flex { public: - Flex2::Flex2(Headstage*, int dock); - void getInfo() override; - Neuropixels::NP_ErrorCode errorCode; + /** Constructor */ + Flex2::Flex2 (Headstage*, int dock); + + /** Gets flex info */ + void getInfo() override; }; -#endif // __NEUROPIXHS2_H_2C4C2D67__ \ No newline at end of file +#endif // __NEUROPIXHS2_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Headstages/Headstage_Analog128.cpp b/Source/Headstages/Headstage_Analog128.cpp index 226bbe8..95fff87 100644 --- a/Source/Headstages/Headstage_Analog128.cpp +++ b/Source/Headstages/Headstage_Analog128.cpp @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2018 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -28,65 +28,57 @@ along with this program. If not, see . void Headstage_Analog128::getInfo() { + int version_major; + int version_minor; - int version_major; - int version_minor; + errorCode = Neuropixels::getHSVersion (basestation->slot, port, &version_major, &version_minor); - errorCode = Neuropixels::getHSVersion(basestation->slot, port, &version_major, &version_minor); + info.version = String (version_major) + "." + String (version_minor); - info.version = String(version_major) + "." + String(version_minor); + errorCode = Neuropixels::readHSSN (basestation->slot, port, &info.serial_number); - errorCode = Neuropixels::readHSSN(basestation->slot, port, &info.serial_number); - - char pn[MAXLEN]; - errorCode = Neuropixels::readHSPN(basestation->slot, port, pn, MAXLEN); - - info.part_number = String(pn); + char pn[MAXLEN]; + errorCode = Neuropixels::readHSPN (basestation->slot, port, pn, MAXLEN); + info.part_number = String (pn); } - void Flex1_NHP::getInfo() { + int version_major; + int version_minor; - int version_major; - int version_minor; - - errorCode = Neuropixels::getFlexVersion(headstage->basestation->slot, - headstage->port, - dock, - &version_major, - &version_minor); + errorCode = Neuropixels::getFlexVersion (headstage->basestation->slot, + headstage->port, + dock, + &version_major, + &version_minor); - info.version = String(version_major) + "." + String(version_minor); + info.version = String (version_major) + "." + String (version_minor); - char pn[MAXLEN]; - errorCode = Neuropixels::readFlexPN(headstage->basestation->slot, - headstage->port, - dock, - pn, - MAXLEN); - - info.part_number = String(pn); + char pn[MAXLEN]; + errorCode = Neuropixels::readFlexPN (headstage->basestation->slot, + headstage->port, + dock, + pn, + MAXLEN); + info.part_number = String (pn); } - -Headstage_Analog128::Headstage_Analog128(Basestation* bs_, int port) : Headstage(bs_, port) +Headstage_Analog128::Headstage_Analog128 (Basestation* bs_, int port) : Headstage (bs_, port) { - getInfo(); + getInfo(); - flexCables.add(new Flex1_NHP(this)); + flexCables.add (new Flex1_NHP (this)); - probes.add(new Neuropixels_NHP_Passive(basestation, this, flexCables[0])); - probes[0]->setStatus(SourceStatus::CONNECTING); + probes.add (new Neuropixels_NHP_Passive (basestation, this, flexCables[0])); + probes[0]->setStatus (SourceStatus::CONNECTING); } - -Flex1_NHP::Flex1_NHP(Headstage* hs_) : Flex(hs_, 0) +Flex1_NHP::Flex1_NHP (Headstage* hs_) : Flex (hs_, 0) { - getInfo(); + getInfo(); - errorCode = Neuropixels::SUCCESS; + errorCode = Neuropixels::SUCCESS; } - diff --git a/Source/Headstages/Headstage_Analog128.h b/Source/Headstages/Headstage_Analog128.h index c694c75..1b3da50 100644 --- a/Source/Headstages/Headstage_Analog128.h +++ b/Source/Headstages/Headstage_Analog128.h @@ -1,52 +1,45 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #ifndef __NEUROPIXHS128_H_2C4C2D67__ #define __NEUROPIXHS128_H_2C4C2D67__ - -#include "../API/v3/NeuropixAPI.h" #include "../NeuropixComponents.h" - class Headstage_Analog128 : public Headstage { public: - Headstage_Analog128::Headstage_Analog128(Basestation*, int port); - void getInfo() override; - bool hasTestModule() override { return false; } - void runTestModule() override {} - - Neuropixels::NP_ErrorCode errorCode; + Headstage_Analog128::Headstage_Analog128 (Basestation*, int port); + void getInfo() override; + bool hasTestModule() override { return false; } + void runTestModule() override {} }; class Flex1_NHP : public Flex { public: - Flex1_NHP::Flex1_NHP(Headstage*); - void getInfo() override; - - Neuropixels::NP_ErrorCode errorCode; + Flex1_NHP::Flex1_NHP (Headstage*); + void getInfo() override; }; -#endif // __NEUROPIXHSNP1V1_H_2C4C2D67__ \ No newline at end of file +#endif // __NEUROPIXHSNP1V1_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Headstages/Headstage_Custom384.cpp b/Source/Headstages/Headstage_Custom384.cpp index f0093ba..4d56506 100644 --- a/Source/Headstages/Headstage_Custom384.cpp +++ b/Source/Headstages/Headstage_Custom384.cpp @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2018 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -28,65 +28,57 @@ along with this program. If not, see . void Headstage_Custom384::getInfo() { + int version_major; + int version_minor; - int version_major; - int version_minor; + errorCode = Neuropixels::getHSVersion (basestation->slot, port, &version_major, &version_minor); - errorCode = Neuropixels::getHSVersion(basestation->slot, port, &version_major, &version_minor); + info.version = String (version_major) + "." + String (version_minor); - info.version = String(version_major) + "." + String(version_minor); + errorCode = Neuropixels::readHSSN (basestation->slot, port, &info.serial_number); - errorCode = Neuropixels::readHSSN(basestation->slot, port, &info.serial_number); - - char pn[MAXLEN]; - errorCode = Neuropixels::readHSPN(basestation->slot, port, pn, MAXLEN); - - info.part_number = String(pn); + char pn[MAXLEN]; + errorCode = Neuropixels::readHSPN (basestation->slot, port, pn, MAXLEN); + info.part_number = String (pn); } - void Flex1_Custom::getInfo() { + int version_major; + int version_minor; - int version_major; - int version_minor; - - errorCode = Neuropixels::getFlexVersion(headstage->basestation->slot, - headstage->port, - dock, - &version_major, - &version_minor); + errorCode = Neuropixels::getFlexVersion (headstage->basestation->slot, + headstage->port, + dock, + &version_major, + &version_minor); - info.version = String(version_major) + "." + String(version_minor); + info.version = String (version_major) + "." + String (version_minor); - char pn[MAXLEN]; - errorCode = Neuropixels::readFlexPN(headstage->basestation->slot, - headstage->port, - dock, - pn, - MAXLEN); - - info.part_number = String(pn); + char pn[MAXLEN]; + errorCode = Neuropixels::readFlexPN (headstage->basestation->slot, + headstage->port, + dock, + pn, + MAXLEN); + info.part_number = String (pn); } - -Headstage_Custom384::Headstage_Custom384(Basestation* bs_, int port) : Headstage(bs_, port) +Headstage_Custom384::Headstage_Custom384 (Basestation* bs_, int port) : Headstage (bs_, port) { - getInfo(); + getInfo(); - flexCables.add(new Flex1_Custom(this)); + flexCables.add (new Flex1_Custom (this)); - probes.add(new CustomPassiveProbe(basestation, this, flexCables[0])); - probes[0]->setStatus(SourceStatus::CONNECTING); + probes.add (new CustomPassiveProbe (basestation, this, flexCables[0])); + probes[0]->setStatus (SourceStatus::CONNECTING); } - -Flex1_Custom::Flex1_Custom(Headstage* hs_) : Flex(hs_, 0) +Flex1_Custom::Flex1_Custom (Headstage* hs_) : Flex (hs_, 0) { - getInfo(); + getInfo(); - errorCode = Neuropixels::SUCCESS; + errorCode = Neuropixels::SUCCESS; } - diff --git a/Source/Headstages/Headstage_Custom384.h b/Source/Headstages/Headstage_Custom384.h index e0f871c..5227739 100644 --- a/Source/Headstages/Headstage_Custom384.h +++ b/Source/Headstages/Headstage_Custom384.h @@ -1,34 +1,31 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #ifndef __NEUROPIXHSCUSTOM_H_2C4C2D67__ #define __NEUROPIXHSCUSTOM_H_2C4C2D67__ - -#include "../API/v3/NeuropixAPI.h" #include "../NeuropixComponents.h" - /** Custom headstage with 384-channel Neuropixels chip @@ -37,20 +34,17 @@ along with this program. If not, see . class Headstage_Custom384 : public Headstage { public: + /** Constructor */ + Headstage_Custom384::Headstage_Custom384 (Basestation*, int port); - /** Constructor */ - Headstage_Custom384::Headstage_Custom384(Basestation*, int port); - - /** Get part numbers*/ - void getInfo() override; + /** Get part numbers*/ + void getInfo() override; - /** Override hasTestModule() */ - bool hasTestModule() override { return false; } + /** Override hasTestModule() */ + bool hasTestModule() override { return false; } - /** No test module available*/ - void runTestModule() override {} - - Neuropixels::NP_ErrorCode errorCode; + /** No test module available*/ + void runTestModule() override {} }; /** @@ -60,14 +54,11 @@ class Headstage_Custom384 : public Headstage class Flex1_Custom : public Flex { public: + /** Constructor */ + Flex1_Custom::Flex1_Custom (Headstage*); - /** Constructor */ - Flex1_Custom::Flex1_Custom(Headstage*); - - /** Get part number */ - void getInfo() override; - - Neuropixels::NP_ErrorCode errorCode; + /** Get part number */ + void getInfo() override; }; -#endif // __NEUROPIXHSNP1V1_H_2C4C2D67__ \ No newline at end of file +#endif // __NEUROPIXHSNP1V1_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Headstages/Headstage_QuadBase.cpp b/Source/Headstages/Headstage_QuadBase.cpp new file mode 100644 index 0000000..d45e135 --- /dev/null +++ b/Source/Headstages/Headstage_QuadBase.cpp @@ -0,0 +1,111 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + +#include "Headstage_QuadBase.h" +#include "../Probes/Neuropixels_QuadBase.h" + +#define MAXLEN 50 + +void Headstage_QuadBase::getInfo() +{ + int version_major; + int version_minor; + + errorCode = Neuropixels::getHSVersion (basestation->slot, port, &version_major, &version_minor); + + info.version = String (version_major) + "." + String (version_minor); + + errorCode = Neuropixels::readHSSN (basestation->slot, port, &info.serial_number); + + char pn[MAXLEN]; + errorCode = Neuropixels::readHSPN (basestation->slot, port, pn, MAXLEN); + + info.part_number = String (pn); +} + +void Flex_QuadBase::getInfo() +{ + int version_major; + int version_minor; + + errorCode = Neuropixels::getFlexVersion (headstage->basestation->slot, + headstage->port, + dock, + &version_major, + &version_minor); + + info.version = String (version_major) + "." + String (version_minor); + + char pn[MAXLEN]; + errorCode = Neuropixels::readFlexPN (headstage->basestation->slot, + headstage->port, + dock, + pn, + MAXLEN); + + info.part_number = String (pn); +} + +Headstage_QuadBase::Headstage_QuadBase (Basestation* bs_, int port) : Headstage (bs_, port) +{ + getInfo(); + + int count; + + Neuropixels::getHSSupportedProbeCount (basestation->slot, port, &count); + + for (int dock = 1; dock <= count; dock++) + { + bool flexDetected; + + Neuropixels::detectFlex (basestation->slot, port, dock, &flexDetected); + + if (flexDetected) + { + flexCables.add (new Flex_QuadBase (this, dock)); + Neuropixels_QuadBase* probe = new Neuropixels_QuadBase (basestation, this, flexCables.getLast(), dock); + + if (probe->isValid) + { + probe->setStatus (SourceStatus::CONNECTING); + probes.add (probe); + } + else + { + delete probe; + probes.add (nullptr); + } + } + else + { + probes.add (nullptr); + } + } +} + +Flex_QuadBase::Flex_QuadBase (Headstage* hs_, int dock) : Flex (hs_, dock) +{ + getInfo(); + + errorCode = Neuropixels::SUCCESS; +} \ No newline at end of file diff --git a/Source/Headstages/Headstage_QuadBase.h b/Source/Headstages/Headstage_QuadBase.h new file mode 100644 index 0000000..deafde1 --- /dev/null +++ b/Source/Headstages/Headstage_QuadBase.h @@ -0,0 +1,45 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 . + +*/ + +#ifndef __NEUROPIXHSP2C_H_2C4C2D67__ +#define __NEUROPIXHSP2C_H_2C4C2D67__ + +#include "../NeuropixComponents.h" + +class Headstage_QuadBase : public Headstage +{ +public: + Headstage_QuadBase::Headstage_QuadBase (Basestation*, int port); + void getInfo() override; + bool hasTestModule() override { return false; } + void runTestModule() override {} +}; + +class Flex_QuadBase : public Flex +{ +public: + Flex_QuadBase::Flex_QuadBase (Headstage*, int dock); + void getInfo() override; +}; + +#endif // __NEUROPIXHSP2C_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/Headstages/SimulatedHeadstage.cpp b/Source/Headstages/SimulatedHeadstage.cpp index cd10fcc..1faafe0 100644 --- a/Source/Headstages/SimulatedHeadstage.cpp +++ b/Source/Headstages/SimulatedHeadstage.cpp @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -26,32 +26,28 @@ along with this program. If not, see . void SimulatedHeadstage::getInfo() { - info.version = "SIM0.0"; - info.part_number = "Simulated headstage"; + info.version = "SIM0.0"; + info.part_number = "Simulated headstage"; } - void SimulatedFlex::getInfo() { - - info.version = "SIM0.0"; - info.part_number = "Simulated flex"; + info.version = "SIM0.0"; + info.part_number = "Simulated flex"; } - -SimulatedHeadstage::SimulatedHeadstage(Basestation* bs, int port, String PN, int SN) : Headstage(bs, port) +SimulatedHeadstage::SimulatedHeadstage (Basestation* bs, int port, String PN, int SN) : Headstage (bs, port) { + getInfo(); - getInfo(); - - flexCables.add(new SimulatedFlex(this)); - - probes.add(new SimulatedProbe(basestation, this, flexCables[0], 1, PN, SN)); - probes[0]->setStatus(SourceStatus::CONNECTING); + flexCables.add (new SimulatedFlex (this)); - if (PN == "NP2000" || PN == "NP2010") - { - probes.add(nullptr); - } + probes.add (new SimulatedProbe (basestation, this, flexCables[0], 1, PN, SN)); + probes[0]->setStatus (SourceStatus::CONNECTING); + if (PN == "NP2003" || PN == "NP2004" || PN == "NP2013" || PN == "NP2014") + { + // 2.0 headstage, add a placeholder for second dock + probes.add (nullptr); + } } \ No newline at end of file diff --git a/Source/Headstages/SimulatedHeadstage.h b/Source/Headstages/SimulatedHeadstage.h index 676986e..9e64e6f 100644 --- a/Source/Headstages/SimulatedHeadstage.h +++ b/Source/Headstages/SimulatedHeadstage.h @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -37,18 +37,17 @@ class SimulatedProbe; class SimulatedHeadstage : public Headstage { public: - SimulatedHeadstage(Basestation* bs, int port, String PN, int SN); - void getInfo() override; - bool hasTestModule() override { return false; } - void runTestModule() override {} + SimulatedHeadstage (Basestation* bs, int port, String PN, int SN); + void getInfo() override; + bool hasTestModule() override { return false; } + void runTestModule() override {} }; class SimulatedFlex : public Flex { public: - SimulatedFlex(Headstage* headstage) : Flex(headstage, 0) { getInfo(); } - void getInfo() override; + SimulatedFlex (Headstage* headstage) : Flex (headstage, 0) { getInfo(); } + void getInfo() override; }; - -#endif // __SIMULATEDCOMPONENTS_H_2C4C2D67__ \ No newline at end of file +#endif // __SIMULATEDCOMPONENTS_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/NeuropixCanvas.cpp b/Source/NeuropixCanvas.cpp index 4586c5e..d2db588 100644 --- a/Source/NeuropixCanvas.cpp +++ b/Source/NeuropixCanvas.cpp @@ -1,87 +1,89 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright(C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 Open Ephys ------------------------------------------------------------------- + ------------------------------------------------------------------ -This program is free software : you can redistribute itand /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 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. + 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/>. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "NeuropixCanvas.h" -#include "UI/NeuropixInterface.h" -#include "UI/OneBoxInterface.h" #include "NeuropixEditor.h" #include "NeuropixThread.h" +#include "UI/NeuropixInterface.h" +#include "UI/OneBoxInterface.h" SettingsUpdater* SettingsUpdater::currentThread = nullptr; -CustomTabComponent::CustomTabComponent(NeuropixEditor* editor_, bool isTopLevel_) : - TabbedComponent(TabbedButtonBar::TabsAtTop), - editor(editor_), - isTopLevel(isTopLevel_) +CustomTabButton::CustomTabButton (const String& name, TabbedComponent* parent, bool isTopLevel_) : TabBarButton (name, parent->getTabbedButtonBar()), + isTopLevel (isTopLevel_) { - setTabBarDepth(26); - setOutline(0); - setIndent(0); } +void CustomTabButton::paintButton (Graphics& g, + bool isMouseOver, + bool isMouseDown) +{ + getTabbedButtonBar().setTabBackgroundColour (getIndex(), Colours::grey); + + getLookAndFeel().drawTabButton (*this, g, isMouseOver, isMouseDown); +} +CustomTabComponent::CustomTabComponent (NeuropixEditor* editor_, bool isTopLevel_) : TabbedComponent (TabbedButtonBar::TabsAtTop), + editor (editor_), + isTopLevel (isTopLevel_) +{ + setTabBarDepth (26); + setOutline (0); + setIndent (0); +} -void CustomTabComponent::currentTabChanged(int newCurrentTabIndex, const String& newCurrentTabName) +void CustomTabComponent::currentTabChanged (int newCurrentTabIndex, const String& newCurrentTabName) { if (isTopLevel) { - TabbedComponent* currentTab = (TabbedComponent*)getCurrentContentComponent(); + TabbedComponent* currentTab = (TabbedComponent*) getCurrentContentComponent(); if (currentTab != nullptr) { - CustomViewport* viewport = (CustomViewport*)currentTab->getCurrentContentComponent(); + CustomViewport* viewport = (CustomViewport*) currentTab->getCurrentContentComponent(); if (viewport != nullptr) - editor->selectSource(viewport->settingsInterface->dataSource); + editor->selectSource (viewport->settingsInterface->dataSource); } - } - else { - CustomViewport* viewport = (CustomViewport*)getCurrentContentComponent(); - + else + { + CustomViewport* viewport = (CustomViewport*) getCurrentContentComponent(); + if (viewport != nullptr) - editor->selectSource(viewport->settingsInterface->dataSource); + editor->selectSource (viewport->settingsInterface->dataSource); } - - // std::cout << newCurrentTabIndex << ", " << newCurrentTabName << std::endl; -} + // std::cout << newCurrentTabIndex << ", " << newCurrentTabName << std::endl; +} -NeuropixCanvas::NeuropixCanvas(GenericProcessor* processor_, NeuropixEditor* editor_, NeuropixThread* thread_) : - processor(processor_), - editor(editor_), - thread(thread_) +NeuropixCanvas::NeuropixCanvas (NeuropixEditor* editor_, NeuropixThread* thread_) : editor (editor_), + thread (thread_) { - - topLevelTabComponent = new CustomTabComponent(editor, true); - - topLevelTabComponent->setColour(TabbedComponent::outlineColourId, - Colours::darkgrey); - topLevelTabComponent->setColour(TabbedComponent::backgroundColourId, - Colours::black.withAlpha(0.0f)); - addAndMakeVisible(topLevelTabComponent); + topLevelTabComponent = std::make_unique (editor, true); + addAndMakeVisible (topLevelTabComponent.get()); Array availableBasestations = thread->getBasestations(); @@ -89,84 +91,24 @@ NeuropixCanvas::NeuropixCanvas(GenericProcessor* processor_, NeuropixEditor* edi for (auto basestation : availableBasestations) { + CustomTabComponent* basestationTab = new CustomTabComponent (editor, false); + topLevelTabComponent->addTab (String (" Slot " + String (basestation->slot) + " "), + Colours::grey, + basestationTab, + true); - CustomTabComponent* basestationTab = new CustomTabComponent(editor, false); - topLevelTabComponent->addTab(String(" Slot " + String(basestation->slot) + " "), - Colour(70,70,70), - basestationTab, - true); - - basestationTab->setTabBarDepth(26); - basestationTab->setIndent(0); // gap to leave around the edge - basestationTab->setOutline(0); - basestationTabs.add(basestationTab); - - int probeCount = basestation->getProbes().size(); - basestations.add(basestation); - - Array availableDataSources = thread->getDataSources(); - - int basestationTabNumber = 0; - - for (auto source : availableDataSources) - { - - if (source->sourceType == DataSourceType::PROBE && source->basestation == basestation) - { - NeuropixInterface* neuropixInterface = new NeuropixInterface(source, thread, editor, this); - settingsInterfaces.add((SettingsInterface*)neuropixInterface); - - basestationTab->addTab(" " + source->getName() + " ", - Colours::darkgrey, - neuropixInterface->viewport.get(), - false); - - topLevelTabIndex.add(topLevelTabNumber); - basestationTabIndex.add(basestationTabNumber++); - - } - else if (source->sourceType == DataSourceType::ADC && source->basestation == basestation) - { - OneBoxInterface* oneBoxInterface = new OneBoxInterface(source, thread, editor, this); - settingsInterfaces.add(oneBoxInterface); - - //addChildComponent(oneBoxInterface->viewport.get()); - basestationTab->addTab(" " + source->getName() + " ", - Colours::darkgrey, - oneBoxInterface->viewport.get(), - false); - - topLevelTabIndex.add(topLevelTabNumber); - basestationTabIndex.add(basestationTabNumber++); - } - // else if (source->sourceType == DataSourceType::DAC) - // { - // DacInterface* dacInterface = new DacInterface(source, thread, editor, this); - // settingsInterfaces.add(dacInterface); - //} - - dataSources.add(source); + basestationTab->setTabBarDepth (26); + basestationTab->setIndent (0); // gap to leave around the edge + basestationTab->setOutline (0); + basestationTabs.add (basestationTab); - } + basestations.add (basestation); - if (basestationTabNumber == 0) - { - BasestationInterface* basestationInterface = new BasestationInterface(basestation, thread, editor, this); - settingsInterfaces.add(basestationInterface); - basestationTab->addTab(" Firmware Update ", - Colours::darkgrey, - basestationInterface->viewport.get(), - false); - topLevelTabIndex.add(topLevelTabNumber); - basestationTabIndex.add(basestationTabNumber++); - - dataSources.add(nullptr); - } + populateSourceTabs (basestation, basestationTab, topLevelTabNumber); - topLevelTabNumber += 1; } - topLevelTabComponent->setCurrentTabIndex(topLevelTabNumber - 1); + topLevelTabComponent->setCurrentTabIndex (topLevelTabNumber - 1); //neuropixViewport->setViewedComponent(settingsInterfaces.getFirst(), false); //addAndMakeVisible(neuropixViewport); @@ -178,14 +120,77 @@ NeuropixCanvas::NeuropixCanvas(GenericProcessor* processor_, NeuropixEditor* edi savedSettings.probeType = ProbeType::NONE; } -NeuropixCanvas::~NeuropixCanvas() +void NeuropixCanvas::populateSourceTabs(Basestation* basestation, CustomTabComponent* basestationTab, int &topLevelTabNumber) { + int probeCount = basestation->getProbes().size(); + Array availableDataSources = thread->getDataSources(); + + int basestationTabNumber = 0; + + for (auto source : availableDataSources) + { + if (source->sourceType == DataSourceType::PROBE && source->basestation == basestation) + { + NeuropixInterface* neuropixInterface = new NeuropixInterface (source, thread, editor, this); + settingsInterfaces.add ((SettingsInterface*) neuropixInterface); + + LOGD("### Setting tab name: ", source->getName()); + + basestationTab->addTab (" " + source->getName() + " ", + Colours::darkgrey, + neuropixInterface->viewport.get(), + false); + + topLevelTabIndex.add (topLevelTabNumber); + basestationTabIndex.add (basestationTabNumber++); + } + else if (source->sourceType == DataSourceType::ADC && source->basestation == basestation) + { + OneBoxInterface* oneBoxInterface = new OneBoxInterface (source, thread, editor, this); + settingsInterfaces.add (oneBoxInterface); + + //addChildComponent(oneBoxInterface->viewport.get()); + basestationTab->addTab (" " + source->getName() + " ", + Colours::darkgrey, + oneBoxInterface->viewport.get(), + false); + + topLevelTabIndex.add (topLevelTabNumber); + basestationTabIndex.add (basestationTabNumber++); + } + // else if (source->sourceType == DataSourceType::DAC) + // { + // DacInterface* dacInterface = new DacInterface(source, thread, editor, this); + // settingsInterfaces.add(dacInterface); + //} + + dataSources.add (source); + } + + if (basestationTabNumber == 0) + { + BasestationInterface* basestationInterface = new BasestationInterface (basestation, thread, editor, this); + settingsInterfaces.add (basestationInterface); + basestationTab->addTab (" Firmware Update ", + Colours::darkgrey, + basestationInterface->viewport.get(), + false); + topLevelTabIndex.add (topLevelTabNumber); + basestationTabIndex.add (basestationTabNumber++); + + dataSources.add (nullptr); + } + + topLevelTabNumber += 1; } -void NeuropixCanvas::paint(Graphics& g) +NeuropixCanvas::~NeuropixCanvas() { +} +void NeuropixCanvas::paint (Graphics& g) +{ } void NeuropixCanvas::refresh() @@ -205,81 +210,80 @@ void NeuropixCanvas::update() for (int i = 0; i < topLevelTabComponent->getNumTabs(); i++) { - CustomTabComponent* t = (CustomTabComponent*)topLevelTabComponent->getTabContentComponent(i); - + CustomTabComponent* t = (CustomTabComponent*) topLevelTabComponent->getTabContentComponent (i); + for (int j = 0; j < t->getNumTabs(); j++) { - if (t->getTabContentComponent(j) != nullptr) - { - CustomViewport* v = (CustomViewport*)t->getTabContentComponent(j); + if (t->getTabContentComponent (j) != nullptr) + { + CustomViewport* v = (CustomViewport*) t->getTabContentComponent (j); if (v != nullptr) { - DataSource* dataSource = v->settingsInterface->dataSource; if (dataSource != nullptr) - t->setTabName(j, " " + dataSource->getName() + " "); + t->setTabName (j, " " + dataSource->getName() + " "); else - t->setTabName(j, "Firmware update"); + t->setTabName (j, "Firmware update"); } - } + } } } } - void NeuropixCanvas::resized() { - - topLevelTabComponent->setBounds(0, -3, getWidth(), getHeight()+3); - + topLevelTabComponent->setBounds (0, -3, getWidth(), getHeight() + 3); } - void NeuropixCanvas::startAcquisition() -{ +{ for (auto settingsInterface : settingsInterfaces) - settingsInterface->startAcquisition(); + { + if (settingsInterface->dataSource != nullptr) + { + settingsInterface->startAcquisition(); + } + } } void NeuropixCanvas::stopAcquisition() { for (auto settingsInterface : settingsInterfaces) - settingsInterface->stopAcquisition(); + { + if (settingsInterface->dataSource != nullptr) + { + settingsInterface->stopAcquisition(); + } + } } -void NeuropixCanvas::setSelectedInterface(DataSource* dataSource) +void NeuropixCanvas::setSelectedInterface (DataSource* dataSource) { if (dataSource != nullptr) { + int index = dataSources.indexOf (dataSource); + // std::cout << "Index: " << index << std::endl; + //std::cout << "Top Level Tab Index: " << topLevelTabIndex[index] << std::endl; + //std::cout << "Basestation Tab Index: " << basestationTabIndex[index] << std::endl; - int index = dataSources.indexOf(dataSource); - // std::cout << "Index: " << index << std::endl; - //std::cout << "Top Level Tab Index: " << topLevelTabIndex[index] << std::endl; - //std::cout << "Basestation Tab Index: " << basestationTabIndex[index] << std::endl; - - topLevelTabComponent->setCurrentTabIndex(topLevelTabIndex[index], false); - basestationTabs[topLevelTabIndex[index]]->setCurrentTabIndex(basestationTabIndex[index], false); + topLevelTabComponent->setCurrentTabIndex (topLevelTabIndex[index], false); + basestationTabs[topLevelTabIndex[index]]->setCurrentTabIndex (basestationTabIndex[index], false); } - } -void NeuropixCanvas::setSelectedBasestation(Basestation* basestation) +void NeuropixCanvas::setSelectedBasestation (Basestation* basestation) { - if (basestation != nullptr) { + int index = basestations.indexOf (basestation); - int index = basestations.indexOf(basestation); - - topLevelTabComponent->setCurrentTabIndex(index, false); - + topLevelTabComponent->setCurrentTabIndex (index, false); } - } -void NeuropixCanvas::storeProbeSettings(ProbeSettings p) +void NeuropixCanvas::storeProbeSettings (ProbeSettings p) { savedSettings = p; } @@ -289,10 +293,9 @@ ProbeSettings NeuropixCanvas::getProbeSettings() return savedSettings; } -void NeuropixCanvas::applyParametersToAllProbes(ProbeSettings p) +void NeuropixCanvas::applyParametersToAllProbes (ProbeSettings p) { - - std::unique_ptr settingsUpdater = std::make_unique(this, p); + std::unique_ptr settingsUpdater = std::make_unique (this, p); /* for (auto settingsInterface : settingsInterfaces) { @@ -311,28 +314,25 @@ void NeuropixCanvas::applyParametersToAllProbes(ProbeSettings p) editor->uiLoader->startThread(); */ - CoreServices::updateSignalChain(editor); + CoreServices::updateSignalChain (editor); } -void NeuropixCanvas::saveCustomParametersToXml(XmlElement* xml) +void NeuropixCanvas::saveCustomParametersToXml (XmlElement* xml) { - for (int i = 0; i < settingsInterfaces.size(); i++) - settingsInterfaces[i]->saveParameters(xml); + settingsInterfaces[i]->saveParameters (xml); } -void NeuropixCanvas::loadCustomParametersFromXml(XmlElement* xml) +void NeuropixCanvas::loadCustomParametersFromXml (XmlElement* xml) { - for (int i = 0; i < settingsInterfaces.size(); i++) - settingsInterfaces[i]->loadParameters(xml); + settingsInterfaces[i]->loadParameters (xml); } -SettingsUpdater::SettingsUpdater(NeuropixCanvas* canvas_, ProbeSettings p) : - ThreadWithProgressWindow("Updating settings", true, true), - canvas(canvas_), - settings(p), - numProbesToUpdate(0) +SettingsUpdater::SettingsUpdater (NeuropixCanvas* canvas_, ProbeSettings p) : ThreadWithProgressWindow ("Updating settings", true, true), + canvas (canvas_), + settings (p), + numProbesToUpdate (0) { SettingsUpdater::currentThread = this; @@ -341,10 +341,10 @@ SettingsUpdater::SettingsUpdater(NeuropixCanvas* canvas_, ProbeSettings p) : { if (settingsInterface->type == SettingsInterface::PROBE_SETTINGS_INTERFACE) { - NeuropixInterface* ni = (NeuropixInterface*)settingsInterface; + NeuropixInterface* ni = (NeuropixInterface*) settingsInterface; if (ni->probe->type == settings.probe->type && ni->probe->getName() != settings.probe->getName()) { - ni->applyProbeSettings(settings, false); + ni->applyProbeSettings (settings, false); numProbesToUpdate++; } } @@ -352,13 +352,13 @@ SettingsUpdater::SettingsUpdater(NeuropixCanvas* canvas_, ProbeSettings p) : if (numProbesToUpdate > 0) { - String message = "Found " + String(numProbesToUpdate) + (numProbesToUpdate > 1 ? " probes " : " probe ") + "to update"; - this->setStatusMessage(message); - runThread(); + String message = "Found " + String (numProbesToUpdate) + (numProbesToUpdate > 1 ? " probes " : " probe ") + "to update"; + this->setStatusMessage (message); + runThread(); } else { - CoreServices::sendStatusMessage("No probes of same type found, not applying settings."); + CoreServices::sendStatusMessage ("No probes of same type found, not applying settings."); } } @@ -371,22 +371,22 @@ void SettingsUpdater::run() { if (settingsInterface->type == SettingsInterface::PROBE_SETTINGS_INTERFACE) { - NeuropixInterface* ni = (NeuropixInterface*)settingsInterface; + NeuropixInterface* ni = (NeuropixInterface*) settingsInterface; if (ni->probe->type == settings.probe->type && settings.probe->getName() != ni->probe->getName()) { count++; - this->setStatusMessage("Updating settings for " + ni->probe->getName() + " (" + String(count) + " of " + String(numProbesToUpdate) + ")"); + this->setStatusMessage ("Updating settings for " + ni->probe->getName() + " (" + String (count) + " of " + String (numProbesToUpdate) + ")"); ni->updateProbeSettingsInBackground(); float updateTime = 1000.0; // milliseconds for (float fraction = 0.0; fraction < 1.0; fraction += 0.01) { - currentThread->setProgress(float(count + fraction - 1) / float(numProbesToUpdate)); - Time::waitForMillisecondCounter(Time::getMillisecondCounter() + updateTime / 100.0); + currentThread->setProgress (float (count + fraction - 1) / float (numProbesToUpdate)); + Time::waitForMillisecondCounter (Time::getMillisecondCounter() + updateTime / 100.0); } while (canvas->editor->uiLoader->isThreadRunning()) - Time::waitForMillisecondCounter(10); + Time::waitForMillisecondCounter (10); } } } - CoreServices::sendStatusMessage("Applied saved settings to all probes of same type."); + CoreServices::sendStatusMessage ("Applied saved settings to all probes of same type."); } diff --git a/Source/NeuropixCanvas.h b/Source/NeuropixCanvas.h index a92542b..fa5fa52 100644 --- a/Source/NeuropixCanvas.h +++ b/Source/NeuropixCanvas.h @@ -2,7 +2,7 @@ ------------------------------------------------------------------ This file is part of the Open Ephys GUI - Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + Copyright (C) 2024 Open Ephys ------------------------------------------------------------------ @@ -21,7 +21,7 @@ */ -#include +#include #include "NeuropixComponents.h" #include "UI/SettingsInterface.h" @@ -31,6 +31,24 @@ class NeuropixEditor; class Probe; +/** + + TabBarButton with custom appearance + +*/ +class CustomTabButton : public TabBarButton +{ +public: + /** Constructor */ + CustomTabButton (const String& name, TabbedComponent* parent, bool isTopLevel_); + + /** Paints the button */ + void paintButton (Graphics& g, bool isMouseOver, bool isMouseDown) override; + +private: + bool isTopLevel; +}; + /** Adds a callback when tab is changed @@ -40,16 +58,21 @@ class Probe; class CustomTabComponent : public TabbedComponent { public: + /** Constructor */ + CustomTabComponent (NeuropixEditor* editor_, bool isTopLevel_); - /** Constructor */ - CustomTabComponent(NeuropixEditor* editor_, bool isTopLevel_); + /** Create tab buttons*/ + TabBarButton* createTabButton (const juce::String& name, int index) override + { + return new CustomTabButton (name, this, isTopLevel); + } - /**/ - void currentTabChanged(int newCurrentTabIndex, const String& newCurrentTabName) override; + /**/ + void currentTabChanged (int newCurrentTabIndex, const String& newCurrentTabName) override; private: - NeuropixEditor* editor; - bool isTopLevel; + NeuropixEditor* editor; + bool isTopLevel; }; /** @@ -60,89 +83,86 @@ class CustomTabComponent : public TabbedComponent class NeuropixCanvas : public Visualizer { public: + /** Constructor */ + NeuropixCanvas (NeuropixEditor*, NeuropixThread*); - /** Constructor */ - NeuropixCanvas(GenericProcessor*, NeuropixEditor*, NeuropixThread*); - - /** Destructor */ - ~NeuropixCanvas(); + /** Destructor */ + ~NeuropixCanvas(); - /** Fills background */ - void paint(Graphics& g); + /** Fills background */ + void paint (Graphics& g); - /** Renders the Visualizer on each animation callback cycle */ - void refresh(); + /** Renders the Visualizer on each animation callback cycle */ + void refresh() override; - /** Starts animation (not needed for this component) */ - void beginAnimation() override { } + /** Starts animation (not needed for this component) */ + void beginAnimation() override {} - /** Stops animation (not needed for this component) */ - void endAnimation() override { } + /** Stops animation (not needed for this component) */ + void endAnimation() override {} - /** Called when the Visualizer's tab becomes visible after being hidden */ - void refreshState(); + /** Called when the Visualizer's tab becomes visible after being hidden */ + void refreshState() override; - /** Called when the Visualizer is first created, and optionally when + /** Called when the Visualizer is first created, and optionally when the parameters of the underlying processor are changed */ - void update(); + void update(); - /** Sets which interface is active */ - void setSelectedInterface(DataSource* d); + /** Sets which interface is active */ + void setSelectedInterface (DataSource* d); - /** Set which basestation interface is active */ - void setSelectedBasestation(Basestation* b); + /** Set which basestation interface is active */ + void setSelectedBasestation (Basestation* b); - /** Starts animation of sub-interfaces */ - void startAcquisition(); + /** Starts animation of sub-interfaces */ + void startAcquisition(); - /** Stops animation of sub-interfaces */ - void stopAcquisition(); + /** Stops animation of sub-interfaces */ + void stopAcquisition(); - /** Stores probe settings (for copying) */ - void storeProbeSettings(ProbeSettings p); + /** Called when the basestation is created or refreshed */ + void populateSourceTabs(Basestation* basestation, CustomTabComponent* basestationTab, int &topLevelTabNumber); - /** Gets the most recent probe settings (for copying) */ - ProbeSettings getProbeSettings(); + /** Stores probe settings (for copying) */ + void storeProbeSettings (ProbeSettings p); - /** Applies settings to all probes */ - void applyParametersToAllProbes(ProbeSettings p); + /** Gets the most recent probe settings (for copying) */ + ProbeSettings getProbeSettings(); - /** Saves custom UI settings */ - void saveCustomParametersToXml(XmlElement* xml) override; + /** Applies settings to all probes */ + void applyParametersToAllProbes (ProbeSettings p); - /** Loads custom UI settings*/ - void loadCustomParametersFromXml(XmlElement* xml) override; + /** Saves custom UI settings */ + void saveCustomParametersToXml (XmlElement* xml) override; - /** Sets bounds of sub-components*/ - void resized(); + /** Loads custom UI settings*/ + void loadCustomParametersFromXml (XmlElement* xml) override; - ProbeSettings savedSettings; + /** Sets bounds of sub-components*/ + void resized(); - OwnedArray settingsInterfaces; - Array dataSources; - Array basestations; + ProbeSettings savedSettings; - NeuropixEditor* editor; - NeuropixThread* thread; + OwnedArray settingsInterfaces; + Array dataSources; + Array basestations; - GenericProcessor* processor; + NeuropixEditor* editor; + NeuropixThread* thread; private: + std::unique_ptr topLevelTabComponent; + Array basestationTabs; - ScopedPointer topLevelTabComponent; - Array basestationTabs; - - Array topLevelTabIndex; - Array basestationTabIndex; - + Array topLevelTabIndex; + Array basestationTabIndex; }; class SettingsUpdater : public ThreadWithProgressWindow { public: - /** Constructor */ - SettingsUpdater(NeuropixCanvas* canvas, ProbeSettings p); + SettingsUpdater (NeuropixCanvas* canvas, ProbeSettings p); /** Destructor */ ~SettingsUpdater() {} @@ -151,7 +171,7 @@ class SettingsUpdater : public ThreadWithProgressWindow void run() override; /** Callback to update progress bar*/ - /* + /* static int settingsUpdateCallback(size_t count) { currentThread->setProgress(float(count) / float(numProbesToUpdate)); @@ -164,6 +184,6 @@ class SettingsUpdater : public ThreadWithProgressWindow int numProbesToUpdate; private: - NeuropixCanvas* canvas; - ProbeSettings settings; + NeuropixCanvas* canvas; + ProbeSettings settings; }; \ No newline at end of file diff --git a/Source/NeuropixComponents.cpp b/Source/NeuropixComponents.cpp index dfec5d6..559404b 100644 --- a/Source/NeuropixComponents.cpp +++ b/Source/NeuropixComponents.cpp @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2018 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -26,220 +26,187 @@ along with this program. If not, see . float FirmwareUpdater::totalFirmwareBytes = 0; FirmwareUpdater* FirmwareUpdater::currentThread = nullptr; - -Probe::Probe(Basestation* bs_, Headstage* hs_, Flex* fl_, int dock_) - : DataSource(bs_), - headstage(hs_), - flex(fl_), - dock(dock_), - isValid(true), - isCalibrated(false), - calibrationWarningShown(false) +Probe::Probe (Basestation* bs_, Headstage* hs_, Flex* fl_, int dock_) + : DataSource (bs_), + headstage (hs_), + flex (fl_), + dock (dock_), + isValid (true), + isCalibrated (false), + calibrationWarningShown (false) { - - for (int i = 0; i < 12 * MAXPACKETS; i++) - timestamp_s[i] = -1.0; - - sourceType = DataSourceType::PROBE; - - for (int i = 0; i < 384; i++) - { - for (int j = 0; j < 100; j++) - { - ap_offsets[i][j] = 0; - lfp_offsets[i][j] = 0; - } - } - + for (int i = 0; i < 12 * MAXPACKETS; i++) + timestamp_s[i] = -1.0; + + sourceType = DataSourceType::PROBE; + + for (int i = 0; i < 384; i++) + { + for (int j = 0; j < 100; j++) + { + ap_offsets[i][j] = 0; + lfp_offsets[i][j] = 0; + } + } } -void Probe::updateOffsets(float* samples, int64 timestamp, bool isApBand) +void Probe::updateOffsets (float* samples, int64 timestamp, bool isApBand) { - - if (isApBand && timestamp > 30000 * 5) // wait for amplifiers to settle - { - - if (ap_offset_counter < 99) - { - for (int i = 0; i < 384; i++) - { - ap_offsets[i][ap_offset_counter+1] = samples[i]; - } - - ap_offset_counter++; - } - else if (ap_offset_counter == 99) - { - for (int i = 0; i < 384; i++) - { - - for (int j = 1; j < 100; j++) - { - ap_offsets[i][0] += ap_offsets[i][j]; - } - - ap_offsets[i][0] /= 99; - - } - - ap_offset_counter++; - } - - } - else if (!isApBand && timestamp > 2500 * 5) // wait for amplifiers to settle - { - - if (lfp_offset_counter < 99) - { - for (int i = 0; i < 384; i++) - { - lfp_offsets[i][lfp_offset_counter+1] = samples[i]; - } - - lfp_offset_counter++; - } - else if (lfp_offset_counter == 99) - { - for (int i = 0; i < 384; i++) - { - - for (int j = 1; j < 100; j++) - { - lfp_offsets[i][0] += lfp_offsets[i][j]; - } - - lfp_offsets[i][0] /= 99; - - } - - lfp_offset_counter++; - } - - } - + if (isApBand && timestamp > 30000 * 5) // wait for amplifiers to settle + { + if (ap_offset_counter < 99) + { + for (int i = 0; i < 384; i++) + { + ap_offsets[i][ap_offset_counter + 1] = samples[i]; + } + + ap_offset_counter++; + } + else if (ap_offset_counter == 99) + { + for (int i = 0; i < 384; i++) + { + for (int j = 1; j < 100; j++) + { + ap_offsets[i][0] += ap_offsets[i][j]; + } + + ap_offsets[i][0] /= 99; + } + + ap_offset_counter++; + } + } + else if (! isApBand && timestamp > 2500 * 5) // wait for amplifiers to settle + { + if (lfp_offset_counter < 99) + { + for (int i = 0; i < 384; i++) + { + lfp_offsets[i][lfp_offset_counter + 1] = samples[i]; + } + + lfp_offset_counter++; + } + else if (lfp_offset_counter == 99) + { + for (int i = 0; i < 384; i++) + { + for (int j = 1; j < 100; j++) + { + lfp_offsets[i][0] += lfp_offsets[i][j]; + } + + lfp_offsets[i][0] /= 99; + } + + lfp_offset_counter++; + } + } } -void Probe::updateNamingScheme(ProbeNameConfig::NamingScheme scheme) +void Probe::updateNamingScheme (ProbeNameConfig::NamingScheme scheme) { - namingScheme = scheme; - - switch (scheme) - { - case ProbeNameConfig::AUTO_NAMING: - displayName = customName.automatic; - break; - case ProbeNameConfig::STREAM_INDICES: - displayName = customName.streamSpecific; - break; - case ProbeNameConfig::PORT_SPECIFIC_NAMING: - displayName = basestation->getCustomPortName(headstage->port, dock); - break; - case ProbeNameConfig::PROBE_SPECIFIC_NAMING: - displayName = customName.probeSpecific; - break; - } + namingScheme = scheme; + + switch (scheme) + { + case ProbeNameConfig::AUTO_NAMING: + displayName = customName.automatic; + break; + case ProbeNameConfig::STREAM_INDICES: + displayName = customName.streamSpecific; + break; + case ProbeNameConfig::PORT_SPECIFIC_NAMING: + displayName = basestation->getCustomPortName (headstage->port, dock); + break; + case ProbeNameConfig::PROBE_SPECIFIC_NAMING: + displayName = customName.probeSpecific; + break; + } } - -FirmwareUpdater::FirmwareUpdater(Basestation* basestation_, File firmwareFile_, FirmwareType type) - : ThreadWithProgressWindow("Firmware Update...", true, false), - basestation(basestation_), - firmwareType(type) +FirmwareUpdater::FirmwareUpdater (Basestation* basestation_, File firmwareFile_, FirmwareType type) + : ThreadWithProgressWindow ("Firmware Update...", true, false), + basestation (basestation_), + firmwareType (type) { - FirmwareUpdater::currentThread = this; - - FirmwareUpdater::totalFirmwareBytes = (float) firmwareFile_.getSize(); + FirmwareUpdater::currentThread = this; - auto window = getAlertWindow(); - window->setColour(AlertWindow::textColourId, Colours::white); - window->setColour(AlertWindow::backgroundColourId, Colour::fromRGB(50, 50, 50)); + FirmwareUpdater::totalFirmwareBytes = (float) firmwareFile_.getSize(); - firmwareFilePath = firmwareFile_.getFullPathName(); + auto window = getAlertWindow(); + window->setColour (AlertWindow::textColourId, Colours::white); + window->setColour (AlertWindow::backgroundColourId, Colour::fromRGB (50, 50, 50)); - LOGD("Firmware path: ", firmwareFilePath); + firmwareFilePath = firmwareFile_.getFullPathName(); - if (firmwareType == FirmwareType::BSC_FIRMWARE) - { - this->setStatusMessage("Updating BSC firmware..."); - } - else { - this->setStatusMessage("Updating BS firmware..."); - } + LOGD ("Firmware path: ", firmwareFilePath); - runThread(); + if (firmwareType == FirmwareType::BSC_FIRMWARE) + { + this->setStatusMessage ("Updating BSC firmware..."); + } + else + { + this->setStatusMessage ("Updating BS firmware..."); + } - if (firmwareType == FirmwareType::BSC_FIRMWARE) - AlertWindow::showMessageBoxAsync(AlertWindow::InfoIcon, "Successful firmware update", - String("Basestation connect board firmware updated successfully. Please update the basestation firmware now.")); - else - AlertWindow::showMessageBoxAsync(AlertWindow::InfoIcon, "Successful firmware update", - String("Please restart your computer and power cycle the PXI chassis for the changes to take effect.")); + runThread(); + if (firmwareType == FirmwareType::BSC_FIRMWARE) + AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Successful firmware update", String ("Basestation connect board firmware updated successfully. Please update the basestation firmware now.")); + else + AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Successful firmware update", String ("Please restart your computer and power cycle the PXI chassis for the changes to take effect.")); } void FirmwareUpdater::run() { - - if (firmwareType == FirmwareType::BSC_FIRMWARE) - { - - if (basestation->type == BasestationType::V1) - { - np::qbsc_update(basestation->slot_c, - firmwareFilePath.getCharPointer(), - firmwareUpdateCallback); - } - else if (basestation->type == BasestationType::SIMULATED) - { - for (int i = 0; i < 20; i++) - { - setProgress(0.05 * i); - Sleep(100); - } - } - else { - Neuropixels::bsc_updateFirmware(basestation->slot, - firmwareFilePath.getCharPointer(), - firmwareUpdateCallback); - } - - } - - else { // BS_FIRMWARE - - if (basestation->type == BasestationType::V1) - { - np::bs_update(basestation->slot_c, - firmwareFilePath.getCharPointer(), - firmwareUpdateCallback); - } - else if (basestation->type == BasestationType::SIMULATED) - { - for (int i = 0; i < 20; i++) - { - setProgress(0.05 * i); - Sleep(100); - } - } - else { - Neuropixels::bs_updateFirmware(basestation->slot, - firmwareFilePath.getCharPointer(), - firmwareUpdateCallback); - } - - } + if (firmwareType == FirmwareType::BSC_FIRMWARE) + { + if (basestation->type == BasestationType::SIMULATED) + { + for (int i = 0; i < 20; i++) + { + setProgress (0.05 * i); + std::this_thread::sleep_for (std::chrono::milliseconds (100)); + } + } + else + { + Neuropixels::bsc_updateFirmware (basestation->slot, + firmwareFilePath.getCharPointer(), + firmwareUpdateCallback); + } + } + + else + { // BS_FIRMWARE + + if (basestation->type == BasestationType::SIMULATED) + { + for (int i = 0; i < 20; i++) + { + setProgress (0.05 * i); + std::this_thread::sleep_for (std::chrono::milliseconds (100)); + } + } + else + { + Neuropixels::bs_updateFirmware (basestation->slot, + firmwareFilePath.getCharPointer(), + firmwareUpdateCallback); + } + } } -void Basestation::updateBscFirmware(File file) +void Basestation::updateBscFirmware (File file) { - - std::unique_ptr firmwareUpdater - = std::make_unique((Basestation*)this, file, FirmwareType::BSC_FIRMWARE); - + std::unique_ptr firmwareUpdater = std::make_unique ((Basestation*) this, file, FirmwareType::BSC_FIRMWARE); } -void Basestation::updateBsFirmware(File file) +void Basestation::updateBsFirmware (File file) { - std::unique_ptr firmwareUpdater - = std::make_unique((Basestation*)this, file, FirmwareType::BS_FIRMWARE); + std::unique_ptr firmwareUpdater = std::make_unique ((Basestation*) this, file, FirmwareType::BS_FIRMWARE); } diff --git a/Source/NeuropixComponents.h b/Source/NeuropixComponents.h index c937ab5..87ed380 100644 --- a/Source/NeuropixComponents.h +++ b/Source/NeuropixComponents.h @@ -1,23 +1,23 @@ /* ------------------------------------------------------------------- + ------------------------------------------------------------------ -This file is part of the Open Ephys GUI -Copyright (C) 2020 Allen Institute for Brain Science and Open Ephys + This file is part of the Open Ephys GUI + Copyright (C) 2024 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -28,19 +28,17 @@ along with this program. If not, see . #include #include -#include "API/v1/NeuropixAPI.h" -#include "API/v3/NeuropixAPI.h" +#include "API/NeuropixAPI.h" #include "UI/ActivityView.h" #include "UI/ProbeNameConfig.h" -# define SAMPLECOUNT 64 -# define MAX_HEADSTAGE_CLK_SAMPLE 3221225475 -# define MAX_ALLOWABLE_TIMESTAMP_JUMP 4 +#define SAMPLECOUNT 64 +#define MAX_HEADSTAGE_CLK_SAMPLE 3221225475 +#define MAX_ALLOWABLE_TIMESTAMP_JUMP 4 #define MAXPACKETS 64 - class BasestationConnectBoard; class Flex; class Headstage; @@ -50,237 +48,306 @@ class NeuropixInterface; struct ComponentInfo { - String version = "UNKNOWN"; - uint64_t serial_number = 0; - int SN = 0; - String part_number = ""; - String boot_version = ""; + String version = "UNKNOWN"; + uint64_t serial_number = 0; + int SN = 0; + String part_number = ""; + String boot_version = ""; }; enum DeviceType { - PXI, - ONEBOX + PXI, + ONEBOX }; -enum class DataSourceType { - PROBE, - ADC, - DAC, - NONE +enum class DataSourceType +{ + PROBE, + ADC, + DAC, + NONE }; -enum class BasestationType { - V1, - V3, - OPTO, - ONEBOX, - SIMULATED +enum class BasestationType +{ + PXI, + OPTO, + ONEBOX, + SIMULATED }; -enum class ProbeType { - NONE = 1, - NP1, - NHP10, - NHP25, - NHP45, - NHP1, - UHD1, - UHD2, - NP2_1, - NP2_4, - OPTO +enum class ProbeType +{ + NONE = 1, + NP1, + NHP10, + NHP25, + NHP45, + NHP1, + UHD1, + UHD2, + NP2_1, + NP2_4, + OPTO, + QUAD_BASE }; -enum class SourceStatus { - DISCONNECTED, //There is no communication between probe and computer - CONNECTING, //Computer has detected the probe and is attempting to connect - CONNECTED, //Computer has established a valid connection with probe - UPDATING, //The probe is currently updating its settings - ACQUIRING, //The probe is currently streaming data to computer - RECORDING, //The probe is recording the streaming data -}; +static std::string probeTypeToString(const ProbeType type) +{ + switch (type) + { + case ProbeType::NP1: + return "Neuropixels 1.0"; + case ProbeType::NHP10: + return "Neuropixels NHP 10 mm"; + case ProbeType::NHP25: + return "Neuropixels NHP 25 mm"; + case ProbeType::NHP45: + return "Neuropixels NHP 45 mm"; + case ProbeType::NHP1: + return "Neuropixels NHP Passive"; + case ProbeType::UHD1: + return "Neuropixels UHD (Fixed)"; + case ProbeType::UHD2: + return "Neuropixels UHD (Switchable)"; + case ProbeType::NP2_1: + return "Neuropixels 2.0 Single Shank"; + case ProbeType::NP2_4: + return "Neuropixels 2.0 Multi Shank"; + case ProbeType::OPTO: + return "Neuropixels Opto"; + case ProbeType::QUAD_BASE: + return "Neuropixels 2.0 Quad Base"; + default: + return "Unknown"; + } +} -enum class Bank { - NONE = -1, - A = 0, - B = 1, - C = 2, - D = 3, - E = 4, - F = 5, - G = 6, - H = 7, - I = 8, - J = 9, - K = 10, - L = 11, - M = 12, - OFF = 255 //used in v1 API +enum class SourceStatus +{ + DISCONNECTED, //There is no communication between probe and computer + CONNECTING, //Computer has detected the probe and is attempting to connect + CONNECTED, //Computer has established a valid connection with probe + UPDATING, //The probe is currently updating its settings + ACQUIRING, //The probe is currently streaming data to computer + RECORDING, //The probe is recording the streaming data + DISABLED //The probe is connected but disabled during acquisition }; -enum class ElectrodeStatus { - CONNECTED, - DISCONNECTED +enum class Bank +{ + NONE = -1, + A = 0, + B = 1, + C = 2, + D = 3, + E = 4, + F = 5, + G = 6, + H = 7, + I = 8, + J = 9, + K = 10, + L = 11, + M = 12, + A1 = 13, // used for quad base + A2 = 14, + A3 = 15, + A4 = 16, + B1 = 17, + B2 = 18, + B3 = 19, + B4 = 20, + C1 = 21, + C2 = 22, + C3 = 23, + C4 = 24, + D1 = 25, + D2 = 26, + D3 = 27, + D4 = 28, + OFF = 255 //used in v1 API }; -enum class ElectrodeType { - ELECTRODE, - REFERENCE +enum class ElectrodeStatus +{ + CONNECTED, + DISCONNECTED }; -enum class BIST { - EMPTY = 0, - SIGNAL = 1, - NOISE = 2, - PSB = 3, - SR = 4, - EEPROM = 5, - I2C = 6, - SERDES = 7, - HB = 8, - BS = 9 +enum class ElectrodeType +{ + ELECTRODE, + REFERENCE }; -enum class FirmwareType { - BS_FIRMWARE, - BSC_FIRMWARE +enum class BIST +{ + EMPTY = 0, + SIGNAL = 1, + NOISE = 2, + PSB = 3, + SR = 4, + EEPROM = 5, + I2C = 6, + SERDES = 7, + HB = 8, + BS = 9 }; -enum class AdcInputRange { - PLUSMINUS2PT5V = 0, - PLUSMINUS5V = 1, - PLUSMINUS10V = 2 +enum class FirmwareType +{ + BS_FIRMWARE, + BSC_FIRMWARE }; -struct ProbeMetadata { - int shank_count; - int electrodes_per_shank; - int num_adcs; - Path shankOutline; - int columns_per_shank; - int rows_per_shank; - ProbeType type; - String name; - Array availableBanks; - bool switchable; +enum class AdcComparatorState +{ + COMPARATOR_OFF = 1, + COMPARATOR_ON = 2 }; -struct ElectrodeMetadata { - int global_index; - int shank_local_index; - int shank; - int column_index; - int channel; - int row_index; - float xpos; // position on shank, in microns - float ypos; // position on shank, in microns - float site_width; // in microns - Bank bank; - ElectrodeStatus status; - ElectrodeType type; - bool isSelected; - Colour colour; +enum class AdcInputRange +{ + PLUSMINUS2PT5V = 1, + PLUSMINUS5V = 2, + PLUSMINUS10V = 3 }; -struct EmissionSiteMetadata { - int global_index; - int shank_index; - float xpos; // position on shank, in microns - float ypos; // position on shank, in microns - bool isSelected; - float wavelength_nm; +enum class AdcThresholdLevel +{ + ONE_VOLT = 1, + THREE_VOLTS = 2 }; +struct ProbeMetadata +{ + int shank_count; + int electrodes_per_shank; + int num_adcs; + int adc_bits; + Path shankOutline; + int columns_per_shank; + int rows_per_shank; + ProbeType type; + String name; + Array availableBanks; + bool switchable; +}; -struct ProbeSettings { - - Array availableElectrodeConfigurations; - Array availableApGains; // Available AP gain values for each channel (if any) - Array availableLfpGains; // Available LFP gain values for each channel (if any) - Array availableReferences; // reference types - Array availableBanks; // bank inds - - int electrodeConfigurationIndex; //UHD probes only - int apGainIndex; - int lfpGainIndex; - int referenceIndex; - bool apFilterState; - - Array selectedBank; // size = channels - Array selectedShank; // size = channels - Array selectedChannel; // size = channels - Array selectedElectrode; // size = channels - - void clearElectrodeSelection() { - selectedBank.clear(); - selectedShank.clear(); - selectedChannel.clear(); - selectedElectrode.clear(); - } +struct ElectrodeMetadata +{ + int global_index; + int shank_local_index; + int shank; + int column_index; + int channel; + int row_index; + float xpos; // position on shank, in microns + float ypos; // position on shank, in microns + float site_width; // in microns + Bank bank; + ElectrodeStatus status; + ElectrodeType type; + bool isSelected; + Colour colour; +}; - ProbeType probeType; +struct EmissionSiteMetadata +{ + int global_index; + int shank_index; + float xpos; // position on shank, in microns + float ypos; // position on shank, in microns + bool isSelected; + float wavelength_nm; +}; - Probe* probe; // pointer to the probe +struct ProbeSettings +{ + Array availableElectrodeConfigurations; + Array availableApGains; // Available AP gain values for each channel (if any) + Array availableLfpGains; // Available LFP gain values for each channel (if any) + Array availableReferences; // reference types + Array availableBanks; // bank inds + + int electrodeConfigurationIndex; //UHD probes only + int apGainIndex; + int lfpGainIndex; + int referenceIndex; + bool apFilterState; + + Array selectedBank; // size = channels + Array selectedShank; // size = channels + Array selectedChannel; // size = channels + Array selectedElectrode; // size = channels + + void clearElectrodeSelection() + { + selectedBank.clear(); + selectedShank.clear(); + selectedChannel.clear(); + selectedElectrode.clear(); + } + + ProbeType probeType; + + Probe* probe; // pointer to the probe + + bool isEnabled = true; }; /** Base class for all Neuropixels components, which must implement the "getInfo" method */ class NeuropixComponent { public: - NeuropixComponent() { } - - ComponentInfo info; - - virtual void getInfo() = 0; -}; + /** Constructor */ + NeuropixComponent() {} -/** Holds info about APIv1, as well as a boolean value to indicate whether or not it is being used*/ -class NeuropixAPIv1 : public NeuropixComponent -{ -public: - NeuropixAPIv1::NeuropixAPIv1() - { - getInfo(); - isActive = false; - } + /** Pure virtual method for getting component info */ + virtual void getInfo() = 0; - void getInfo() override { + /** Holds component info */ + ComponentInfo info; - unsigned char version_major; - unsigned char version_minor; - np::getAPIVersion(&version_major, &version_minor); + /** Checks error messages */ + Neuropixels::NP_ErrorCode checkError (Neuropixels::NP_ErrorCode error, const String& function = "") + { + if (error != Neuropixels::SUCCESS) + { + LOGE (function, ": ", Neuropixels::getErrorMessage (error)); + } - info.version = String(version_major) + "." + String(version_minor); - } + return error; + } - bool isActive; + /** Holds error codes*/ + Neuropixels::NP_ErrorCode errorCode; }; /** Holds info about APIv3, as well as a boolean value to indicate whether or not it is being used*/ class NeuropixAPIv3 : public NeuropixComponent { public: - - NeuropixAPIv3::NeuropixAPIv3() - { - getInfo(); - isActive = false; - } - - void getInfo() override { - - int version_major; - int version_minor; - Neuropixels::getAPIVersion(&version_major, &version_minor); - - info.version = String(version_major) + "." + String(version_minor); - } - - bool isActive; + NeuropixAPIv3::NeuropixAPIv3() + { + getInfo(); + isActive = false; + } + + void getInfo() override + { + int version_major; + int version_minor; + Neuropixels::getAPIVersion (&version_major, &version_minor); + + info.version = String (version_major) + "." + String (version_minor); + } + + bool isActive; }; - /** Represents any type of data source connected to @@ -293,62 +360,65 @@ class NeuropixAPIv3 : public NeuropixComponent class DataSource : public NeuropixComponent, public Thread { public: + /** Constructor */ + DataSource (Basestation* bs_) : NeuropixComponent(), + Thread ("DataSourceThread") + { + basestation = bs_; + } - /** Constructor */ - DataSource(Basestation* bs_) : NeuropixComponent(), Thread("DataSourceThread") - { - basestation = bs_; - } + // --------- PURE VIRTUAL METHODS --------- // - // --------- PURE VIRTUAL METHODS --------- // + /** Opens the connection to the data source */ + virtual bool open() = 0; - /** Opens the connection to the data source */ - virtual bool open() = 0; + /** Closes the connection to the data source */ + virtual bool close() = 0; - /** Closes the connection to the data source */ - virtual bool close() = 0; + /** Prepares for data acquisition */ + virtual void initialize (bool signalChainIsLoading) = 0; - /** Prepares for data acquisition */ - virtual void initialize(bool signalChainIsLoading) = 0; + /** Starts data streaming */ + virtual void startAcquisition() = 0; - /** Starts data streaming */ - virtual void startAcquisition() = 0; + /** Stops data streaming */ + virtual void stopAcquisition() = 0; - /** Stops data streaming */ - virtual void stopAcquisition() = 0; + /** Returns the name of the data source */ + virtual String getName() = 0; - /** Returns the name of the data source */ - virtual String getName() = 0; + // --------- GET / SET METHODS --------- // - // --------- GET / SET METHODS --------- // + /** Sets the status (CONNECTING, CONNECTED, etc.) */ + void setStatus (SourceStatus status_) + { + status = status_; + } - /** Sets the status (CONNECTING, CONNECTED, etc.) */ - void setStatus(SourceStatus status_) { - status = status_; - } + /** Gets the status of this source */ + SourceStatus getStatus() + { + return status; + } - /** Gets the status of this source */ - SourceStatus getStatus() { - return status; - } + /** Basestation for this source */ + Basestation* basestation; - /** Basestation for this source */ - Basestation* basestation; + /** Properties of this data source */ + int channel_count; + float sample_rate; + DataSourceType sourceType; - /** Properties of this data source */ - int channel_count; - float sample_rate; - DataSourceType sourceType; + /** The data buffer used by this source */ + DataBuffer* apBuffer; - /** The data buffer used by this source */ - DataBuffer* apBuffer; + /** Flags if the the data source is enabled */ + bool isEnabled = true; protected: - SourceStatus status; - + SourceStatus status; }; - /** Represents a Neuropixels probe of any type. @@ -357,159 +427,160 @@ class DataSource : public NeuropixComponent, public Thread class Probe : public DataSource { public: + /** Constructor */ + Probe (Basestation*, + Headstage*, + Flex*, + int dock); - /** Constructor */ - Probe(Basestation*, - Headstage*, - Flex*, - int dock); + // --------- PURE VIRTUAL METHODS --------- // - // --------- PURE VIRTUAL METHODS --------- // + /** Returns true if the probe generates a separate stream for LFP data */ + virtual bool generatesLfpData() = 0; - /** Returns true if the probe generates a separate stream for LFP data */ - virtual bool generatesLfpData() = 0; + /** Returns true if the probe has a selectable AP filter cut */ + virtual bool hasApFilterSwitch() = 0; - /** Returns true if the probe has a selectable AP filter cut */ - virtual bool hasApFilterSwitch() = 0; + /** Used to select channels. Returns the currently active electrodes*/ + virtual void selectElectrodes() = 0; - /** Used to select channels. Returns the currently active electrodes*/ - virtual void selectElectrodes() = 0; + /** Returns selected electrodes for a named preset electrode configuration*/ + virtual Array selectElectrodeConfiguration (String config) = 0; - /** Returns selected electrodes for a named preset electrode configuration*/ - virtual Array selectElectrodeConfiguration(String config) = 0; + /** Used to set references (same for all channels).*/ + virtual void setAllReferences() = 0; - /** Used to set references (same for all channels).*/ - virtual void setAllReferences() = 0; + /** Used to set gains (same for all channels).*/ + virtual void setAllGains() = 0; - /** Used to set gains (same for all channels).*/ - virtual void setAllGains() = 0; + /** Used to set AP filter cut (if available).*/ + virtual void setApFilterState() = 0; - /** Used to set AP filter cut (if available).*/ - virtual void setApFilterState() = 0; + /** Writes probe configuration after calling setAllReferences / setAllGains / selectElectrodes */ + virtual void writeConfiguration() = 0; - /** Writes probe configuration after calling setAllReferences / setAllGains / selectElectrodes */ - virtual void writeConfiguration() = 0; + /** Applies calibration info from a file.*/ + virtual void calibrate() = 0; - /** Applies calibration info from a file.*/ - virtual void calibrate() = 0; + /** Runs a built-in self-test for a specified port */ + virtual bool runBist (BIST bistType) = 0; - /** Runs a built-in self-test for a specified port */ - virtual bool runBist(BIST bistType) = 0; + /** Main loop -- copies data from the probe into a DataBuffer object */ + virtual void run() = 0; - /** Main loop -- copies data from the probe into a DataBuffer object */ - virtual void run() = 0; + // ---------------------------------------- // - // ---------------------------------------- // + String getName() { return displayName; } - String getName() { return displayName; } + Headstage* headstage; // owned by Basestation + Flex* flex; // owned by Headstage - Headstage* headstage; // owned by Basestation - Flex* flex; // owned by Headstage + bool isValid = true; //True if the PN is supported by the API + bool invertSyncLine = false; - bool isValid = true; //True if the PN is supported by the API - bool invertSyncLine = false; + bool isCalibrated = false; + bool calibrationWarningShown; - bool isCalibrated = false; - bool calibrationWarningShown; + int port; + int dock; - int port; - int dock; - - /** Separate buffer for LFP data */ - DataBuffer* lfpBuffer; + /** Separate buffer for LFP data */ + DataBuffer* lfpBuffer; - float ap_sample_rate; - float lfp_sample_rate; + /** Additional buffers for quad base probe */ + Array quadBaseBuffers; - float ap_offsets[384][100]; - float lfp_offsets[384][100]; + float ap_sample_rate; + float lfp_sample_rate; - double timestamp_s[12 * MAXPACKETS]; + float ap_offsets[384][100]; + float lfp_offsets[384][100]; - int64 ap_timestamp; - int64 lfp_timestamp; + double timestamp_s[12 * MAXPACKETS]; - Array electrodeMetadata; - Array emissionSiteMetadata; - ProbeMetadata probeMetadata; + int64 ap_timestamp; + int64 lfp_timestamp; - ProbeSettings settings; + Array electrodeMetadata; + Array emissionSiteMetadata; + ProbeMetadata probeMetadata; - Path shankOutline; - - NeuropixInterface* ui; + ProbeSettings settings; - /** Updates the settings object for this probe */ - void updateSettings(ProbeSettings p) - { - settings = p; - } + Path shankOutline; - /** Updates the naming scheme */ - void updateNamingScheme(ProbeNameConfig::NamingScheme scheme); + NeuropixInterface* ui; - void updateOffsets(float* samples, int64 timestamp, bool isApBand); + /** Updates the settings object for this probe */ + void updateSettings (ProbeSettings p) + { + settings = p; + } - int ap_offset_counter = 0; - int lfp_offset_counter = 0; + /** Updates the naming scheme */ + void updateNamingScheme (ProbeNameConfig::NamingScheme scheme); - ProbeType type; - - int electrode_count; - float ap_band_sample_rate; - float lfp_band_sample_rate; + void updateOffsets (float* samples, int64 timestamp, bool isApBand); - int buffer_size; + int ap_offset_counter = 0; + int lfp_offset_counter = 0; - float fifoFillPercentage; + ProbeType type; - /* Stores the generic probe model name e.g. Neuripixels 2.0 - Single Shank */ - String name; + int electrode_count; + float ap_band_sample_rate; + float lfp_band_sample_rate; - /* Stores the name assigned to the probe/streams (default is autoName) */ - String displayName; + int buffer_size; - /** Stores the index of the first (AP) data stream */ - int streamIndex; + float fifoFillPercentage; - /* Stores port-specific and probe-specific names */ - struct CustomNames { - String automatic; - String streamSpecific; - String portSpecific; - String probeSpecific; - }; - - CustomNames customName; + /* Stores the generic probe model name e.g. Neuripixels 2.0 - Single Shank */ + String name; - ProbeNameConfig::NamingScheme namingScheme; + /* Stores the name assigned to the probe/streams (default is autoName) */ + String displayName; - void sendSyncAsContinuousChannel(bool shouldSend) { - sendSync = shouldSend; - } + /** Stores the index of the first (AP) data stream */ + int streamIndex; - bool sendSync = false; + /* Stores port-specific and probe-specific names */ + struct CustomNames + { + String automatic; + String streamSpecific; + String portSpecific; + String probeSpecific; + }; - uint32_t last_npx_timestamp; - bool passedOneSecond; + CustomNames customName; - const float* getPeakToPeakValues(ActivityToView currentView = ActivityToView::APVIEW) - { - if (currentView == ActivityToView::APVIEW) - return apView->getPeakToPeakValues(); - else - return lfpView->getPeakToPeakValues(); - } + ProbeNameConfig::NamingScheme namingScheme; -protected: + void sendSyncAsContinuousChannel (bool shouldSend) + { + sendSync = shouldSend; + } - ScopedPointer apView; - ScopedPointer lfpView; + bool sendSync = false; - uint64 eventCode; - Array gains; // available gain values + uint32_t last_npx_timestamp; + bool passedOneSecond; + const float* getPeakToPeakValues (ActivityToView currentView = ActivityToView::APVIEW) + { + if (currentView == ActivityToView::APVIEW) + return apView->getPeakToPeakValues(); + else + return lfpView->getPeakToPeakValues(); + } + +protected: + std::unique_ptr apView; + std::unique_ptr lfpView; + uint64 eventCode; + Array gains; // available gain values }; class Basestation; @@ -517,321 +588,323 @@ class Basestation; class FirmwareUpdater : public ThreadWithProgressWindow { public: + /** Constructor */ + FirmwareUpdater (Basestation* basestation, File firmwareFile, FirmwareType type); - /** Constructor */ - FirmwareUpdater(Basestation* basestation, File firmwareFile, FirmwareType type); + /** Destructor */ + ~FirmwareUpdater() {} - /** Destructor */ - ~FirmwareUpdater() {} + /** Thread for firmware update */ + void run() override; - /** Thread for firmware update */ - void run() override; - - /** Callback to update progress bar*/ - static int firmwareUpdateCallback(size_t bytes) - { - currentThread->setProgress(float(bytes) / totalFirmwareBytes); - - return 1; - } + /** Callback to update progress bar*/ + static int firmwareUpdateCallback (size_t bytes) + { + currentThread->setProgress (float (bytes) / totalFirmwareBytes); - static FirmwareUpdater* currentThread; - static float totalFirmwareBytes; + return 1; + } - Basestation* basestation; - FirmwareType firmwareType; - String firmwareFilePath; + static FirmwareUpdater* currentThread; + static float totalFirmwareBytes; + Basestation* basestation; + FirmwareType firmwareType; + String firmwareFilePath; }; -/** Represents a PXI basestation card */ +/** Represents a data acquisition device */ class Basestation : public NeuropixComponent { public: + /** Constructor -- Sets the slot values. */ + Basestation (NeuropixThread* neuropixThread_, int slot_) : NeuropixComponent() + { + probesInitialized = false; + neuropixThread = neuropixThread_; + slot = slot_; + slot_c = (unsigned char) slot_; - /** Constructor -- Sets the slot values. */ - Basestation(NeuropixThread* neuropixThread_, int slot_) : NeuropixComponent() { - probesInitialized = false; - neuropixThread = neuropixThread_; - slot = slot_; - slot_c = (unsigned char) slot_; - - bsFirmwarePath = ""; - bscFirmwarePath = ""; - - for (int p = 0; p < 4; p++) - { - for (int d = 0; d < 2; d++) - { - customPortNames.add("slot" + String(slot) + "-port" + String(p+1) + "-" + String(d+1)); - } - } - } - - /** Destructor */ - virtual ~Basestation() {} + bsFirmwarePath = ""; + bscFirmwarePath = ""; - // --------- PURE VIRTUAL METHODS --------- // + for (int p = 0; p < 4; p++) + { + for (int d = 0; d < 2; d++) + { + customPortNames.add ("slot" + String (slot) + "-port" + String (p + 1) + "-" + String (d + 1)); + } + } + } - /** Opens the connection and retrieves info about available components; should be fast */ - /** Returns false if the API version does not match */ - virtual bool open() = 0; + /** Destructor */ + virtual ~Basestation() {} - /** Closes the connection */ - virtual void close() = 0; + // --------- PURE VIRTUAL METHODS --------- // - /** Initializes all components for acquisition; may inclue some delays */ - virtual void initialize(bool signalChainIsLoading) = 0; + /** Opens the connection and retrieves info about available components; should be fast */ + /** Returns false if the API version does not match */ + virtual bool open() = 0; - /** Sets the sync channel as an "input" (for external sync) */ - virtual void setSyncAsInput() = 0; + /** Closes the connection */ + virtual void close() = 0; - /** Sets the sync channel as an "output" (and specifies the frequency index) */ - virtual void setSyncAsOutput(int freqIndex) = 0; + /** Initializes all components for acquisition; may inclue some delays */ + virtual void initialize (bool signalChainIsLoading) = 0; - /** Returns an array of available sync frequencies for this basestation */ - virtual Array getSyncFrequencies() = 0; + /** Searches for probes connected to this basestion */ + virtual void searchForProbes() = 0; - /** Starts data streaming */ - virtual void startAcquisition() = 0; + /** Sets the sync channel as an "input" (for external sync) */ + virtual void setSyncAsInput() = 0; - /** Stops data streaming */ - virtual void stopAcquisition() = 0; + /** Sets the sync channel as an "output" (and specifies the frequency index) */ + virtual void setSyncAsOutput (int freqIndex) = 0; - /** Returns the percentage of the FIFO buffer that is filled */ - virtual float getFillPercentage() = 0; + /** Sets the sync channel to inherit from the PXI backplane */ + virtual void setSyncAsPassive() = 0; - /** Returns the total number of probes connected to this basestation */ - virtual int getProbeCount() = 0; + /** Returns an array of available sync frequencies for this basestation */ + virtual Array getSyncFrequencies() = 0; - // ----------- OTHER METHODS ----------- // + /** Starts data streaming */ + virtual void startAcquisition() = 0; - /** Launches FirmwareUpdater to update the BSC firmware */ - void updateBscFirmware(File file); + /** Stops data streaming */ + virtual void stopAcquisition() = 0; - /** Launches FirmwareUpdater to update the BS firmware */ - void updateBsFirmware(File file); + /** Returns the percentage of the FIFO buffer that is filled */ + virtual float getFillPercentage() = 0; - /** Checks the status of any initialization threads */ - virtual bool isBusy() { return false; } + /** Returns the total number of probes connected to this basestation */ + virtual int getProbeCount() = 0; - /** Waits for initialization threads to exit */ - virtual void waitForThreadToExit() { } + // ----------- OTHER METHODS ----------- // - /** Returns an array of headstages connected to this basestation - (can include null values for disconnected headstages) */ - Array getHeadstages() { + /** Launches FirmwareUpdater to update the BSC firmware */ + void updateBscFirmware (File file); - Array headstage_array; + /** Launches FirmwareUpdater to update the BS firmware */ + void updateBsFirmware (File file); - for (auto h : headstages) - { - headstage_array.add(h); - } + /** Checks the status of any initialization threads */ + virtual bool isBusy() { return false; } - return headstage_array; - } + /** Waits for initialization threads to exit */ + virtual void waitForThreadToExit() {} - virtual Array getAdditionalDataSources() { - - return Array(); - - } - - /** Returns an array of probes connected to this basestation (cannot include null values) */ - Array getProbes() - { - return probes; - } - - /** Informs all probes to add the sync channel value to the continuous buffer */ - void sendSyncAsContinuousChannel(bool shouldSend) { - - for (auto probe : getProbes()) - { - probe->sendSyncAsContinuousChannel(shouldSend); - } - } - - /** Sets saving directory for NPX files (not used) */ - void setSavingDirectory(File directory) { - savingDirectory = directory; - } - - /** Gets the saving directory for NPX files (not used) */ - File getSavingDirectory() { - return savingDirectory; - } - - /** Sets the naming scheme for all probes in this basestation */ - void setNamingScheme(ProbeNameConfig::NamingScheme namingScheme_) { - namingScheme = namingScheme_; - for (auto p : probes) - p->updateNamingScheme(namingScheme); - } - - /** Returns the naming scheme for this basestation */ - ProbeNameConfig::NamingScheme getNamingScheme() { - return namingScheme; - } + /** Checks that firmware version matches what's expected by the plugin */ + virtual void checkFirmwareVersion() {} - BasestationType type; - - unsigned char slot_c; - int slot; - - ScopedPointer basestationConnectBoard; - - OwnedArray headstages; - Array probes; - - String getCustomPortName(int port, int dock) { - - if (dock == 0) - { - return customPortNames[(port - 1) * 2]; - } - else { - return customPortNames[(port - 1) * 2 + (dock - 1)]; - } - - } - void setCustomPortName(String name, int port, int dock) { - - if (dock == 0) - { - customPortNames.set((port - 1) * 2, name); - } - else { - customPortNames.set((port - 1) * 2 + (dock - 1), name); - } - - } - - NeuropixThread* neuropixThread; // Probes can access this via Basestation pointer + /** Returns an array of headstages connected to this basestation + (can include null values for disconnected headstages) */ + Array getHeadstages() + { + Array headstage_array; + + for (auto h : headstages) + { + headstage_array.add (h); + } + + return headstage_array; + } + + virtual Array getAdditionalDataSources() + { + return Array(); + } + + /** Returns an array of probes connected to this basestation (cannot include null values) */ + Array getProbes() + { + return probes; + } + + /** Informs all probes to add the sync channel value to the continuous buffer */ + void sendSyncAsContinuousChannel (bool shouldSend) + { + for (auto probe : getProbes()) + { + probe->sendSyncAsContinuousChannel (shouldSend); + } + } + + /** Sets saving directory for NPX files (not used) */ + void setSavingDirectory (File directory) + { + savingDirectory = directory; + } + + /** Gets the saving directory for NPX files (not used) */ + File getSavingDirectory() + { + return savingDirectory; + } + + /** Sets the naming scheme for all probes in this basestation */ + void setNamingScheme (ProbeNameConfig::NamingScheme namingScheme_) + { + namingScheme = namingScheme_; + for (auto p : probes) + p->updateNamingScheme (namingScheme); + } + + /** Returns the naming scheme for this basestation */ + ProbeNameConfig::NamingScheme getNamingScheme() + { + return namingScheme; + } + + BasestationType type; + + unsigned char slot_c; + int slot; + + std::unique_ptr basestationConnectBoard; + + OwnedArray headstages; + Array probes; + + String getCustomPortName (int port, int dock) + { + if (dock == 0) + { + return customPortNames[(port - 1) * 2]; + } + else + { + return customPortNames[(port - 1) * 2 + (dock - 1)]; + } + } + void setCustomPortName (String name, int port, int dock) + { + if (dock == 0) + { + customPortNames.set ((port - 1) * 2, name); + } + else + { + customPortNames.set ((port - 1) * 2 + (dock - 1), name); + } + } + + NeuropixThread* neuropixThread; // Probes can access this via Basestation pointer protected: + bool probesInitialized; + Array syncFrequencies; + File savingDirectory; + ProbeNameConfig::NamingScheme namingScheme = ProbeNameConfig::NamingScheme::AUTO_NAMING; - bool probesInitialized; - Array syncFrequencies; - File savingDirectory; - ProbeNameConfig::NamingScheme namingScheme = ProbeNameConfig::NamingScheme::AUTO_NAMING; + StringArray customPortNames; - StringArray customPortNames; - - String bscFirmwarePath; - String bsFirmwarePath; + String bscFirmwarePath; + String bsFirmwarePath; }; /** Represents a basestation connect board */ class BasestationConnectBoard : public NeuropixComponent { public: - BasestationConnectBoard(Basestation* bs_) : NeuropixComponent() { - basestation = bs_; - } + BasestationConnectBoard (Basestation* bs_) : NeuropixComponent() + { + basestation = bs_; + } - Basestation* basestation; + Basestation* basestation; }; /** Represents a Headstage Test Module */ class HeadstageTestModule : public NeuropixComponent { public: + /** Constructor */ + HeadstageTestModule::HeadstageTestModule (Basestation* bs_, Headstage* hs_) : NeuropixComponent() + { + basestation = bs_; + headstage = hs_; + } - /** Constructor */ - HeadstageTestModule::HeadstageTestModule(Basestation* bs_, Headstage* hs_) : NeuropixComponent() - { - basestation = bs_; - headstage = hs_; - } - - /** Run all available headstage tests */ - virtual void runAll() = 0; + /** Run all available headstage tests */ + virtual void runAll() = 0; - /** Show test results */ - virtual void showResults() = 0; + /** Show test results */ + virtual void showResults() = 0; private: - Basestation* basestation; - Headstage* headstage; - + Basestation* basestation; + Headstage* headstage; }; - - /** Represents a Neuropixels headstage of any type */ class Headstage : public NeuropixComponent { public: + /** Constructor */ + Headstage::Headstage (Basestation* bs_, int port_) : NeuropixComponent() + { + basestation = bs_; + port_c = (signed char) port_; + port = port_; + } - /** Constructor */ - Headstage::Headstage(Basestation* bs_, int port_) : NeuropixComponent() { - basestation = bs_; - port_c = (signed char) port_; - port = port_; - } + /** Returns all probes connected to this headstage */ + Array getProbes() + { + Array probe_array; - /** Returns all probes connected to this headstage */ - Array getProbes() { + for (auto p : probes) + { + probe_array.add (p); + } - Array probe_array; + return probe_array; + } - for (auto p : probes) - { - probe_array.add(p); - } + /** Returns all flex cables connected to this headstage */ + Array getFlexCables() + { + Array flex_array; - return probe_array; - } + for (auto f : flexCables) + { + flex_array.add (f); + } - /** Returns all flex cables connected to this headstage */ - Array getFlexCables() - { - Array flex_array; + return flex_array; + } - for (auto f : flexCables) - { - flex_array.add(f); - } - - return flex_array; - } - - signed char port_c; - int port; + signed char port_c; + int port; - OwnedArray probes; - OwnedArray flexCables; + OwnedArray probes; + OwnedArray flexCables; - HeadstageTestModule* testModule; + HeadstageTestModule* testModule; - Basestation* basestation; + Basestation* basestation; - // ** Returns true if headstage test module is available */ - virtual bool hasTestModule() = 0; + // ** Returns true if headstage test module is available */ + virtual bool hasTestModule() = 0; - // ** Runs the headstage test module and shows the results in a pop-window */ - virtual void runTestModule() = 0; + // ** Runs the headstage test module and shows the results in a pop-window */ + virtual void runTestModule() = 0; }; /** Represents a Neuropixels flex cable */ class Flex : public NeuropixComponent { public: - - /** Constructor */ - Flex::Flex(Headstage* hs_, int dock_) - { - headstage = hs_; - dock = dock_; - } - - Headstage* headstage; - int dock; + /** Constructor */ + Flex::Flex (Headstage* hs_, int dock_) + { + headstage = hs_; + dock = dock_; + } + + Headstage* headstage; + int dock; }; - - - -#endif // __NEUROPIXCOMPONENTS_H_2C4C2D67__ \ No newline at end of file +#endif // __NEUROPIXCOMPONENTS_H_2C4C2D67__ \ No newline at end of file diff --git a/Source/NeuropixEditor.cpp b/Source/NeuropixEditor.cpp index 2812535..ae687b4 100644 --- a/Source/NeuropixEditor.cpp +++ b/Source/NeuropixEditor.cpp @@ -2,7 +2,7 @@ ------------------------------------------------------------------ This file is part of the Open Ephys GUI - Copyright (C) 2016 Allen Institute for Brain Science and Open Ephys + Copyright (C) 2024 Open Ephys ------------------------------------------------------------------ @@ -23,804 +23,1087 @@ #include "NeuropixEditor.h" -#include "NeuropixThread.h" #include "NeuropixCanvas.h" #include "NeuropixComponents.h" +#include "NeuropixThread.h" +#include "UI/NeuropixInterface.h" -SlotButton::SlotButton(Basestation* bs, NeuropixThread* thread_) : Button(String(bs->slot)) -{ - isEnabled = true; - thread = thread_; - basestation = bs; - slot = basestation->slot; -} - -void SlotButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown) +RefreshButton::RefreshButton() : Button ("Refresh") { - g.setFont(26); + XmlDocument xmlDoc (R"( + + + + )"); - if (isMouseOver && isEnabled) - g.setColour(Colours::yellow); - else - g.setColour(Colours::darkgrey); + refreshIcon = Drawable::createFromSVG (*xmlDoc.getDocumentElement().get()); - g.drawText(String(slot), 0, 0, getWidth(), getHeight(), Justification::centred); + setClickingTogglesState (false); } -void SlotButton::mouseUp(const MouseEvent& event) +void RefreshButton::paintButton (Graphics& g, bool isMouseOver, bool isButtonDown) { + Colour buttonColour = Colours::darkgrey; - if (!isEnabled) - return; + if (isMouseOver && isEnabled()) + buttonColour = Colours::yellow; - ProbeNameConfig* probeNamingPopup = new ProbeNameConfig(basestation, thread); + refreshIcon->replaceColour (Colours::black, buttonColour); - CallOutBox& myBox - = CallOutBox::launchAsynchronously(std::unique_ptr(probeNamingPopup), - getScreenBounds(), - nullptr); + refreshIcon->drawWithin (g, getLocalBounds().toFloat(), RectanglePlacement::centred, 1.0f); - myBox.addComponentListener(this); - myBox.setDismissalMouseClicksAreAlwaysConsumed(true); + refreshIcon->replaceColour (buttonColour, Colours::black); } -void SlotButton::componentBeingDeleted(Component& component) +void RefreshButton::parentSizeChanged() { - - CoreServices::updateSignalChain((GenericEditor*)(getParentComponent()->getParentComponent())); + setBounds (getParentWidth() - 65, 4, 16, 16); } -EditorBackground::EditorBackground(NeuropixThread* t, bool freqSelectEnabled) - : basestations(t->getBasestations()), type(t->type), - freqSelectEnabled(freqSelectEnabled) +SlotButton::SlotButton (Basestation* bs, NeuropixThread* thread_) : Button (String (bs->slot)) { + isEnabled = true; + thread = thread_; + basestation = bs; + slot = basestation->slot; +} - numBasestations = basestations.size(); +void SlotButton::paintButton (Graphics& g, bool isMouseOver, bool isButtonDown) +{ + g.setFont (26); - for (int i = 0; i < numBasestations; i++) - { - LOGD("Creating slot button."); - slotButtons.push_back(std::make_unique(basestations[i], t)); - slotButtons[slotButtons.size()-1]->setBounds(90 * i + 72, 28, 25, 26); - addAndMakeVisible(slotButtons[slotButtons.size()-1].get()); - } + if (isMouseOver && isEnabled) + g.setColour (Colours::yellow); + else + g.setColour (Colours::darkgrey); + g.drawText (String (slot), 0, 0, getWidth(), getHeight(), Justification::centredLeft); } -void EditorBackground::setFreqSelectAvailable(bool isAvailable) +void SlotButton::mouseUp (const MouseEvent& event) { - freqSelectEnabled = isAvailable; -} + if (! isEnabled) + return; -void EditorBackground::paint(Graphics& g) -{ + ProbeNameConfig* probeNamingPopup = new ProbeNameConfig (basestation, thread); - if (numBasestations > 0) - { - for (int i = 0; i < numBasestations; i++) - { - g.setColour(Colours::lightgrey); - g.drawRoundedRectangle(90 * i + 32, 13, 32, 98, 4, 3); - g.setColour(Colours::darkgrey); - g.drawRoundedRectangle(90 * i + 32, 13, 32, 98, 4, 1); + CallOutBox& myBox = CallOutBox::launchAsynchronously (std::unique_ptr (probeNamingPopup), + getScreenBounds(), + nullptr); - g.setColour(Colours::darkgrey); - g.setFont(10); - g.drawText("SLOT", 90 * i + 72, 15, 50, 12, Justification::centredLeft); + myBox.addComponentListener (this); + myBox.setDismissalMouseClicksAreAlwaysConsumed (true); +} - //g.setFont(26); - //g.drawText(String(basestations[i]->slot), 90 * i + 72, 28, 25, 26, Justification::centredLeft); - g.setFont(8); - g.drawText(String("0"), 90 * i + 87, 100, 50, 10, Justification::centredLeft); - g.drawText(String("100"), 90 * i + 87, 60, 50, 10, Justification::centredLeft); - g.drawText(String("%"), 90 * i + 87, 80, 50, 10, Justification::centredLeft); +void SlotButton::componentBeingDeleted (Component& component) +{ + CoreServices::updateSignalChain ((GenericEditor*) (getParentComponent()->getParentComponent())); +} - for (int j = 0; j < 4; j++) - { - g.setFont(10); - g.drawText(String(j + 1), 90 * i + 22, 90 - j * 22, 10, 10, Justification::centredLeft); - } - } +EditorBackground::EditorBackground (NeuropixThread* t, bool freqSelectEnabled) + : basestations (t->getBasestations()), + type (t->type), + freqSelectEnabled (freqSelectEnabled) +{ + numBasestations = basestations.size(); - g.setColour(Colours::darkgrey); - g.setFont(10); - g.drawText(String("MAIN SYNC SLOT"), 90 * (numBasestations)+32, 13, 100, 10, Justification::centredLeft); - g.drawText(String("CONFIG AS"), 90 * (numBasestations)+32, 46, 100, 10, Justification::centredLeft); - if (freqSelectEnabled) - g.drawText(String("WITH FREQ"), 90 * (numBasestations)+32, 79, 100, 10, Justification::centredLeft); - } - else { - g.setColour(Colours::darkgrey); - g.setFont(15); - if (type == PXI) - { - g.drawText(String("NO BASESTATIONS DETECTED"), 0, 10, 250, 100, Justification::centred); - } - else if (type == ONEBOX) { - g.drawText(String("NO ONEBOX DETECTED"), 0, 10, 250, 100, Justification::centred); - } - - } + for (int i = 0; i < numBasestations; i++) + { + LOGD ("Creating slot button."); + slotButtons.push_back (std::make_unique (basestations[i], t)); + slotButtons[slotButtons.size() - 1]->setBounds (90 * i + 72, 28, 35, 26); + addAndMakeVisible (slotButtons[slotButtons.size() - 1].get()); + } +} +void EditorBackground::setFreqSelectAvailable (bool isAvailable) +{ + freqSelectEnabled = isAvailable; } +void EditorBackground::paint (Graphics& g) +{ + if (numBasestations > 0) + { + for (int i = 0; i < numBasestations; i++) + { + g.setColour (Colours::lightgrey); + g.drawRoundedRectangle (90 * i + 30, 13, 35, 98, 4, 1); + + g.setColour (Colours::darkgrey); + + g.setFont (10); + g.drawText ("SLOT", 90 * i + 72, 15, 50, 12, Justification::centredLeft); + + g.setFont (8); + g.drawText (String ("0"), 90 * i + 87, 100, 50, 10, Justification::centredLeft); + g.drawText (String ("100"), 90 * i + 87, 60, 50, 10, Justification::centredLeft); + g.drawText (String ("%"), 90 * i + 87, 80, 50, 10, Justification::centredLeft); + + for (int j = 0; j < 4; j++) + { + g.setFont (10); + + if (type == ONEBOX && j == 3) + { + g.drawText (String ("ADC"), 90 * i + 20 - 12, 90 - j * 22 + 1, 20, 10, Justification::centredLeft); + } + else if (type == ONEBOX && j == 2) + { + // skip + } + else + { + g.drawText (String (j + 1), 90 * i + 20, 90 - j * 22 + 1, 10, 10, Justification::centredLeft); + } + } + } + + g.setFont (10); + if (type != ONEBOX) + g.drawText (String ("MAIN SYNC SLOT"), 90 * (numBasestations) + 32, 13, 100, 10, Justification::centredLeft); + g.drawText (String ("SMA CONFIGURATION"), 90 * (numBasestations) + 32, 48, 100, 10, Justification::centredLeft); + if (freqSelectEnabled) + g.drawText (String ("WITH FREQ"), 90 * (numBasestations) + 32, 82, 100, 10, Justification::centredLeft); + } + else + { + g.setColour (Colours::darkgrey); + g.setFont (15); + if (type == PXI) + { + g.drawText (String ("NO BASESTATIONS DETECTED"), 0, 10, 250, 100, Justification::centred); + } + else if (type == ONEBOX) + { + g.drawText (String ("NO ONEBOX DETECTED"), 0, 10, 250, 100, Justification::centred); + } + } +} -FifoMonitor::FifoMonitor(int id_, Basestation* basestation_) : id(id_), basestation(basestation_), fillPercentage(0.0) +FifoMonitor::FifoMonitor (int id_, Basestation* basestation_) : id (id_), + basestation (basestation_), + fillPercentage (0.0) { - startTimer(500); // update fill percentage every 0.5 seconds + startTimer (500); // update fill percentage every 0.5 seconds } void FifoMonitor::timerCallback() { - - if (slot != 255) - { - setFillPercentage(basestation->getFillPercentage()); - } + if (slot != 255) + { + setFillPercentage (basestation->getFillPercentage()); + } } - -void FifoMonitor::setSlot(unsigned char slot_) +void FifoMonitor::setSlot (unsigned char slot_) { - slot = slot_; + slot = slot_; } -void FifoMonitor::setFillPercentage(float fill_) +void FifoMonitor::setFillPercentage (float fill_) { - fillPercentage = fill_; + fillPercentage = fill_; - repaint(); + repaint(); } -void FifoMonitor::paint(Graphics& g) +void FifoMonitor::paint (Graphics& g) { - g.setColour(Colours::grey); - g.fillRoundedRectangle(0, 0, this->getWidth(), this->getHeight(), 4); - g.setColour(Colours::lightslategrey); - g.fillRoundedRectangle(2, 2, this->getWidth()-4, this->getHeight()-4, 2); - - g.setColour(Colours::yellow); - float barHeight = (this->getHeight() - 4) * fillPercentage; - g.fillRoundedRectangle(2, this->getHeight()-2-barHeight, this->getWidth() - 4, barHeight, 2); + g.setColour (Colours::grey); + g.fillRoundedRectangle (0, 0, this->getWidth(), this->getHeight(), 4); + g.setColour (Colours::lightslategrey); + g.fillRoundedRectangle (2, 2, this->getWidth() - 4, this->getHeight() - 4, 2); + + g.setColour (Colours::yellow); + float barHeight = (this->getHeight() - 4) * fillPercentage; + g.fillRoundedRectangle (2, this->getHeight() - 2 - barHeight, this->getWidth() - 4, barHeight, 2); } -SourceButton::SourceButton(int id_, DataSource* source_, Basestation* basestation_) - : id(id_), dataSource(source_), selected(false), basestation(basestation_) +SourceButton::SourceButton (int id_, DataSource* source_, Basestation* basestation_) + : id (id_), + dataSource (source_), + selected (false), + basestation (basestation_) { - status = SourceStatus::DISCONNECTED; + status = SourceStatus::DISCONNECTED; - if (dataSource != nullptr) - { - sourceType = dataSource->sourceType; - } - else { - sourceType = DataSourceType::NONE; - } + if (dataSource != nullptr) + { + sourceType = dataSource->sourceType; + } + else + { + sourceType = DataSourceType::NONE; + } - setRadioGroupId(979); + setRadioGroupId (979); - startTimer(500); // update probe status and fifo monitor every 500 ms + startTimer (500); // update probe status and fifo monitor every 500 ms } - -void SourceButton::setSelectedState(bool state) +void SourceButton::setSelectedState (bool state) { - selected = state; + selected = state; } -void SourceButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown) +void SourceButton::paintButton (Graphics& g, bool isMouseOver, bool isButtonDown) { - if (isMouseOver && connected) - g.setColour(Colours::antiquewhite); - else - g.setColour(Colours::darkgrey); - g.fillEllipse(0, 0, 15, 15); + if (isMouseOver && connected) + g.setColour (Colours::antiquewhite); + else + g.setColour (Colours::darkgrey); - Colour baseColour; + g.fillEllipse (0, 0, 15, 15); - if (sourceType == DataSourceType::PROBE) - { - baseColour = Colours::green; - } - else if (sourceType == DataSourceType::ADC) - { - baseColour = Colours::purple; - } - else if (sourceType == DataSourceType::DAC) - { - baseColour = Colours::blue; - } - else { - baseColour = Colours::grey; - } + Colour baseColour; - if (status == SourceStatus::CONNECTED) - { - if (selected) - { - if (isMouseOver) - g.setColour(baseColour.brighter(0.9f)); - else - g.setColour(baseColour.brighter(0.8f)); - } - else { - if (isMouseOver) - g.setColour(baseColour.brighter(0.2f)); - else - g.setColour(baseColour); - } - } - else if (status == SourceStatus::CONNECTING || status == SourceStatus::UPDATING) - { - if (selected) - { - if (isMouseOver) - g.setColour(Colours::lightsalmon); - else - g.setColour(Colours::lightsalmon); - } - else { - if (isMouseOver) - g.setColour(Colours::orange); - else - g.setColour(Colours::orange); - } - } - else { - g.setColour(Colours::lightgrey); - } - - g.fillEllipse(2, 2, 11, 11); + if (sourceType == DataSourceType::PROBE) + { + baseColour = Colours::green; + } + else if (sourceType == DataSourceType::ADC) + { + baseColour = Colours::purple; + } + else if (sourceType == DataSourceType::DAC) + { + baseColour = Colours::blue; + } + else + { + baseColour = Colours::grey; + } + + if (status == SourceStatus::CONNECTED) + { + if (selected) + { + if (isMouseOver) + g.setColour (baseColour.brighter (0.9f)); + else + g.setColour (baseColour.brighter (0.8f)); + } + else + { + if (isMouseOver) + g.setColour (baseColour.brighter (0.2f)); + else + g.setColour (baseColour); + } + } + else if (status == SourceStatus::CONNECTING || status == SourceStatus::UPDATING) + { + if (selected) + { + if (isMouseOver) + g.setColour (Colours::lightsalmon); + else + g.setColour (Colours::lightsalmon); + } + else + { + if (isMouseOver) + g.setColour (Colours::orange); + else + g.setColour (Colours::orange); + } + } + else if (status == SourceStatus::DISABLED) + { + if (selected) + { + if (isMouseOver) + g.setColour (Colours::red); + else + g.setColour (Colours::red); + } + else + { + if (isMouseOver) + g.setColour (Colours::red); + else + g.setColour (Colours::red); + } + } + else + { + g.setColour (Colours::lightgrey); + } + + g.fillEllipse (2, 2, 11, 11); } -void SourceButton::setSourceStatus(SourceStatus status) +void SourceButton::setSourceStatus (SourceStatus status) { - if (dataSource != nullptr) - { - this->status = status; - - repaint(); - } + if (dataSource != nullptr) + { + this->status = status; + repaint(); + } } SourceStatus SourceButton::getSourceStatus() { - return status; + return status; } void SourceButton::timerCallback() { - - if (dataSource != nullptr) - { - setSourceStatus(dataSource->getStatus()); - } + if (dataSource != nullptr) + { + setSourceStatus (dataSource->getStatus()); + } } -BackgroundLoader::BackgroundLoader(NeuropixThread* thread_, NeuropixEditor* editor_) - : Thread("Neuropix Loader"), - thread(thread_), - editor(editor_), - isInitialized(false), - signalChainIsLoading(false) +BackgroundLoaderWithProgressWindow::BackgroundLoaderWithProgressWindow (NeuropixThread* thread_, NeuropixEditor* editor_) + : ThreadWithProgressWindow ("Re-scanning Neuropixels devices", true, false), + BackgroundLoader (thread_, editor_) { + progressWindowLookAndFeel = std::make_unique(); + progressWindowLookAndFeel->setColour (AlertWindow::backgroundColourId, Colour (0xffededed)); + progressWindowLookAndFeel->setColour (AlertWindow::textColourId, Colours::black); + progressWindowLookAndFeel->setColour (AlertWindow::outlineColourId, Colour (0xff666666)); + progressWindowLookAndFeel->setColour (ProgressBar::backgroundColourId, Colours::lightgrey); + progressWindowLookAndFeel->setColour (ProgressBar::foregroundColourId, Colours::orange); + getAlertWindow()->setLookAndFeel (progressWindowLookAndFeel.get()); } -BackgroundLoader::~BackgroundLoader() +BackgroundLoaderWithProgressWindow::~BackgroundLoaderWithProgressWindow() { - - if (isThreadRunning()) - { - waitForThreadToExit(30000); - } - + getAlertWindow()->setLookAndFeel (nullptr); } -void BackgroundLoader::run() +void BackgroundLoaderWithProgressWindow::updateProbeMap() { + std::map, std::pair> updatedMap; - LOGC("Running background thread..."); + ProbeSettings temp; - /* Initializes the NPX-PXI probe connections in the background to prevent this - plugin from blocking the main GUI*/ - if (!isInitialized) - { - LOGC("Not initialized."); - thread->initializeBasestations(signalChainIsLoading); - isInitialized = true; - - //if (!signalChainIsLoading) - //{ - LOGC("Updating settings for ", thread->getProbes().size(), " probes."); - - MessageManagerLock mml; - CoreServices::updateSignalChain(editor); - - for (auto probe : thread->getProbes()) - { - LOGC(" Updating queue for probe ", probe->name); - thread->updateProbeSettingsQueue(ProbeSettings(probe->settings)); - } - - editor->checkCanvas(); - - //} - } + //Assume basestation counts/slots do not change + for (int i = 0; i < thread->getBasestations().size(); i++) + { + Basestation* bs = thread->getBasestations()[i]; + if (bs != nullptr) + { + bs->close(); + bs->open(); + + // Restore sync state + if (editor->inputOutputSyncSelector->getSelectedItemIndex() == 0) + bs->setSyncAsInput(); + + for (auto hs : bs->getHeadstages()) + { + if (hs != nullptr) + { + for (auto probe : hs->getProbes()) + { + if (probe != nullptr) + { + //Check for existing probe settings + std::tuple current_location = std::make_tuple (bs->slot, hs->port, probe->dock); + + LOGD ("Checking for probe at slot ", bs->slot, " port ", hs->port, " dock ", probe->dock); + + if (thread->probeMap.find (current_location) != thread->probeMap.end()) + { + LOGD ("Found matching probe."); + + if (std::get<0> (thread->probeMap[current_location]) == probe->info.serial_number) + { + temp = ProbeSettings (thread->probeMap[current_location].second); + temp.probe = probe; + updatedMap[current_location] = std::make_pair (probe->info.serial_number, temp); + continue; + } + } + + bool found = false; + std::tuple old_location; + + for (auto it = thread->probeMap.begin(); it != thread->probeMap.end(); it++) + { + uint64 old_serial = it->second.first; + if (old_serial == probe->info.serial_number) + { + //Existing probe moved to new location + found = true; + old_location = it->first; + temp = ProbeSettings (it->second.second); + temp.probe = probe; + updatedMap[current_location] = std::make_pair (probe->info.serial_number, temp); + break; + } + } + if (! found) + { + //New probe connected + updatedMap[current_location] = std::make_pair (probe->info.serial_number, probe->settings); + } + } + } + } + } + } + } - LOGC("Initialized, applying probe settings..."); + //Update the probe map + LOGD ("Updating probe map..."); + thread->probeMap = updatedMap; - /* Apply any saved settings */ - thread->applyProbeSettingsQueue(); - + setStatusMessage ("Initializing probes..."); + + LOGD ("Initializing probes..."); + thread->initializeProbes(); + thread->updateStreamInfo(); } -void NeuropixEditor::initialize(bool signalChainIsLoading) +void BackgroundLoaderWithProgressWindow::run() { - uiLoader->signalChainIsLoading = signalChainIsLoading; - uiLoader->startThread(); + setProgress (-1); // endless moving progress bar + + setStatusMessage ("Checking for hardware changes..."); + LOGC ("Scanning for hardware changes..."); + updateProbeMap(); + + thread->isRefreshing = false; } +BackgroundLoader::BackgroundLoader (NeuropixThread* thread_, NeuropixEditor* editor_) + : Thread ("Neuropix Loader"), + thread (thread_), + editor (editor_) +{ +} -NeuropixEditor::NeuropixEditor(GenericProcessor* parentNode, NeuropixThread* t) - : VisualizerEditor(parentNode, t->type == ONEBOX ? "OneBox" : "Neuropix PXI") +BackgroundLoader::~BackgroundLoader() { + if (isThreadRunning()) + { + waitForThreadToExit (30000); + } +} - thread = t; - canvas = nullptr; +void BackgroundLoader::run() +{ + LOGC ("Running background thread..."); - Array basestations = t->getBasestations(); - - bool foundFirst = false; - - int id = 0; - - for (int i = 0; i < basestations.size(); i++) - { - Array headstages = basestations[i]->getHeadstages(); // can return null - - int probeCount = basestations[i]->getProbeCount(); - - for (int j = 0; j < headstages.size(); j++) - { - - int slotIndex = i; - int portIndex = j; - - if (headstages[j] != nullptr) - { - Array probes = headstages[j]->getProbes(); - - for (int k = 0; k < probes.size(); k++) - { - int offset; - - if (probes.size() == 2) - offset = 20 * k; - else - offset = 10; - - int x_pos = slotIndex * 90 + 30 + offset; - int y_pos = 125 - (portIndex + 1) * 22; - - SourceButton* p = new SourceButton(id++, probes[k]); - p->setBounds(x_pos, y_pos, 15, 15); - p->addListener(this); - addAndMakeVisible(p); - sourceButtons.add(p); - } - } - else { - int x_pos = slotIndex * 90 + 40; - int y_pos = 125 - (portIndex + 1) * 22; - - SourceButton* p; - - if (probeCount == 0) - p = new SourceButton(id++, nullptr, basestations[i]); - else - p = new SourceButton(id++, nullptr, nullptr); - - p->setBounds(x_pos, y_pos, 15, 15); - p->addListener(this); - addAndMakeVisible(p); - sourceButtons.add(p); - } - } - - Array additionalDataSources = basestations[i]->getAdditionalDataSources(); // can return null - - for (int j = 0; j < additionalDataSources.size(); j++) - { - LOGD("Creating source button for ADCs"); - - int slotIndex = i; - int portIndex = j + 3; - - int x_pos = slotIndex * 90 + 40; - int y_pos = 125 - (portIndex + 1) * 22; - - SourceButton* p = new SourceButton(id++, additionalDataSources[j]); - p->setBounds(x_pos, y_pos, 15, 15); - p->addListener(this); - addAndMakeVisible(p); - sourceButtons.add(p); - } - } + /* Initializes the NPX-PXI probe connections in the background to prevent this + plugin from blocking the main GUI*/ - + if (! isInitialized) + { + LOGC ("Not initialized."); + thread->initializeBasestations (signalChainIsLoading); + isInitialized = true; - for (int i = 0; i < basestations.size(); i++) - { - int x_pos = i * 90 + 70; - int y_pos = 50; + LOGC ("Updating settings for ", thread->getProbes().size(), " probes."); - UtilityButton* b = new UtilityButton("", Font("Small Text", 13, Font::plain)); - b->setBounds(x_pos, y_pos, 30, 20); - b->addListener(this); - //addAndMakeVisible(b); - directoryButtons.add(b); + //MessageManagerLock mml; + //CoreServices::updateSignalChain (editor); - savingDirectories.add(File()); - slotNamingSchemes.add(0); + bool updateStreamInfoRequired = false; - FifoMonitor* f = new FifoMonitor(i, basestations[i]); - f->setBounds(x_pos + 2, 75, 12, 50); - addAndMakeVisible(f); - f->setSlot(basestations[i]->slot); - fifoMonitors.add(f); - } + for (auto probe : thread->getProbes()) + { + LOGC (" Updating queue for probe ", probe->name); + thread->updateProbeSettingsQueue (ProbeSettings (probe->settings)); - mainSyncSelector = new ComboBox("Basestation that acts as main synchronizer"); - mainSyncSelector->setBounds(90 * (basestations.size())+32, 39, 38, 20); - for (int i = 0; i < basestations.size(); i++) - { - mainSyncSelector->addItem(String(basestations[i]->slot), i + 1); - } - mainSyncSelector->setSelectedItemIndex(0, dontSendNotification); - mainSyncSelector->addListener(this); - addChildComponent(mainSyncSelector); - - inputOutputSyncSelector = new ComboBox("Toggles the main synchronizer as input or output"); - inputOutputSyncSelector->setBounds(90 * (basestations.size())+32, 72, 78, 20); - inputOutputSyncSelector->addItem(String("INPUT"), 1); - inputOutputSyncSelector->addItem(String("OUTPUT"), 2); - inputOutputSyncSelector->setSelectedItemIndex(0, dontSendNotification); - inputOutputSyncSelector->addListener(this); - addChildComponent(inputOutputSyncSelector); - - Array syncFrequencies = t->getSyncFrequencies(); - - syncFrequencySelector = new ComboBox("Select the sync frequency (if in output mode)"); - syncFrequencySelector->setBounds(90 * (basestations.size())+32, 105, 70, 20); - for (int i = 0; i < syncFrequencies.size(); i++) - { - syncFrequencySelector->addItem(String(syncFrequencies[i])+String(" Hz"), i+1); - } - syncFrequencySelector->setSelectedItemIndex(0, dontSendNotification); - syncFrequencySelector->addListener(this); - addChildComponent(syncFrequencySelector); - - - background = new EditorBackground(t, false); - background->setBounds(0, 15, 500, 150); - addAndMakeVisible(background); - background->toBack(); - background->repaint(); - - addSyncChannelButton = new UtilityButton("+", Font("Small Text", 13, Font::plain)); - addSyncChannelButton->setBounds(90 * basestations.size() + 78, 40, 20, 20); - addSyncChannelButton->addListener(this); - addSyncChannelButton->setTooltip("Add sync channel to the continuous data stream."); - addSyncChannelButton->setClickingTogglesState(true); - addChildComponent(addSyncChannelButton); - - if (basestations.size() > 0) - { - mainSyncSelector->setVisible(true); - inputOutputSyncSelector->setVisible(true); - addSyncChannelButton->setVisible(true); - desiredWidth = 100 * basestations.size() + 120; - } - else - { - desiredWidth = 250; - } + if (! probe->isEnabled) + updateStreamInfoRequired = true; + } + + if (updateStreamInfoRequired) + { + thread->updateStreamInfo (true); + MessageManagerLock mml; + CoreServices::updateSignalChain (editor); + } - uiLoader = new BackgroundLoader(t, this); - + //editor->checkCanvas(); + } + + LOGC ("Initialized, applying probe settings..."); + + /* Apply any queued settings */ + thread->applyProbeSettingsQueue(); } -void NeuropixEditor::collapsedStateChanged() +void NeuropixEditor::resetCanvas() { - if (inputOutputSyncSelector->getSelectedId() == 1) - syncFrequencySelector->setVisible(false); + if (canvas != nullptr) + { + VisualizerEditor::canvas.reset(); + + checkForCanvas(); + + if (tabIndex != -1) + { + removeTab (tabIndex); + addTab (thread->type == ONEBOX ? "OneBox" : "Neuropix PXI", + VisualizerEditor::canvas.get()); + } + else + { + if (dataWindow != nullptr) + dataWindow->setContentNonOwned (VisualizerEditor::canvas.get(), false); + } + } } -void NeuropixEditor::update() +void NeuropixEditor::initialize (bool signalChainIsLoading) { - if (canvas != nullptr) - canvas->update(); + uiLoader->signalChainIsLoading = signalChainIsLoading; + uiLoader->startThread(); + + checkCanvas(); } -void NeuropixEditor::comboBoxChanged(ComboBox* comboBox) +NeuropixEditor::~NeuropixEditor() { + LOGD ("NeuropixEditor destructor."); - int slotIndex = mainSyncSelector->getSelectedId() - 1; - - if (comboBox == mainSyncSelector) - { - thread->setMainSync(slotIndex); - inputOutputSyncSelector->setSelectedItemIndex(0, true); - syncFrequencySelector->setVisible(false); - background->setFreqSelectAvailable(false); - syncFrequencySelector->setSelectedItemIndex(0, true); - } - else if (comboBox == inputOutputSyncSelector) - { - bool asOutput = inputOutputSyncSelector->getSelectedId() == 2; - - if (asOutput) - { - thread->setSyncOutput(slotIndex); - syncFrequencySelector->setVisible(true); - background->setFreqSelectAvailable(true); - } - else - { - thread->setMainSync(slotIndex); - syncFrequencySelector->setVisible(false); - background->setFreqSelectAvailable(false); - } - - syncFrequencySelector->setSelectedItemIndex(0, true); - } - else /* comboBox == freqSelectBox */ - { - int freqIndex = syncFrequencySelector->getSelectedId() - 1; - thread->setSyncFrequency(slotIndex, freqIndex); + if (uiLoader->isThreadRunning()) + { + uiLoader->waitForThreadToExit (5000); } - background->repaint(); - } -void NeuropixEditor::startAcquisition() +NeuropixEditor::NeuropixEditor (GenericProcessor* parentNode, NeuropixThread* t) + : VisualizerEditor (parentNode, t->type == ONEBOX ? "OneBox" : "Neuropix PXI") { + canvas = nullptr; - if (canvas) - canvas->startAcquisition(); + thread = t; + Array basestations = t->getBasestations(); - addSyncChannelButton->setEnabled(false); - background->setEnabled(false); -} + drawBasestations (basestations); -void NeuropixEditor::stopAcquisition() -{ - if (canvas) - canvas->stopAcquisition(); + mainSyncSelector = std::make_unique ("Basestation that acts as main synchronizer"); + mainSyncSelector->setBounds (90 * (basestations.size()) + 32, 39, 50, 20); + for (int i = 0; i < basestations.size(); i++) + { + mainSyncSelector->addItem (String (basestations[i]->slot), i + 1); + } + mainSyncSelector->setSelectedItemIndex (0, dontSendNotification); + mainSyncSelector->addListener (this); + addChildComponent (mainSyncSelector.get()); + + inputOutputSyncSelector = std::make_unique ("Toggles the main synchronizer as input or output"); + inputOutputSyncSelector->setBounds (90 * (basestations.size()) + 32, 74, 78, 20); + inputOutputSyncSelector->addItem (String ("INPUT"), 1); + inputOutputSyncSelector->addItem (String ("OUTPUT"), 2); + inputOutputSyncSelector->setSelectedItemIndex (0, dontSendNotification); + inputOutputSyncSelector->addListener (this); + addChildComponent (inputOutputSyncSelector.get()); + + Array syncFrequencies = t->getSyncFrequencies(); + + // syncFrequencySelector = std::make_unique ("Select the sync frequency (if in output mode)"); + // syncFrequencySelector->setBounds (90 * (basestations.size()) + 32, 105, 70, 20); + // for (int i = 0; i < syncFrequencies.size(); i++) + // { + // syncFrequencySelector->addItem (String (syncFrequencies[i]) + String (" Hz"), i + 1); + // } + // syncFrequencySelector->setSelectedItemIndex (0, dontSendNotification); + // syncFrequencySelector->addListener (this); + // addChildComponent (syncFrequencySelector.get()); + + syncFrequencyLabel = std::make_unique